texlive[60344] trunk: l3build (28aug21)

commits+karl at tug.org commits+karl at tug.org
Sat Aug 28 22:36:53 CEST 2021


Revision: 60344
          http://tug.org/svn/texlive?view=revision&revision=60344
Author:   karl
Date:     2021-08-28 22:36:53 +0200 (Sat, 28 Aug 2021)
Log Message:
-----------
l3build (28aug21)

Modified Paths:
--------------
    trunk/Build/source/texk/texlive/linked_scripts/l3build/l3build.lua
    trunk/Master/texmf-dist/doc/latex/l3build/CHANGELOG.md
    trunk/Master/texmf-dist/doc/latex/l3build/README.md
    trunk/Master/texmf-dist/doc/latex/l3build/l3build.pdf
    trunk/Master/texmf-dist/doc/man/man1/l3build.1
    trunk/Master/texmf-dist/doc/man/man1/l3build.man1.pdf
    trunk/Master/texmf-dist/scripts/l3build/l3build-arguments.lua
    trunk/Master/texmf-dist/scripts/l3build/l3build-check.lua
    trunk/Master/texmf-dist/scripts/l3build/l3build-ctan.lua
    trunk/Master/texmf-dist/scripts/l3build/l3build-file-functions.lua
    trunk/Master/texmf-dist/scripts/l3build/l3build-upload.lua
    trunk/Master/texmf-dist/scripts/l3build/l3build-variables.lua
    trunk/Master/texmf-dist/scripts/l3build/l3build.lua
    trunk/Master/texmf-dist/source/latex/l3build/l3build.dtx

Added Paths:
-----------
    trunk/Master/texmf-dist/scripts/l3build/l3build-zip.lua

Modified: trunk/Build/source/texk/texlive/linked_scripts/l3build/l3build.lua
===================================================================
--- trunk/Build/source/texk/texlive/linked_scripts/l3build/l3build.lua	2021-08-28 20:36:31 UTC (rev 60343)
+++ trunk/Build/source/texk/texlive/linked_scripts/l3build/l3build.lua	2021-08-28 20:36:53 UTC (rev 60344)
@@ -25,7 +25,7 @@
 --]]
 
 -- 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 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 @@
         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

Modified: trunk/Master/texmf-dist/doc/latex/l3build/CHANGELOG.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3build/CHANGELOG.md	2021-08-28 20:36:31 UTC (rev 60343)
+++ trunk/Master/texmf-dist/doc/latex/l3build/CHANGELOG.md	2021-08-28 20:36:53 UTC (rev 60344)
@@ -7,6 +7,23 @@
 
 ## [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 @@
 - 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

Modified: trunk/Master/texmf-dist/doc/latex/l3build/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3build/README.md	2021-08-28 20:36:31 UTC (rev 60343)
+++ trunk/Master/texmf-dist/doc/latex/l3build/README.md	2021-08-28 20:36:53 UTC (rev 60344)
@@ -1,7 +1,7 @@
 l3build: a testing and building system for LaTeX
 =================================================
 
-Release 2021-05-06
+Release 2021-08-28
 
 Overview
 --------

Modified: trunk/Master/texmf-dist/doc/latex/l3build/l3build.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/man/man1/l3build.1
===================================================================
--- trunk/Master/texmf-dist/doc/man/man1/l3build.1	2021-08-28 20:36:31 UTC (rev 60343)
+++ trunk/Master/texmf-dist/doc/man/man1/l3build.1	2021-08-28 20:36:53 UTC (rev 60344)
@@ -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

Modified: trunk/Master/texmf-dist/doc/man/man1/l3build.man1.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/scripts/l3build/l3build-arguments.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/l3build/l3build-arguments.lua	2021-08-28 20:36:31 UTC (rev 60343)
+++ trunk/Master/texmf-dist/scripts/l3build/l3build-arguments.lua	2021-08-28 20:36:53 UTC (rev 60344)
@@ -139,6 +139,12 @@
         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",

Modified: trunk/Master/texmf-dist/scripts/l3build/l3build-check.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/l3build/l3build-check.lua	2021-08-28 20:36:31 UTC (rev 60343)
+++ trunk/Master/texmf-dist/scripts/l3build/l3build-check.lua	2021-08-28 20:36:53 UTC (rev 60344)
@@ -574,14 +574,16 @@
   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 @@
     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 @@
   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 @@
     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 @@
     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 @@
 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")

Modified: trunk/Master/texmf-dist/scripts/l3build/l3build-ctan.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/l3build/l3build-ctan.lua	2021-08-28 20:36:31 UTC (rev 60343)
+++ trunk/Master/texmf-dist/scripts/l3build/l3build-ctan.lua	2021-08-28 20:36:53 UTC (rev 60344)
@@ -25,9 +25,12 @@
 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 @@
 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 string
+      return function(name)
+        for n, patt in ipairs(patterns) do
+          if name:match"([^/]*)$":match(patt) then return true end
+        end
+        return false
+      end
     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 @@
     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)

Modified: trunk/Master/texmf-dist/scripts/l3build/l3build-file-functions.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/l3build/l3build-file-functions.lua	2021-08-28 20:36:31 UTC (rev 60343)
+++ trunk/Master/texmf-dist/scripts/l3build/l3build-file-functions.lua	2021-08-28 20:36:53 UTC (rev 60344)
@@ -211,6 +211,20 @@
   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 @@
     -- 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 @@
   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,9 +298,6 @@
   local function always_true()
     return true
   end
-  local function is_dir(file)
-    return attributes(file, "mode") == "directory"
-  end
   --- at type table<integer,tree_entry_t>
   local result = { {
     src = ".",
@@ -318,7 +304,7 @@
     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`
     --- at param p tree_entry_t path counterpart relative to the current working directory
     --- at param table table

Modified: trunk/Master/texmf-dist/scripts/l3build/l3build-upload.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/l3build/l3build-upload.lua	2021-08-28 20:36:31 UTC (rev 60343)
+++ trunk/Master/texmf-dist/scripts/l3build/l3build-upload.lua	2021-08-28 20:36:53 UTC (rev 60344)
@@ -116,12 +116,25 @@
   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,13 +187,24 @@
   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=""
       io.stdout:write("> ")

Modified: trunk/Master/texmf-dist/scripts/l3build/l3build-variables.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/l3build/l3build-variables.lua	2021-08-28 20:36:31 UTC (rev 60343)
+++ trunk/Master/texmf-dist/scripts/l3build/l3build-variables.lua	2021-08-28 20:36:53 UTC (rev 60344)
@@ -84,6 +84,7 @@
 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 @@
 -- 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"}

Added: trunk/Master/texmf-dist/scripts/l3build/l3build-zip.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/l3build/l3build-zip.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/scripts/l3build/l3build-zip.lua	2021-08-28 20:36:53 UTC (rev 60344)
@@ -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


Property changes on: trunk/Master/texmf-dist/scripts/l3build/l3build-zip.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/scripts/l3build/l3build.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/l3build/l3build.lua	2021-08-28 20:36:31 UTC (rev 60343)
+++ trunk/Master/texmf-dist/scripts/l3build/l3build.lua	2021-08-28 20:36:53 UTC (rev 60344)
@@ -25,7 +25,7 @@
 --]]
 
 -- 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 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 @@
         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

Modified: trunk/Master/texmf-dist/source/latex/l3build/l3build.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3build/l3build.dtx	2021-08-28 20:36:31 UTC (rev 60343)
+++ trunk/Master/texmf-dist/source/latex/l3build/l3build.dtx	2021-08-28 20:36:53 UTC (rev 60344)
@@ -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



More information about the tex-live-commits mailing list.