diff options
36 files changed, 1535 insertions, 2 deletions
diff --git a/Build/source/texk/kpathsea/ChangeLog b/Build/source/texk/kpathsea/ChangeLog index 61602772f0e..68be0ec6891 100644 --- a/Build/source/texk/kpathsea/ChangeLog +++ b/Build/source/texk/kpathsea/ChangeLog @@ -1,3 +1,8 @@ +2024-03-17 Karl Berry <karl@tug.org> + + * texmf.cnf (shell_escape_commands): add l3sys-query + after analysis on tex-live. https://ctan.org/pkg/l3sys-query + 2024-03-10 Karl Berry <karl@tug.org> * TL'24 release. diff --git a/Build/source/texk/kpathsea/texmf.cnf b/Build/source/texk/kpathsea/texmf.cnf index 4cb01e45b15..a3fa528268b 100644 --- a/Build/source/texk/kpathsea/texmf.cnf +++ b/Build/source/texk/kpathsea/texmf.cnf @@ -652,6 +652,7 @@ bibtex,bibtex8,\ extractbb,\ gregorio,\ kpsewhich,\ +l3sys-query,\ makeindex,\ memoize-extract.pl,\ memoize-extract.py,\ diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.am b/Build/source/texk/texlive/linked_scripts/Makefile.am index d59131d316f..e6645224af8 100644 --- a/Build/source/texk/texlive/linked_scripts/Makefile.am +++ b/Build/source/texk/texlive/linked_scripts/Makefile.am @@ -162,6 +162,7 @@ texmf_other_scripts = \ kotex-utils/komkindex.pl \ kotex-utils/ttf2kotexfont.pl \ l3build/l3build.lua \ + l3sys-query/l3sys-query.lua \ latex-git-log/latex-git-log \ latex-papersize/latex-papersize.py \ latex2man/latex2man \ diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.in b/Build/source/texk/texlive/linked_scripts/Makefile.in index 5d643ccb129..fe85e5e3e29 100644 --- a/Build/source/texk/texlive/linked_scripts/Makefile.in +++ b/Build/source/texk/texlive/linked_scripts/Makefile.in @@ -379,6 +379,7 @@ texmf_other_scripts = \ kotex-utils/komkindex.pl \ kotex-utils/ttf2kotexfont.pl \ l3build/l3build.lua \ + l3sys-query/l3sys-query.lua \ latex-git-log/latex-git-log \ latex-papersize/latex-papersize.py \ latex2man/latex2man \ diff --git a/Build/source/texk/texlive/linked_scripts/l3sys-query/l3sys-query.lua b/Build/source/texk/texlive/linked_scripts/l3sys-query/l3sys-query.lua new file mode 100755 index 00000000000..03e86296af4 --- /dev/null +++ b/Build/source/texk/texlive/linked_scripts/l3sys-query/l3sys-query.lua @@ -0,0 +1,569 @@ +#!/usr/bin/env texlua + +--[[ + +File l3sys-query.lua Copyright (C) 2024 The LaTeX Project + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----------------------------------------------------------------------- + +The development version of the bundle can be found at + + https://github.com/latex3/l3sys-query + +for those people who are interested. + +--]] + +-- +-- Details of the script itself, etc. +-- +local copyright = "Copyright (C) 2024 The LaTeX Project" +local release_date = "2024-03-15" +local script_desc = "System queries for LaTeX using Lua\n" +local script_name = "l3sys-query" + +-- +-- Setup for the CLI: commands and options +-- +local cmd_impl = {} +local cmd_desc = {} + +local option_list = + { + exclude = + { + cmds = {"ls"}, + desc = "Exclude entries from directory listing", + type = "string" + }, + ["ignore-case"] = + { + cmds = {"ls"}, + desc = "Ignore case when sorting directory listing", + type = "boolean" + }, + help = + { + desc = "Prints this message and exits", + short = "h", + type = "boolean" + }, + pattern = + { + cmds = {"ls"}, + desc = "Treat (x)args as a Lua pattern", + short = "p", + type = "boolean" + }, + recursive = + { + cmds = {"ls"}, + desc = "Activates recursive directory listing", + short = "r", + type = "boolean" + }, + reverse = + { + cmds = {"ls"}, + desc = "Reversing sorting order", + type = "boolean" + }, + sort = + { + cmds = {"ls"}, + desc = "Method used to sort directory listing", + type = "string" + }, + type = + { + cmds = {"ls"}, + desc = "Selects the type of entry in a directory listing", + type = "string" + }, + version = + { + desc = "Prints version information and exits", + short = "v", + type = "boolean" + } + } + +-- +-- Local copies of globals used here +-- +local io = io +local stderr = io.stderr + +local lfs = lfs +local attributes = lfs.attributes +local currentdir = lfs.currentdir +local dir = lfs.dir + +local os = os +local exit = os.exit + +local string = string +local find = string.find +local gmatch = string.gmatch +local lower = string.lower +local match = string.match +local rep = string.rep +local sub = string.sub + +local table = table +local concat = table.concat +local insert = table.insert +local sort = table.sort + +-- +-- Support functions and data +-- + +-- Remove '...' around an entire text: +-- we need this to support restricted shell escape on Windows +local function dequote(text) + if (match(text,"^'") and match(text,"'$")) then + return sub(text,2,-2) + end + return text +end + + +-- A short auxiliary used whever the script bails out +local function info_and_quit(s) + stderr:write("\n" .. s .. "\nTry '" .. script_name .. " --help' for more information.\n") + exit(1) +end + +-- Convert a file glob into a pattern for use by e.g. string.gub +-- Based on https://github.com/davidm/lua-glob-pattern +-- Simplified substantially: "[...]" syntax not supported as is not +-- required by the file patterns used by the team. Also note style +-- changes to match coding approach in rest of this file. +-- +-- License for original globtopattern +--[[ + + (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT). + +--]] +local function glob_to_pattern(glob,skip_convert) + if skip_convert then + return glob + end + + local pattern = "^" -- pattern being built + local i = 0 -- index in glob + local char -- char at index i in glob + + -- escape pattern char + local function escape(char) + return match(char,"^%w$") and char or "%" .. char + end + + -- Convert tokens. + while true do + i = i + 1 + char = sub(glob,i,i) + if char == "" then + pattern = pattern .. "$" + break + elseif char == "?" then + pattern = pattern .. "." + elseif char == "*" then + pattern = pattern .. ".*" + elseif char == "[" then -- ] + -- Ignored + info_and_quit("[...] syntax not supported in globs!") + elseif char == "\\" then + i = i + 1 + char = sub(glob,i,i) + if char == "" then + pattern = pattern .. "\\$" + break + end + pattern = pattern .. escape(char) + else + pattern = pattern .. escape(char) + end + end + return pattern +end + + +-- Initial data for the command line parser +local cmd = "" +local options = {} +local arg_list = "" + +local function parse_args() + -- Turn long/short options into two lookup tables + local long_options = {} + local short_options = {} + for k,v in pairs(option_list) do + if v.short then + short_options[v.short] = k + end + long_options[k] = k + end + + -- Minor speed-up + local arg = arg + + -- arg[1] is a special case: must be a command or a very limited + -- subset (--help|-h or --version|-v) + local a = arg[1] + if a then + -- No options are allowed in position 1, so filter those out + if a == "--version" or a == "-v" then + cmd = "version" + elseif not match(a,"^%-") then + cmd = a + end + end + + -- Stop here if help or version is required + if cmd == "help" or cmd == "version" then + return + end + + -- An auxiliary to grab all file names into a string: + -- this reflects the fact that the use case for l3sys-query doesn't + -- allow quoting spaces + local function tidy(num) + local t = {} + for i = num,#arg do + insert(t,dequote(arg[i])) + end + return concat(t," ") + end + + -- Examine all other arguments + -- Use a while loop rather than for as this makes it easier + -- to grab arg for optionals where appropriate + local i = 2 + while i <= #arg do + local a = arg[i] + -- Terminate search for options + if a == "--" then + arg_list = tidy(i + 1) + return + end + + -- Look for optionals + local opt + local optarg + local opts + -- Look for and option and get it into a variable + if match(a,"^%-") then + if match(a,"^%-%-") then + opts = long_options + local pos = find(a,"=") + if pos then + opt = sub(a,3,pos - 1) + optarg = sub(a,pos + 1) + else + opt = sub(a,3) + end + else + opts = short_options + opt = sub(a,2,2) + -- Only set optarg if it is there + if #a > 2 then + optarg = sub(a,3) + end + end + + -- Now check that the option is valid and sort out the argument + -- if required + local optname = opts[opt] + if optname then + -- Tidy up arguments + if option_list[optname].type == "boolean" then + if optarg then + local opt = "-" .. (match(a,"^%-%-") and "-" or "") .. opt + info_and_quit("Value not allowed for option " .. opt) + end + else + if not optarg then + optarg = arg[i + 1] + if not optarg then + info_and_quit("Missing value for option " .. a) + end + i = i + 1 + end + end + else + info_and_quit("Unknown option " .. a) + end + + -- Store the result + if optarg then + if option_list[optname].type == "string" then + options[optname] = optarg + else + local opts = options[optname] or {} + for hit in gmatch(optarg,"([^,%s]+)") do + insert(opts,hit) + end + options[optname] = opts + end + else + options[optname] = true + end + i = i + 1 + end + + -- Collect up the remaining arguments + if not opt then + arg_list = tidy(i) + break + end + end +end + +parse_args() + +-- +-- The help functions: local only and hard-coded +-- + +local function help() + -- Find the longest entry to pad + local function format_list(list) + local longest = 0 + for k,_ in pairs(list) do + if k:len() > longest then + longest = k:len() + end + end + -- Sort the list + local t = {} + for k,_ in pairs(list) do + insert(t,k) + end + sort(t) + return t,longest + end + + -- 'Header' of fixed info + print("Usage: " .. script_name .. " <cmd> [<options>] [<args>]\n") + print("Valid <cmd>s are:") + + -- Sort the commands, pad the descriptions, print + local t,longest = format_list(cmd_desc) + for _,k in ipairs(t) do + local cmd = cmd_desc[k] + local filler = rep(" ",longest - k:len() + 1) + print(" " .. k .. filler .. cmd) + end + + -- Same for the options + print("\nValid <options> are:") + t,longest = format_list(option_list) + for _,name in ipairs(t) do + local opt = option_list[name] + local filler = rep(" ",longest - name:len() + 1) + if opt.desc then + if opt.short then + print(" --" .. name .. "|-" .. opt.short .. filler .. opt.desc) + else + print(" --" .. name .. " " .. filler .. opt.desc) + end + end + end + + -- Postamble + print("\nFull manual available via 'texdoc " .. script_name .. "'.\n") + print("Repository : https://github.com/latex3/" .. script_name) + print("Bug tracker: https://github.com/latex3/" .. script_name .. "/issues") + print("\n" .. copyright) +end + +local function version() + print(script_name .. " " .. release_date) +end + +-- +-- The functions for commands: all held in the table cmd_impl +-- with docstrings in the table cmd_desc. +-- + +-- The aim here is to convert a user file specification (if given) into a +-- Lua pattern, and then to do a listing. +cmd_desc.ls = "Prints a listing based on the <args> and <options>" +function cmd_impl.ls(arg_list) + if not arg_list or arg_list == "" or arg_list == "." then + arg_list = "*" + end + -- Look for absolute paths or any trying to leave the confines of the current + -- directory: this is not supported. + if match(arg_list,"%.%.") or + match(arg_list,"^/") or + match(arg_list,"^\\") or + match(arg_list,"[a-zA-Z]:") then + return + end + -- Tidy up and convert to a pattern. + path,glob = match(arg_list,"^(.*)/([^/]*)$") + if not path then + path = "." + glob = arg_list + end + if path == "" then + path = "." + end + if not match(path,"^%.") then + path = "./" .. path + end + local conv_pattern = options.pattern + local pattern = glob_to_pattern(glob,conv_pattern) + local exclude_pattern + if options.exclude then + local exclude = dequote(options.exclude) + exclude_pattern = glob_to_pattern(exclude,conv_pattern) + end + -- A lookup table for attributes: map between lfs- and Unix-type naming + local attrib_map = {d = "directory", f = "file"} + + -- A bit of setup to store the sorting data as well as the entry itself + local i = 0 -- If no sorting active, just track the order from lfs + local entries = {} + local sort_mode = options.sort or "none" + local function store(entry,full_entry) + if not match(entry,pattern) + or (exclude_pattern and match(entry,exclude_pattern)) then + return + end + i = i + 1 + local key = i + if sort_mode == "date" then + key = attributes(full_entry,"modification") + elseif sort_mode == "name" then + key = full_entry + end + entries[key] = full_entry + end + + -- Build a table of entries, excluding "." and "..", and return as a string + -- with one entry per line. + local opt = options.type + local is_rec = options.recursive + local function browse(path) + for entry in dir(path) do + if entry ~= "." and entry ~= ".." and not match(entry,"^%.") then + local full_entry = path .. "/" .. entry + local ft = attributes(full_entry,"mode") + if not opt or ft == attrib_map[opt] then + store(entry,full_entry) + end + if is_rec and ft == "directory" then + browse(full_entry) + end + end + end + end + -- Start a search at the top level + browse(path) + + -- Extract keys and sort + local s = {} + for k,_ in pairs(entries) do + insert(s,k) + end + + -- Setup for case-insensitve sorting + local function case(s) + return s + end + if options["ignore-case"] then + function case(s) + return lower(s) + end + end + + if options.reverse then + sort(s,function(a,b) return case(a) > case(b) end) + else + sort(s,function(a,b) return case(a) < case(b) end) + end + + local result = {} + for _,v in ipairs(s) do + insert(result,entries[v]) + end + + return concat(result,"\n") +end + +-- A simple rename +cmd_desc.pwd = "Prints the present working directory" +function cmd_impl.pwd() + return currentdir() +end + +-- +-- Execute the given command +-- + +-- Only 'known' commands do anything at all +if cmd == "version" then + version() + exit(0) +elseif not cmd_impl[cmd] then + if cmd == "" then + help() + else + info_and_quit(script_name .. ": '" .. cmd .. "' is not a " .. script_name .. + " command.") + end + exit(1) +end + +-- Check options are valid for cmd +for k,_ in pairs(options) do + local cmds = option_list[k].cmds + if not cmds then + -- Should not be possible: + -- everything except --help and --version should have an entry + print("Internal error") + exit(1) + else + -- Make a lookup table + local t = {} + for _,v in pairs(cmds) do + t[v] = true + end + if not t[cmd] then + info_and_quit(script_name .. ": Option '" .. k .. + "' does not apply to '" .. cmd .. "'") + end + end +end + +local result = cmd_impl[cmd](arg_list) + +if result then + print(result) + exit(0) +else + exit(1) +end diff --git a/Build/source/texk/texlive/linked_scripts/scripts.lst b/Build/source/texk/texlive/linked_scripts/scripts.lst index efa9be90b7c..12fa2241416 100644 --- a/Build/source/texk/texlive/linked_scripts/scripts.lst +++ b/Build/source/texk/texlive/linked_scripts/scripts.lst @@ -103,6 +103,7 @@ kotex-utils/jamo-normalize.pl kotex-utils/komkindex.pl kotex-utils/ttf2kotexfont.pl l3build/l3build.lua +l3sys-query/l3sys-query.lua latex-git-log/latex-git-log latex-papersize/latex-papersize.py latex2man/latex2man diff --git a/Master/bin/aarch64-linux/l3sys-query b/Master/bin/aarch64-linux/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/aarch64-linux/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/amd64-freebsd/l3sys-query b/Master/bin/amd64-freebsd/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/amd64-freebsd/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/amd64-netbsd/l3sys-query b/Master/bin/amd64-netbsd/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/amd64-netbsd/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/armhf-linux/l3sys-query b/Master/bin/armhf-linux/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/armhf-linux/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/i386-freebsd/l3sys-query b/Master/bin/i386-freebsd/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/i386-freebsd/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/i386-linux/l3sys-query b/Master/bin/i386-linux/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/i386-linux/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/i386-netbsd/l3sys-query b/Master/bin/i386-netbsd/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/i386-netbsd/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/i386-solaris/l3sys-query b/Master/bin/i386-solaris/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/i386-solaris/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/universal-darwin/l3sys-query b/Master/bin/universal-darwin/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/universal-darwin/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/windows/l3sys-query.exe b/Master/bin/windows/l3sys-query.exe Binary files differnew file mode 100755 index 00000000000..3332231b08c --- /dev/null +++ b/Master/bin/windows/l3sys-query.exe diff --git a/Master/bin/x86_64-cygwin/l3sys-query b/Master/bin/x86_64-cygwin/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/x86_64-cygwin/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/x86_64-darwinlegacy/l3sys-query b/Master/bin/x86_64-darwinlegacy/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/x86_64-darwinlegacy/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/x86_64-linux/l3sys-query b/Master/bin/x86_64-linux/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/x86_64-linux/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/x86_64-linuxmusl/l3sys-query b/Master/bin/x86_64-linuxmusl/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/x86_64-linuxmusl/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/bin/x86_64-solaris/l3sys-query b/Master/bin/x86_64-solaris/l3sys-query new file mode 120000 index 00000000000..2d072dc033b --- /dev/null +++ b/Master/bin/x86_64-solaris/l3sys-query @@ -0,0 +1 @@ +../../texmf-dist/scripts/l3sys-query/l3sys-query.lua
\ No newline at end of file diff --git a/Master/texmf-dist/doc/man/man1/l3sys-query.1 b/Master/texmf-dist/doc/man/man1/l3sys-query.1 new file mode 100644 index 00000000000..146d0e4c2c6 --- /dev/null +++ b/Master/texmf-dist/doc/man/man1/l3sys-query.1 @@ -0,0 +1,16 @@ +.TH L3SYS-QUERY 1 "2024-03-15" "LaTeX" + +.SH NAME +l3sys-query + +.SH SYNOPSIS + Usage l3sys-query <cmd> [<options>] [<args>] + +.SH DESCRIPTION + +The l3sys-query script provides a method for TeX runs to obtain system +information via shell escape to Lua. The facilities are more limited than the +similar Java script texosquery, but since it uses Lua, l3sys-query can be +used 'out of the box' with any install TeX system. The script is written taking +account of TeX Live security requirement; it is therefore suitable for use with +restricted shell escape, the standard setting when installing a TeX system. diff --git a/Master/texmf-dist/doc/man/man1/l3sys-query.man1.pdf b/Master/texmf-dist/doc/man/man1/l3sys-query.man1.pdf Binary files differnew file mode 100644 index 00000000000..e518f97c762 --- /dev/null +++ b/Master/texmf-dist/doc/man/man1/l3sys-query.man1.pdf diff --git a/Master/texmf-dist/doc/support/l3sys-query/CHANGELOG.md b/Master/texmf-dist/doc/support/l3sys-query/CHANGELOG.md new file mode 100644 index 00000000000..b11654d5124 --- /dev/null +++ b/Master/texmf-dist/doc/support/l3sys-query/CHANGELOG.md @@ -0,0 +1,25 @@ +# Changelog +All notable changes to the `l3sys-query` will be documented in this file. + +The format is based on [Keep a +Changelog](https://keepachangelog.com/en/1.0.0/), this project uses date-based +'snapshot' version identifiers. + +## [Unreleased] + +## [2024-03-15] + +### Added +- PDF documentation in distribution +- `man` file in distribution + +### Changed +- Documentation tweaks + +## [2024-03-14] + +### Added +- New script + +[Unreleased]: https://github.com/latex3/l3sys-query/compare/2024-03-15...HEAD +[2024-03-15]: https://github.com/latex3/l3sys-query/compare/2024-03-14...2024-03-15 diff --git a/Master/texmf-dist/doc/support/l3sys-query/README.md b/Master/texmf-dist/doc/support/l3sys-query/README.md new file mode 100644 index 00000000000..1b9998f29ee --- /dev/null +++ b/Master/texmf-dist/doc/support/l3sys-query/README.md @@ -0,0 +1,36 @@ +# `l3sys-query`: System queries for LaTeX using Lua + +Release 2024-03-15 + +## Overview + +The `l3sys-query` script provides a method for TeX runs to obtain system +information _via_ shell escape to Lua. The facilities are more limited than the +similar Java script `texosquery`, but since it uses Lua, `l3sys-query` can be +used 'out of the box' with any install TeX system. The script is written taking +account of TeX Live security requirement; it is therefore suitable for use with +restricted shell escape, the standard setting when installing a TeX system. + +The supported queries are +- `ls`: Directory listing supporting a range of options +- `pwd`: Obtaining details of the current working directory + +## Issues + +The issue tracker for LaTeX is currently located +[on GitHub](https://github.com/latex3/l3sys-query/issues). + +## Development team + +This code is developed by [The LaTeX Project](https://latex-project.org). + +## License + +This project licensed under the same terms as Lua (MIT): see LICENSE or the top +of source files for the legal text. + +----- + +<p>Copyright (C) 2024 The LaTeX Project <br /> +<a href="https://latex-project.org/">https://latex-project.org/</a> <br /> +All rights reserved.</p> diff --git a/Master/texmf-dist/doc/support/l3sys-query/SECURITY.md b/Master/texmf-dist/doc/support/l3sys-query/SECURITY.md new file mode 100644 index 00000000000..6eacf730129 --- /dev/null +++ b/Master/texmf-dist/doc/support/l3sys-query/SECURITY.md @@ -0,0 +1,17 @@ +# Security Policy + +## Link to TeX Live Security Model + +As described in the script documentation, the primary aim of `l3sys-query` is +to support system queries in the context of restricted shell escape from a TeX +run. Specifically, the script is intended to respect _restricted_ shell escape. + +## Reporting a Vulnerability + +Security vulnerabilities can be reported privately _via_ GitHub at +https://github.com/latex3/l3sys-query/security. Using this mechanism means that +the potential issue does not show in the public issues list, and will give the +team chance to review the report before it is made public. + +Alternative, the LaTeX Team can be contacted by email: +latex-team@latex-project.org. diff --git a/Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.pdf b/Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.pdf Binary files differnew file mode 100644 index 00000000000..78e26662695 --- /dev/null +++ b/Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.pdf diff --git a/Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.tex b/Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.tex new file mode 100644 index 00000000000..d9b99d59c1c --- /dev/null +++ b/Master/texmf-dist/doc/support/l3sys-query/l3sys-query-tool.tex @@ -0,0 +1,264 @@ +\iffalse meta-comment + +File l3sys-query-tool.tex Copyright (C) 2024 The LaTeX Project + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----------------------------------------------------------------------- + +The development version of the bundle can be found at + + https://github.com/latex3/l3sys-query + +for those people who are interested. + +----------------------------------------------------------------------- + +\fi + +\documentclass{l3doc} + +\begin{document} + +\title{The \pkg{l3sys-query} script: System queries for LaTeX using Lua} + +\author{% + The \LaTeX{} Project\thanks{% + Email: \href{mailto:latex-team@latex-project.org} + {latex-team@latex-project.org}% + }% +} + +\date{Release 2024-03-15} + +\maketitle +\tableofcontents + +\begin{documentation} + +\section{Introduction} + +\TeX{} engines provide only very limited access to information about the system +they are used on: using primitives, one can for example get the size of a single +file, but not a list of files in a given location. For most documents, this is +not an issue as they are self-contained. However, for cases where +\enquote{dynamic} construction of parts of a document is needed based on file +lists or other system-dependent data, methods to obtain this from (restricted) +shell escape are desirable. + +Security considerations mean that directly querying the system shell is +problematic for general use. Instead, \emph{restricted} shell escape may be used +to get many details, provided a suitable tool is available to provide the +information in a platform-neutral and security-conscious way. The Java program +\texttt{texosquery}, written by Nicola Talbot, has been available for a number +of years to provide this facility. As well as file system insight, +\texttt{texosquery} also provides for example locale data and other system +information. However, the requirement for Java means that the script is not +automatically usable when a \TeX{} system is installed. + +The \LaTeX{} team have therefore provided a Lua-based script, +\texttt{l3sys-query}, which conforms to the security requirements of \TeX{} Live +using Lua to obtain the system information. This means that it can be used +\enquote{out of the box} across platforms. The facilities provided by +\texttt{l3sys-query} are more limited than \texttt{texosquery}, partly as some +information is available in modern \TeX{} systems using primitives, and partly +as the aim of \texttt{l3sys-query} is to provide information where there are +defined use cases. Requests for additional data interfaces are welcome. + +\section{The command line interface} + +The command line interface to +\begin{center} + \ttfamily + l3sys-query \meta{cmd} [\meta{option(s)}] [\meta{args}] +\end{center} +where \texttt{\meta{cmd}} can be one of the following: +\begin{itemize}[noitemsep]\ttfamily + \item ls + \item ls \meta{args} + \item pwd +\end{itemize} +The \meta{cmd} are described below. The result of the \meta{cmd} will be printed +to the terminal in an interactive run; in normal usage, this will be piped to +the calling \TeX{} process. Results containing path separators \emph{always} +use~|/|, irrespective of the platform in use. + +As well as these targets, the script recognizes the options +\begin{itemize} + \item |--exclude| Specification for directory entries to exclude + \item |--ignore-case| Ignores case when sorting directory listings + \item |--pattern| (|-p|) Treat the \meta{args} as Lua patterns rather + than converting from wildcards + \item |--recursive| (|-r|) Enables recursive searching during directory + listings + \item |--reverse| Causes sorting to go from highest to lowest rather + than lowest to highest + \item |--sort| Sets the method used to sort entries returned by |ls| + \item |--type| Selects the type of entry returned by |ls| +\end{itemize} +The action of these options on the appropriate \meta{cmd(s)} is detailed below. + +\subsection{\texttt{ls [\meta{args}]}} + +Lists the contents of one or more directories, in a manner somewhat reminiscent +of the Unix command |ls| or the Windows command |dir|. The exact nature of the +output will depend on the \meta{args}, if given, along with the prevailing +options. Note that the options names are inspired by ideas from the Unix +commands |ls| and |find| as well as the Windows command |dir|: they therefore do +not map directly to those of any one of the command line tools that they +somewhat mirror. + +When no \meta{args} are given, all entries in the current directory will be +listed, one per line in the output. This will include both files and +subdirectories. Each entry will include a path relative to the current +directory: for files \emph{in} the current directory, this will be |./|. The +order of results will be determined by the underlying operating system process: +unless requested \emph{via} an option, no sorting takes place. + +As standard, the \meta{args} are treated as a file/path name potentially +including |?| and |*| as wildcards, for example |*.png| or |file?.txt|. +\begin{verbatim} + l3sys-query ls '*.png' +\end{verbatim} +Some care is needed in preventing expansion of such wildcards by the shell or +\texttt{texlua} process: these are detailed in Section~\ref{sec:wildcard}. In +this section, |'| is used to indicate a character being used to suppress +expansion: this is for example normal on macOS and Linux. + +Removal of entries from the listing can be achieved using the |--exclude| +option, which should be given with a \meta{xarg}, for example +\begin{verbatim} + l3sys-query ls --exclude '*.bak' 'graphics/*' +\end{verbatim} +Directory entries starting |.| are traditionally hidden on Linux and macOS +systems: these \enquote{dot} entries are excluded from the output of +\texttt{l3sys-query}. The entries |.| and |..| for the current and parent +directory are also excluded from the results returned by \texttt{l3sys-query} as +they can always be assumed. + +For more complex matching, the \meta{args} can be treated as a Lua pattern using +the |--pattern| (|-p|) option; this also applies to the \meta{xarg} argument to +the |--exclude| option. For example, the equivalent to wildcard |*.png| could be +obtained using +\begin{verbatim} + l3sys-query ls --pattern '^.*%.png$' +\end{verbatim} + +The results returned by |ls| can be sorted using the |--sort| option. This can +be set to |none| (use the order from the file system: the default), |name| (sort +by file name) or |date| (sort by date last modified). The sorting order can be +reversed using |--reverse|. Sorting normally takes account of case: this can be +suppressed with the |--ignore-case| option. + +The listing can be filtered based on the type of entry using the |--type| +option. This takes a string argument, one of |d| (directory) or |f| (file). + +As standard, only the path specified as part of the \meta{args} is queried. +However, if the |--recursive| (|-r|) option is set, the query is applied within +all subdirectories. Subdirectories starting with~|.| (macOS and Linux hidden) +are excluded from recursion. + +For security reasons, only paths within the current working directory can be +queried, this for example |graphics/*.png| will list all |png| files in the +|graphics| subdirectory, but |../graphics/*.png| will yield no output. + +\subsection{\texttt{pwd}} + +Returns the absolute path to the current working directory from which +\texttt{l3sys-query} is run. From within a \TeX{} run, this will (usually) be +the directory containing the main file, assuming a command such as +\begin{verbatim} + pdflatex main.tex +\end{verbatim} +The \texttt{pwd} command is unaffected by any options. + +\section{Spaces in arguments} + +Since \texttt{l3sys-query} is intended primarily for use with restricted shell +escape calls from \TeX{} processes, handling of spaces is unusual. It is not +possible to quote spaces in such a call, so for example whilst +\begin{verbatim} + l3sys-query ls "foo *" +\end{verbatim} +does work from the command prompt to find all files with names starting +\verb*|foo |, it would not work \emph{via} restricted shell escape. To +circumvent this, \texttt{l3sys-query} will collect all command line arguments +after any \meta{options}, and combine these as a space-separated \meta{args}, +for example allowing +\begin{verbatim} + l3sys-query ls foo '*' +\end{verbatim} +to achieve the same result as the first example. The result is that the +\meta{args} will only every be interpreted by \texttt{l3sys-query} as a single +argument. It also means that spaces cannot be used at the start or end of the +argument, nor can multiple spaces appear between non-space arguments. + +\section{Wildcard expansion handling\label{sec:wildcard}} + +The handling of wildcards needs some further comment for those using +\texttt{l3sys-query} from the command line: the \pkg{expl3} interface described +in Section~\ref{sec:expl3} handles this aspect automatically for the user. + +On macOS and Linux, the shell normally expands globs, which include the +wildcards |*| and |?|, before passing arguments to the appropriate command. +This can be suppressed by surrounding the argument with |'| characters, hence +the formulation +\begin{verbatim} + l3sys-query ls '*.png' +\end{verbatim} +earlier. + +On Windows, the shell does no expansion, and thus arguments are passed as-is to +the relevant command. As such, |'| has no special meaning here. However, to +allow quoting of wildcards from the shell in a platform-neutral manner, +\texttt{l3sys-query} will strip exactly one set of |'| characters around each +argument before further processing. + +It is not possible to use |"| quotes at all in the argument passed to +\texttt{l3sys-query} from \TeX{}, as the \TeX{} system removes all |"| in +|\input| while handling space quoting. + +Restricted shell escape prevents shell expansion of wildcards entirely. On +non-Windows systems, it does this by ensuring that each argument is |'| quoted +to ensure further expansion. Thus a \TeX{} call such as +\begin{verbatim} + \input|"l3sys-query ls '*.png'" +\end{verbatim} +will work if |--shell-escape| is used as the argument is passed directly to the +shell, but in restricted shell escape will give an error such as: +\begin{verbatim} +! I can't find file `"|l3sys-query ls '*.png'"'. +\end{verbatim} +The \LaTeX{} interfaces described below adust the quoting used depending on the +|shell-escape| status. + +\section{The \LaTeX{} interface\label{sec:expl3}} + +Using \texttt{l3sys-query} is not tied to access \emph{via} \pkg{expl3}, but +this is the preferred approach for the \LaTeX{} Team. Details of how to use +\texttt{l3sys-query} as an \pkg{expl3} programmer will covered in +\texttt{interface3.pdf} once the macro code is finalized. A document level +interface will also be provided via a \pkg{l3sys-query} package which is based +on the \pkg{expl3} interface and will be described here. + +\end{documentation} + +\PrintIndex + +\end{document} diff --git a/Master/texmf-dist/scripts/l3sys-query/l3sys-query.lua b/Master/texmf-dist/scripts/l3sys-query/l3sys-query.lua new file mode 100755 index 00000000000..03e86296af4 --- /dev/null +++ b/Master/texmf-dist/scripts/l3sys-query/l3sys-query.lua @@ -0,0 +1,569 @@ +#!/usr/bin/env texlua + +--[[ + +File l3sys-query.lua Copyright (C) 2024 The LaTeX Project + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----------------------------------------------------------------------- + +The development version of the bundle can be found at + + https://github.com/latex3/l3sys-query + +for those people who are interested. + +--]] + +-- +-- Details of the script itself, etc. +-- +local copyright = "Copyright (C) 2024 The LaTeX Project" +local release_date = "2024-03-15" +local script_desc = "System queries for LaTeX using Lua\n" +local script_name = "l3sys-query" + +-- +-- Setup for the CLI: commands and options +-- +local cmd_impl = {} +local cmd_desc = {} + +local option_list = + { + exclude = + { + cmds = {"ls"}, + desc = "Exclude entries from directory listing", + type = "string" + }, + ["ignore-case"] = + { + cmds = {"ls"}, + desc = "Ignore case when sorting directory listing", + type = "boolean" + }, + help = + { + desc = "Prints this message and exits", + short = "h", + type = "boolean" + }, + pattern = + { + cmds = {"ls"}, + desc = "Treat (x)args as a Lua pattern", + short = "p", + type = "boolean" + }, + recursive = + { + cmds = {"ls"}, + desc = "Activates recursive directory listing", + short = "r", + type = "boolean" + }, + reverse = + { + cmds = {"ls"}, + desc = "Reversing sorting order", + type = "boolean" + }, + sort = + { + cmds = {"ls"}, + desc = "Method used to sort directory listing", + type = "string" + }, + type = + { + cmds = {"ls"}, + desc = "Selects the type of entry in a directory listing", + type = "string" + }, + version = + { + desc = "Prints version information and exits", + short = "v", + type = "boolean" + } + } + +-- +-- Local copies of globals used here +-- +local io = io +local stderr = io.stderr + +local lfs = lfs +local attributes = lfs.attributes +local currentdir = lfs.currentdir +local dir = lfs.dir + +local os = os +local exit = os.exit + +local string = string +local find = string.find +local gmatch = string.gmatch +local lower = string.lower +local match = string.match +local rep = string.rep +local sub = string.sub + +local table = table +local concat = table.concat +local insert = table.insert +local sort = table.sort + +-- +-- Support functions and data +-- + +-- Remove '...' around an entire text: +-- we need this to support restricted shell escape on Windows +local function dequote(text) + if (match(text,"^'") and match(text,"'$")) then + return sub(text,2,-2) + end + return text +end + + +-- A short auxiliary used whever the script bails out +local function info_and_quit(s) + stderr:write("\n" .. s .. "\nTry '" .. script_name .. " --help' for more information.\n") + exit(1) +end + +-- Convert a file glob into a pattern for use by e.g. string.gub +-- Based on https://github.com/davidm/lua-glob-pattern +-- Simplified substantially: "[...]" syntax not supported as is not +-- required by the file patterns used by the team. Also note style +-- changes to match coding approach in rest of this file. +-- +-- License for original globtopattern +--[[ + + (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT). + +--]] +local function glob_to_pattern(glob,skip_convert) + if skip_convert then + return glob + end + + local pattern = "^" -- pattern being built + local i = 0 -- index in glob + local char -- char at index i in glob + + -- escape pattern char + local function escape(char) + return match(char,"^%w$") and char or "%" .. char + end + + -- Convert tokens. + while true do + i = i + 1 + char = sub(glob,i,i) + if char == "" then + pattern = pattern .. "$" + break + elseif char == "?" then + pattern = pattern .. "." + elseif char == "*" then + pattern = pattern .. ".*" + elseif char == "[" then -- ] + -- Ignored + info_and_quit("[...] syntax not supported in globs!") + elseif char == "\\" then + i = i + 1 + char = sub(glob,i,i) + if char == "" then + pattern = pattern .. "\\$" + break + end + pattern = pattern .. escape(char) + else + pattern = pattern .. escape(char) + end + end + return pattern +end + + +-- Initial data for the command line parser +local cmd = "" +local options = {} +local arg_list = "" + +local function parse_args() + -- Turn long/short options into two lookup tables + local long_options = {} + local short_options = {} + for k,v in pairs(option_list) do + if v.short then + short_options[v.short] = k + end + long_options[k] = k + end + + -- Minor speed-up + local arg = arg + + -- arg[1] is a special case: must be a command or a very limited + -- subset (--help|-h or --version|-v) + local a = arg[1] + if a then + -- No options are allowed in position 1, so filter those out + if a == "--version" or a == "-v" then + cmd = "version" + elseif not match(a,"^%-") then + cmd = a + end + end + + -- Stop here if help or version is required + if cmd == "help" or cmd == "version" then + return + end + + -- An auxiliary to grab all file names into a string: + -- this reflects the fact that the use case for l3sys-query doesn't + -- allow quoting spaces + local function tidy(num) + local t = {} + for i = num,#arg do + insert(t,dequote(arg[i])) + end + return concat(t," ") + end + + -- Examine all other arguments + -- Use a while loop rather than for as this makes it easier + -- to grab arg for optionals where appropriate + local i = 2 + while i <= #arg do + local a = arg[i] + -- Terminate search for options + if a == "--" then + arg_list = tidy(i + 1) + return + end + + -- Look for optionals + local opt + local optarg + local opts + -- Look for and option and get it into a variable + if match(a,"^%-") then + if match(a,"^%-%-") then + opts = long_options + local pos = find(a,"=") + if pos then + opt = sub(a,3,pos - 1) + optarg = sub(a,pos + 1) + else + opt = sub(a,3) + end + else + opts = short_options + opt = sub(a,2,2) + -- Only set optarg if it is there + if #a > 2 then + optarg = sub(a,3) + end + end + + -- Now check that the option is valid and sort out the argument + -- if required + local optname = opts[opt] + if optname then + -- Tidy up arguments + if option_list[optname].type == "boolean" then + if optarg then + local opt = "-" .. (match(a,"^%-%-") and "-" or "") .. opt + info_and_quit("Value not allowed for option " .. opt) + end + else + if not optarg then + optarg = arg[i + 1] + if not optarg then + info_and_quit("Missing value for option " .. a) + end + i = i + 1 + end + end + else + info_and_quit("Unknown option " .. a) + end + + -- Store the result + if optarg then + if option_list[optname].type == "string" then + options[optname] = optarg + else + local opts = options[optname] or {} + for hit in gmatch(optarg,"([^,%s]+)") do + insert(opts,hit) + end + options[optname] = opts + end + else + options[optname] = true + end + i = i + 1 + end + + -- Collect up the remaining arguments + if not opt then + arg_list = tidy(i) + break + end + end +end + +parse_args() + +-- +-- The help functions: local only and hard-coded +-- + +local function help() + -- Find the longest entry to pad + local function format_list(list) + local longest = 0 + for k,_ in pairs(list) do + if k:len() > longest then + longest = k:len() + end + end + -- Sort the list + local t = {} + for k,_ in pairs(list) do + insert(t,k) + end + sort(t) + return t,longest + end + + -- 'Header' of fixed info + print("Usage: " .. script_name .. " <cmd> [<options>] [<args>]\n") + print("Valid <cmd>s are:") + + -- Sort the commands, pad the descriptions, print + local t,longest = format_list(cmd_desc) + for _,k in ipairs(t) do + local cmd = cmd_desc[k] + local filler = rep(" ",longest - k:len() + 1) + print(" " .. k .. filler .. cmd) + end + + -- Same for the options + print("\nValid <options> are:") + t,longest = format_list(option_list) + for _,name in ipairs(t) do + local opt = option_list[name] + local filler = rep(" ",longest - name:len() + 1) + if opt.desc then + if opt.short then + print(" --" .. name .. "|-" .. opt.short .. filler .. opt.desc) + else + print(" --" .. name .. " " .. filler .. opt.desc) + end + end + end + + -- Postamble + print("\nFull manual available via 'texdoc " .. script_name .. "'.\n") + print("Repository : https://github.com/latex3/" .. script_name) + print("Bug tracker: https://github.com/latex3/" .. script_name .. "/issues") + print("\n" .. copyright) +end + +local function version() + print(script_name .. " " .. release_date) +end + +-- +-- The functions for commands: all held in the table cmd_impl +-- with docstrings in the table cmd_desc. +-- + +-- The aim here is to convert a user file specification (if given) into a +-- Lua pattern, and then to do a listing. +cmd_desc.ls = "Prints a listing based on the <args> and <options>" +function cmd_impl.ls(arg_list) + if not arg_list or arg_list == "" or arg_list == "." then + arg_list = "*" + end + -- Look for absolute paths or any trying to leave the confines of the current + -- directory: this is not supported. + if match(arg_list,"%.%.") or + match(arg_list,"^/") or + match(arg_list,"^\\") or + match(arg_list,"[a-zA-Z]:") then + return + end + -- Tidy up and convert to a pattern. + path,glob = match(arg_list,"^(.*)/([^/]*)$") + if not path then + path = "." + glob = arg_list + end + if path == "" then + path = "." + end + if not match(path,"^%.") then + path = "./" .. path + end + local conv_pattern = options.pattern + local pattern = glob_to_pattern(glob,conv_pattern) + local exclude_pattern + if options.exclude then + local exclude = dequote(options.exclude) + exclude_pattern = glob_to_pattern(exclude,conv_pattern) + end + -- A lookup table for attributes: map between lfs- and Unix-type naming + local attrib_map = {d = "directory", f = "file"} + + -- A bit of setup to store the sorting data as well as the entry itself + local i = 0 -- If no sorting active, just track the order from lfs + local entries = {} + local sort_mode = options.sort or "none" + local function store(entry,full_entry) + if not match(entry,pattern) + or (exclude_pattern and match(entry,exclude_pattern)) then + return + end + i = i + 1 + local key = i + if sort_mode == "date" then + key = attributes(full_entry,"modification") + elseif sort_mode == "name" then + key = full_entry + end + entries[key] = full_entry + end + + -- Build a table of entries, excluding "." and "..", and return as a string + -- with one entry per line. + local opt = options.type + local is_rec = options.recursive + local function browse(path) + for entry in dir(path) do + if entry ~= "." and entry ~= ".." and not match(entry,"^%.") then + local full_entry = path .. "/" .. entry + local ft = attributes(full_entry,"mode") + if not opt or ft == attrib_map[opt] then + store(entry,full_entry) + end + if is_rec and ft == "directory" then + browse(full_entry) + end + end + end + end + -- Start a search at the top level + browse(path) + + -- Extract keys and sort + local s = {} + for k,_ in pairs(entries) do + insert(s,k) + end + + -- Setup for case-insensitve sorting + local function case(s) + return s + end + if options["ignore-case"] then + function case(s) + return lower(s) + end + end + + if options.reverse then + sort(s,function(a,b) return case(a) > case(b) end) + else + sort(s,function(a,b) return case(a) < case(b) end) + end + + local result = {} + for _,v in ipairs(s) do + insert(result,entries[v]) + end + + return concat(result,"\n") +end + +-- A simple rename +cmd_desc.pwd = "Prints the present working directory" +function cmd_impl.pwd() + return currentdir() +end + +-- +-- Execute the given command +-- + +-- Only 'known' commands do anything at all +if cmd == "version" then + version() + exit(0) +elseif not cmd_impl[cmd] then + if cmd == "" then + help() + else + info_and_quit(script_name .. ": '" .. cmd .. "' is not a " .. script_name .. + " command.") + end + exit(1) +end + +-- Check options are valid for cmd +for k,_ in pairs(options) do + local cmds = option_list[k].cmds + if not cmds then + -- Should not be possible: + -- everything except --help and --version should have an entry + print("Internal error") + exit(1) + else + -- Make a lookup table + local t = {} + for _,v in pairs(cmds) do + t[v] = true + end + if not t[cmd] then + info_and_quit(script_name .. ": Option '" .. k .. + "' does not apply to '" .. cmd .. "'") + end + end +end + +local result = cmd_impl[cmd](arg_list) + +if result then + print(result) + exit(0) +else + exit(1) +end diff --git a/Master/texmf-dist/web2c/texmf.cnf b/Master/texmf-dist/web2c/texmf.cnf index 4cb01e45b15..a3fa528268b 100644 --- a/Master/texmf-dist/web2c/texmf.cnf +++ b/Master/texmf-dist/web2c/texmf.cnf @@ -652,6 +652,7 @@ bibtex,bibtex8,\ extractbb,\ gregorio,\ kpsewhich,\ +l3sys-query,\ makeindex,\ memoize-extract.pl,\ memoize-extract.py,\ diff --git a/Master/tlpkg/bin/tl-update-asy b/Master/tlpkg/bin/tl-update-asy index 027e4bf30d2..da3929daee4 100755 --- a/Master/tlpkg/bin/tl-update-asy +++ b/Master/tlpkg/bin/tl-update-asy @@ -69,7 +69,8 @@ elif test "x$1" = x--build; then ./configure --prefix=/tmp/ainst --enable-static \ --with-latex=/tmp/ainst/latex --with-context=/tmp/ainst/context \ --disable-fftw --disable-gl --disable-gsl --disable-lsp \ - --enable-texlive-build CFLAGS=-g CXXFLAGS=-std=c++11 + --enable-texlive-build \ + CFLAGS=-g CXXFLAGS=-std=c++11 LDFLAGS="-static-libgcc -static-libstdc++" make make check make install-prebuilt diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check index d1808505931..d08a54f851b 100755 --- a/Master/tlpkg/bin/tlpkg-ctan-check +++ b/Master/tlpkg/bin/tlpkg-ctan-check @@ -467,7 +467,7 @@ my @TLP_working = qw( ktv-texdata ku-template kurdishlipsum kurier kvdefinekeys kvmap kvoptions kvsetkeys l2picfaq l2tabu l2tabu-english l2tabu-french l2tabu-italian l2tabu-spanish - l3backend l3build l3kernel l3packages l3experimental + l3backend l3build l3kernel l3packages l3experimental l3sys-query labbook labels labels4easylist labelschanged labyrinth ladder lambda-lists lambdax langcode langnames langsci langsci-avm diff --git a/Master/tlpkg/doc/releng.txt b/Master/tlpkg/doc/releng.txt index 6df5b43542f..380244c7522 100644 --- a/Master/tlpkg/doc/releng.txt +++ b/Master/tlpkg/doc/releng.txt @@ -121,8 +121,13 @@ critical=--critical # tlcritical needed for new release version tl_update_auto=false # keep files as-is for now net_frozen=true # stay local for now, no update of tlpretest catalogue_compare=false # avoid for initial test + First build happens below, after many more changes; don't start it yet. +Even if tlmgr itself is up to date, probably need to set --critical +because of other changes, such as doc or certs; see /tmp/tlcrit.diff. +In any case, doesn't hurt, so safest to always set it. + 4. After setting up for pretest (not before), basic updates for release year: Master/.mkisofsrc Master/release-texlive.txt diff --git a/Master/tlpkg/libexec/ctan2tds b/Master/tlpkg/libexec/ctan2tds index 4baae7a746c..845ea589098 100755 --- a/Master/tlpkg/libexec/ctan2tds +++ b/Master/tlpkg/libexec/ctan2tds @@ -3772,6 +3772,7 @@ $standardttf = '\.ttf|\.TTC'; 'ketcindy' => 'ketcindy\.pl', 'kotex-utils' => '\.pl$', 'l3build' => 'l3build\.lua$', + 'l3sys-query' => 'l3sys-query\.lua$', 'latex-git-log' => 'latex-git-log$', 'latex-papersize' => '\.py$', 'latex2man' => 'latex2man$', @@ -3908,6 +3909,7 @@ $standardttf = '\.ttf|\.TTC'; 'git-latexdiff' => '\.1$', 'glossaries' => '\.1$', 'l3build' => '\.1$', + 'l3sys-query' => '\.1$', 'latex-git-log' => '\.1$', 'latex2man' => '\.1$', 'latexdiff' => '\.1$', diff --git a/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc index 663e3d337f2..f05a7edd868 100644 --- a/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc +++ b/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc @@ -48,6 +48,7 @@ depend gsftopk depend hook-pre-commit-pkg depend installfont depend ketcindy +depend l3sys-query depend lacheck depend latex-git-log depend latex-papersize diff --git a/Master/tlpkg/tlpsrc/l3sys-query.tlpsrc b/Master/tlpkg/tlpsrc/l3sys-query.tlpsrc new file mode 100644 index 00000000000..03a5f997080 --- /dev/null +++ b/Master/tlpkg/tlpsrc/l3sys-query.tlpsrc @@ -0,0 +1,4 @@ +binpattern f bin/${ARCH}/${PKGNAME} + +# just in case someone wants it early. +depend luatex |