diff options
| -rw-r--r-- | spec/persist_spec.lua | 8 | ||||
| -rw-r--r-- | src/luarocks/persist.lua | 75 |
2 files changed, 70 insertions, 13 deletions
diff --git a/spec/persist_spec.lua b/spec/persist_spec.lua index dccb0ec4..734b2a4e 100644 --- a/spec/persist_spec.lua +++ b/spec/persist_spec.lua | |||
| @@ -36,6 +36,14 @@ foo = { | |||
| 36 | ]], persist.save_from_table_to_string({foo = {1, 2, 3, 4}, bar = {baz = "string"}})) | 36 | ]], persist.save_from_table_to_string({foo = {1, 2, 3, 4}, bar = {baz = "string"}})) |
| 37 | end) | 37 | end) |
| 38 | 38 | ||
| 39 | it("table with a keyword key (#947)", function() | ||
| 40 | assert.are.same([[ | ||
| 41 | bar = { | ||
| 42 | ["function"] = "foo" | ||
| 43 | } | ||
| 44 | ]], persist.save_from_table_to_string({bar = {["function"] = "foo"}})) | ||
| 45 | end) | ||
| 46 | |||
| 39 | it("strings with quotes", function() | 47 | it("strings with quotes", function() |
| 40 | assert.are.same([[ | 48 | assert.are.same([[ |
| 41 | bar = "a \\backslash?" | 49 | bar = "a \\backslash?" |
diff --git a/src/luarocks/persist.lua b/src/luarocks/persist.lua index 6dc8b9ab..73f92bea 100644 --- a/src/luarocks/persist.lua +++ b/src/luarocks/persist.lua | |||
| @@ -42,6 +42,51 @@ local function write_value(out, v, level, sub_order) | |||
| 42 | end | 42 | end |
| 43 | end | 43 | end |
| 44 | 44 | ||
| 45 | local is_valid_plain_key | ||
| 46 | do | ||
| 47 | local keywords = { | ||
| 48 | ["and"] = true, | ||
| 49 | ["break"] = true, | ||
| 50 | ["do"] = true, | ||
| 51 | ["else"] = true, | ||
| 52 | ["elseif"] = true, | ||
| 53 | ["end"] = true, | ||
| 54 | ["false"] = true, | ||
| 55 | ["for"] = true, | ||
| 56 | ["function"] = true, | ||
| 57 | ["goto"] = true, | ||
| 58 | ["if"] = true, | ||
| 59 | ["in"] = true, | ||
| 60 | ["local"] = true, | ||
| 61 | ["nil"] = true, | ||
| 62 | ["not"] = true, | ||
| 63 | ["or"] = true, | ||
| 64 | ["repeat"] = true, | ||
| 65 | ["return"] = true, | ||
| 66 | ["then"] = true, | ||
| 67 | ["true"] = true, | ||
| 68 | ["until"] = true, | ||
| 69 | ["while"] = true, | ||
| 70 | } | ||
| 71 | function is_valid_plain_key(k) | ||
| 72 | return type(k) == "string" | ||
| 73 | and k:match("^[a-zA-Z_][a-zA-Z0-9_]*$") | ||
| 74 | and not keywords[k] | ||
| 75 | end | ||
| 76 | end | ||
| 77 | |||
| 78 | local function write_table_key_assignment(out, k, level) | ||
| 79 | if is_valid_plain_key(k) then | ||
| 80 | out:write(k) | ||
| 81 | else | ||
| 82 | out:write("[") | ||
| 83 | write_value(out, k, level) | ||
| 84 | out:write("]") | ||
| 85 | end | ||
| 86 | |||
| 87 | out:write(" = ") | ||
| 88 | end | ||
| 89 | |||
| 45 | --- Write a table as Lua code in curly brackets notation to a writer object. | 90 | --- Write a table as Lua code in curly brackets notation to a writer object. |
| 46 | -- Only numbers, strings and tables (containing numbers, strings | 91 | -- Only numbers, strings and tables (containing numbers, strings |
| 47 | -- or other recursively processed tables) are supported. | 92 | -- or other recursively processed tables) are supported. |
| @@ -64,15 +109,7 @@ write_table = function(out, tbl, level, field_order) | |||
| 64 | if k == i then | 109 | if k == i then |
| 65 | i = i + 1 | 110 | i = i + 1 |
| 66 | else | 111 | else |
| 67 | if type(k) == "string" and k:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then | 112 | write_table_key_assignment(out, k, level) |
| 68 | out:write(k) | ||
| 69 | else | ||
| 70 | out:write("[") | ||
| 71 | write_value(out, k, level) | ||
| 72 | out:write("]") | ||
| 73 | end | ||
| 74 | |||
| 75 | out:write(" = ") | ||
| 76 | end | 113 | end |
| 77 | 114 | ||
| 78 | write_value(out, v, level, sub_order) | 115 | write_value(out, v, level, sub_order) |
| @@ -95,12 +132,17 @@ end | |||
| 95 | -- @param out table or userdata: a writer object supporting :write() method. | 132 | -- @param out table or userdata: a writer object supporting :write() method. |
| 96 | -- @param tbl table: the table to be written. | 133 | -- @param tbl table: the table to be written. |
| 97 | -- @param field_order table: optional prioritization table | 134 | -- @param field_order table: optional prioritization table |
| 135 | -- @return true if successful; nil and error message if failed. | ||
| 98 | local function write_table_as_assignments(out, tbl, field_order) | 136 | local function write_table_as_assignments(out, tbl, field_order) |
| 99 | for k, v, sub_order in util.sortedpairs(tbl, field_order) do | 137 | for k, v, sub_order in util.sortedpairs(tbl, field_order) do |
| 138 | if not is_valid_plain_key(k) then | ||
| 139 | return nil, "cannot store '"..tostring(k).."' as a plain key." | ||
| 140 | end | ||
| 100 | out:write(k.." = ") | 141 | out:write(k.." = ") |
| 101 | write_value(out, v, 0, sub_order) | 142 | write_value(out, v, 0, sub_order) |
| 102 | out:write("\n") | 143 | out:write("\n") |
| 103 | end | 144 | end |
| 145 | return true | ||
| 104 | end | 146 | end |
| 105 | 147 | ||
| 106 | --- Write a table as series of assignments to a writer object. | 148 | --- Write a table as series of assignments to a writer object. |
| @@ -109,7 +151,8 @@ end | |||
| 109 | local function write_table_as_table(out, tbl) | 151 | local function write_table_as_table(out, tbl) |
| 110 | out:write("return {\n") | 152 | out:write("return {\n") |
| 111 | for k, v, sub_order in util.sortedpairs(tbl) do | 153 | for k, v, sub_order in util.sortedpairs(tbl) do |
| 112 | out:write(" " .. k .. " = ") | 154 | out:write(" ") |
| 155 | write_table_key_assignment(out, k, 1) | ||
| 113 | write_value(out, v, 1, sub_order) | 156 | write_value(out, v, 1, sub_order) |
| 114 | out:write(",\n") | 157 | out:write(",\n") |
| 115 | end | 158 | end |
| @@ -122,11 +165,14 @@ end | |||
| 122 | -- or other recursively processed tables) are supported. | 165 | -- or other recursively processed tables) are supported. |
| 123 | -- @param tbl table: the table containing the data to be written | 166 | -- @param tbl table: the table containing the data to be written |
| 124 | -- @param field_order table: an optional array indicating the order of top-level fields. | 167 | -- @param field_order table: an optional array indicating the order of top-level fields. |
| 125 | -- @return string | 168 | -- @return persisted data as string; or nil and an error message |
| 126 | function persist.save_from_table_to_string(tbl, field_order) | 169 | function persist.save_from_table_to_string(tbl, field_order) |
| 127 | local out = {buffer = {}} | 170 | local out = {buffer = {}} |
| 128 | function out:write(data) table.insert(self.buffer, data) end | 171 | function out:write(data) table.insert(self.buffer, data) end |
| 129 | write_table_as_assignments(out, tbl, field_order) | 172 | local ok, err = write_table_as_assignments(out, tbl, field_order) |
| 173 | if not ok then | ||
| 174 | return nil, err | ||
| 175 | end | ||
| 130 | return table.concat(out.buffer) | 176 | return table.concat(out.buffer) |
| 131 | end | 177 | end |
| 132 | 178 | ||
| @@ -144,8 +190,11 @@ function persist.save_from_table(filename, tbl, field_order) | |||
| 144 | if not out then | 190 | if not out then |
| 145 | return nil, "Cannot create file at "..filename | 191 | return nil, "Cannot create file at "..filename |
| 146 | end | 192 | end |
| 147 | write_table_as_assignments(out, tbl, field_order) | 193 | local ok, err = write_table_as_assignments(out, tbl, field_order) |
| 148 | out:close() | 194 | out:close() |
| 195 | if not ok then | ||
| 196 | return nil, err | ||
| 197 | end | ||
| 149 | return true | 198 | return true |
| 150 | end | 199 | end |
| 151 | 200 | ||
