From a50299e1d6b280f5ca635b2c7ac9fe889befd6d6 Mon Sep 17 00:00:00 2001 From: V1K1NGbg Date: Tue, 30 Jul 2024 13:05:10 +0300 Subject: test persist --- src/luarocks/core/cfg.d.tl | 2 +- src/luarocks/fs.d.tl | 2 +- src/luarocks/persist-original.lua | 259 ++++++++++++++++++++++++++++++++++++++ src/luarocks/persist.lua | 171 +++++++++++++------------ 4 files changed, 352 insertions(+), 82 deletions(-) create mode 100644 src/luarocks/persist-original.lua diff --git a/src/luarocks/core/cfg.d.tl b/src/luarocks/core/cfg.d.tl index 33b9be66..fccfe0e3 100644 --- a/src/luarocks/core/cfg.d.tl +++ b/src/luarocks/core/cfg.d.tl @@ -54,7 +54,7 @@ local record cfg record cache luajit_version_checked: boolean luajit_version: string - rocks_provided: {string: string} --? right type? infered from + rocks_provided: {string: string} --? right type? infered from util end record variables diff --git a/src/luarocks/fs.d.tl b/src/luarocks/fs.d.tl index 80747f9b..88034b65 100644 --- a/src/luarocks/fs.d.tl +++ b/src/luarocks/fs.d.tl @@ -8,7 +8,7 @@ local record fs end -- util is_dir: function(dir: string): boolean - dir: function(dir: string): function(): string --? right iterator + dir: function(dir: string): function(): string make_dir: function(string): boolean, string is_file: function(file: string): boolean current_dir: function(): string diff --git a/src/luarocks/persist-original.lua b/src/luarocks/persist-original.lua new file mode 100644 index 00000000..4dcd930a --- /dev/null +++ b/src/luarocks/persist-original.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 diff --git a/src/luarocks/persist.lua b/src/luarocks/persist.lua index 4dcd930a..eb501f2e 100644 --- a/src/luarocks/persist.lua +++ b/src/luarocks/persist.lua @@ -1,26 +1,38 @@ +local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local io = _tl_compat and _tl_compat.io or io; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table + ---- 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") +local cfg = require("luarocks.core.cfg") + + + 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 @@ -29,13 +41,13 @@ function persist.write_value(out, v, level, sub_order) if v:match("[\r\n]") then local open, close = "[[", "]]" local equals = 0 - local v_with_bracket = v.."]" + 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.."]" + open, close = "[" .. eqs .. "[", "]" .. eqs .. "]" end - out:write(open.."\n"..v..close) + out:write(open .. "\n" .. v .. close) else out:write(("%q"):format(v)) end @@ -71,14 +83,13 @@ do ["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] + return 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 + if type(k) == "string" and is_valid_plain_key(k) then out:write(k) else out:write("[") @@ -89,26 +100,26 @@ local function write_table_key_assignment(out, k, level) 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) + + + + + + + +write_table = function(out, tbl, level, sort_by) 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 + for k, v, sub_order in util.sortedpairs(tbl, sort_by) do out:write(sep) if indent then for _ = 1, level do out:write(indentation) end end - if k == i then + if type(k) == "number" then i = i + 1 else write_table_key_assignment(out, k, level) @@ -130,26 +141,26 @@ write_table = function(out, tbl, level, field_order) 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." + + + + + +local function write_table_as_assignments(out, tbl, sort_by) + for k, v, sub_order in util.sortedpairs(tbl, sort_by) do + if not (type(k) == "string" and is_valid_plain_key(k)) then + return nil, "cannot store '" .. tostring(k) .. "' as a plain key." end - out:write(k.." = ") + 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 @@ -161,40 +172,40 @@ local function write_table_as_table(out, tbl) 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 persist.save_from_table_to_string(tbl, sort_by) + local out = { buffer = {} } function out:write(data) table.insert(self.buffer, data) end - local ok, err = write_table_as_assignments(out, tbl, field_order) + local ok, err = write_table_as_assignments(out, tbl, sort_by) 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) + + + + + + + + + +function persist.save_from_table(filename, tbl, sort_by) 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 + return nil, "Cannot create file at " .. filename end - local ok, err = write_table_as_assignments(out, tbl, field_order) + local ok, err = write_table_as_assignments(out, tbl, sort_by) out:close() if not ok then return nil, err @@ -202,37 +213,37 @@ function persist.save_from_table(filename, tbl, field_order) 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 + 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) +function persist.load_config_file_if_basic(filename, config) local env = { - home = cfg.home + home = config.home, } - local result, err, errcode = persist.load_into_table(filename, env) + local result, _, 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 @@ -243,13 +254,13 @@ function persist.load_config_file_if_basic(filename, cfg) end function persist.save_default_lua_version(prefix, lua_version) - local ok, err = fs.make_dir(prefix) + local ok, err_makedir = fs.make_dir(prefix) if not ok then - return nil, err + return nil, err_makedir end - local fd, err = io.open(dir.path(prefix, "default-lua-version.lua"), "w") + local fd, err_open = io.open(dir.path(prefix, "default-lua-version.lua"), "w") if not fd then - return nil, err + return nil, err_open end fd:write('return "' .. lua_version .. '"\n') fd:close() -- cgit v1.2.3-55-g6feb