From d0aa4e236883fc7e118cab32207e8d585a935023 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Sun, 20 May 2012 23:27:38 -0300 Subject: Add support for a priority table when writing files. --- src/luarocks/persist.lua | 68 ++++++++++++++++++++++++++++++++++-------------- src/luarocks/util.lua | 35 +++++++++++++++++++++---- 2 files changed, 79 insertions(+), 24 deletions(-) diff --git a/src/luarocks/persist.lua b/src/luarocks/persist.lua index 182b3da6..0d37b04a 100644 --- a/src/luarocks/persist.lua +++ b/src/luarocks/persist.lua @@ -45,6 +45,37 @@ function load_into_table(filename, tbl) return result 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. +-- @param v: the value to be written. +-- @param level number: the indentation level +-- @param sub_order table: optional prioritization table +-- @see write_table +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 + local open, close = "[[", "]]" + local equals = 0 + while v:find(open,1,true) or 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("\"", "\\\"").."\"") + 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 @@ -52,21 +83,23 @@ end -- @param out userdata: a file object, open for writing. -- @param tbl table: the table to be written. -- @param level number: the indentation level -local function write_table(out, tbl, 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 in util.sortedpairs(tbl) do + for k, v, sub_order in util.sortedpairs(tbl, field_order) do out:write(sep) if indent then - for n = 1,level do out:write(" ") end + 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).."]=") + out:write("["..tostring(k).."]=") else i = i + 1 end @@ -75,25 +108,19 @@ local function write_table(out, tbl, level) elseif type(k) == "table" then out:write("[") write_table(out, k, level + 1) - out:write("]=") + out:write("] = ") else - if k:match("^[a-z_]+$") then - out:write(k.."=") + if k:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then + out:write(k.." = ") else - out:write("['"..k:gsub("'", "\\'").."']=") + out:write("['"..k:gsub("'", "\\'").."'] = ") end end - if type(v) == "table" then - write_table(out, v, level + 1) - elseif type(v) == "string" then - out:write("'"..v:gsub("'", "\\'").."'") - else - out:write(tostring(v)) - end + write_value(out, v, level, sub_order) end if sep ~= "\n" then out:write("\n") - for n = 1,level-1 do out:write(" ") end + for n = 1,level-1 do out:write(indentation) end end out:write("}") end @@ -102,16 +129,19 @@ end -- 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 save_from_table(filename, tbl) +function save_from_table(filename, tbl, field_order) local out = io.open(filename, "w") if not out then return nil, "Cannot create file at "..filename end - for k, v in util.sortedpairs(tbl) do + for k, v, sub_order in util.sortedpairs(tbl, field_order) do out:write(k.." = ") - write_table(out, v, 1) + write_value(out, v, 0, sub_order) out:write("\n") end out:close() diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua index 96ea03b8..2955be50 100644 --- a/src/luarocks/util.lua +++ b/src/luarocks/util.lua @@ -236,17 +236,42 @@ end -- @see sortedpairs local function sortedpairs_iterator(tbl, sort_function) local ks = keys(tbl) - table.sort(ks, sort_function or default_sort) - for _, k in ipairs(ks) do - coroutine.yield(k, tbl[k]) + if not sort_function or type(sort_function) == "function" then + table.sort(ks, sort_function or default_sort) + for _, k in ipairs(ks) do + coroutine.yield(k, tbl[k]) + end + else + local order = sort_function + local done = {} + for _, k in ipairs(order) do + local sub_order + if type(k) == "table" then + sub_order = k[2] + k = k[1] + end + if tbl[k] then + done[k] = true + coroutine.yield(k, tbl[k], sub_order) + end + end + table.sort(ks, default_sort) + for _, k in ipairs(ks) do + if not done[k] then + coroutine.yield(k, tbl[k]) + end + end end end --- A table iterator generator that returns elements sorted by key, -- to be used in "for" loops. -- @param tbl table: The table to be iterated. --- @param sort_function function or nil: An optional comparison function --- to be used by table.sort when sorting keys. +-- @param sort_function function or table or nil: An optional comparison function +-- to be used by table.sort when sorting keys, or an array listing an explicit order +-- for keys. If a value itself is an array, it is taken so that the first element +-- is a string representing the field name, and the second element is a priority table +-- for that key. -- @return function: the iterator function. function sortedpairs(tbl, sort_function) return coroutine.wrap(function() sortedpairs_iterator(tbl, sort_function) end) -- cgit v1.2.3-55-g6feb