summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Build/source/texk/texlive/linked_scripts/l3build/l3build.lua33
-rw-r--r--Master/texmf-dist/doc/latex/l3build/CHANGELOG.md21
-rw-r--r--Master/texmf-dist/doc/latex/l3build/README.md2
-rw-r--r--Master/texmf-dist/doc/latex/l3build/l3build.pdfbin708832 -> 740399 bytes
-rw-r--r--Master/texmf-dist/doc/man/man1/l3build.12
-rw-r--r--Master/texmf-dist/doc/man/man1/l3build.man1.pdfbin15724 -> 15624 bytes
-rw-r--r--Master/texmf-dist/scripts/l3build/l3build-arguments.lua6
-rw-r--r--Master/texmf-dist/scripts/l3build/l3build-check.lua76
-rw-r--r--Master/texmf-dist/scripts/l3build/l3build-ctan.lua50
-rw-r--r--Master/texmf-dist/scripts/l3build/l3build-file-functions.lua46
-rw-r--r--Master/texmf-dist/scripts/l3build/l3build-upload.lua40
-rw-r--r--Master/texmf-dist/scripts/l3build/l3build-variables.lua3
-rw-r--r--Master/texmf-dist/scripts/l3build/l3build-zip.lua119
-rwxr-xr-xMaster/texmf-dist/scripts/l3build/l3build.lua33
-rw-r--r--Master/texmf-dist/source/latex/l3build/l3build.dtx39
15 files changed, 391 insertions, 79 deletions
diff --git a/Build/source/texk/texlive/linked_scripts/l3build/l3build.lua b/Build/source/texk/texlive/linked_scripts/l3build/l3build.lua
index 82994397648..51b7a493e31 100644
--- a/Build/source/texk/texlive/linked_scripts/l3build/l3build.lua
+++ b/Build/source/texk/texlive/linked_scripts/l3build/l3build.lua
@@ -25,7 +25,7 @@ for those people who are interested.
--]]
-- Version information
-release_date = "2021-05-06"
+release_date = "2021-08-28"
-- File operations are aided by the LuaFileSystem module
local lfs = require("lfs")
@@ -43,6 +43,8 @@ local print = print
local select = select
local tonumber = tonumber
local exit = os.exit
+local open = io.open
+local stdout = io.stdout
-- l3build setup and functions
kpse.set_program_name("kpsewhich")
@@ -160,6 +162,35 @@ if options["target"] == "check" then
end
print("")
end
+ if options["show-saves"] then
+ local savecmds, recheckcmds = "", ""
+ for _,config in ipairs(failed) do
+ local testdir = testdir
+ if config ~= "build" then
+ testdir = testdir .. "-" .. config
+ end
+ local f = open(testdir .. "/.savecommands")
+ if not f then
+ print("Error: Cannot find save commands for configuration " ..
+ config)
+ exit(2)
+ end
+ for line in f:lines() do
+ if line == "" then break end
+ savecmds = savecmds .. " " .. line .. "\n"
+ end
+ for line in f:lines() do
+ recheckcmds = recheckcmds .. " " .. line .. "\n"
+ end
+ f:close()
+ end
+ print"To regenerate the test files, run\n"
+ print(savecmds)
+ if recheckcmds ~= "" then
+ print"To detect engine specific differences, run after that\n"
+ print(recheckcmds)
+ end
+ end
exit(1)
else
-- Avoid running the 'main' set of tests twice
diff --git a/Master/texmf-dist/doc/latex/l3build/CHANGELOG.md b/Master/texmf-dist/doc/latex/l3build/CHANGELOG.md
index e46a935c3f7..f5be81a9372 100644
--- a/Master/texmf-dist/doc/latex/l3build/CHANGELOG.md
+++ b/Master/texmf-dist/doc/latex/l3build/CHANGELOG.md
@@ -7,6 +7,23 @@ this project uses date-based 'snapshot' version identifiers.
## [Unreleased]
+## [2021-08-28]
+
+### Fixed
+- Creation of zip files on Windows
+- Only match filename and not full path for `exefiles`
+
+## [2021-08-27]
+
+### Added
+- Add the `--show-saves` flag for `l3build check` to generate a list of
+ `l3build save` commands to regenerate all failing tests
+
+### Changed
+- No longer call an external program to generate `zip` files and generate
+ them directly instead. This disables the options `zipexe` and `zipopts`.
+- Copy TDS-style zip files to main dir
+
## [2021-05-06]
### Fixed
@@ -492,7 +509,9 @@ this project uses date-based 'snapshot' version identifiers.
- Rationalise short option names: removed `-d`, `-E`, `-r`
- Target `cmdcheck`: specific to LaTeX kernel work
-[Unreleased]: https://github.com/latex3/l3build/compare/2021-05-06...HEAD
+[Unreleased]: https://github.com/latex3/l3build/compare/2021-08-28...HEAD
+[2021-08-28]: https://github.com/latex3/l3build/compare/2021-08-27...2021-08-28
+[2021-08-27]: https://github.com/latex3/l3build/compare/2021-05-06...2021-08-27
[2021-05-06]: https://github.com/latex3/l3build/compare/2021-05-05...2021-05-06
[2021-05-05]: https://github.com/latex3/l3build/compare/2020-06-04...2021-05-05
[2020-06-04]: https://github.com/latex3/l3build/compare/2020-03-25...2020-06-04
diff --git a/Master/texmf-dist/doc/latex/l3build/README.md b/Master/texmf-dist/doc/latex/l3build/README.md
index 219b1ad36c2..635693ae9ff 100644
--- a/Master/texmf-dist/doc/latex/l3build/README.md
+++ b/Master/texmf-dist/doc/latex/l3build/README.md
@@ -1,7 +1,7 @@
l3build: a testing and building system for LaTeX
=================================================
-Release 2021-05-06
+Release 2021-08-28
Overview
--------
diff --git a/Master/texmf-dist/doc/latex/l3build/l3build.pdf b/Master/texmf-dist/doc/latex/l3build/l3build.pdf
index 447ba668a8c..fe2778114f0 100644
--- a/Master/texmf-dist/doc/latex/l3build/l3build.pdf
+++ b/Master/texmf-dist/doc/latex/l3build/l3build.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/man/man1/l3build.1 b/Master/texmf-dist/doc/man/man1/l3build.1
index 8e21697dabe..6c2f071a46a 100644
--- a/Master/texmf-dist/doc/man/man1/l3build.1
+++ b/Master/texmf-dist/doc/man/man1/l3build.1
@@ -1,4 +1,4 @@
-.TH l3build 1 "2021-05-06"
+.TH l3build 1 "2021-08-28"
.SH NAME
l3build \- Checking and building packages
.SH SYNOPSIS
diff --git a/Master/texmf-dist/doc/man/man1/l3build.man1.pdf b/Master/texmf-dist/doc/man/man1/l3build.man1.pdf
index 7d9af7120ac..ecb6a8a15cd 100644
--- a/Master/texmf-dist/doc/man/man1/l3build.man1.pdf
+++ b/Master/texmf-dist/doc/man/man1/l3build.man1.pdf
Binary files differ
diff --git a/Master/texmf-dist/scripts/l3build/l3build-arguments.lua b/Master/texmf-dist/scripts/l3build/l3build-arguments.lua
index 80f19d66ad5..8f62e8b433f 100644
--- a/Master/texmf-dist/scripts/l3build/l3build-arguments.lua
+++ b/Master/texmf-dist/scripts/l3build/l3build-arguments.lua
@@ -139,6 +139,12 @@ option_list =
desc = "If 'halt-on-error' stops, show the full log of the failure",
type = "boolean"
},
+ ["show-saves"] =
+ {
+ desc = "If tests fail, show the l3build save invocation to regenerate the tests",
+ short = "S",
+ type = "boolean"
+ },
shuffle =
{
desc = "Shuffle order of tests",
diff --git a/Master/texmf-dist/scripts/l3build/l3build-check.lua b/Master/texmf-dist/scripts/l3build/l3build-check.lua
index 47ab19ced60..f83dee4e448 100644
--- a/Master/texmf-dist/scripts/l3build/l3build-check.lua
+++ b/Master/texmf-dist/scripts/l3build/l3build-check.lua
@@ -574,14 +574,16 @@ function runcheck(name, hide)
if options["engine"] then
checkengines = options["engine"]
end
+ local failedengines = {}
-- Used for both .lvt and .pvt tests
local test_type = test_types[kind]
local function check_and_diff(engine)
- runtest(name, engine, hide, test_type.test, test_type, true)
+ runtest(name, engine, hide, test_type.test, test_type, not forcecheckruns)
local errorlevel = base_compare(test_type,name,engine)
if errorlevel == 0 then
return errorlevel
end
+ failedengines[#failedengines + 1] = engine
if options["show-log-on-error"] then
showfailedlog(name)
end
@@ -595,14 +597,20 @@ function runcheck(name, hide)
setup_check(name,engine)
local errlevel = check_and_diff(engine)
if errlevel ~= 0 and options["halt-on-error"] then
- return 1
+ return 1, failedengines
end
if errlevel > errorlevel then
errorlevel = errlevel
end
end
+ for i=1, #failedengines do
+ if failedengines[i] == stdengine then
+ failedengines = {stdengine}
+ break
+ end
+ end
-- Return everything
- return errorlevel
+ return errorlevel, failedengines
end
function setup_check(name, engine)
@@ -845,11 +853,57 @@ function testexists(test)
end
end
+-- A short auxiliary to print the list of differences for check
+local function showsavecommands(failurelist)
+ local savecmds = {}
+ local checkcmd = "l3build check --show-saves"
+ local prefix = "l3build save"
+ if options.config and options.config[1] ~= 'build' then
+ local config = " -c " .. options.config[1]
+ prefix = prefix .. config
+ checkcmd = checkcmd .. config
+ end
+ for name, engines in pairs(failurelist) do
+ for i = 1, #engines do
+ local engine = engines[i]
+ local cmd = savecmds[engine]
+ if not cmd then
+ if engine == stdengine then
+ cmd = prefix
+ else
+ cmd = prefix .. " -e " .. engine
+ end
+ end
+ savecmds[engine] = cmd .. " " .. name
+ if engine == stdengine then
+ checkcmd = checkcmd .. " " .. name
+ end
+ end
+ end
+ print(" To regenerate the test files, run\n")
+ local f = open(testdir .. "/.savecommands", "w")
+ for _, cmds in pairs(savecmds) do
+ print(" " .. cmds)
+ f:write(cmds, "\n")
+ end
+ f:write"\n"
+ if savecmds[stdengine] then
+ print("\n Afterwards test for engine specific changes using\n")
+ print(" " .. checkcmd)
+ f:write(checkcmd)
+ end
+ f:close()
+ print("")
+end
+
function check(names)
local errorlevel = 0
if testfiledir ~= "" and direxists(testfiledir) then
if not options["rerun"] then
- checkinit()
+ errorlevel = checkinit()
+ if errorlevel ~= 0 then
+ return errorlevel
+ end
end
local hide = true
if names and next(names) then
@@ -933,11 +987,13 @@ function check(names)
end
-- Actually run the tests
print("Running checks on")
+ local failurelist = {}
for i, name in ipairs(names) do
print(" " .. name .. " (" .. i .. "/" .. #names ..")")
- local errlevel = runcheck(name, hide)
+ local errlevel, failedengines = runcheck(name, hide)
-- Return value must be 1 not errlevel
if errlevel ~= 0 then
+ failurelist[name] = failedengines
if options["halt-on-error"] then
return 1
else
@@ -949,6 +1005,9 @@ function check(names)
end
if errorlevel ~= 0 then
checkdiff()
+ if options["show-saves"] then
+ showsavecommands(failurelist)
+ end
else
print("\n All checks passed\n")
end
@@ -994,7 +1053,12 @@ function showfaileddiff()
end
function save(names)
- checkinit()
+ do
+ local errorlevel = checkinit()
+ if errorlevel ~= 0 then
+ return errorlevel
+ end
+ end
local engines = options["engine"] or {stdengine}
if names == nil then
print("Arguments are required for the save command")
diff --git a/Master/texmf-dist/scripts/l3build/l3build-ctan.lua b/Master/texmf-dist/scripts/l3build/l3build-ctan.lua
index fd1491dd584..e5b3b7e8f84 100644
--- a/Master/texmf-dist/scripts/l3build/l3build-ctan.lua
+++ b/Master/texmf-dist/scripts/l3build/l3build-ctan.lua
@@ -25,9 +25,12 @@ for those people who are interested.
local pairs = pairs
local print = print
+local attributes = lfs.attributes
local lower = string.lower
local match = string.match
+local newzip = require"l3build-zip"
+
-- Copy files to the main CTAN release directory
function copyctan()
mkdir(ctandir .. "/" .. ctanpkg)
@@ -68,33 +71,33 @@ end
function ctan()
-- Always run tests for all engines
options["engine"] = nil
- local function dirzip(dir, name)
- local zipname = name .. ".zip"
- local function tab_to_str(table)
- local string = ""
- for _,i in ipairs(table) do
- string = string .. " " .. "\"" .. i .. "\""
+ local function dirzip(dir, zipname)
+ zipname = zipname .. ".zip"
+ local zip = newzip(dir .. '/' .. zipname)
+ local function tab_to_check(table)
+ local patterns = {}
+ for n,i in ipairs(table) do
+ patterns[n] = glob_to_pattern(i)
+ end
+ return function(name)
+ for n, patt in ipairs(patterns) do
+ if name:match"([^/]*)$":match(patt) then return true end
+ end
+ return false
end
- return string
end
-- Convert the tables of files to quoted strings
- local binfiles = tab_to_str(binaryfiles)
- local exclude = tab_to_str(excludefiles)
+ local binfile = tab_to_check(binaryfiles)
+ local exclude = tab_to_check(excludefiles)
+ local exefile = tab_to_check(exefiles)
-- First, zip up all of the text files
- run(
- dir,
- zipexe .. " " .. zipopts .. " -ll ".. zipname .. " " .. "."
- .. (
- (binfiles or exclude) and (" -x" .. binfiles .. " " .. exclude)
- or ""
- )
- )
- -- Then add the binary ones
- run(
- dir,
- zipexe .. " " .. zipopts .. " -g ".. zipname .. " " .. ". -i" ..
- binfiles .. (exclude and (" -x" .. exclude) or "")
- )
+ for _, p in ipairs(tree(dir, "**")) do
+ local src = p.src:sub(3) -- Strip ./
+ if not (attributes(p.cwd, "mode") == "directory" or exclude(src) or src == zipname) then
+ zip:add(p.cwd, src, binfile(src), exefile(src))
+ end
+ end
+ return zip:close()
end
local errorlevel
local standalone = false
@@ -146,6 +149,7 @@ function ctan()
dirzip(tdsdir, ctanpkg .. ".tds")
if packtdszip then
cp(ctanpkg .. ".tds.zip", tdsdir, ctandir)
+ cp(ctanpkg .. ".tds.zip", tdsdir, currentdir)
end
dirzip(ctandir, ctanzip)
cp(ctanzip .. ".zip", ctandir, currentdir)
diff --git a/Master/texmf-dist/scripts/l3build/l3build-file-functions.lua b/Master/texmf-dist/scripts/l3build/l3build-file-functions.lua
index 6ca1cc60111..53364bd3010 100644
--- a/Master/texmf-dist/scripts/l3build/l3build-file-functions.lua
+++ b/Master/texmf-dist/scripts/l3build/l3build-file-functions.lua
@@ -211,6 +211,20 @@ function cleandir(dir)
return rm(dir, "**")
end
+function direxists(dir)
+ return attributes(dir, "mode") == "directory"
+end
+
+function fileexists(file)
+ local f = open(file, "r")
+ if f ~= nil then
+ f:close()
+ return true
+ else
+ return false -- also file exits and is not readable
+ end
+end
+
-- Copy files 'quietly'
function cp(glob, source, dest)
local errorlevel
@@ -218,7 +232,7 @@ function cp(glob, source, dest)
-- 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(p.cwd, "mode") == "directory" then
+ if direxists(p.cwd) then
errorlevel = execute(
'xcopy /y /e /i "' .. unix_to_win(p.cwd) .. '" "'
.. unix_to_win(dest .. '/' .. p.src) .. '" > nul'
@@ -241,31 +255,6 @@ function cp(glob, source, dest)
return 0
end
--- OS-dependent test for a directory
-function direxists(dir)
- local errorlevel
- if os_type == "windows" then
- errorlevel =
- execute("if not exist \"" .. unix_to_win(dir) .. "\" exit 1")
- else
- errorlevel = execute("[ -d '" .. dir .. "' ]")
- end
- if errorlevel ~= 0 then
- return false
- end
- return true
-end
-
-function fileexists(file)
- local f = open(file, "r")
- if f ~= nil then
- f:close()
- return true
- else
- return false -- also file exits and is not readable
- end
-end
-
-- Generate a table containing all file names of the given glob or all files
-- if absent
function filelist(path, glob)
@@ -309,16 +298,13 @@ function tree(src_path, glob)
local function always_true()
return true
end
- local function is_dir(file)
- return attributes(file, "mode") == "directory"
- end
---@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
+ local accept = sep == "/" and direxists 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
diff --git a/Master/texmf-dist/scripts/l3build/l3build-upload.lua b/Master/texmf-dist/scripts/l3build/l3build-upload.lua
index 629d2ee7c77..47268f5b6a9 100644
--- a/Master/texmf-dist/scripts/l3build/l3build-upload.lua
+++ b/Master/texmf-dist/scripts/l3build/l3build-upload.lua
@@ -116,11 +116,24 @@ function upload(tagnames)
end
-- avoid lower level error from post command if zip file missing
- local zip=open(trim_space(tostring(uploadfile)),"r")
- if zip~=nil then
- close(zip)
- else
- error("Missing zip file '" .. tostring(uploadfile) .. "'")
+ local ziptime = lfs.attributes(trim_space(tostring(uploadfile)), 'modification')
+ if not ziptime then
+ error("Missing zip file '" .. tostring(uploadfile) .. "'. \z
+ Maybe you forgot to run 'l3build ctan' first?")
+ end
+ local age = os.time() - ziptime
+ if age >= 86400 then
+ print(string.format("------------------------------------------\n\z
+ | The local archive is older than %3i days. |\n\z
+ | Are you sure that you executed 'l3build ctan' first? |\n\z
+ --------------------------------------------------------",
+ age // 86400))
+ print("Are you sure you want to continue? [y/n]" )
+ io.stdout:write("> "):flush()
+ if lower(read(),1,1) ~= "y" then
+ print'Aborting'
+ return 1
+ end
end
ctan_post = construct_ctan_post(uploadfile,options["debug"])
@@ -174,12 +187,23 @@ end
end
-- if upload requested and validation succeeded repost to the upload URL
- if (exit_status==0 or exit_status==nil) then
+ if (exit_status==0 or exit_status==nil) then
if (ctanupload ~=nil and ctanupload ~=false and ctanupload ~= true) then
if (match(fp_return,"WARNING")) then
- print("Warnings from CTAN package validation:" .. fp_return:gsub("%[","\n["):gsub("%]%]","]\n]"))
+ print("Warnings from CTAN package validation:" .. fp_return:gsub("%[","\n["):gsub("%]%]","]\n]"))
else
- print("Validation successful." )
+ print("Validation successful." )
+ end
+ print("" )
+ if age < 86400 and age >= 60 then
+ if age >= 3600 then
+ print("----------------------------------------------------" )
+ print(string.format("| The local archive is older than %2i hours. |", age//3600 ))
+ print("| Have you executed l3build ctan first? If so ... |" )
+ print("----------------------------------------------------" )
+ else
+ print(string.format("The local archive is %i minutes old.", age//60 ))
+ end
end
print("Do you want to upload to CTAN? [y/n]" )
local answer=""
diff --git a/Master/texmf-dist/scripts/l3build/l3build-variables.lua b/Master/texmf-dist/scripts/l3build/l3build-variables.lua
index e3ae64e13be..f1032004b60 100644
--- a/Master/texmf-dist/scripts/l3build/l3build-variables.lua
+++ b/Master/texmf-dist/scripts/l3build/l3build-variables.lua
@@ -84,6 +84,7 @@ demofiles = demofiles or { }
docfiles = docfiles or { }
dynamicfiles = dynamicfiles or { }
excludefiles = excludefiles or {"*~"}
+exefiles = exefiles or { }
installfiles = installfiles or {"*.sty","*.cls"}
makeindexfiles = makeindexfiles or {"*.ist"}
scriptfiles = scriptfiles or { }
@@ -106,12 +107,10 @@ unpackdeps = unpackdeps or { }
-- Executable names plus following options
typesetexe = typesetexe or "pdflatex"
unpackexe = unpackexe or "pdftex"
-zipexe = zipexe or "zip"
checkopts = checkopts or "-interaction=nonstopmode"
typesetopts = typesetopts or "-interaction=nonstopmode"
unpackopts = unpackopts or ""
-zipopts = zipopts or "-v -r -X"
-- Engines for testing
checkengines = checkengines or {"pdftex", "xetex", "luatex"}
diff --git a/Master/texmf-dist/scripts/l3build/l3build-zip.lua b/Master/texmf-dist/scripts/l3build/l3build-zip.lua
new file mode 100644
index 00000000000..06f37cd8b3c
--- /dev/null
+++ b/Master/texmf-dist/scripts/l3build/l3build-zip.lua
@@ -0,0 +1,119 @@
+--[[
+
+File l3build-zip.lua Copyright (C) 2021 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
+license or (at your option) any later version. The latest version
+of this license is in the file
+
+ http://www.latex-project.org/lppl.txt
+
+This file is part of the "l3build bundle" (The Work in LPPL)
+and all files in that bundle must be distributed together.
+
+-----------------------------------------------------------------------
+
+The development version of the bundle can be found at
+
+ https://github.com/latex3/l3build
+
+for those people who are interested.
+
+--]]
+
+local concat = table.concat
+local open = io.open
+local osdate = os.date
+local pack = string.pack
+local setmetatable = setmetatable
+local iotype = io.type
+
+local compress = zlib.compress
+local crc32 = zlib.crc32
+
+local function encode_time(unix)
+ local t = osdate('*t', unix)
+ local date = t.day | (t.month << 5) | ((t.year-1980) << 9)
+ local time = (t.sec//2) | (t.min << 5) | (t.hour << 11)
+ return date, time
+end
+
+local meta = {__index = {
+ add = function(z, filename, innername, binary, executable)
+ innername = innername or filename
+
+ local offset = z.f:seek'cur'
+
+ local content do
+ local f = iotype(filename) and filename or assert(open(filename, binary and 'rb' or 'r'))
+ content = f:read'*a'
+ f:close()
+ end
+ local crc32 = crc32(crc32(), content)
+ local compressed = compress(content, nil, nil, -15)
+ if #compressed >= #content then
+ compressed = nil
+ end
+ local date, time = encode_time(nil)
+ z.f:write(pack("<c4I2I2I2I2I2I4I4I4I2I2",
+ 'PK\3\4',
+ compressed and 20 or 10, -- ZIP 2.0 to allow deflate
+ 0, -- We never set flags
+ compressed and 8 or 0, -- Always use deflate
+ time,
+ date,
+ crc32,
+ compressed and #compressed or #content,
+ #content,
+ #innername,
+ 0),
+ innername,
+ compressed or content)
+ local central = pack("<c4I2I2I2I2I2I2I4I4I4I2I2I2I2I2I4I4",
+ 'PK\1\2',
+ (3 << 8) | 63, -- Use UNIX attributes, written against ZIP 6.3
+ compressed and 20 or 10, -- ZIP 2.0 to allow deflate
+ 0, -- We never set flags
+ compressed and 8 or 0, -- Always use deflate
+ time,
+ date,
+ crc32,
+ compressed and #compressed or #content,
+ #content,
+ #innername,
+ 0, -- no extra data
+ 0, -- no comment
+ 0, -- Disc 0
+ binary and 0 or 1,
+ (executable and 0x81ED--[[0100755]] or 0x81A4--[[0100644]]) << 16,
+ offset)
+ z.central[#z.central+1] = central .. innername
+ end,
+ close = function(z, comment)
+ comment = comment or ''
+
+ local offset = z.f:seek'cur'
+ local central = concat(z.central)
+ z.f:write(central, pack("<c4I2I2I2I2I4I4I2",
+ 'PK\5\6',
+ 0, -- This is disc 0
+ 0, -- central dictionary started on disc 0
+ #z.central, -- Central disctionary entries on this disc
+ #z.central, -- Central disctionary entries on all discs
+ #central,
+ offset,
+ #comment), comment)
+ return z.f:close()
+ end,
+}}
+
+return function(filename)
+ local f, msg = open(filename, 'wb')
+ if not f then return f, msg end
+ return setmetatable({
+ f = f,
+ offset = 1,
+ central = {},
+ }, meta)
+end
diff --git a/Master/texmf-dist/scripts/l3build/l3build.lua b/Master/texmf-dist/scripts/l3build/l3build.lua
index 82994397648..51b7a493e31 100755
--- a/Master/texmf-dist/scripts/l3build/l3build.lua
+++ b/Master/texmf-dist/scripts/l3build/l3build.lua
@@ -25,7 +25,7 @@ for those people who are interested.
--]]
-- Version information
-release_date = "2021-05-06"
+release_date = "2021-08-28"
-- File operations are aided by the LuaFileSystem module
local lfs = require("lfs")
@@ -43,6 +43,8 @@ local print = print
local select = select
local tonumber = tonumber
local exit = os.exit
+local open = io.open
+local stdout = io.stdout
-- l3build setup and functions
kpse.set_program_name("kpsewhich")
@@ -160,6 +162,35 @@ if options["target"] == "check" then
end
print("")
end
+ if options["show-saves"] then
+ local savecmds, recheckcmds = "", ""
+ for _,config in ipairs(failed) do
+ local testdir = testdir
+ if config ~= "build" then
+ testdir = testdir .. "-" .. config
+ end
+ local f = open(testdir .. "/.savecommands")
+ if not f then
+ print("Error: Cannot find save commands for configuration " ..
+ config)
+ exit(2)
+ end
+ for line in f:lines() do
+ if line == "" then break end
+ savecmds = savecmds .. " " .. line .. "\n"
+ end
+ for line in f:lines() do
+ recheckcmds = recheckcmds .. " " .. line .. "\n"
+ end
+ f:close()
+ end
+ print"To regenerate the test files, run\n"
+ print(savecmds)
+ if recheckcmds ~= "" then
+ print"To detect engine specific differences, run after that\n"
+ print(recheckcmds)
+ end
+ end
exit(1)
else
-- Avoid running the 'main' set of tests twice
diff --git a/Master/texmf-dist/source/latex/l3build/l3build.dtx b/Master/texmf-dist/source/latex/l3build/l3build.dtx
index 5171f109720..8d340552275 100644
--- a/Master/texmf-dist/source/latex/l3build/l3build.dtx
+++ b/Master/texmf-dist/source/latex/l3build/l3build.dtx
@@ -121,7 +121,6 @@
\luavarseparator
\luavarset{typesetexe} {"pdflatex"} {Executable for compiling \texttt{doc(s)}}
\luavarset{unpackexe} {"pdftex"} {Executable for running \texttt{unpack}}
-\luavarset{zipexe} {"zip"} {Executable for creating archive with \texttt{ctan}}
\luavarset{biberexe} {"biber"} {Biber executable}
\luavarset{bibtexexe} {"bibtex8"} {\BibTeX{} executable}
\luavarset{makeindexexe} {"makeindex"}{MakeIndex executable}
@@ -130,7 +129,6 @@
\luavarset{checkopts} {"-interaction=nonstopmode"}{Options passed to engine when running checks}
\luavarset{typesetopts}{"-interaction=nonstopmode"}{Options passed to engine when typesetting}
\luavarset{unpackopts} {""} {Options passed to engine when unpacking}
-\luavarset{zipopts} {"-v -r -X"} {Options passed to zip program}
\luavarset{biberopts} {""} {Biber options}
\luavarset{bibtexopts} {"-W"} {\BibTeX{} options}
\luavarset{makeindexopts}{""} {MakeIndex options}
@@ -148,6 +146,7 @@
\luavarseparator
\luavarset{asciiengines}{\{"pdftex"\}}{Engines which should log as pure ASCII}
\luavarset{checkruns} {1} {Number of runs to complete for a test before comparing the log}
+\luavarset{forcecheckruns}{false} {Always run \texttt{checkruns} runs and never stop early}
\luavarset{ctanreadme}{"README.md"} {Name of the file to send to CTAN as \texttt{README.\meta{ext}}}
\luavarset{ctanzip}{ctanpkg ... "-ctan"}{Name of the zip file (without extension) created for upload to CTAN}
\luavarset{epoch} {1463734800} {Epoch (Unix date) to set for test runs}
@@ -237,7 +236,7 @@
% }^^A
% }
%
-% \date{Released 2021-05-06}
+% \date{Released 2021-08-28}
%
% \maketitle
% \tableofcontents
@@ -314,7 +313,7 @@
%
% When the build system runs, it creates a directory |build/| for various unpacking, compilation, and testing purposes.
% For a module, this build folder can be in the main directory of the package itself, but for a bundle it should be common for the bundle itself and for all modules within that bundle.
-% A |build/| folder can be safety deleted; all material within is re-generated for each command of the \pkg{l3build} system.
+% A |build/| folder can be safely deleted; all material within is re-generated for each command of the \pkg{l3build} system.
%
% \subsection{The \texttt{build.lua} file}
%
@@ -379,6 +378,8 @@
% \item |--rerun| Run tests without unpacking/set up
% \item |--show-log-on-error| To be used in addition to \texttt{--halt-on-error} and results
% in the full \texttt{.log} file of a failed test to be shown on the console
+% \item |--show-saves| (|-S|) When tests fail, print the \texttt{l3build save} commands needed
+% to regenerate the tests assuming that the failures were false negatives.
% \item |--shuffle| Shuffle the order in which tests run
% \item |--texmfhome| Sets the location of the user tree for installing
% \end{itemize}
@@ -495,7 +496,7 @@
%
% Binary files should be specified with the \var{binaryfiles} variable (default \luavar{binaryfiles}); these are added to the zip archive without normalising line endings (text files are automatically converted to Unix-style line endings).
%
-% To create the archive, by default the binary \var{zipexe} is used (\luavar{zipexe}) with options \var{zipopts} (|-v -r -X|). The intermediate build directories \var{ctandir} and \var{tdsdir} are used to construct the archive.
+% The intermediate build directories \var{ctandir} and \var{tdsdir} are used to construct the archive.
% \end{buildcmd}
%
%
@@ -1117,6 +1118,34 @@
% \label{fig:test-tasks}
% \end{figure}
%
+% \subsection{Instructions for rebuilding test output}
+%
+% Sometimes changes to fundamental parts of the code can cause a lot of tests
+% to fail even though the actually tested systems are still working correctly.
+% This is especially common when the logging and error reporting systems
+% changes and therefore all log file based tests using the component fail with
+% these changes.
+%
+% In these cases, the option |--show-saves| can be passed to
+% |l3build check| in order to generate a list of |l3build save| commands which
+% can be executed to regenerate the expected output of all tests which fail.
+% Additionally it sometimes prints a list of |l3build check| commands for tests
+% which might still fail due to engine differences after running the |save|
+% commands. After running all these |l3build check| commands and all
+% |l3build save| commands listed by them, all tests will succeed.
+%
+% When bundles are used |l3build check --show-saves| has to be executed
+% separately for every module in the bundle.
+%
+% This option is potentially dangerous and therefore should only be used with
+% care. It can easily hide valid test failures between a bunch of spurious
+% changes. Therefore you should always take a close look at the difference
+% files generated by |l3build check| before running the generated
+% |l3build save| commands. Additionally it should only be used when you are
+% aware of the reason why a large number of tests failed and the change
+% causing the failures has been tested separately to have no unintended
+% side effects.
+%
% \subsection{Epoch setting}
%
% To produce predictable output when using dates, the test system offers the