Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
--- 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