From 25f20b6d8ccd4edcdfec23c1a3c908516076ee06 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Thu, 6 May 2021 03:00:58 +0000 Subject: CTAN sync 202105060300 --- macros/latex/contrib/easybook/easybook.dtx | 217 ++++++----- macros/latex/contrib/easybook/easybook.pdf | Bin 477941 -> 479006 bytes macros/latex/contrib/l3build/CHANGELOG.md | 20 +- macros/latex/contrib/l3build/CONTRIBUTING.md | 2 +- macros/latex/contrib/l3build/README.md | 12 +- macros/latex/contrib/l3build/l3build-arguments.lua | 10 +- macros/latex/contrib/l3build/l3build-aux.lua | 134 ++++--- macros/latex/contrib/l3build/l3build-check.lua | 423 +++++++++++---------- macros/latex/contrib/l3build/l3build-clean.lua | 50 ++- macros/latex/contrib/l3build/l3build-ctan.lua | 8 +- .../contrib/l3build/l3build-file-functions.lua | 128 ++++--- macros/latex/contrib/l3build/l3build-help.lua | 10 +- macros/latex/contrib/l3build/l3build-install.lua | 82 ++-- .../contrib/l3build/l3build-manifest-setup.lua | 26 +- macros/latex/contrib/l3build/l3build-manifest.lua | 5 +- macros/latex/contrib/l3build/l3build-stdmain.lua | 10 +- macros/latex/contrib/l3build/l3build-tagging.lua | 11 +- .../latex/contrib/l3build/l3build-typesetting.lua | 41 +- macros/latex/contrib/l3build/l3build-unpack.lua | 12 +- macros/latex/contrib/l3build/l3build-upload.lua | 20 +- macros/latex/contrib/l3build/l3build-variables.lua | 22 +- macros/latex/contrib/l3build/l3build.1 | 4 +- macros/latex/contrib/l3build/l3build.dtx | 132 ++++--- macros/latex/contrib/l3build/l3build.ins | 4 +- macros/latex/contrib/l3build/l3build.lua | 25 +- macros/latex/contrib/l3build/l3build.pdf | Bin 707231 -> 708509 bytes 26 files changed, 781 insertions(+), 627 deletions(-) mode change 100755 => 100644 macros/latex/contrib/l3build/l3build.lua (limited to 'macros/latex') diff --git a/macros/latex/contrib/easybook/easybook.dtx b/macros/latex/contrib/easybook/easybook.dtx index 71eec1dedc..2247ca0125 100644 --- a/macros/latex/contrib/easybook/easybook.dtx +++ b/macros/latex/contrib/easybook/easybook.dtx @@ -24,11 +24,11 @@ % \changes{v1.20}{2021/01/09}{修改和完善用户文档。} % \changes{v1.20}{2021/01/09}{模板更改为使用 CC-BY 许可协议。} % \changes{v1.23}{2021/03/19}{修复在 \pkg{ctex} v2.5.6 更新后 \cls{easybook} 与 \pkg{hyperref} 冲突问题。} -% \changes{v1.25a}{2021/05/03}{取消附带的示例文件,可查看历史版本及其它来源的使用样例。} +% \changes{v1.25b}{2021/05/03}{取消附带的示例文件,可查看历史版本及其它来源的使用样例。} % % \title{\sffamily easybook 文档类手册} % \author{瞿毅} -% \date{2021/05/04\hskip\ccwd\relax v1.25a\thanks{\url{https://gitee.com/texl3/easybook}}} +% \date{2021/05/05\hskip\ccwd\relax v1.25b\thanks{\url{https://gitee.com/texl3/easybook}}} % % \maketitle % \begin{abstract} @@ -118,7 +118,7 @@ % \end{syntax} % 传递给 \cls{ctexbook} 设置字体,最好不要使用原有的 \opt{fontset} 选项,默认情况下使用自定义字体而不开启这个选项,可根据安装的字体及电脑系统选取。\opt{noto} 与 \opt{none} 选项的相关描述见小节 \ref{subsec:font settings},\opt{overleaf} 是一个各系统通用选项,会检测系统环境选取对应字体。 % \changes{v1.21}{2021/01/12}{默认字体与 \CTeX 一致,不再是自定义字体。} -% \changes{v1.25a}{2021/05/04}{修复使用 \pkg{xeCJK} 与 \pkg{fontspec} 宏包的字体设置命令在 \hologo{LuaLaTeX} 下失效的问题。} +% \changes{v1.25b}{2021/05/04}{修复使用 \pkg{xeCJK} 与 \pkg{fontspec} 宏包的字体设置命令在 \hologo{LuaLaTeX} 下失效的问题。} % \end{function} % % \begin{function}[rEXP,added = 2021-01-05,updated = 2021-01-13]{paper} @@ -145,8 +145,10 @@ % \changes{v1.23}{2021/03/16}{增加 article 文章模式,可用于短篇幅的文章。} % \end{function} % +% \clearpage % \subsection{文档命令} % \label{subsec:document command} +% \subsubsection{文区命令} % \begin{function}[added = 2021-02-20,updated = 2021-04-29]{\frontmatter,\mainmatter,\backmatter,\cleardoublepage} % \begin{syntax} % \tn{frontmatter*}\oarg{编号格式|(Roman)} @@ -158,15 +160,16 @@ % \changes{v1.23}{2021/02/20}{重新定义文档结构划分命令。} % \end{function} % -% \begin{function}[added = 2021-02-20,updated = 2021-05-04]{\tableofcontents,\listoffigures,\listoftables,\listoflistings} +% \subsubsection{目录命令} +% \begin{function}[added = 2021-02-20,updated = 2021-05-05]{\tableofcontents,\listoffigures,\listoftables,\listoflistings} % \begin{syntax} -% \tn{tableofcontents+}\oarg{键值列表} +% \tn{tableofcontents+}\oarg{键值列表}\parg{附加代码} % \tn{listoffigures*+}\oarg{键值列表} % \tn{listoftables*+}\oarg{键值列表} % \tn{listoflistings*+}\oarg{键值列表} % \end{syntax} -% \tn{listoffigures} 命令输出图片目录,\tn{listoftables} 输出表格目录,\tn{listoflistings} 输出代码目录。带有星号的目录命令不将标题添加进主文档目录,带有+号的目录命令可以使当前标题编号。\tn{tableofcontents+} 与其它命令不同是用于输出双语目录,需要与双语目录标题命令 \tn{bichapter} 等配合使用。目录的键值列表选项如下 -% \changes{v1.25a}{2021/05/04}{命令 \tn{tableofcontents} 可以输出双语目录。} +% \tn{listoffigures} 命令输出图片目录,\tn{listoftables} 输出表格目录,\tn{listoflistings} 输出代码目录。带有星号的目录命令不将标题添加进主文档目录,带有+号的目录命令可以使当前标题编号。\tn{tableofcontents+} 与其它命令不同是用于输出双语目录,需要与双语目录标题命令 \tn{bichapter} 等或设置图片、表格和代码等英文目录的标题配合使用,附加代码是中文与英文目录之间的代码,可以插入文本和换页命令等。目录的键值列表选项如下 +% \changes{v1.25b}{2021/05/05}{命令 \tn{tableofcontents} 可以输出双语目录。} % \end{function} % % \begin{function}{multoc,title,book,article} @@ -174,19 +177,40 @@ % multoc = % title = \{<中文目录标题>,<英文目录标题>\} % \end{syntax} -% \opt{multoc} 与 \opt{style/multoc} 选项具有相同的效果,但是具有优先性且可单独设置不同目录是否双栏排版。\opt{title} 选项用于更改目录的标题,标题之间用一个半角逗号分开,也可以只有一部分,表示中文目录的标题,不过英文目录标题目前仅对 \tn{tableofcontents} 命令有效。\opt{book} 选项使目录标题按照 \opt{chapter} 级别输出,\opt{article} 选项使目录标题按照 \opt{article} 级别输出,默认为 \opt{chapter} 级别。 +% \opt{multoc} 与 \opt{style/multoc} 选项具有相同的效果,但是具有优先性且可单独设置不同目录是否双栏排版。\opt{title} 选项用于更改目录的标题,标题之间用一个半角逗号分开,也可以只有一部分,表示中文目录的标题。当设置了英文目录标题时,英文目录标题将会自动加入主文档目录,与 \tn{tableofcontents+} 配合输出。\opt{book} 选项使目录标题按照 \opt{chapter} 级别输出,\opt{article} 选项使目录标题按照 \opt{article} 级别输出,默认为 \opt{chapter} 级别。 % \changes{v1.23}{2021/03/15}{为几个目录增加键值列表的选项,可设置标题输出级别以及是否加入主目录。} % \changes{v1.24}{2021/04/04}{目录命令的可选参数增加标题键值。} % \end{function} % -% \begin{function}[added = 2021-05-04]{\bichapter,\bisection,\bisubsection} +% \subsubsection{标题命令} +% \begin{function}[added = 2021-05-05]{\bichapter,\bisection,\bisubsection,\bichapter*,\bisection*,\bisubsection*} % \begin{syntax} -% \tn{bichapter}\marg{中文标题}\marg{英文标题(在目录中)} -% \tn{bichapter}\marg{中文标题}\marg{英文标题(在目录中)} -% \tn{bichapter}\marg{中文标题}\marg{英文标题(在目录中)} +% \tn{bichapter}\oarg{目录中文标题}\marg{中文标题}\marg{目录英文标题} +% \tn{bisection}\oarg{目录中文标题}\marg{中文标题}\marg{目录英文标题} +% \tn{bisubsection}\oarg{目录中文标题}\marg{中文标题}\marg{目录英文标题} +% \tn{bichapter*}\oarg{目录中文标题}\marg{中文标题}\marg{目录英文标题} +% \tn{bisection*}\oarg{目录中文标题}\marg{中文标题}\marg{目录英文标题} +% \tn{bisubsection*}\oarg{目录中文标题}\marg{中文标题}\marg{目录英文标题} % \end{syntax} -% 双语目录的标题命令目前设置了三个级别,它们将中文标题正常输出,并将中英文标题加入双语目录,这个功能是为国内一些大学的学位论文模板的要求设计,当然在英文模式下不需要使用。双语目录的格式是一致的,使用 \tn{tocset} 设置,英文目录的章级别标题名为 Chapter 暂不支持修改。 -% \changes{v1.25a}{2021/05/04}{增加与双语目录配合的标题命令。} +% 双语目录的标题命令目前设置了常用的三个级别,它们将中文标题正常输出,并使中英文标题加入双语目录,这个功能是为国内一些大学的学位论文模板的要求设计,当然在英文模式下不需要使用。 +% +% 它们的星号变体命令使文中标题不编号,但是仍然加入双语目录,若英文标题参数空置那么仅加入中文目录而不加入英文目录,这一点与 \tn{chapter*} 等命令的行为不太一样。可选参数是目录中的中文标题,默认与中文标题一致,正文标题过长时可用它设置在目录中显示的标题。双语目录的格式是一致的,共享使用 \tn{tocset} 的设置,英文目录的章级别标题名及编号的修改方式如下 +% \changes{v1.25b}{2021/05/05}{增加与双语目录配合的标题命令。} +% \end{function} +% +% \begin{function}{biname,binmuber} +% \begin{syntax} +% chapter/biname = \{<英文目录前名字|(Chapter\tn{space})>,<英文目录后名字>\} +% chapter/binmuber = <英文目录数字输出命令|(\tn{arabic\{chapter\}})> +% \end{syntax} +% 类似 \CTeX 的 \opt{name} 和 \opt{nmuber} 选项,它们用于设置主文区 \tn{bichapter} 等标题命令在英文目录中的前后名字与编号,目前只支持通常改变名字与编号的 chapter 级别。 +% \end{function} +% +% \begin{function}[added = 2021-05-05]{\appendix} +% \begin{syntax} +% \tn{appendix}\oarg{英文附录目录前名字}\parg{英文附录目录数字输出命令}\oarg{英文附录目录后名字} +% \end{syntax} +% \tn{appendix} 命令后的章节标题变为附录形式。英文目录中附录标题的格式用可选参数修改,英文附录目录前名字默认为 Appendix\tn{space},英文附录目录数字输出命令默认为 \tn{Alph}\{chapter\},英文附录目录后名字默认为空。 % \end{function} % % \section{接口选项} @@ -389,7 +413,7 @@ % headpunct = <(empty)> % bodyfont = <(empty)> % notefont = <(empty)> -% headfont = <(\tn{color}\marg{ctex@emph}\tn{sffamily})> +% headfont = <(\tn{color}\{ctex@emph\}\tn{sffamily})> % headindent = <(0\tn{ccwd})> % spaceabove = <(0.75ex plus .1ex)> % spacebelow = <(0.75ex plus .1ex)> @@ -692,7 +716,7 @@ % \end{syntax} % 习题环境 \env{exercise} 的标题紧接上一节编号并加入目录与页眉,当使用星号参数时不进行编号,使用+号参数启用 \pkg{tcolorbox} 支持生成标题。\meta{颜色名} 选项在使用+号参数时有效,其中颜色为自定义或 \pkg{xcolor} 包含的颜色名称。题目编号格式与小节 \ref{subsec:sort list} 排序列表相同,标题名默认为习题。 % -% 配置选项在是否使用+号参数时用法不同,使用+号参数时为 \pkg{tcolorbox} 的盒子选项,例如 \opt{boxrule} 和 \opt{fontupper}。不使用+号参数时相当于设置 \tn{ctexset}\marg{section = {\#1}} 键值选项列表,例如 \opt{format} 和 \opt{beforeskip}。\meta{序言} 选项用于在习题环境开始前插入一段内容,可以是文本或者代码。注意,环境具有相同定界符的可选参数只能\textbf{从右往左}省略,省略的参数使用默认值。 +% 配置选项在是否使用+号参数时用法不同,使用+号参数时为 \pkg{tcolorbox} 的盒子选项,例如 \opt{boxrule} 和 \opt{fontupper}。不使用+号参数时相当于设置 \tn{ctexset}\{section = {\#1}\} 键值选项列表,例如 \opt{format} 和 \opt{beforeskip}。\meta{序言} 选项用于在习题环境开始前插入一段内容,可以是文本或者代码。注意,环境具有相同定界符的可选参数只能\textbf{从右往左}省略,省略的参数使用默认值。 % \changes{v1.23}{2021/02/08}{增加准确的习题盒子标题目录锚点。} % \end{function} % @@ -921,7 +945,7 @@ %<*class> \NeedsTeXFormat{LaTeX2e}[2020/10/01] \RequirePackage{l3keys2e,etoolbox} -\ProvidesExplClass{easybook}{2021/05/04}{1.25a}{beta} +\ProvidesExplClass{easybook}{2021/05/05}{1.25b}{beta} \cs_generate_variant:Nn \eb_ctex_define:nn { nx } \cs_generate_variant:Nn \int_to_arabic:n { v } @@ -1144,10 +1168,7 @@ \cs_new_protected:Npn \eb_font_double_engine_set:n #1 { \exp_args:Nc \RenewDocumentCommand {set #1 font}{O{}mO{}} - { - \ctex_at_end_preamble:n - { \use:c { eb_set #1 font:nn }{##2}{##1,##3} } - } + {\use:c { eb_set #1 font:nn }{##2}{##1,##3}} } \seq_const_from_clist:Nn \c__eb_font_reset_family_seq { main,sans,mono,CJKmain,CJKsans,CJKmono } @@ -1395,9 +1416,7 @@ } \bool_if:NT \l__eb_compile_draft_bool { - \bool_if:NTF \l__eb_page_twoside_bool - { \easyfoot[C]{\color{SlateGray}\sffamily\today} } - { \easyhead[C]{\color{SlateGray}\sffamily\today} } + \easyfoot[C]{\color{SlateGray}\sffamily\today} \geometry{showframe} } } @@ -1609,16 +1628,14 @@ } } -\contentsuse{}{bitoc} +\contentsuse{}{tec} \cs_set_protected:Npn \CTEX@addbitocline #1#2 { \group_begin: - \ctex_set:n - { - chapter/name = Chapter\space, - chapter/number = \arabic{chapter} - } - \addcontentsline{bitoc}{#1} + \def\CTEX@prechapter{\CTEX@prebichapter} + \def\CTEX@thechapter{\CTEX@bichapter@number} + \def\CTEX@postchapter{\CTEX@postbichapter} + \addcontentsline{tec}{#1} {\use:c { CTEX@#1@tocline }{#1}{#2}} \group_end: } @@ -1626,8 +1643,18 @@ { chapter,section,subsection } \seq_map_inline:Nn \c__eb_bitoc_title_level_seq { - \cs_new_protected:cpn {bi #1} ##1##2 - { \use:c {#1}{##1}\CTEX@addbitocline{#1}{##2} } + \exp_args:Nc \NewDocumentCommand {bi #1}{sO{##3}mm} + { + \IfBooleanTF{##1} + { + \use:c {#1}*{\phantomsection ##3} + \CTEX@addtocline{#1}{##2} + \tl_if_empty:oF {##4} { \CTEX@addbitocline{#1}{##4} } + }{ + \use:c {#1}[##2]{##3} + \tl_if_empty:oF {##4} { \CTEX@addbitocline{#1}{##4} } + } + } } \eb_appto_cmd:Nn \@chapter @@ -1652,6 +1679,7 @@ } \tl_set:Nn \l__eb_toc_type_tl { book } +\tl_new:N \eb@bitoc@title \keys_define:nn { eb/listoc } { article .code:n = \tl_set:Nn \l__eb_toc_type_tl { article }, @@ -1694,13 +1722,11 @@ { \tl_if_eq:NnTF \l__eb_toc_type_tl { book } { - \chapter*{\phantomsection #1} - \CTEX@addtocline{chapter}{#1} + \bichapter*{#1}{\eb@bitoc@title} \eb@nonumber@markdouble{#1} } { - \section*{\phantomsection #1} - \CTEX@addtocline{section}{#1} + \bisection*{#1}{\eb@bitoc@title} \bool_if:NTF \l__eb_class_book_bool { \eb@nonumber@markright{#1} } { \eb@nonumber@markdouble{#1} } @@ -1725,8 +1751,8 @@ \IfBooleanTF{#1} { \tl_if_eq:NnTF \l__eb_toc_type_tl { book } - { \chapter{\eb@toc@title} } - { \section{\eb@toc@title} } + { \bichapter{\eb@toc@title}{\eb@bitoc@title} } + { \bisection{\eb@toc@title}{\eb@bitoc@title} } } { \IfBooleanTF{#2} @@ -1734,17 +1760,11 @@ { \eb_title_mark_intoc:n {\eb@toc@title} } } } -\cs_new_protected:Npn \eb_class_title_level_bool:n #1 +\cs_new_protected:Npn \eb_biber_title_level_bool:n #1 { \bool_if:NTF \l__eb_class_book_bool - { - \chapter*{\phantomsection #1} - \CTEX@addtocline{chapter}{#1} - } - { - \section*{\phantomsection #1} - \CTEX@addtocline{section}{#1} - } + { \bichapter*{#1}{\l__eb_bib_bitoc_title} } + { \bisection*{#1}{\l__eb_bib_bitoc_title} } \eb@nonumber@markdouble{#1} } \cs_new_protected:Npn \eb_multoc_pre_bool: @@ -1767,7 +1787,7 @@ \bool_if:NT \l__eb_class_book_bool { \ifbool{@restonecol}{\twocolumn}{\onecolumn} } } -\RenewDocumentCommand{\tableofcontents}{t+o} +\RenewDocumentCommand{\tableofcontents}{t+oD(){}} { \group_begin: \tl_set_eq:NN \eb@toc@title \contentsname @@ -1779,9 +1799,9 @@ \@starttoc{toc} \IfBooleanT{#1} { - \eb_title_mark_notoc:n { \eb@bitoc@title } + #3\eb_title_mark_notoc:n { \eb@bitoc@title } \vspace*{\dim_use:N \l__eb_toc_offset_dim} - \@starttoc{bitoc} + \@starttoc{tec} } \eb_multoc_post_bool: \group_end: @@ -1854,6 +1874,52 @@ } } +\eb_ctex_define:nn { chapter } + { + biname .code:n = + { \ctex_assign_heading_name:nn { bichapter } {#1} }, + biname .initial:n = Chapter\space, + binmuber .tl_set:N = \CTEX@bichapter@number, + binmuber .initial:n = \arabic{chapter} + } +\RenewDocumentCommand{\appendix} + {O{Appendix\space}D(){\Alph{chapter}}O{}} + { + \int_compare:nNnTF { \c@chapter } > { 0 } + { + \ExplSyntaxOn\char_set_catcode_letter:N \@ + \eb_patch_cmd:Nnn \CTEX@addbitocline + { + \def\CTEX@prechapter{\CTEX@prebichapter} + \def\CTEX@thechapter{\CTEX@bichapter@number} + \def\CTEX@postchapter{\CTEX@postbichapter} + } + { + \def\CTEX@prechapter{#1} + \def\CTEX@thechapter{#2} + \def\CTEX@postchapter{#3} + } + \ExplSyntaxOff\char_set_catcode_other:N \@ + \setcounter{chapter}{0} + \setcounter{section}{0} + \gdef\thechapter{\@Alph\c@chapter} + \gdef\CTEX@prechapter{\CTEX@preappendix} + \gdef\CTEX@thechapter{\CTEX@appendix@number} + \gdef\CTEX@postchapter{\CTEX@postappendix} + \gdef\CTEX@chapter@numbering{\CTEX@appendix@numbering} + } + { + \setcounter{section}{0} + \setcounter{subsection}{0} + \gdef\thesection{\@Alph\c@section} + \gdef\CTEX@presection{\CTEX@preappendix} + \gdef\CTEX@thesection{\CTEX@appendix@number} + \gdef\CTEX@postsection{\CTEX@postappendix} + \gdef\CTEX@section@numbering{\CTEX@appendix@numbering} + \ctex_set:nn { appendix } { number = \@Alph\c@section,name = { } } + } + } + \tl_new:N \l__eb_font_table_tl \tl_new:N \l__eb_font_figure_tl \tl_new:N \l__eb_font_listing_tl @@ -1924,40 +1990,7 @@ \eb_arabic:n {#1} } } -\cs_gset_protected:Npn \appendix - { - \int_compare:nNnTF { \c@chapter } > { 0 } - { - \ExplSyntaxOn\char_set_catcode_letter:N \@ - \eb_patch_cmd:Nnn \CTEX@addbitocline - { - chapter/name = Chapter\space, - chapter/number = \arabic{chapter} - } - { - chapter/name = Appendix\space, - chapter/number = \alph{chapter} - } - \ExplSyntaxOff\char_set_catcode_other:N \@ - \setcounter{chapter}{0} - \setcounter{section}{0} - \gdef\thechapter{\@Alph\c@chapter} - \gdef\CTEX@prechapter{\CTEX@preappendix} - \gdef\CTEX@thechapter{\CTEX@appendix@number} - \gdef\CTEX@postchapter{\CTEX@postappendix} - \gdef\CTEX@chapter@numbering{\CTEX@appendix@numbering} - } - { - \setcounter{section}{0} - \setcounter{subsection}{0} - \gdef\thesection{\@Alph\c@section} - \gdef\CTEX@presection{\CTEX@preappendix} - \gdef\CTEX@thesection{\CTEX@appendix@number} - \gdef\CTEX@postsection{\CTEX@postappendix} - \gdef\CTEX@section@numbering{\CTEX@appendix@numbering} - \ctex_set:nn { appendix } { number = \@Alph\c@section,name = { } } - } - } + \AtBeginEnvironment{tabularx} { \exp_args:Nx \linespread { \fp_use:N \l__eb_spread_table_fp } @@ -1994,8 +2027,11 @@ footnote .initial:n = 1, spread-all .meta:n = { - line = #1,table = #1,math = #1, - caption = #1,footnote = #1 + line = #1, + table = #1, + math = #1, + caption = #1, + footnote = #1 } } @@ -2395,7 +2431,10 @@ bib-loadpkg .bool_set:N = \l__eb_bib_loadpkg_bool, bib-loadpkg .default:n = true, - bib-loadpkg .initial:n = true + bib-loadpkg .initial:n = true, + + bitoc-title .tl_set:N = \l__eb_bib_bitoc_title, + bitoc-title .initial:n = Reference } \cs_new_protected:Npn \EbBibtexSet @@ -2449,7 +2488,7 @@ \exp_args:NV \addbibresource \l__eb_bib_file_tl \tl_gset:Nn \blx@default@theheading { bibintoc } \defbibheading{bibintoc}[\bibname] - {\eb_class_title_level_bool:n {##1}} + {\eb_biber_title_level_bool:n {##1}} \skip_zero:N \bibitemsep } \eb_at_end_preamble:n diff --git a/macros/latex/contrib/easybook/easybook.pdf b/macros/latex/contrib/easybook/easybook.pdf index e96c6f6bc9..64d2cf8aee 100644 Binary files a/macros/latex/contrib/easybook/easybook.pdf and b/macros/latex/contrib/easybook/easybook.pdf differ diff --git a/macros/latex/contrib/l3build/CHANGELOG.md b/macros/latex/contrib/l3build/CHANGELOG.md index 012467cd78..7a1a7862b2 100644 --- a/macros/latex/contrib/l3build/CHANGELOG.md +++ b/macros/latex/contrib/l3build/CHANGELOG.md @@ -7,6 +7,21 @@ this project uses date-based 'snapshot' version identifiers. ## [Unreleased] +## [2021-05-05] + +### Changed +- Normalise Lua function calls (issue #127) - may require `.tlg` update +- LuaTeX from TL'21 is no longer 'off by one' in log files - may require + `.tlg` update + +### Fixed +- Installation now supports deeper directory levels (issue #182) +- The `texmfhome` directory is now created before use if required +- Crash caused by yyyy-mm-dd epoch format + +### Removed +- Support for use as `texlua build.lua ` + ## [2020-06-04] ### Added @@ -470,9 +485,10 @@ this project uses date-based 'snapshot' version identifiers. ### Removed - Rationalise short option names: removed `-d`, `-E`, `-r` -- Target `cmdcheck`: specific to LaTeX3 kernel work +- Target `cmdcheck`: specific to LaTeX kernel work -[Unreleased]: https://github.com/latex3/l3build/compare/2020-06-04...HEAD +[Unreleased]: https://github.com/latex3/l3build/compare/2021-05-05...HEAD +[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 [2020-03-25]: https://github.com/latex3/l3build/compare/2020-03-16...2020-03-25 [2020-03-16]: https://github.com/latex3/l3build/compare/2020-03-13...2020-03-16 diff --git a/macros/latex/contrib/l3build/CONTRIBUTING.md b/macros/latex/contrib/l3build/CONTRIBUTING.md index a152299e83..e85fa762d3 100644 --- a/macros/latex/contrib/l3build/CONTRIBUTING.md +++ b/macros/latex/contrib/l3build/CONTRIBUTING.md @@ -1,5 +1,5 @@ Thanks for considering contributing to `l3build`: feedback, fixes and ideas are -all useful. Here, we ([The LaTeX3 Project](https://www.latex-project.org)) have +all useful. Here, we ([The LaTeX Project](https://www.latex-project.org)) have collected together a few pointers to help things along. ## Bugs diff --git a/macros/latex/contrib/l3build/README.md b/macros/latex/contrib/l3build/README.md index c3630c8f0d..a5f4913712 100644 --- a/macros/latex/contrib/l3build/README.md +++ b/macros/latex/contrib/l3build/README.md @@ -1,7 +1,7 @@ -l3build: a testing and building system for LaTeX3 +l3build: a testing and building system for LaTeX ================================================= -Release 2020-06-04 +Release 2021-05-05 Overview -------- @@ -14,23 +14,23 @@ high-quality LaTeX code by providing: The bundle consists of a Lua script to run the tasks and a `.tex` file which provides the testing environment. These were -originally developed for supporting LaTeX3 development but +originally developed for supporting LaTeX development but are designed such that they can be readily used by others. Full documentation is provided. Issues ------ -The issue tracker for LaTeX3 is currently located +The issue tracker for LaTeX is currently located [on GitHub](https://github.com/latex3/l3build/issues). Development team ---------------- -The LaTeX kernel is developed by [The LaTeX3 Project](https://latex-project.org). +The LaTeX kernel is developed by [The LaTeX Project](https://latex-project.org). ----- -

Copyright (C) 2014-2020 The LaTeX3 Project
+

Copyright (C) 2014-2020 The LaTeX Project
http://latex-project.org/
All rights reserved.

diff --git a/macros/latex/contrib/l3build/l3build-arguments.lua b/macros/latex/contrib/l3build/l3build-arguments.lua index aa2f086d61..80f19d66ad 100644 --- a/macros/latex/contrib/l3build/l3build-arguments.lua +++ b/macros/latex/contrib/l3build/l3build-arguments.lua @@ -1,6 +1,6 @@ --[[ -File l3build-arguments.lua Copyright (C) 2018-2020 The LaTeX3 Project +File l3build-arguments.lua Copyright (C) 2018-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -170,7 +170,7 @@ local function argparse() end long_options[k] = k end - local args = args + local arg = arg -- arg[1] is a special case: must be a command or "-h"/"--help" -- Deal with this by assuming help and storing only apparently-valid -- input @@ -239,21 +239,21 @@ local function argparse() if optarg then local opt = "-" .. (match(a, "^%-%-") and "-" or "") .. opt stderr:write("Value not allowed for option " .. opt .."\n") - return {"help"} + return { target = "help" } end else if not optarg then optarg = arg[i + 1] if not optarg then stderr:write("Missing value for option " .. a .."\n") - return {"help"} + return { target = "help" } end i = i + 1 end end else stderr:write("Unknown option " .. a .."\n") - return {"help"} + return { target = "help" } end -- Store the result if optarg then diff --git a/macros/latex/contrib/l3build/l3build-aux.lua b/macros/latex/contrib/l3build/l3build-aux.lua index 8fa4b0cd82..12fe704af4 100644 --- a/macros/latex/contrib/l3build/l3build-aux.lua +++ b/macros/latex/contrib/l3build/l3build-aux.lua @@ -1,6 +1,6 @@ --[[ -File l3build-aux.lua Copyright (C) 2018-2020 The LaTeX3 Project +File l3build-aux.lua Copyright (C) 2018-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -22,6 +22,8 @@ for those people who are interested. --]] +-- local safety guards and shortcuts + local match = string.match local pairs = pairs @@ -29,97 +31,137 @@ local print = print local lookup = kpse.lookup +local os_time = os.time -- -- Auxiliary functions which are used by more than one main function -- -function normalise_epoch() +---Convert the given `epoch` to a number. +---@param epoch string +---@return number +---@see l3build.lua +---@usage private? +function normalise_epoch(epoch) + assert(epoch, 'normalize_epoch argument must not be nil') -- If given as an ISO date, turn into an epoch number local y, m, d = match(epoch, "^(%d%d%d%d)-(%d%d)-(%d%d)$") if y then - epoch = - os_time({year = y, month = m, day = d, hour = 0, sec = 0, isdst = nil}) - - os_time({year = 1970, month = 1, day = 1, hour = 0, sec = 0, isdst = nil}) + return os_time({ + year = y, month = m, day = d, + hour = 0, sec = 0, isdst = nil + }) - os_time({ + year = 1970, month = 1, day = 1, + hour = 0, sec = 0, isdst = nil + }) elseif match(epoch, "^%d+$") then - epoch = tonumber(epoch) + return tonumber(epoch) else - epoch = 0 + return 0 end end -function setepoch() - return +---Returns the CLI command (ending with `os_concat`) to set the epoch +---when forcecheckepoch is true, a void string otherwise. +---Will be run while checking or typesetting +---@param epoch string +---@param force boolean +---@return string +---@see check, typesetting +---@usage private? +function set_epoch_cmd(epoch, force) + return force and ( os_setenv .. " SOURCE_DATE_EPOCH=" .. epoch .. os_concat .. os_setenv .. " SOURCE_DATE_EPOCH_TEX_PRIMITIVES=1" .. os_concat .. os_setenv .. " FORCE_SOURCE_DATE=1" .. os_concat + ) or "" end -local function getscriptname() +---Returns the script name depending on the calling sequence. +---`l3build ...` -> full path of `l3build.lua` in the TDS +---When called via `texlua l3build.lua ...`, `l3build.lua` is resolved to either +---`./l3build.lua` or the full path of `l3build.lua` in the TDS. +---`texlua l3build.lua` -> `/Library/TeX/texbin/l3build.lua` or `./l3build.lua` +---@return string +local function get_script_name() if match(arg[0], "l3build$") or match(arg[0], "l3build%.lua$") then return lookup("l3build.lua") else - return arg[0] + return arg[0] -- Why no lookup here? end end --- Do some subtarget for all modules in a bundle -function call(dirs, target, opts) - -- Turn the option table into a string - local opts = opts or options - local s = "" +-- Performs the task named target given modules in a bundle. +---A module is the path of a directory relative to the main one. +---Uses `run` to launch a command. +---@param modules table List of modules. +---@param target string +---@param opts table +---@return number 0 on proper termination, a non 0 error code otherwise. +---@see many places, including latex2e/build.lua +---@usage Public +function call(modules, target, opts) + -- Turn the option table into a CLI option string + opts = opts or options + local cli_opts = "" for k,v in pairs(opts) do - if k ~= "names" and k ~= "target" then -- Special cases - local t = option_list[k] or { } - local arg = "" + if k ~= "names" and k ~= "target" then -- Special cases, TODO enhance the design to remove the need for this comment + local t = option_list[k] or {} + local value = "" if t["type"] == "string" then - arg = arg .. "=" .. v - end - if t["type"] == "table" then + value = value .. "=" .. v + elseif t["type"] == "table" then for _,a in pairs(v) do - if arg == "" then - arg = "=" .. a -- Add the initial "=" here + if value == "" then + value = "=" .. a -- Add the initial "=" here else - arg = arg .. "," .. a + value = value .. "," .. a end end end - s = s .. " --" .. k .. arg + cli_opts = cli_opts .. " --" .. k .. value end end - if opts["names"] then - for _,v in pairs(opts["names"]) do - s = s .. " " .. v + if opts.names then + for _, name in pairs(opts.names) do + cli_opts = cli_opts .. " " .. name end end - local scriptname = getscriptname() - for _,i in ipairs(dirs) do - local text = " for module " .. i - if i == "." and opts["config"] then + local script_name = get_script_name() + for _, module in ipairs(modules) do + local text + if module == "." and opts["config"] and #opts["config"]>0 then text = " with configuration " .. opts["config"][1] + else + text = " for module " .. module end print("Running l3build with target \"" .. target .. "\"" .. text ) - local errorlevel = run( - i, - "texlua " .. scriptname .. " " .. target .. s + local error_level = run( + module, + "texlua " .. script_name .. " " .. target .. cli_opts ) - if errorlevel ~= 0 then - return errorlevel + if error_level ~= 0 then + return error_level end end return 0 end --- Unpack files needed to support testing/typesetting/unpacking -function depinstall(deps) - local errorlevel - for _,i in ipairs(deps) do - print("Installing dependency: " .. i) - errorlevel = run(i, "texlua " .. getscriptname() .. " unpack -q") - if errorlevel ~= 0 then - return errorlevel +---Unpack the given dependencies. +---A dependency is the path of a directory relative to the main one. +---@param deps table regular array of dependencies. +---@return number 0 on proper termination, a non 0 error code otherwise. +---@see stdmain, check, unpack, typesetting +---@usage Private? +function dep_install(deps) + local error_level + for _, dep in ipairs(deps) do + print("Installing dependency: " .. dep) + error_level = run(dep, "texlua " .. get_script_name() .. " unpack -q") + if error_level ~= 0 then + return error_level end end return 0 diff --git a/macros/latex/contrib/l3build/l3build-check.lua b/macros/latex/contrib/l3build/l3build-check.lua index ff022c6079..dce9e68c6a 100644 --- a/macros/latex/contrib/l3build/l3build-check.lua +++ b/macros/latex/contrib/l3build/l3build-check.lua @@ -1,6 +1,6 @@ --[[ -File l3build-check.lua Copyright (C) 2018-2020 The LaTeX3 Project +File l3build-check.lua Copyright (C) 2018-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -34,7 +34,7 @@ local luatex_version = status.luatex_version local len = string.len local char = string.char -local format = string.format +local str_format = string.format local gmatch = string.gmatch local gsub = string.gsub local match = string.match @@ -59,7 +59,7 @@ function checkinit() cleandir(testdir) cleandir(resultdir) end - depinstall(checkdeps) + dep_install(checkdeps) -- Copy dependencies to the test directory itself: this makes the paths -- a lot easier to manage, and is important for dealing with the log and -- with file input/output tests @@ -85,7 +85,7 @@ function checkinit() return checkinit_hook() end -checkinit_hook = checkinit_hook or function() return 0 end +function checkinit_hook() return 0 end local function rewrite(source,result,processor,...) local file = assert(open(source,"rb")) @@ -102,7 +102,7 @@ end -- the 'business' part from the tests and removes system-dependent stuff local function normalize_log(content,engine,errlevels) local maxprintline = maxprintline - if match(engine,"^lua") or match(engine,"^harf") then + if (match(engine,"^lua") or match(engine,"^harf")) and luatex_version < 113 then maxprintline = maxprintline + 1 -- Deal with an out-by-one error end local function killcheck(line) @@ -134,7 +134,7 @@ local function normalize_log(content,engine,errlevels) not match(line, "%.%.%.$") then return "", (lastline or "") .. line end - local line = (lastline or "") .. line + line = (lastline or "") .. line lastline = "" -- Zap ./ at begin of filename line = gsub(line, "%(%.%/", "(") @@ -223,15 +223,19 @@ local function normalize_log(content,engine,errlevels) -- Remove '\displace 0.0' lines in (u)pTeX if match(line,"^%.*\\displace 0%.0$") then return "" - end - end - -- Remove the \special line that in DVI mode keeps PDFs comparable + end + end + -- Deal with Lua function calls + if match(line, "^Lua function") then + line = gsub(line,"= %d+$","= ...") + end + -- Remove the \special line that in DVI mode keeps PDFs comparable if match(line, "^%.*\\special%{pdf: docinfo << /Creator") or match(line, "^%.*\\special%{ps: /setdistillerparams") or match(line, "^%.*\\special%{! <") or match(line, "^used option >") or match(line, "^used structure >") then - return "" + return "" end -- The first time a new font is used by LuaTeX, it shows up -- as being cached: make it appear loaded every time @@ -265,7 +269,7 @@ local function normalize_log(content,engine,errlevels) -- tidy up to match pdfTeX if an ASCII engine is in use if next(asciiengines) then for i = 128, 255 do - line = gsub(line, utf8_char(i), "^^" .. format("%02x", i)) + line = gsub(line, utf8_char(i), "^^" .. str_format("%02x", i)) end end return line, lastline @@ -341,7 +345,7 @@ local function normalize_lua_log(content,luatex) l, m .. " (%-?)%d+%.%d+", m .. " %1" - .. format( + .. str_format( "%.3f", match(line, m .. " %-?(%d+%.%d+)") or 0 ) @@ -370,20 +374,20 @@ local function normalize_lua_log(content,luatex) -- This block only applies to the output of LuaTeX itself, -- hence needing a flag to skip the case of the reference log if luatex and - tonumber(luatex_version) >= 107 and - match(line, "^%.*\\kern") then - -- Re-insert the space in explicit kerns - if match(line, "kern%-?%d+%.%d+ *$") then - line = gsub(line, "kern", "kern ") - elseif match(line, "%(accent%)$") then - line = gsub(line, "kern", "kern ") - line = gsub(line, "%(accent%)$", "(for accent)") - elseif match(line, "%(italic%)$") then - line = gsub(line, "kern", "kern ") - line = gsub(line, " %(italic%)$", "") - else - line = gsub(line, " %(font%)$", "") - end + tonumber(luatex_version) >= 107 and + match(line, "^%.*\\kern") then + -- Re-insert the space in explicit kerns + if match(line, "kern%-?%d+%.%d+ *$") then + line = gsub(line, "kern", "kern ") + elseif match(line, "%(accent%)$") then + line = gsub(line, "kern", "kern ") + line = gsub(line, "%(accent%)$", "(for accent)") + elseif match(line, "%(italic%)$") then + line = gsub(line, "kern", "kern ") + line = gsub(line, " %(italic%)$", "") + else + line = gsub(line, " %(font%)$", "") + end end -- Changes in PDF specials line = gsub(line, "\\pdfliteral origin", "\\pdfliteral") @@ -394,8 +398,8 @@ local function normalize_lua_log(content,luatex) -- 'Recover' some discretionary data if match(lastline, "^%.+\\discretionary %(penalty 50%)$") and match(line, boxprefix(lastline) .. "%.= ") then - line = gsub(line," %(font%)$","") - return gsub(line, "%.= ", ""),"" + line = gsub(line," %(font%)$","") + return gsub(line, "%.= ", ""),"" end -- Where the last line was a discretionary, looks for the -- info one level in about what it represents @@ -406,13 +410,13 @@ local function normalize_lua_log(content,luatex) local prefix = boxprefix(lastline) if match(line, prefix .. "%.") or match(line, prefix .. "%|") then - if match(lastline, " replacing $") and - not dropping then - -- Modify the return line - return gsub(line, "^%.", ""), lastline, true - else - return "", lastline, true - end + if match(lastline, " replacing $") and + not dropping then + -- Modify the return line + return gsub(line, "^%.", ""), lastline, true + else + return "", lastline, true + end else if dropping then -- End of a \discretionary block @@ -431,7 +435,7 @@ local function normalize_lua_log(content,luatex) end end -- Look for another form of \discretionary, replacing a "-" - pattern = "^%.+\\discretionary replacing *$" + local pattern = "^%.+\\discretionary replacing *$" if match(line, pattern) then return "", line else @@ -461,7 +465,7 @@ local function normalize_lua_log(content,luatex) match(line, "^%.+\\localbrokenpenalty=0$") or match(line, "^%.+\\localleftbox=null$") or match(line, "^%.+\\localrightbox=null$") then - return "", "" + return "", "" end -- Older LuaTeX versions set the above up as a whatsit -- (at some stage this can therefore go) @@ -522,7 +526,7 @@ local function normalize_pdf(content) if binary then new_content = new_content .. "[BINARY STREAM]" .. os_newline else - new_content = new_content .. stream_content .. line .. os_newline + new_content = new_content .. stream_content .. line .. os_newline end binary = false else @@ -541,7 +545,7 @@ local function normalize_pdf(content) stream = true stream_content = "stream" .. os_newline elseif not match(line, "^ *$") and - not match(line,"^%%%%Invocation") and + not match(line,"^%%%%Invocation") and not match(line,"^%%%%%+") then line = gsub(line,"%/ID( ?)%[<[^>]+><[^>]+>]","/ID%1[]") new_content = new_content .. line .. os_newline @@ -550,10 +554,19 @@ local function normalize_pdf(content) return new_content end +function rewrite_log(source, result, engine, errlevels) + return rewrite(source, result, normalize_log, engine, errlevels) +end + +function rewrite_pdf(source, result, engine, errlevels) + return rewrite(source, result, normalize_pdf, engine, errlevels) +end + -- Run one test which may have multiple engine-dependent comparisons -- Should create a difference file for each failed test function runcheck(name, hide) - if not testexists(name) then + local test_filename, kind = testexists(name) + if not test_filename then print("Failed to find input for test " .. name) return 1 end @@ -562,9 +575,10 @@ function runcheck(name, hide) checkengines = options["engine"] end -- Used for both .lvt and .pvt tests - local function check_and_diff(ext,engine,comp,pdftest) - runtest(name,engine,hide,ext,pdftest,true) - local errorlevel = comp(name,engine) + local test_type = test_types[kind] + local function check_and_diff(engine) + runtest(name, engine, hide, test_type.test, test_type, true) + local errorlevel = base_compare(test_type,name,engine) if errorlevel == 0 then return errorlevel end @@ -579,12 +593,7 @@ function runcheck(name, hide) local errorlevel = 0 for _,engine in pairs(checkengines) do setup_check(name,engine) - local errlevel = 0 - if fileexists(testfiledir .. "/" .. name .. pvtext) then - errlevel = check_and_diff(pvtext,engine,compare_pdf,true) - else - errlevel = check_and_diff(lvtext,engine,compare_tlg) - end + local errlevel = check_and_diff(engine) if errlevel ~= 0 and options["halt-on-error"] then return 1 end @@ -598,64 +607,73 @@ end function setup_check(name, engine) local testname = name .. "." .. engine - local tlgfile = locate( - {testfiledir, unpackdir}, - {testname .. tlgext, name .. tlgext} - ) - local tpffile = locate( - {testfiledir, unpackdir}, - {testname .. tpfext, name .. tpfext} - ) - -- Attempt to generate missing reference file from expectation - if not (tlgfile or tpffile) then - if not locate({unpackdir, testfiledir}, {name .. lveext}) then - print( - "Error: failed to find " .. tlgext .. ", " .. tpfext .. " or " - .. lveext .. " file for " .. name .. "!" + local found + for _, kind in ipairs(test_order) do + local reference_ext = test_types[kind].reference + local reference_file = locate( + {testfiledir, unpackdir}, + {testname .. reference_ext, name .. reference_ext} + ) + if reference_file then + found = true + -- Install comparison file found + cp( + match(reference_file, ".*/(.*)"), + match(reference_file, "(.*)/.*"), + testdir ) - exit(1) end - runtest(name, engine, true, lveext) - ren(testdir, testname .. logext, testname .. tlgext) - else - -- Install comparison files found - for _,v in pairs({tlgfile, tpffile}) do - if v then - cp( - match(v, ".*/(.*)"), - match(v, "(.*)/.*"), - testdir - ) - end + end + if found then + return + end + -- Attempt to generate missing reference file from expectation + for _, kind in ipairs(test_order) do + local test_type = test_types[kind] + local exp_ext = test_type.expectation + local expectation_file = exp_ext and locate( + {testfiledir, unpackdir}, + {name .. exp_ext} + ) + if expectation_file then + found = true + runtest(name, engine, true, exp_ext, test_type) + ren(testdir, testname .. test_type.generated, testname .. test_type.reference) end end + if found then + return + end + print( + "Error: failed to find any reference or expectation file for " + .. name .. "!" + ) + exit(1) end -function compare_pdf(name,engine,cleanup) +function base_compare(test_type,name,engine,cleanup) local testname = name .. "." .. engine - local difffile = testdir .. "/" .. testname .. pdfext .. os_diffext - local pdffile = testdir .. "/" .. testname .. pdfext - local tpffile = locate({testdir}, {testname .. tpfext, name .. tpfext}) - if not tpffile then + local difffile = testdir .. "/" .. testname.. os_diffext + local genfile = testdir .. "/" .. testname .. test_type.generated + local reffile = locate({testdir}, {testname .. test_type.reference, name .. test_type.reference}) + if not reffile then return 1 end + local compare = test_type.compare + if compare then + return compare(difffile, reffile, genfile, cleanup, name, engine) + end local errorlevel = execute(os_diffexe .. " " - .. normalize_path(tpffile .. " " .. pdffile .. " > " .. difffile)) + .. normalize_path(reffile .. " " .. genfile .. " > " .. difffile)) if errorlevel == 0 or cleanup then remove(difffile) end return errorlevel end -function compare_tlg(name,engine,cleanup) +function compare_tlg(difffile, tlgfile, logfile, cleanup, name, engine) local errorlevel local testname = name .. "." .. engine - local difffile = testdir .. "/" .. testname .. os_diffext - local logfile = testdir .. "/" .. testname .. logext - local tlgfile = locate({testdir}, {testname .. tlgext, name .. tlgext}) - if not tlgfile then - return 1 - end -- Do additional log formatting if the engine is LuaTeX, there is no -- LuaTeX-specific .tlg file and the default engine is not LuaTeX if (match(engine,"^lua") or match(engine,"^harf")) @@ -687,22 +705,22 @@ end -- Run one of the test files: doesn't check the result so suitable for -- both creating and verifying -function runtest(name, engine, hide, ext, pdfmode, breakout) +function runtest(name, engine, hide, ext, test_type, breakout) local lvtfile = name .. (ext or lvtext) cp(lvtfile, fileexists(testfiledir .. "/" .. lvtfile) and testfiledir or unpackdir, testdir) local checkopts = checkopts - local engine = engine or stdengine + engine = engine or stdengine local binary = engine local format = gsub(engine,"tex$",checkformat) -- Special binary/format combos - if specialformats[checkformat] and next(specialformats[checkformat]) then - local t = specialformats[checkformat] - if t[engine] and next(t[engine]) then - local t = t[engine] - binary = t.binary or binary - checkopts = t.options or checkopts - format = t.format or format + local special_check = specialformats[checkformat] + if special_check and next(special_check) then + local engine_info = special_check[engine] + if engine_info then + binary = engine_info.binary or binary + format = engine_info.format or format + checkopts = engine_info.options or checkopts end end -- Finalise format string @@ -710,7 +728,7 @@ function runtest(name, engine, hide, ext, pdfmode, breakout) format = " --fmt=" .. format end -- Special casing for XeTeX engine - if match(engine, "xetex") and not pdfmode then + if match(engine, "xetex") and test_type.generated ~= pdfext then checkopts = checkopts .. " -no-pdf" end -- Special casing for ConTeXt @@ -721,10 +739,8 @@ function runtest(name, engine, hide, ext, pdfmode, breakout) function setup(file) return ' "' .. file .. '" ' end end local basename = testdir .. "/" .. name - local logfile = basename .. logext - local newfile = basename .. "." .. engine .. logext - local pdffile = basename .. pdfext - local npffile = basename .. "." .. engine .. pdfext + local gen_file = basename .. test_type.generated + local new_file = basename .. "." .. engine .. test_type.generated local asciiopt = "" for _,i in ipairs(asciiengines) do if binary == i then @@ -737,7 +753,7 @@ function runtest(name, engine, hide, ext, pdfmode, breakout) rm(testdir,filetype) end -- Ensure there is no stray .log file - rm(testdir,name .. logext) + rmfile(testdir,name .. logext) local errlevels = {} local localtexmf = "" if texmfdir and texmfdir ~= "" and direxists(texmfdir) then @@ -760,7 +776,7 @@ function runtest(name, engine, hide, ext, pdfmode, breakout) -- Allow for local texmf files os_setenv .. " TEXMFCNF=." .. os_pathsep .. os_concat .. - (forcecheckepoch and setepoch() or "") .. + set_epoch_cmd(epoch, forcecheckepoch) .. -- Ensure lines are of a known length os_setenv .. " max_print_line=" .. maxprintline .. os_concat .. @@ -773,47 +789,34 @@ function runtest(name, engine, hide, ext, pdfmode, breakout) ) -- Break the loop if the result is stable if breakout and i < checkruns then - if pdfmode then + if test_type.generated == pdfext then if fileexists(testdir .. "/" .. name .. dviext) then dvitopdf(name, testdir, engine, hide) end - rewrite(pdffile,npffile,normalize_pdf) - if compare_pdf(name,engine,true) == 0 then - break - end - else - rewrite(logfile,newfile,normalize_log,engine,errlevels) - if compare_tlg(name,engine,true) == 0 then - break - end + end + test_type.rewrite(gen_file,new_file,engine,errlevels) + if base_compare(test_type,name,engine,true) == 0 then + break end end end - if pdfmode and fileexists(testdir .. "/" .. name .. dviext) then - dvitopdf(name, testdir, engine, hide) - end - if pdfmode then + if test_type.generated == pdfext then + if fileexists(testdir .. "/" .. name .. dviext) then + dvitopdf(name, testdir, engine, hide) + end cp(name .. pdfext,testdir,resultdir) ren(resultdir,name .. pdfext,name .. "." .. engine .. pdfext) - rewrite(pdffile,npffile,normalize_pdf) - else - rewrite(logfile,newfile,normalize_log,engine,errlevels) end + test_type.rewrite(gen_file,new_file,engine,errlevels) -- Store secondary files for this engine for _,filetype in pairs(auxfiles) do for _,file in pairs(filelist(testdir, filetype)) do - if match(file,"^" .. name .. ".[^.]+$") then - local ext = match(file, "%.[^.]+$") - if ext ~= lvtext and - ext ~= tlgext and - ext ~= lveext and - ext ~= logext then - local newname = gsub(file,"(%.[^.]+)$","." .. engine .. "%1") - if fileexists(testdir,newname) then - rm(testdir,newname) - end - ren(testdir,file,newname) + if match(file,"^" .. name .. "%.[^.]+$") then + local newname = gsub(file,"(%.[^.]+)$","." .. engine .. "%1") + if fileexists(testdir .. "/" .. newname) then + rmfile(testdir,newname) end + ren(testdir,file,newname) end end end @@ -821,14 +824,25 @@ function runtest(name, engine, hide, ext, pdfmode, breakout) end -- A hook to allow additional tasks to run for the tests -runtest_tasks = runtest_tasks or function(name,run) +function runtest_tasks(name,run) return "" end -- Look for a test: could be in the testfiledir or the unpackdir function testexists(test) - return(locate({testfiledir, unpackdir}, - {test .. lvtext, test .. pvtext})) + local filenames = {} + for i, kind in ipairs(test_order) do + filenames[i] = test .. test_types[kind].test + end + local found = locate({testfiledir, unpackdir}, filenames) + if found then + for i, kind in ipairs(test_order) do + local filename = filenames[i] + if found:sub(-#filename) == filename then + return found, kind + end + end + end end function check(names) @@ -844,36 +858,42 @@ function check(names) names = names or { } -- No names passed: find all test files if not next(names) then - local excludenames = { } - for _,glob in pairs(excludetests) do - for _,name in pairs(filelist(testfiledir, glob .. lvtext)) do - excludenames[jobname(name)] = true - end - for _,name in pairs(filelist(unpackdir, glob .. lvtext)) do - excludenames[jobname(name)] = true - end - for _,name in pairs(filelist(testfiledir, glob .. pvtext)) do - excludenames[jobname(name)] = true - end - end - local function addname(name) - if not excludenames[jobname(name)] then - insert(names,jobname(name)) - end - end - for _,glob in pairs(includetests) do - for _,name in pairs(filelist(testfiledir, glob .. lvtext)) do - addname(name) - end - for _,name in pairs(filelist(testfiledir, glob .. pvtext)) do - addname(name) + for _, kind in ipairs(test_order) do + local ext = test_types[kind].test + local excludepatterns = { } + local num_exclude = 0 + for _,glob in pairs(excludetests) do + num_exclude = num_exclude+1 + excludepatterns[num_exclude] = glob_to_pattern(glob .. ext) end - for _,name in pairs(filelist(unpackdir, glob .. lvtext)) do - if fileexists(testfiledir .. "/" .. name) then - print("Duplicate test file: " .. i) - return 1 + for _,glob in pairs(includetests) do + for _,name in pairs(filelist(testfiledir, glob .. ext)) do + local exclude + for i=1, num_exclude do + if match(name, excludepatterns[i]) then + exclude = true + break + end + end + if not exclude then + insert(names,jobname(name)) + end + end + for _,name in pairs(filelist(unpackdir, glob .. ext)) do + local exclude + for i=1, num_exclude do + if not match(name, excludepatterns[i]) then + exclude = true + break + end + end + if not exclude then + if fileexists(testfiledir .. "/" .. name) then + return 1 + end + insert(names,jobname(name)) + end end - addname(name) end end sort(names) @@ -904,24 +924,17 @@ function check(names) end end end - -- https://stackoverflow.com/a/32167188 - local function shuffle(tbl) - local len, random = #tbl, rnd - for i = len, 2, -1 do - local j = random(1, i) - tbl[i], tbl[j] = tbl[j], tbl[i] - end - return tbl - end if options["shuffle"] then - names = shuffle(names) + -- https://stackoverflow.com/a/32167188 + for i = #names, 2, -1 do + local j = rnd(1, i) + names[i], names[j] = names[j], names[i] + end end -- Actually run the tests print("Running checks on") - local i = 0 - for _,name in ipairs(names) do - i = i + 1 - print(" " .. name .. " (" .. i.. "/" .. #names ..")") + for i, name in ipairs(names) do + print(" " .. name .. " (" .. i .. "/" .. #names ..")") local errlevel = runcheck(name, hide) -- Return value must be 1 not errlevel if errlevel ~= 0 then @@ -988,39 +1001,31 @@ function save(names) return 1 end for _,name in pairs(names) do - if testexists(name) then - for _,engine in pairs(engines) do - local testengine = ((engine == stdengine and "") or "." .. engine) - local function save_test(test_ext,gen_ext,out_ext,pdfmode) - local out_file = name .. testengine .. out_ext - local gen_file = name .. "." .. engine .. gen_ext - print("Creating and copying " .. out_file) - runtest(name,engine,false,test_ext,pdfmode) - ren(testdir,gen_file,out_file) - cp(out_file,testdir,testfiledir) - if fileexists(unpackdir .. "/" .. out_file) then - print("Saved " .. out_ext - .. " file overrides unpacked version of the same name") - return 1 - end - return 0 - end - local errorlevel - if fileexists(testfiledir .. "/" .. name .. lvtext) then - errorlevel = save_test(lvtext,logext,tlgext) - else - errorlevel = save_test(pvtext,pdfext,tpfext,true) - end - if errorlevel ~=0 then return errorlevel end - end - elseif locate({unpackdir, testfiledir}, {name .. lveext}) then - print("Saved " .. tlgext .. " file overrides a " - .. lveext .. " file of the same name") - return 1 - else + local test_filename, kind = testexists(name) + if not test_filename then print('Test "' .. name .. '" not found') return 1 end + local test_type = test_types[kind] + if locate({unpackdir, testfiledir}, {name .. test_type.expectation}) then + print("Saved " .. test_type.test .. " file would override a " + .. test_type.expectation .. " file of the same name") + return 1 + end + for _,engine in pairs(engines) do + local testengine = engine == stdengine and "" or ("." .. engine) + local out_file = name .. testengine .. test_type.reference + local gen_file = name .. "." .. engine .. test_type.generated + print("Creating and copying " .. out_file) + runtest(name, engine, false, test_type.test, test_type) + ren(testdir, gen_file, out_file) + cp(out_file, testdir, testfiledir) + if fileexists(unpackdir .. "/" .. test_type.reference) then + print("Saved " .. test_type.reference + .. " file overrides unpacked version of the same name") + return 1 + end + end end return 0 end diff --git a/macros/latex/contrib/l3build/l3build-clean.lua b/macros/latex/contrib/l3build/l3build-clean.lua index 27ed42be9c..f548a392eb 100644 --- a/macros/latex/contrib/l3build/l3build-clean.lua +++ b/macros/latex/contrib/l3build/l3build-clean.lua @@ -1,6 +1,6 @@ --[[ -File l3build-clean.lua Copyright (C) 2018,2020 The LaTeX3 Project +File l3build-clean.lua Copyright (C) 2018,2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -22,36 +22,46 @@ for those people who are interested. --]] +local pairs = pairs +local ipairs = ipairs +local insert = table.insert + -- Remove all generated files function clean() -- To make sure that distribdir never contains any stray subdirs, -- it is entirely removed then recreated rather than simply deleting -- all of the files - local errorlevel = - rmdir(distribdir) + - mkdir(distribdir) + - cleandir(localdir) + - cleandir(testdir) + - cleandir(typesetdir) + - cleandir(unpackdir) + local errorlevel = rmdir(distribdir) + + mkdir(distribdir) + + cleandir(localdir) + + cleandir(testdir) + + cleandir(typesetdir) + + cleandir(unpackdir) if errorlevel ~= 0 then return errorlevel end - local clean_list = { } for _,dir in pairs(remove_duplicates({maindir,sourcefiledir,docfiledir})) do + local clean_list = {} + local flags = {} for _,glob in pairs(cleanfiles) do - for file,_ in pairs(tree(dir,glob)) do - clean_list[file] = true + for _,p in ipairs(tree(dir,glob)) do + insert(clean_list, p.src) + flags[p.src] = true end end for _,glob in pairs(sourcefiles) do - for file,_ in pairs(tree(dir,glob)) do - clean_list[file] = nil + for _,p in ipairs(tree(dir,glob)) do + flags[p.src] = nil end end - for file,_ in pairs(clean_list) do - errorlevel = rm(dir,file) - if errorlevel ~= 0 then return errorlevel end + for i = #clean_list, 1, -1 do + local p_src = clean_list[i] + if flags[p_src] then + errorlevel = rm(dir,p_src) + if errorlevel ~= 0 then + return errorlevel + end + end end end @@ -63,10 +73,8 @@ function bundleclean() for _,i in ipairs(cleanfiles) do errorlevel = rm(currentdir, i) + errorlevel end - return ( - errorlevel + - rmdir(ctandir) + - rmdir(tdsdir) - ) + return errorlevel + + rmdir(ctandir) + + rmdir(tdsdir) end diff --git a/macros/latex/contrib/l3build/l3build-ctan.lua b/macros/latex/contrib/l3build/l3build-ctan.lua index df1daf9728..fd1491dd58 100644 --- a/macros/latex/contrib/l3build/l3build-ctan.lua +++ b/macros/latex/contrib/l3build/l3build-ctan.lua @@ -1,6 +1,6 @@ --[[ -File l3build-ctan.lua Copyright (C) 2018-2020 The LaTeX3 Project +File l3build-ctan.lua Copyright (C) 2018-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -38,12 +38,12 @@ function copyctan() end else for _,filetype in pairs(files) do - for file,_ in pairs(tree(source,filetype)) do - local path = splitpath(file) + for _,p in ipairs(tree(source,filetype)) do + local path = dirname(p.src) local ctantarget = ctandir .. "/" .. ctanpkg .. "/" .. source .. "/" .. path mkdir(ctantarget) - cp(file,source,ctantarget) + cp(p.src,source,ctantarget) end end end diff --git a/macros/latex/contrib/l3build/l3build-file-functions.lua b/macros/latex/contrib/l3build/l3build-file-functions.lua index 7d13fc933e..6ca1cc6011 100644 --- a/macros/latex/contrib/l3build/l3build-file-functions.lua +++ b/macros/latex/contrib/l3build/l3build-file-functions.lua @@ -1,6 +1,6 @@ --[[ -File l3build-file-functions.lua Copyright (C) 2018-2020 The LaTeX3 Project +File l3build-file-functions.lua Copyright (C) 2018-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -36,7 +36,6 @@ local execute = os.execute local exit = os.exit local getenv = os.getenv local remove = os.remove -local os_time = os.time local os_type = os.type local luatex_revision = status.luatex_revision @@ -171,14 +170,19 @@ function normalize_path(path) end -- Return an absolute path from a relative one +-- Due to chdir, path must exist and be accessible. function abspath(path) local oldpwd = currentdir() - chdir(path) - local result = currentdir() - chdir(oldpwd) - return escapepath(gsub(result, "\\", "/")) + local ok, msg = chdir(path) + if ok then + local result = currentdir() + chdir(oldpwd) + return escapepath(gsub(result, "\\", "/")) + end + error(msg) end +-- TODO: Fix the cross platform problem function escapepath(path) if os_type == "windows" then local path,count = gsub(path,'"','') @@ -210,22 +214,25 @@ end -- Copy files 'quietly' function cp(glob, source, dest) local errorlevel - for i,_ in pairs(tree(source, glob)) do - local source = source .. "/" .. i + for _,p in ipairs(tree(source, glob)) do + -- p_src is a path relative to `source` whereas + -- p_cwd is the counterpart relative to the current working directory if os_type == "windows" then - if attributes(source)["mode"] == "directory" then + if attributes(p.cwd, "mode") == "directory" then errorlevel = execute( - 'xcopy /y /e /i "' .. unix_to_win(source) .. '" "' - .. unix_to_win(dest .. '/' .. i) .. '" > nul' - ) + 'xcopy /y /e /i "' .. unix_to_win(p.cwd) .. '" "' + .. unix_to_win(dest .. '/' .. p.src) .. '" > nul' + ) and 0 or 1 else errorlevel = execute( - 'xcopy /y "' .. unix_to_win(source) .. '" "' + 'xcopy /y "' .. unix_to_win(p.cwd) .. '" "' .. unix_to_win(dest .. '/') .. '" > nul' - ) + ) and 0 or 1 end else - errorlevel = execute("cp -RLf '" .. source .. "' '" .. dest .. "'") + errorlevel = execute( + "cp -RLf '" .. p.cwd .. "' '" .. dest .. "'" + ) and 0 or 1 end if errorlevel ~=0 then return errorlevel @@ -255,7 +262,7 @@ function fileexists(file) f:close() return true else - return false + return false -- also file exits and is not readable end end @@ -283,54 +290,73 @@ function filelist(path, glob) return files end --- Does what filelist does, but can also glob subdirectories. In the returned --- table, the keys are paths relative to the given starting path, the values --- are their counterparts relative to the current working directory. -function tree(path, glob) +---@class tree_entry_t +---@field src string path relative to the source directory +---@field cwd string path counterpart relative to the current working directory + +---Does what filelist does, but can also glob subdirectories. +---In the returned table, the keys are paths relative to the given source path, +---the values are their counterparts relative to the current working directory. +---@param src_path string +---@param glob string +---@return table +function tree(src_path, glob) local function cropdots(path) - return gsub(gsub(path, "^%./", ""), "/%./", "/") + return path:gsub( "^%./", ""):gsub("/%./", "/") end + src_path = cropdots(src_path) + glob = cropdots(glob) local function always_true() return true end local function is_dir(file) - return attributes(file)["mode"] == "directory" + return attributes(file, "mode") == "directory" end - local dirs = {["."] = cropdots(path)} - for pattern, criterion in gmatch(cropdots(glob), "([^/]+)(/?)") do - local criterion = criterion == "/" and is_dir or always_true - function fill(path, dir, table) - for _, file in ipairs(filelist(dir, pattern)) do - local fullpath = path .. "/" .. file - if file ~= "." and file ~= ".." and - fullpath ~= builddir - then - local fulldir = dir .. "/" .. file - if criterion(fulldir) then - table[fullpath] = fulldir + ---@type table + local result = { { + src = ".", + cwd = src_path, + } } + for glob_part, sep in glob:gmatch("([^/]+)(/?)/*") do + local accept = sep == "/" and is_dir or always_true + ---Feeds the given table according to `glob_part` + ---@param p tree_entry_t path counterpart relative to the current working directory + ---@param table table + local function fill(p, table) + for _,file in ipairs(filelist(p.cwd, glob_part)) do + if file ~= "." and file ~= ".." then + local pp = { + src = p.src .. "/" .. file, + cwd = p.cwd .. "/" .. file, + } + if pp.cwd ~= builddir -- TODO: ensure that `builddir` is properly formatted + and accept(pp.cwd) + then + insert(table, pp) end end end end - local newdirs = {} - if pattern == "**" then + local new_result = {} + if glob_part == "**" then + local i = 1 while true do - path, dir = next(dirs) - if not path then + local p = result[i] + i = i + 1 + if not p then break end - dirs[path] = nil - newdirs[path] = dir - fill(path, dir, dirs) + insert(new_result, p) -- shorter path + fill(p, result) -- after longer end else - for path, dir in pairs(dirs) do - fill(path, dir, newdirs) + for _,p in ipairs(result) do + fill(p, new_result) end end - dirs = newdirs + result = new_result end - return dirs + return result end function remove_duplicates(a) @@ -353,7 +379,7 @@ function mkdir(dir) if os_type == "windows" then -- Windows (with the extensions) will automatically make directory trees -- but issues a warning if the dir already exists: avoid by including a test - local dir = unix_to_win(dir) + dir = unix_to_win(dir) return execute( "if not exist " .. dir .. "\\nul " .. "mkdir " .. dir ) @@ -364,10 +390,10 @@ end -- Rename function ren(dir, source, dest) - local dir = dir .. "/" + dir = dir .. "/" if os_type == "windows" then - local source = gsub(source, "^%.+/", "") - local dest = gsub(dest, "^%.+/", "") + source = gsub(source, "^%.+/", "") + dest = gsub(dest, "^%.+/", "") return execute("ren " .. unix_to_win(dir) .. source .. " " .. dest) else return execute("mv " .. dir .. source .. " " .. dir .. dest) @@ -376,8 +402,8 @@ end -- Remove file(s) based on a glob function rm(source, glob) - for i,_ in pairs(tree(source, glob)) do - rmfile(source,i) + for _,p in ipairs(tree(source, glob)) do + rmfile(source,p.src) end -- os.remove doesn't give a sensible errorlevel return 0 diff --git a/macros/latex/contrib/l3build/l3build-help.lua b/macros/latex/contrib/l3build/l3build-help.lua index 055fc1a918..6431ac547e 100644 --- a/macros/latex/contrib/l3build/l3build-help.lua +++ b/macros/latex/contrib/l3build/l3build-help.lua @@ -1,6 +1,6 @@ --[[ -File l3build-help.lua Copyright (C) 2018,2020 The LaTeX3 Project +File l3build-help.lua Copyright (C) 2018,2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -32,14 +32,14 @@ function version() "\n" .. "l3build: A testing and building system for LaTeX\n\n" .. "Release " .. release_date .. "\n" .. - "Copyright (C) 2014-2020 The LaTeX3 Project" + "Copyright (C) 2014-2020 The LaTeX Project" ) end function help() local function setup_list(list) local longest = 0 - for k,v in pairs(list) do + for k,_ in pairs(list) do if k:len() > longest then longest = k:len() end @@ -70,7 +70,7 @@ function help() end print("") print("Valid options are:") - local longest,t = setup_list(option_list) + longest,t = setup_list(option_list) for _,k in ipairs(t) do local opt = option_list[k] local filler = rep(" ", longest - k:len() + 1) @@ -87,5 +87,5 @@ function help() print("") print("Repository : https://github.com/latex3/l3build") print("Bug tracker : https://github.com/latex3/l3build/issues") - print("Copyright (C) 2014-2020 The LaTeX3 Project") + print("Copyright (C) 2014-2020 The LaTeX Project") end diff --git a/macros/latex/contrib/l3build/l3build-install.lua b/macros/latex/contrib/l3build/l3build-install.lua index 77c15fd0e2..f4839fdca7 100644 --- a/macros/latex/contrib/l3build/l3build-install.lua +++ b/macros/latex/contrib/l3build/l3build-install.lua @@ -1,6 +1,6 @@ --[[ -File l3build-install.lua Copyright (C) 2018-2020 The LaTeX3 Project +File l3build-install.lua Copyright (C) 2018-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -37,7 +37,9 @@ local insert = table.insert local function gethome() set_program("latex") - return abspath(options["texmfhome"] or var_value("TEXMFHOME")) + local result = options["texmfhome"] or var_value("TEXMFHOME") + mkdir(result) + return abspath(result) end function uninstall() @@ -68,15 +70,15 @@ function uninstall() -- Any script man files need special handling local manfiles = { } for _,glob in pairs(scriptmanfiles) do - for file,_ in pairs(tree(docfiledir,glob)) do + for _,p in ipairs(tree(docfiledir,glob)) do -- Man files should have a single-digit extension: the type - local installdir = gethome() .. "/doc/man/man" .. match(file,".$") - if fileexists(installdir .. "/" .. file) then + local installdir = gethome() .. "/doc/man/man" .. match(p.src,".$") + if fileexists(installdir .. "/" .. p.src) then if options["dry-run"] then - insert(manfiles,"man" .. match(file,".$") .. "/" .. - select(2,splitpath(file))) + insert(manfiles,"man" .. match(p.src,".$") .. "/" .. + select(2,splitpath(p.src))) else - errorlevel = errorlevel + rm(installdir,file) + errorlevel = errorlevel + rm(installdir,p.src) end end end @@ -97,7 +99,7 @@ function uninstall() if errorlevel ~= 0 then return errorlevel end -- Finally, clean up special locations for _,location in ipairs(tdslocations) do - local path,glob = splitpath(location) + local path = dirname(location) errorlevel = zapdir(path) if errorlevel ~= 0 then return errorlevel end end @@ -127,9 +129,9 @@ function install_files(target,full,dry_run) -- Generate a file list and include the directory for _,glob_table in pairs(files) do for _,glob in pairs(glob_table) do - for file,_ in pairs(tree(source,glob)) do + for _,p in ipairs(tree(source,glob)) do -- Just want the name - local path,filename = splitpath(file) + local path,filename = splitpath(p.src) local sourcepath = "/" if path == "." then sourcepaths[filename] = source @@ -140,11 +142,11 @@ function install_files(target,full,dry_run) end local matched = false for _,location in ipairs(tdslocations) do - local path,glob = splitpath(location) - local pattern = glob_to_pattern(glob) + local l_dir,l_glob = splitpath(location) + local pattern = glob_to_pattern(l_glob) if match(filename,pattern) then - insert(paths,path) - insert(filenames,path .. sourcepath .. filename) + insert(paths,l_dir) + insert(filenames,l_dir .. sourcepath .. filename) matched = true break end @@ -161,20 +163,20 @@ function install_files(target,full,dry_run) -- The target is only created if there are actual files to install if next(filenames) then if not dry_run then - for _,path in pairs(paths) do - local dir = target .. "/" .. path - if not cleanpaths[dir] then - errorlevel = cleandir(dir) + for _,path in ipairs(paths) do + local target_path = target .. "/" .. path + if not cleanpaths[target_path] then + errorlevel = cleandir(target_path) if errorlevel ~= 0 then return errorlevel end end - cleanpaths[dir] = true + cleanpaths[target_path] = true end end - for _,file in ipairs(filenames) do + for _,name in ipairs(filenames) do if dry_run then - print("- " .. file) + print("- " .. name) else - local path,file = splitpath(file) + local path,file = splitpath(name) insert(installmap, {file = file, source = sourcepaths[file], dest = target .. "/" .. path}) end @@ -187,30 +189,30 @@ function install_files(target,full,dry_run) if errorlevel ~= 0 then return errorlevel end -- Creates a 'controlled' list of files - local function excludelist(dir,include,exclude) + local function create_file_list(dir,include,exclude) + dir = dir or currentdir include = include or { } exclude = exclude or { } - dir = dir or currentdir - local includelist = { } local excludelist = { } for _,glob_table in pairs(exclude) do for _,glob in pairs(glob_table) do - for file,_ in pairs(tree(dir,glob)) do - excludelist[file] = true + for _,p in ipairs(tree(dir,glob)) do + excludelist[p.src] = true end end end + local result = { } for _,glob in pairs(include) do - for file,_ in pairs(tree(dir,glob)) do - if not excludelist[file] then - insert(includelist, file) + for _,p in ipairs(tree(dir,glob)) do + if not excludelist[p.src] then + insert(result, p.src) end end end - return includelist + return result end - local installlist = excludelist(unpackdir,installfiles,{scriptfiles}) + local installlist = create_file_list(unpackdir,installfiles,{scriptfiles}) if full then errorlevel = doc() @@ -229,8 +231,8 @@ function install_files(target,full,dry_run) end -- Set up lists: global as they are also needed to do CTAN releases - typesetlist = excludelist(docfiledir,typesetfiles,{sourcefiles}) - sourcelist = excludelist(sourcefiledir,sourcefiles, + typesetlist = create_file_list(docfiledir,typesetfiles,{sourcefiles}) + sourcelist = create_file_list(sourcefiledir,sourcefiles, {bstfiles,installfiles,makeindexfiles,scriptfiles}) if dry_run then @@ -255,15 +257,15 @@ function install_files(target,full,dry_run) -- Any script man files need special handling local manfiles = { } for _,glob in pairs(scriptmanfiles) do - for file,_ in pairs(tree(docfiledir,glob)) do + for _,p in ipairs(tree(docfiledir,glob)) do if dry_run then - insert(manfiles,"man" .. match(file,".$") .. "/" .. - select(2,splitpath(file))) + insert(manfiles,"man" .. match(p.src,".$") .. "/" .. + select(2,splitpath(p.src))) else -- Man files should have a single-digit extension: the type - local installdir = target .. "/doc/man/man" .. match(file,".$") + local installdir = target .. "/doc/man/man" .. match(p.src,".$") errorlevel = errorlevel + mkdir(installdir) - errorlevel = errorlevel + cp(file,docfiledir,installdir) + errorlevel = errorlevel + cp(p.src,docfiledir,installdir) end end end diff --git a/macros/latex/contrib/l3build/l3build-manifest-setup.lua b/macros/latex/contrib/l3build/l3build-manifest-setup.lua index 26bf1ca008..9fcf493729 100644 --- a/macros/latex/contrib/l3build/l3build-manifest-setup.lua +++ b/macros/latex/contrib/l3build/l3build-manifest-setup.lua @@ -1,6 +1,6 @@ --[[ -File l3build-manifest-setup.lua Copyright (C) 2018,2020 The LaTeX3 Project +File l3build-manifest-setup.lua Copyright (C) 2018,2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -54,7 +54,7 @@ for those people who are interested. --]] -manifest_setup = manifest_setup or function() +function manifest_setup() local groups = { { subheading = "Repository manifest", @@ -221,18 +221,16 @@ end --]] manifest_sort_within_match = manifest_sort_within_match or function(files) - local f = files - table.sort(f) - return f + table.sort(files) + return files end manifest_sort_within_group = manifest_sort_within_group or function(files) - local f = files --[[ -- no-op by default; make your own definition to customise. E.g.: - table.sort(f) + table.sort(files) --]] - return f + return files end --[[ @@ -240,7 +238,7 @@ end --------------- --]] -manifest_write_opening = manifest_write_opening or function(filehandle) +function manifest_write_opening(filehandle) filehandle:write("# Manifest for " .. module .. "\n\n") filehandle:write([[ @@ -250,7 +248,7 @@ It is automatically generated with `texlua build.lua manifest`. end -manifest_write_subheading = manifest_write_subheading or function(filehandle,heading,description) +function manifest_write_subheading(filehandle,heading,description) filehandle:write("\n\n## " .. heading .. "\n\n") @@ -260,7 +258,7 @@ manifest_write_subheading = manifest_write_subheading or function(filehandle,hea end -manifest_write_group_heading = manifest_write_group_heading or function (filehandle,heading,description) +function manifest_write_group_heading(filehandle,heading,description) filehandle:write("\n### " .. heading .. "\n\n") @@ -270,7 +268,7 @@ manifest_write_group_heading = manifest_write_group_heading or function (filehan end -manifest_write_group_file = manifest_write_group_file or function(filehandle,filename,param) +function manifest_write_group_file(filehandle,filename,param) --[[ filehandle : write file object filename : the count of the filename to be written @@ -296,7 +294,7 @@ manifest_write_group_file = manifest_write_group_file or function(filehandle,fil end -manifest_write_group_file_descr = manifest_write_group_file_descr or function(filehandle,filename,descr,param) +function manifest_write_group_file_descr(filehandle,filename,descr,param) --[[ filehandle : write file object filename : the name of the file to write @@ -326,7 +324,7 @@ end ------------------------------------------- --]] -manifest_extract_filedesc = manifest_extract_filedesc or function(filehandle) +function manifest_extract_filedesc(filehandle) -- no-op by default; two examples below diff --git a/macros/latex/contrib/l3build/l3build-manifest.lua b/macros/latex/contrib/l3build/l3build-manifest.lua index dc5138952c..f9b1c4e82e 100644 --- a/macros/latex/contrib/l3build/l3build-manifest.lua +++ b/macros/latex/contrib/l3build/l3build-manifest.lua @@ -1,6 +1,6 @@ --[[ -File l3build-manifest.lua Copyright (C) 2018,2020 The LaTeX3 Project +File l3build-manifest.lua Copyright (C) 2018,2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -33,7 +33,7 @@ for those people who are interested. `l3build-manifest-setup.lua`. --]] -manifest = manifest or function() +function manifest() -- build list of ctan files ctanfiles = {} @@ -277,4 +277,3 @@ manifest_write_group = function(f,entry) end end - diff --git a/macros/latex/contrib/l3build/l3build-stdmain.lua b/macros/latex/contrib/l3build/l3build-stdmain.lua index 10303b71f7..80b5cc84be 100644 --- a/macros/latex/contrib/l3build/l3build-stdmain.lua +++ b/macros/latex/contrib/l3build/l3build-stdmain.lua @@ -1,6 +1,6 @@ --[[ -File l3build-stdmain.lua Copyright (C) 2018-2020 The LaTeX3 Project +File l3build-stdmain.lua Copyright (C) 2018-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -22,6 +22,8 @@ for those people who are interested. --]] +local lfs = require("lfs") + local exit = os.exit local insert = table.insert @@ -49,7 +51,7 @@ target_list = bundlecheck = { func = check, - pre = function() + pre = function(names) if names then print("Bundle checks should not list test names") help() @@ -65,7 +67,7 @@ target_list = bundleunpack = { func = bundleunpack, - pre = function() return(depinstall(unpackdeps)) end + pre = function() return(dep_install(unpackdeps)) end }, -- Public targets check = @@ -149,7 +151,7 @@ target_list = -- The overall main function -- -function stdmain(target,names) +function main(target,names) -- Deal with unknown targets up-front if not target_list[target] then help() diff --git a/macros/latex/contrib/l3build/l3build-tagging.lua b/macros/latex/contrib/l3build/l3build-tagging.lua index a00180b34c..e255aba5cd 100644 --- a/macros/latex/contrib/l3build/l3build-tagging.lua +++ b/macros/latex/contrib/l3build/l3build-tagging.lua @@ -1,6 +1,6 @@ --[[ -File l3build-tagging.lua Copyright (C) 2018-2020 The LaTeX3 Project +File l3build-tagging.lua Copyright (C) 2018-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -28,7 +28,7 @@ local os_date = os.date local match = string.match local gsub = string.gsub -update_tag = update_tag or function(filename,content,tagname,tagdate) +function update_tag(filename,content,tagname,tagdate) return content end @@ -51,7 +51,7 @@ local function update_file_tag(file,tagname,tagdate) else local path = dirname(file) ren(path,filename,filename .. ".bak") - local f = assert(open(file,"w")) + f = assert(open(file,"w")) -- Convert line ends back if required during write -- Watch for the second return value! f:write((gsub(updated_content,"\n",os_newline))) @@ -71,8 +71,8 @@ function tag(tagnames) local errorlevel = 0 for _,dir in pairs(dirs) do for _,filetype in pairs(tagfiles) do - for file,_ in pairs(tree(dir,filetype)) do - errorlevel = update_file_tag(dir .. "/" .. file,tagname,tagdate) + for _,p in ipairs(tree(dir,filetype)) do + errorlevel = update_file_tag(dir .. "/" .. p.src,tagname,tagdate) if errorlevel ~= 0 then return errorlevel end @@ -81,4 +81,3 @@ function tag(tagnames) end return tag_hook(tagname,tagdate) end - diff --git a/macros/latex/contrib/l3build/l3build-typesetting.lua b/macros/latex/contrib/l3build/l3build-typesetting.lua index 540ac3f384..716648f7fd 100644 --- a/macros/latex/contrib/l3build/l3build-typesetting.lua +++ b/macros/latex/contrib/l3build/l3build-typesetting.lua @@ -1,6 +1,6 @@ --[[ -File l3build-typesetting.lua Copyright (C) 2018-2020 The LaTeX3 Project +File l3build-typesetting.lua Copyright (C) 2018-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -38,20 +38,20 @@ local os_type = os.type function dvitopdf(name, dir, engine, hide) run( dir, - (forcecheckepoch and setepoch() or "") .. + set_epoch_cmd(epoch, forcecheckepoch) .. "dvips " .. name .. dviext .. (hide and (" > " .. os_null) or "") .. os_concat .. - "ps2pdf " .. ps2pdfopt .. name .. psext + "ps2pdf " .. ps2pdfopt .. name .. psext .. (hide and (" > " .. os_null) or "") ) end -- An auxiliary used to set up the environmental variables function runcmd(cmd,dir,vars) - local dir = dir or "." - local dir = abspath(dir) - local vars = vars or {} + dir = dir or "." + dir = abspath(dir) + vars = vars or {} -- Allow for local texmf files local env = os_setenv .. " TEXMFCNF=." .. os_pathsep local localtexmf = "" @@ -68,7 +68,7 @@ function runcmd(cmd,dir,vars) for _,var in pairs(vars) do env = env .. os_concat .. os_setenv .. " " .. var .. "=" .. envpaths end - return run(dir,(forcedocepoch and setepoch() or "") .. env .. os_concat .. cmd) + return run(dir,set_epoch_cmd(epoch, forcedocepoch) .. env .. os_concat .. cmd) end function biber(name,dir) @@ -80,7 +80,7 @@ function biber(name,dir) end function bibtex(name,dir) - local dir = dir or "." + dir = dir or "." if fileexists(dir .. "/" .. name .. ".aux") then -- LaTeX always generates an .aux file, so there is a need to -- look inside it for a \citation line @@ -105,7 +105,7 @@ function bibtex(name,dir) end function makeindex(name,dir,inext,outext,logext,style) - local dir = dir or "." + dir = dir or "." if fileexists(dir .. "/" .. name .. inext) then if style == "" then style = nil end return runcmd(makeindexexe .. " " .. makeindexopts @@ -119,15 +119,15 @@ function makeindex(name,dir,inext,outext,logext,style) end function tex(file,dir,cmd) - local dir = dir or "." - local cmd = cmd or typesetexe .. typesetopts + dir = dir or "." + cmd = cmd or typesetexe .. " " .. typesetopts return runcmd(cmd .. " \"" .. typesetcmds .. "\\input " .. file .. "\"", dir,{"TEXINPUTS","LUAINPUTS"}) end local function typesetpdf(file,dir) - local dir = dir or "." + dir = dir or "." local name = jobname(file) print("Typesetting " .. name) local fn = typeset @@ -141,12 +141,12 @@ local function typesetpdf(file,dir) print(" ! Compilation failed") return errorlevel end - pdfname = name .. pdfext + local pdfname = name .. pdfext rm(docfiledir,pdfname) return cp(pdfname,dir,docfiledir) end -typeset = typeset or function(file,dir,exe) +function typeset(file,dir,exe) dir = dir or "." local errorlevel = tex(file,dir,exe) if errorlevel ~= 0 then @@ -168,7 +168,7 @@ typeset = typeset or function(file,dir,exe) end -- A hook to allow additional typesetting of demos -typeset_demo_tasks = typeset_demo_tasks or function() +function typeset_demo_tasks() return 0 end @@ -188,7 +188,7 @@ local function docinit() for _,file in pairs(typesetsuppfiles) do cp(file, supportdir, typesetdir) end - depinstall(typesetdeps) + dep_install(typesetdeps) unpack({sourcefiles, typesetsourcefiles}, {sourcefiledir, docfiledir}) -- Main loop for doc creation local errorlevel = typeset_demo_tasks() @@ -198,7 +198,7 @@ local function docinit() return docinit_hook() end -docinit_hook = docinit_hook or function() return 0 end +function docinit_hook() return 0 end -- Typeset all required documents -- Uses a set of dedicated auxiliaries that need to be available to others @@ -209,8 +209,8 @@ function doc(files) for _,typesetfiles in ipairs({typesetdemofiles,typesetfiles}) do for _,glob in pairs(typesetfiles) do for _,dir in ipairs({typesetdir,unpackdir}) do - for _,file in pairs(tree(dir,glob)) do - local path,srcname = splitpath(file) + for _,p in ipairs(tree(dir,glob)) do + local path,srcname = splitpath(p.cwd) local name = jobname(srcname) if not done[name] then local typeset = true @@ -226,7 +226,7 @@ function doc(files) end -- Now know if we should typeset this source if typeset then - local errorlevel = typesetpdf(srcname,path) + errorlevel = typesetpdf(srcname,path) if errorlevel ~= 0 then return errorlevel else @@ -240,4 +240,3 @@ function doc(files) end return 0 end - diff --git a/macros/latex/contrib/l3build/l3build-unpack.lua b/macros/latex/contrib/l3build/l3build-unpack.lua index 412b5e84da..7ab21ee09d 100644 --- a/macros/latex/contrib/l3build/l3build-unpack.lua +++ b/macros/latex/contrib/l3build/l3build-unpack.lua @@ -1,6 +1,6 @@ --[[ -File l3build-unpack.lua Copyright (C) 2018-2020 The LaTeX3 Project +File l3build-unpack.lua Copyright (C) 2018-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -22,12 +22,10 @@ for those people who are interested. --]] -local execute = os.execute - -- Unpack the package files using an 'isolated' system: this requires -- a copy of the 'basic' DocStrip program, which is used then removed function unpack(sources, sourcedirs) - local errorlevel = depinstall(unpackdeps) + local errorlevel = dep_install(unpackdeps) if errorlevel ~= 0 then return errorlevel end @@ -46,7 +44,7 @@ end -- Split off from the main unpack so it can be used on a bundle and not -- leave only one modules files -bundleunpack = bundleunpack or function(sourcedirs, sources) +function bundleunpack(sourcedirs, sources) local errorlevel = mkdir(localdir) if errorlevel ~=0 then return errorlevel @@ -72,8 +70,8 @@ bundleunpack = bundleunpack or function(sourcedirs, sources) end end for _,i in ipairs(unpackfiles) do - for j,_ in pairs(tree(unpackdir, i)) do - local path, name = splitpath(j) + for _,p in ipairs(tree(unpackdir, i)) do + local path, name = splitpath(p.src) local localdir = abspath(localdir) local success = io.popen( "cd " .. unpackdir .. "/" .. path .. os_concat .. diff --git a/macros/latex/contrib/l3build/l3build-upload.lua b/macros/latex/contrib/l3build/l3build-upload.lua index ba74309492..629d2ee7c7 100644 --- a/macros/latex/contrib/l3build/l3build-upload.lua +++ b/macros/latex/contrib/l3build/l3build-upload.lua @@ -1,6 +1,6 @@ --[[ -File l3build-upload.lua Copyright (C) 2018-2020 The LaTeX3 Project +File l3build-upload.lua Copyright (C) 2018-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -78,6 +78,12 @@ end -- if upload is anything else, the user will be prompted whether to upload. -- For now, this is undocumented. I think I would prefer to keep it always set to ask for the time being. +local ctan_post -- this is private to the module + +-- TODO: next is a public global method, +-- but following functions are semantically local +-- despite they are declared globally. + function upload(tagnames) local uploadfile = ctanzip..".zip" @@ -100,7 +106,7 @@ function upload(tagnames) uploadconfig.note = uploadconfig.note or file_contents(uploadconfig.note_file) - local tagnames = tagnames or { } + tagnames = tagnames or { } uploadconfig.version = tagnames[1] or uploadconfig.version local override_update_check = false @@ -214,7 +220,7 @@ end function shell(s) local h = assert(popen(s, 'r')) - t = assert(h:read('*a')) + local t = assert(h:read('*a')) h:close() return t end @@ -248,12 +254,6 @@ function construct_ctan_post(uploadfile,debug) ctan_field("uploader", uploadconfig.uploader, 255, "Name of uploader", true, false ) ctan_field("version", uploadconfig.version, 32, "Package version", true, false ) - -- finish constructing the curl command: - local qq = '"' - if os_type == "windows" then - qq = '\"' - end --- commandline ctan_post = ctan_post .. ' --form ' .. qq .. 'file=@' .. tostring(uploadfile) .. ';filename=' .. tostring(uploadfile) .. qq ctan_post = ctan_post .. '\nform="file=@' .. tostring(uploadfile) .. ';filename=' .. tostring(uploadfile) .. '"' return ctan_post @@ -352,7 +352,7 @@ function file_contents (filename) local f= open(filename,"r") if f==nil then return nil - else + else local s = f:read("*all") close(f) return s diff --git a/macros/latex/contrib/l3build/l3build-variables.lua b/macros/latex/contrib/l3build/l3build-variables.lua index 87ce01d611..e3ae64e13b 100644 --- a/macros/latex/contrib/l3build/l3build-variables.lua +++ b/macros/latex/contrib/l3build/l3build-variables.lua @@ -1,6 +1,6 @@ --[[ -File l3build-variables.lua Copyright (C) 2018-2020 The LaTeX3 Project +File l3build-variables.lua Copyright (C) 2018-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -22,8 +22,6 @@ for those people who are interested. --]] -local exit = os.exit - -- "module" is a deprecated function in Lua 5.2: as we want the name -- for other purposes, and it should eventually be 'free', simply -- remove the built-in @@ -209,6 +207,24 @@ pvtext = pvtext or ".pvt" tlgext = tlgext or ".tlg" tpfext = tpfext or ".tpf" +test_types = test_types or { } +test_types.log = test_types.log or { + test = lvtext, + generated = logext, + reference = tlgext, + expectation = lveext, + compare = compare_tlg, + rewrite = rewrite_log, +} +test_types.pdf = test_types.pdf or { + test = pvtext, + generated = pdfext, + reference = tpfext, + rewrite = rewrite_pdf, +} + +test_order = test_order or {"log", "pdf"} + -- Manifest options manifestfile = manifestfile or "MANIFEST.md" diff --git a/macros/latex/contrib/l3build/l3build.1 b/macros/latex/contrib/l3build/l3build.1 index 9262d7c5b6..2bb47c3068 100644 --- a/macros/latex/contrib/l3build/l3build.1 +++ b/macros/latex/contrib/l3build/l3build.1 @@ -1,4 +1,4 @@ -.TH l3build 1 "2020-06-04" +.TH l3build 1 "2021-05-05" .SH NAME l3build \- Checking and building packages .SH SYNOPSIS @@ -59,7 +59,7 @@ Shuffle order of tests Location of user texmf tree .SH BUGS .SH AUTHOR -The LaTeX3 Project (latex-team@latex-project.org) +The LaTeX Project (latex-team@latex-project.org) .PP Please log issues on the GitHub homepage: https://github.com/latex3/l3build/issues. diff --git a/macros/latex/contrib/l3build/l3build.dtx b/macros/latex/contrib/l3build/l3build.dtx index 198042469e..9359b941b1 100644 --- a/macros/latex/contrib/l3build/l3build.dtx +++ b/macros/latex/contrib/l3build/l3build.dtx @@ -1,6 +1,6 @@ % \iffalse % -% File l3build.dtx (C) Copyright 2014-2020 The LaTeX3 Project +% File l3build.dtx (C) Copyright 2014-2020 The LaTeX Project % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -114,6 +114,8 @@ \luavarset{stdengine} {"pdftex"}{Engine to generate \texttt{.tlg} file from} \luavarset{checkformat} {"latex"} {Format to use for tests} \luavarset{specialformats}{\meta{table}} {Non-standard engine/format combinations} +\luavarset{\detokenize{test_types}} {\meta{table}} {Custom test variants} +\luavarset{\detokenize{test_order}} {\{"log", "pdf"\}} {Which kinds of tests to evaluate} \luavarseparator \luavarset{checkconfigs}{\{\}}{Configurations to use for tests} \luavarseparator @@ -227,7 +229,7 @@ % } % % \author{^^A -% The \LaTeX3 Project\thanks +% The \LaTeX{} Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} @@ -235,7 +237,7 @@ % }^^A % } % -% \date{Released 2020-06-04} +% \date{Released 2021-05-05} % % \maketitle % \tableofcontents @@ -274,7 +276,7 @@ % The \pkg{l3build} system is also capable of building and checking \emph{bundles} of packages. % To avoid confusion, we refer to either a standalone package or a package within a bundle as a \emph{module}. % -% For example, within the \LaTeX3 project we have the \textsf{l3packages} bundle which contains the \textsf{xparse}, \textsf{xtemplate}, etc., modules. +% For example, within the \LaTeX{} project we have the \textsf{l3packages} bundle which contains the \textsf{xparse}, \textsf{xtemplate}, etc., modules. % These are all built and distributed as one bundle for installation, distribution \emph{via} CTAN and so forth. % % Each module in a bundle will have its own build script, and a bundle build script brings them all together. @@ -320,16 +322,19 @@ % which is read during execution. In the current release of \pkg{l3build}, % \texttt{build.lua} is read automatically and can access all of the global % functions provided by the script. Thus it may contain a simple list of -% variable settings \emph{or} additionally custom code to change the build -% process. A number of example scripts are given in Section~\ref{sec:examples}. +% variable settings \emph{or} additional code to customize the build +% process. +% +%The example scripts given in Section~\ref{sec:examples} largely cover the required knowledge in Lua programing. +% For a more advanced usage, one may consult general Lua documentations including \url{http://www.lua.org/manual/5.3/manual.html} and for the few |texlua| specific additions see section 4.2 of the \LuaTeX{} manual available locally with |texdoc luatex| command line or at \url{https://www.pragma-ade.com/general/manuals/luatex.pdf}. % % \subsection{Main build targets} % % In the working directory of a bundle or module, \pkg{l3build} is run by executing % \begin{center} -% \texttt{l3build \meta{targets} [\meta{option(s)}]} +% \texttt{l3build \meta{target} [\meta{option(s)}]} % \end{center} -% where \texttt{\meta{targets}} can be one of the following: +% where \texttt{\meta{target}} can be one of the following: % \begin{itemize}[noitemsep]\ttfamily % \item check % \item check \meta{name(s)} @@ -340,11 +345,10 @@ % \item install % \item manifest % \item save \meta{name(s)} -% \item tag \meta{tag} +% \item tag [\meta{tag name}] % \item uninstall % \item unpack -% \item upload -% \item upload \meta{tag} +% \item upload [\meta{version}] % \end{itemize} % These targets are described below. % @@ -408,8 +412,8 @@ % % Checking can be performed with any or all of the `engines' \texttt{pdftex}, \texttt{xetex}, and \texttt{luatex}. % By default, each test is executed with all three, being compared against the \texttt{.tlg} file produced from the \var{pdftex} engine (these defaults are controlled by the |checkengines| and |stdengine| variable respectively). -% The format used for tests can be altered by setting \var{checkformat}: the default setting \texttt{latex} means that tests are run using \emph{e.g.}~\texttt{pdflatex}, whereas setting to \texttt{plain} will run tests using \emph{e.g.}~\texttt{pdftex}. -% (Currently, this should be one of \texttt{latex} or \texttt{plain}.) +% The format used for tests can be altered by setting \var{checkformat}: the default setting \texttt{latex} means that tests are run using \emph{e.g.}~\texttt{pdflatex}, whereas setting to \texttt{tex} will run tests using \emph{e.g.}~\texttt{pdftex}. +% (Currently, this should be one of \texttt{latex} or \texttt{tex}.) % To perform the check, the engine typesets each test up to \var{checkruns} times. % More detail on this in the documentation on |save|. % Options passed to the binary are defined in the variable \var{checkopts}. @@ -563,17 +567,14 @@ % Improvements to this process are planned for the future. % \end{buildcmd} % -% \begin{buildcmd}{tag} -% Modifies the contents of files specified by |tagfiles| using a search pattern -% to automatically update the `release tag' (or package version) and date. -% The tag is given as the command line option and the date using -% |--date| (|-d|). If not given, the date will default to the current date in -% ISO format (YYYY-MM-DD). If no option is given (i.e., no tag specified) the tag -% is passed through as |nil| to allow setting the tag programmatically. -% -% The standard setup has no search pattern defined for this target and so no action -% will be taken \emph{unless} tag substitution is set up by defining the Lua function -% |update_tag()|. See Section~\ref{sec:tagging} for full details on this feature. +% \begin{buildcmd}{tag [\meta{tag name}]} +% Apply the Lua |update_tag()| function to modify the contents of files specified by |tagfiles| to update the `release tag' (or package version) and date. +% The tag is given as the optional command line argument \meta{tag name} and the date using +% |--date| (or |-d|). If not given, the date will default to the current date in +% ISO format (YYYY-MM-DD). If no \meta{tag name} is given, the tag will default to |nil|. +% Both are passed as arguments to the |update_tag()| function. +% +% The standard setup does nothing unless tag update is set up by defining a custom |update_tag()| function. See Section~\ref{sec:tagging} for full details on this feature. % \end{buildcmd} % % \begin{buildcmd}{unpack} @@ -588,11 +589,11 @@ % By default this process allows files to be accessed in all standard |texmf| trees; this can be disabled by setting \var{unpacksearch} to |false|. % \end{buildcmd} % -% \begin{buildcmd}{upload} +% \begin{buildcmd}{upload [\meta{version}]} % This target uses \texttt{curl} to upload the package zip file (created using \texttt{ctan}) to CTAN. % To control the metadata used to upload the package, the \texttt{uploadconfig} table should be populated with a number of fields. % These are documented in Table~\ref{tab:upload-setup}. -% Missing required fields will result in an interactive prompt for manual entry. +% Missing required fields will result in an interactive prompt for manual entry. When given, \meta{version} overrides \texttt{uploadconfig.version}. % % See Section~\ref{sec:upload} for full details on this feature. % \end{buildcmd} @@ -620,12 +621,12 @@ % \end{figure} % % An example of a bundle build script for \pkg{l3packages} is shown in Figure~\ref{fig:bundle}. -% Note for \LaTeX3 we use a common file to set all build variables in one place, and the path to the |l3build.lua| script is hard-coded so we always use our own most recent version of the script. +% Note for \LaTeX{} we use a common file to set all build variables in one place, and the path to the |l3build.lua| script is hard-coded so we always use our own most recent version of the script. % An example of an accompanying module build script is shown in Figure~\ref{fig:module}. % % \begin{figure}[p] % \begin{lstlisting}[frame=single,language={[5.2]Lua},gobble = 6] -% -- Build script for LaTeX3 "l3packages" files +% -- Build script for LaTeX "l3packages" files % % -- Identify the bundle: there is no module as this is the "driver" % bundle = "l3packages" @@ -639,7 +640,7 @@ % % \begin{figure}[p] % \begin{lstlisting}[frame=single,language={[5.2]Lua},gobble = 6] -% -- Build script for LaTeX3 "xparse" files +% -- Build script for LaTeX "xparse" files % % -- Identify the bundle and module: % bundle = "l3packages" @@ -656,28 +657,6 @@ % A collection of full examples (source files in various layouts) are available % at \url{https://github.com/latex3/l3build/tree/master/examples}. % -% \subsection{Backwards compatibility} -% -% Earlier releases of \pkg{l3build} required that the last line of -% \texttt{build.lua} ran the main script, \emph{i.e.}~that \texttt{build.lua} -% was what the user called rather than \texttt{l3build.lua}. To allow scripts -% to support both forms \emph{for the transition}, a simple test may be -% included as showing in Figure~\ref{fig:build-compat}. -% \begin{figure} -% \begin{lstlisting}[frame=single,language={[5.2]Lua},gobble = 6] -% if not release_date then -% dofile(kpse.lookup("l3build.lua")) -% end -% \end{lstlisting} -% \caption{Final lines for a \texttt{build.lua} script usable with both older -% and newer releases of \pkg{l3build}.} -% \label{fig:build-compat} -% \end{figure} -% -% Note that in time support for loading \pkg{l3build} by calling the -% \texttt{build.lua} script \emph{may} be removed: the recommended approach for -% new scripts is to run \texttt{l3build}. -% % \subsection{Variables} % % This section lists all variables defined in the |l3build.lua| script that are available for customisation. @@ -696,10 +675,10 @@ % \subsection{Selective running of tests} % % The variables |includetests| and |excludetests| may be used to select which -% tests are run: these variables take test \emph{names} not full file names. +% tests are run: these variables take raw test \emph{names} not full file names. % The list of tests in |excludetests| overrides any matches in |includetests|, % meaning that tests can be disabled selectively. It also makes it possible -% to disable test on for example a platform basis: the Lua core variable +% to disable test on for example a platform basis: the |texlua| specific variable % |os.type| may be used to set |excludetests| only on some systems. % % \subsection{Multiple sets of tests} @@ -741,10 +720,10 @@ % \subsection{Dependencies} % % If you have multiple packages that are developed separately but still interact in some way, it's often desirable to integrate them when performing regression tests. -% For \LaTeX3, for example, when we make changes to \pkg{l3kernel} it's important to check that the tests for \pkg{l3packages} still run correctly, so it's necessary to include the \pkg{l3kernel} files in the build process for \pkg{l3packages}. +% For \LaTeX{}, for example, when we make changes to \pkg{l3kernel} it's important to check that the tests for \pkg{l3packages} still run correctly, so it's necessary to include the \pkg{l3kernel} files in the build process for \pkg{l3packages}. % % In other words, \pkg{l3packages} is \emph{dependent} on \pkg{l3kernel}, and this is specified in \pkg{l3build} by setting appropriately the variables \texttt{checkdeps}, \texttt{typesetdeps}, and \texttt{unpackdeps}. -% The relevant parts of the \LaTeX3 repository is structured as the following. +% The relevant parts of the \LaTeX{} repository is structured as the following. % \Needspace{3\baselineskip} % \begin{Verbatim} % l3/ @@ -763,7 +742,7 @@ % xparse.ins % support/ % \end{Verbatim} -% For \LaTeX3 build files, |maindir| is defined as top level folder |l3|, so all support files are located here, and the build directories will be created there. +% For \LaTeX{} build files, |maindir| is defined as top level folder |l3|, so all support files are located here, and the build directories will be created there. % To set \pkg{l3kernel} as a dependency of \pkg{l3package}, within |l3packages/xparse/build.lua| the equivalent of the following is set: % \begin{Verbatim} % maindir = "../.." @@ -1246,6 +1225,38 @@ % engine-specific, thus one |.tpf| file should be stored per engine to be % tested. % +% \subsection{Custom tests} +% +% If neither the text-based methods nor PDF-based tests are sufficient, +% there is the additional option of defining custom variants with individual +% normalization rules. +% +% For this, the variant has to be registered in the \texttt{test_types} table +% and then activated in \texttt{test_order}. +% +% Every element in \texttt{test_types} is a table with fields \texttt{test} +% (the extension of the test file), \texttt{reference} (the extension of the +% file the output is compared with), \texttt{generated} (extension of the +% analyzed \LaTeX{} output file) and \texttt{rewrite} (A Lua function for +% normalizing the output file, taking as parameters the name of the unnormalized +% \LaTeX{} output file to be read, the name of the normalized file to be written, +% the engine name and a potential errorcode). +% +% For example: +% \begin{verbatim} +% test_types = { +% mytest = { +% test = ".mylvt", +% reference = ".mytlg", +% generated = ".log", +% rewrite = function(source, normalized, engine, errorcode) +% -- In this example we just copy the logfile without any normalization +% os.execute(string.format("cp %s %s", source, normalized) +% end, +% }, +% } +% test_order = {"mylvt", "log", "pdf"} +% \end{verbatim} % % \section{Release-focussed features} % @@ -1294,7 +1305,7 @@ % \label{sec:tagging} % % The |tag| target can automatically edit -% source files to modify date and release tag. As standard, no automatic +% source files to modify date and release tag name. As standard, no automatic % replacement takes place, but setting up a |update_tag()| function % will allow this to happen. This function takes four input arguments: % \begin{enumerate}[nosep] @@ -1334,7 +1345,7 @@ % % To allow more complex tasks to take place, a hook |tag_hook()| is also % available. It will receive the tag name and date as arguments, and -% may be used to carry out arbitrary tasks after the main tagging process. +% may be used to carry out arbitrary tasks after all files have been updated. % For example, this can be used to set a version control tag for an entire repository. % % @@ -1426,7 +1437,7 @@ % % The CTAN upload process is backed by an API, which \pkg{l3build} can use % to send zip files for release. Along with the file, a variety of metadata -% must be specified about the package, including the version, license, and so on. +% must be specified about the package, including the version, license, and so on, explained at \url{https://www.ctan.org/upload}. % A description of this metadata is outlined in Table~\ref{tab:upload-setup}, % and a simple example of an extract from a \texttt{build.lua} file using this is shown % in Figure~\ref{fig:uploadconfig}. @@ -1666,7 +1677,7 @@ % \begin{syntax} % |fileexists(|\meta{file}|)| % \end{syntax} -% Tests if the \meta{file} exists; returns a boolean value. +% Tests if the \meta{file} exists and is readable; returns a boolean value. % \end{function} % % \begin{function}{filelist()} @@ -1882,6 +1893,7 @@ % the |names| as an argument; this allows checking of the |name| data % without impact on the main |func|. % \end{itemize} +% The functions |func|, |bundle_func| and |pre| must return 0 on success. % % \subsection{Customising the manifest file} % \label{sec:manifest} diff --git a/macros/latex/contrib/l3build/l3build.ins b/macros/latex/contrib/l3build/l3build.ins index 483bab9d4a..bdb0fb7a52 100644 --- a/macros/latex/contrib/l3build/l3build.ins +++ b/macros/latex/contrib/l3build/l3build.ins @@ -1,6 +1,6 @@ \iffalse meta-comment -File l3build.ins Copyright (C) 2014-2018 The LaTeX3 Project +File l3build.ins Copyright (C) 2014-2018,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 @@ -32,7 +32,7 @@ license information is placed in the derived files. \preamble -Copyright (C) 2014-2018 The LaTeX3 Project +Copyright (C) 2014-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 diff --git a/macros/latex/contrib/l3build/l3build.lua b/macros/latex/contrib/l3build/l3build.lua old mode 100755 new mode 100644 index e7acd47fb3..0b68ee1617 --- a/macros/latex/contrib/l3build/l3build.lua +++ b/macros/latex/contrib/l3build/l3build.lua @@ -2,7 +2,7 @@ --[[ -File l3build.lua Copyright (C) 2014-2020 The LaTeX3 Project +File l3build.lua Copyright (C) 2014-2020 The LaTeX Project It may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this @@ -25,7 +25,7 @@ for those people who are interested. --]] -- Version information -release_date = "2020-06-04" +release_date = "2021-05-05" -- File operations are aided by the LuaFileSystem module local lfs = require("lfs") @@ -79,18 +79,12 @@ elseif options["target"] == "version" then exit(0) end --- Allow main function to be disabled 'higher up' -main = main or stdmain - --- Load configuration file if running as a script -if match(arg[0], "l3build$") or match(arg[0], "l3build%.lua$") then - -- Look for some configuration details - if fileexists("build.lua") then - dofile("build.lua") - else - print("Error: Cannot find configuration build.lua") - exit(1) - end +-- Look for some configuration details +if fileexists("build.lua") then + dofile("build.lua") +else + print("Error: Cannot find configuration build.lua") + exit(1) end -- Load standard settings for variables: @@ -120,7 +114,7 @@ if options["epoch"] then forcecheckepoch = true forcedocepoch = true end -normalise_epoch() +epoch = normalise_epoch(epoch) -- Sanity check check_engines() @@ -159,7 +153,6 @@ if options["target"] == "check" then print("\n Check failed with difference files") local testdir = testdir if config ~= "build" then - resultdir = resultdir .. "-" .. config testdir = testdir .. "-" .. config end for _,i in ipairs(filelist(testdir,"*" .. os_diffext)) do diff --git a/macros/latex/contrib/l3build/l3build.pdf b/macros/latex/contrib/l3build/l3build.pdf index 958de58c4d..709314feef 100644 Binary files a/macros/latex/contrib/l3build/l3build.pdf and b/macros/latex/contrib/l3build/l3build.pdf differ -- cgit v1.2.3