diff options
Diffstat (limited to 'luarocks/src/luarocks/persist.lua')
-rw-r--r-- | luarocks/src/luarocks/persist.lua | 151 |
1 files changed, 87 insertions, 64 deletions
diff --git a/luarocks/src/luarocks/persist.lua b/luarocks/src/luarocks/persist.lua index 9d601a4..354b17c 100644 --- a/luarocks/src/luarocks/persist.lua +++ b/luarocks/src/luarocks/persist.lua @@ -9,60 +9,85 @@ package.loaded["luarocks.persist"] = persist local util = require("luarocks.util") +--- Load and run a Lua file in an environment. +-- @param filename string: the name of the file. +-- @param env table: the environment table. +-- @return (true, any) or (nil, string, string): true and the return value +-- of the file, or nil, an error message and an error code ("open", "load" +-- or "run") in case of errors. +local function run_file(filename, env) + local fd, err = io.open(filename) + if not fd then + return nil, err, "open" + end + local str, err = fd:read("*a") + fd:close() + if not str then + return nil, err, "open" + end + str = str:gsub("^#![^\n]*\n", "") + local chunk, ran + if _VERSION == "Lua 5.1" then -- Lua 5.1 + chunk, err = loadstring(str, filename) + if chunk then + setfenv(chunk, env) + ran, err = pcall(chunk) + end + else -- Lua 5.2 + chunk, err = load(str, filename, "t", env) + if chunk then + ran, err = pcall(chunk) + end + end + if not chunk then + return nil, "Error loading file: "..err, "load" + end + if not ran then + return nil, "Error running file: "..err, "run" + end + return true, err +end + --- Load a Lua file containing assignments, storing them in a table. -- The global environment is not propagated to the loaded file. -- @param filename string: the name of the file. -- @param tbl table or nil: if given, this table is used to store -- loaded values. --- @return table or (nil, string): a table with the file's assignments --- as fields, or nil and a message in case of errors. +-- @return (table, table) or (nil, string, string): a table with the file's assignments +-- as fields and set of undefined globals accessed in file, +-- or nil, an error message and an error code ("open"; couldn't open the file, +-- "load"; compile-time error, or "run"; run-time error) +-- in case of errors. function persist.load_into_table(filename, tbl) assert(type(filename) == "string") assert(type(tbl) == "table" or not tbl) - local result, chunk, ran, err - result = tbl or {} + local result = tbl or {} local globals = {} local globals_mt = { - __index = function(t, n) - globals[n] = true - return rawget(t, n) + __index = function(t, k) + globals[k] = true end } local save_mt = getmetatable(result) setmetatable(result, globals_mt) - if _VERSION == "Lua 5.1" then -- Lua 5.1 - chunk, err = loadfile(filename) - if chunk then - setfenv(chunk, result) - ran, err = pcall(chunk) - end - else -- Lua 5.2 - chunk, err = loadfile(filename, "t", result) - if chunk then - ran, err = pcall(chunk) - end - end - setmetatable(result, save_mt) - if not chunk then - if err:sub(1,5) ~= filename:sub(1,5) then - return false, err - end - return nil, "Error loading file: "..err - end - if not ran then - return nil, "Error running file: "..err + local ok, err, errcode = run_file(filename, result) + + setmetatable(result, save_mt) + + if not ok then + return nil, err, errcode end return result, globals end local write_table ---- Write a value as Lua code, invoking write_table. --- This function handles only numbers, strings and tables --- are keys (tables are handled recursively). --- @param out userdata: a file object, open for writing. +--- Write a value as Lua code. +-- This function handles only numbers and strings, invoking write_table +-- to write tables. +-- @param out table or userdata: a writer object supporting :write() method. -- @param v: the value to be written. -- @param level number: the indentation level -- @param sub_order table: optional prioritization table @@ -71,28 +96,27 @@ local function write_value(out, v, level, sub_order) if type(v) == "table" then write_table(out, v, level + 1, sub_order) elseif type(v) == "string" then - if v:match("\n") then + if v:match("[\r\n]") then local open, close = "[[", "]]" local equals = 0 - while v:find(open,1,true) or v:find(close,1,true) do + while v:find(close, 1, true) do equals = equals + 1 local eqs = ("="):rep(equals) open, close = "["..eqs.."[", "]"..eqs.."]" end out:write(open.."\n"..v..close) else - out:write("\""..v:gsub("\"", "\\\"").."\"") + out:write("\""..v:gsub("\\", "\\\\"):gsub("\"", "\\\"").."\"") end else out:write(tostring(v)) end end ---- Write a table as Lua code representing a table to disk --- (that is, in curly brackets notation). --- This function handles only numbers, strings and tables --- are keys (tables are handled recursively). --- @param out userdata: a file object, open for writing. +--- Write a table as Lua code in curly brackets notation to a writer object. +-- Only numbers, strings and tables (containing numbers, strings +-- or other recursively processed tables) are supported. +-- @param out table or userdata: a writer object supporting :write() method. -- @param tbl table: the table to be written. -- @param level number: the indentation level -- @param field_order table: optional prioritization table @@ -107,28 +131,29 @@ write_table = function(out, tbl, level, field_order) if indent then for n = 1,level do out:write(indentation) end end - sep = ",\n" - indent = true - if type(k) == "number" then - if k ~= i then - out:write("["..tostring(k).."]=") - else - i = i + 1 - end - indent = false - sep = ", " - elseif type(k) == "table" then - out:write("[") - write_table(out, k, level + 1) - out:write("] = ") + + if k == i then + i = i + 1 else - if k:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then - out:write(k.." = ") + if type(k) == "string" and k:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then + out:write(k) else - out:write("['"..k:gsub("'", "\\'").."'] = ") + out:write("[") + write_value(out, k, level) + out:write("]") end + + out:write(" = ") end + write_value(out, v, level, sub_order) + if type(k) == "number" then + sep = ", " + indent = false + else + sep = ",\n" + indent = true + end end if sep ~= "\n" then out:write("\n") @@ -137,18 +162,16 @@ write_table = function(out, tbl, level, field_order) out:write("}") end ---- Writes a table to an io-like object. --- @param out userdata: a file object, open for writing. +--- Write a table as series of assignments to a writer object. +-- @param out table or userdata: a writer object supporting :write() method. -- @param tbl table: the table to be written. -- @param field_order table: optional prioritization table --- @return userdata The file object originally passed in as the `out` parameter. -local function write_table(out, tbl, field_order) +local function write_table_as_assignments(out, tbl, field_order) for k, v, sub_order in util.sortedpairs(tbl, field_order) do out:write(k.." = ") write_value(out, v, 0, sub_order) out:write("\n") end - return out end --- Save the contents of a table to a string. @@ -161,7 +184,7 @@ end function persist.save_from_table_to_string(tbl, field_order) local out = {buffer = {}} function out:write(data) table.insert(self.buffer, data) end - write_table(out, tbl, field_order) + write_table_as_assignments(out, tbl, field_order) return table.concat(out.buffer) end @@ -179,7 +202,7 @@ function persist.save_from_table(filename, tbl, field_order) if not out then return nil, "Cannot create file at "..filename end - write_table(out, tbl, field_order) + write_table_as_assignments(out, tbl, field_order) out:close() return true end |