summaryrefslogtreecommitdiff
path: root/src/luarocks/persist.lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/luarocks/persist.lua')
-rw-r--r--src/luarocks/persist.lua259
1 files changed, 259 insertions, 0 deletions
diff --git a/src/luarocks/persist.lua b/src/luarocks/persist.lua
new file mode 100644
index 0000000..4dcd930
--- /dev/null
+++ b/src/luarocks/persist.lua
@@ -0,0 +1,259 @@
+
+--- Utility module for loading files into tables and
+-- saving tables into files.
+local persist = {}
+
+local core = require("luarocks.core.persist")
+local util = require("luarocks.util")
+local dir = require("luarocks.dir")
+local fs = require("luarocks.fs")
+
+persist.run_file = core.run_file
+persist.load_into_table = core.load_into_table
+
+local write_table
+
+--- 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
+-- @see write_table
+function persist.write_value(out, v, level, sub_order)
+ if type(v) == "table" then
+ level = level or 0
+ write_table(out, v, level + 1, sub_order)
+ elseif type(v) == "string" then
+ if v:match("[\r\n]") then
+ local open, close = "[[", "]]"
+ local equals = 0
+ local v_with_bracket = v.."]"
+ while v_with_bracket: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(("%q"):format(v))
+ end
+ else
+ out:write(tostring(v))
+ end
+end
+
+local is_valid_plain_key
+do
+ local keywords = {
+ ["and"] = true,
+ ["break"] = true,
+ ["do"] = true,
+ ["else"] = true,
+ ["elseif"] = true,
+ ["end"] = true,
+ ["false"] = true,
+ ["for"] = true,
+ ["function"] = true,
+ ["goto"] = true,
+ ["if"] = true,
+ ["in"] = true,
+ ["local"] = true,
+ ["nil"] = true,
+ ["not"] = true,
+ ["or"] = true,
+ ["repeat"] = true,
+ ["return"] = true,
+ ["then"] = true,
+ ["true"] = true,
+ ["until"] = true,
+ ["while"] = true,
+ }
+ function is_valid_plain_key(k)
+ return type(k) == "string"
+ and k:match("^[a-zA-Z_][a-zA-Z0-9_]*$")
+ and not keywords[k]
+ end
+end
+
+local function write_table_key_assignment(out, k, level)
+ if is_valid_plain_key(k) then
+ out:write(k)
+ else
+ out:write("[")
+ persist.write_value(out, k, level)
+ out:write("]")
+ end
+
+ out:write(" = ")
+end
+
+--- 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
+write_table = function(out, tbl, level, field_order)
+ out:write("{")
+ local sep = "\n"
+ local indentation = " "
+ local indent = true
+ local i = 1
+ for k, v, sub_order in util.sortedpairs(tbl, field_order) do
+ out:write(sep)
+ if indent then
+ for _ = 1, level do out:write(indentation) end
+ end
+
+ if k == i then
+ i = i + 1
+ else
+ write_table_key_assignment(out, k, level)
+ end
+
+ persist.write_value(out, v, level, sub_order)
+ if type(v) == "number" then
+ sep = ", "
+ indent = false
+ else
+ sep = ",\n"
+ indent = true
+ end
+ end
+ if sep ~= "\n" then
+ out:write("\n")
+ for _ = 1, level - 1 do out:write(indentation) end
+ end
+ out:write("}")
+end
+
+--- 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 true if successful; nil and error message if failed.
+local function write_table_as_assignments(out, tbl, field_order)
+ for k, v, sub_order in util.sortedpairs(tbl, field_order) do
+ if not is_valid_plain_key(k) then
+ return nil, "cannot store '"..tostring(k).."' as a plain key."
+ end
+ out:write(k.." = ")
+ persist.write_value(out, v, 0, sub_order)
+ out:write("\n")
+ end
+ return true
+end
+
+--- Write a table using Lua table syntax to a writer object.
+-- @param out table or userdata: a writer object supporting :write() method.
+-- @param tbl table: the table to be written.
+local function write_table_as_table(out, tbl)
+ out:write("return {\n")
+ for k, v, sub_order in util.sortedpairs(tbl) do
+ out:write(" ")
+ write_table_key_assignment(out, k, 1)
+ persist.write_value(out, v, 1, sub_order)
+ out:write(",\n")
+ end
+ out:write("}\n")
+end
+
+--- Save the contents of a table to a string.
+-- Each element of the table is saved as a global assignment.
+-- Only numbers, strings and tables (containing numbers, strings
+-- or other recursively processed tables) are supported.
+-- @param tbl table: the table containing the data to be written
+-- @param field_order table: an optional array indicating the order of top-level fields.
+-- @return persisted data as string; or nil and an error message
+function persist.save_from_table_to_string(tbl, field_order)
+ local out = {buffer = {}}
+ function out:write(data) table.insert(self.buffer, data) end
+ local ok, err = write_table_as_assignments(out, tbl, field_order)
+ if not ok then
+ return nil, err
+ end
+ return table.concat(out.buffer)
+end
+
+--- Save the contents of a table in a file.
+-- Each element of the table is saved as a global assignment.
+-- Only numbers, strings and tables (containing numbers, strings
+-- or other recursively processed tables) are supported.
+-- @param filename string: the output filename
+-- @param tbl table: the table containing the data to be written
+-- @param field_order table: an optional array indicating the order of top-level fields.
+-- @return boolean or (nil, string): true if successful, or nil and a
+-- message in case of errors.
+function persist.save_from_table(filename, tbl, field_order)
+ local prefix = dir.dir_name(filename)
+ fs.make_dir(prefix)
+ local out = io.open(filename, "w")
+ if not out then
+ return nil, "Cannot create file at "..filename
+ end
+ local ok, err = write_table_as_assignments(out, tbl, field_order)
+ out:close()
+ if not ok then
+ return nil, err
+ end
+ return true
+end
+
+--- Save the contents of a table as a module.
+-- The module contains a 'return' statement that returns the table.
+-- Only numbers, strings and tables (containing numbers, strings
+-- or other recursively processed tables) are supported.
+-- @param filename string: the output filename
+-- @param tbl table: the table containing the data to be written
+-- @return boolean or (nil, string): true if successful, or nil and a
+-- message in case of errors.
+function persist.save_as_module(filename, tbl)
+ local out = io.open(filename, "w")
+ if not out then
+ return nil, "Cannot create file at "..filename
+ end
+ write_table_as_table(out, tbl)
+ out:close()
+ return true
+end
+
+function persist.load_config_file_if_basic(filename, cfg)
+ local env = {
+ home = cfg.home
+ }
+ local result, err, errcode = persist.load_into_table(filename, env)
+ if errcode == "load" or errcode == "run" then
+ -- bad config file or depends on env, so error out
+ return nil, "Could not read existing config file " .. filename
+ end
+
+ local tbl
+ if errcode == "open" then
+ -- could not open, maybe file does not exist
+ tbl = {}
+ else
+ tbl = result
+ tbl.home = nil
+ end
+
+ return tbl
+end
+
+function persist.save_default_lua_version(prefix, lua_version)
+ local ok, err = fs.make_dir(prefix)
+ if not ok then
+ return nil, err
+ end
+ local fd, err = io.open(dir.path(prefix, "default-lua-version.lua"), "w")
+ if not fd then
+ return nil, err
+ end
+ fd:write('return "' .. lua_version .. '"\n')
+ fd:close()
+ return true
+end
+
+return persist