summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3build/l3build-file-functions.lua
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2021-05-06 03:00:58 +0000
committerNorbert Preining <norbert@preining.info>2021-05-06 03:00:58 +0000
commit25f20b6d8ccd4edcdfec23c1a3c908516076ee06 (patch)
treef889e071118d7d2db80066d14d14b020c50a2238 /macros/latex/contrib/l3build/l3build-file-functions.lua
parent75db33dc347ec9cfbaa2f3ec538a2697351f571b (diff)
CTAN sync 202105060300
Diffstat (limited to 'macros/latex/contrib/l3build/l3build-file-functions.lua')
-rw-r--r--macros/latex/contrib/l3build/l3build-file-functions.lua128
1 files changed, 77 insertions, 51 deletions
diff --git a/macros/latex/contrib/l3build/l3build-file-functions.lua b/macros/latex/contrib/l3build/l3build-file-functions.lua
index 7d13fc933e..6ca1cc6011 100644
--- a/macros/latex/contrib/l3build/l3build-file-functions.lua
+++ b/macros/latex/contrib/l3build/l3build-file-functions.lua
@@ -1,6 +1,6 @@
--[[
-File l3build-file-functions.lua Copyright (C) 2018-2020 The LaTeX3 Project
+File l3build-file-functions.lua Copyright (C) 2018-2020 The LaTeX Project
It may be distributed and/or modified under the conditions of the
LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -36,7 +36,6 @@ local execute = os.execute
local exit = os.exit
local getenv = os.getenv
local remove = os.remove
-local os_time = os.time
local os_type = os.type
local luatex_revision = status.luatex_revision
@@ -171,14 +170,19 @@ function normalize_path(path)
end
-- Return an absolute path from a relative one
+-- Due to chdir, path must exist and be accessible.
function abspath(path)
local oldpwd = currentdir()
- chdir(path)
- local result = currentdir()
- chdir(oldpwd)
- return escapepath(gsub(result, "\\", "/"))
+ local ok, msg = chdir(path)
+ if ok then
+ local result = currentdir()
+ chdir(oldpwd)
+ return escapepath(gsub(result, "\\", "/"))
+ end
+ error(msg)
end
+-- TODO: Fix the cross platform problem
function escapepath(path)
if os_type == "windows" then
local path,count = gsub(path,'"','')
@@ -210,22 +214,25 @@ end
-- Copy files 'quietly'
function cp(glob, source, dest)
local errorlevel
- for i,_ in pairs(tree(source, glob)) do
- local source = source .. "/" .. i
+ for _,p in ipairs(tree(source, glob)) do
+ -- p_src is a path relative to `source` whereas
+ -- p_cwd is the counterpart relative to the current working directory
if os_type == "windows" then
- if attributes(source)["mode"] == "directory" then
+ if attributes(p.cwd, "mode") == "directory" then
errorlevel = execute(
- 'xcopy /y /e /i "' .. unix_to_win(source) .. '" "'
- .. unix_to_win(dest .. '/' .. i) .. '" > nul'
- )
+ 'xcopy /y /e /i "' .. unix_to_win(p.cwd) .. '" "'
+ .. unix_to_win(dest .. '/' .. p.src) .. '" > nul'
+ ) and 0 or 1
else
errorlevel = execute(
- 'xcopy /y "' .. unix_to_win(source) .. '" "'
+ 'xcopy /y "' .. unix_to_win(p.cwd) .. '" "'
.. unix_to_win(dest .. '/') .. '" > nul'
- )
+ ) and 0 or 1
end
else
- errorlevel = execute("cp -RLf '" .. source .. "' '" .. dest .. "'")
+ errorlevel = execute(
+ "cp -RLf '" .. p.cwd .. "' '" .. dest .. "'"
+ ) and 0 or 1
end
if errorlevel ~=0 then
return errorlevel
@@ -255,7 +262,7 @@ function fileexists(file)
f:close()
return true
else
- return false
+ return false -- also file exits and is not readable
end
end
@@ -283,54 +290,73 @@ function filelist(path, glob)
return files
end
--- Does what filelist does, but can also glob subdirectories. In the returned
--- table, the keys are paths relative to the given starting path, the values
--- are their counterparts relative to the current working directory.
-function tree(path, glob)
+---@class tree_entry_t
+---@field src string path relative to the source directory
+---@field cwd string path counterpart relative to the current working directory
+
+---Does what filelist does, but can also glob subdirectories.
+---In the returned table, the keys are paths relative to the given source path,
+---the values are their counterparts relative to the current working directory.
+---@param src_path string
+---@param glob string
+---@return table<integer,tree_entry_t>
+function tree(src_path, glob)
local function cropdots(path)
- return gsub(gsub(path, "^%./", ""), "/%./", "/")
+ return path:gsub( "^%./", ""):gsub("/%./", "/")
end
+ src_path = cropdots(src_path)
+ glob = cropdots(glob)
local function always_true()
return true
end
local function is_dir(file)
- return attributes(file)["mode"] == "directory"
+ return attributes(file, "mode") == "directory"
end
- local dirs = {["."] = cropdots(path)}
- for pattern, criterion in gmatch(cropdots(glob), "([^/]+)(/?)") do
- local criterion = criterion == "/" and is_dir or always_true
- function fill(path, dir, table)
- for _, file in ipairs(filelist(dir, pattern)) do
- local fullpath = path .. "/" .. file
- if file ~= "." and file ~= ".." and
- fullpath ~= builddir
- then
- local fulldir = dir .. "/" .. file
- if criterion(fulldir) then
- table[fullpath] = fulldir
+ ---@type table<integer,tree_entry_t>
+ local result = { {
+ src = ".",
+ cwd = src_path,
+ } }
+ for glob_part, sep in glob:gmatch("([^/]+)(/?)/*") do
+ local accept = sep == "/" and is_dir or always_true
+ ---Feeds the given table according to `glob_part`
+ ---@param p tree_entry_t path counterpart relative to the current working directory
+ ---@param table table
+ local function fill(p, table)
+ for _,file in ipairs(filelist(p.cwd, glob_part)) do
+ if file ~= "." and file ~= ".." then
+ local pp = {
+ src = p.src .. "/" .. file,
+ cwd = p.cwd .. "/" .. file,
+ }
+ if pp.cwd ~= builddir -- TODO: ensure that `builddir` is properly formatted
+ and accept(pp.cwd)
+ then
+ insert(table, pp)
end
end
end
end
- local newdirs = {}
- if pattern == "**" then
+ local new_result = {}
+ if glob_part == "**" then
+ local i = 1
while true do
- path, dir = next(dirs)
- if not path then
+ local p = result[i]
+ i = i + 1
+ if not p then
break
end
- dirs[path] = nil
- newdirs[path] = dir
- fill(path, dir, dirs)
+ insert(new_result, p) -- shorter path
+ fill(p, result) -- after longer
end
else
- for path, dir in pairs(dirs) do
- fill(path, dir, newdirs)
+ for _,p in ipairs(result) do
+ fill(p, new_result)
end
end
- dirs = newdirs
+ result = new_result
end
- return dirs
+ return result
end
function remove_duplicates(a)
@@ -353,7 +379,7 @@ function mkdir(dir)
if os_type == "windows" then
-- Windows (with the extensions) will automatically make directory trees
-- but issues a warning if the dir already exists: avoid by including a test
- local dir = unix_to_win(dir)
+ dir = unix_to_win(dir)
return execute(
"if not exist " .. dir .. "\\nul " .. "mkdir " .. dir
)
@@ -364,10 +390,10 @@ end
-- Rename
function ren(dir, source, dest)
- local dir = dir .. "/"
+ dir = dir .. "/"
if os_type == "windows" then
- local source = gsub(source, "^%.+/", "")
- local dest = gsub(dest, "^%.+/", "")
+ source = gsub(source, "^%.+/", "")
+ dest = gsub(dest, "^%.+/", "")
return execute("ren " .. unix_to_win(dir) .. source .. " " .. dest)
else
return execute("mv " .. dir .. source .. " " .. dir .. dest)
@@ -376,8 +402,8 @@ end
-- Remove file(s) based on a glob
function rm(source, glob)
- for i,_ in pairs(tree(source, glob)) do
- rmfile(source,i)
+ for _,p in ipairs(tree(source, glob)) do
+ rmfile(source,p.src)
end
-- os.remove doesn't give a sensible errorlevel
return 0