From 8ce78d83b8a16118e81ff2d800ebaa09108688bd Mon Sep 17 00:00:00 2001 From: LogCreative Date: Sat, 27 Aug 2022 01:35:54 +0800 Subject: [PATCH] ci: add l3build commands for caching unit tests (#117) --- src/build.lua | 172 +++++++++++++++++++++++++++++---- src/doc/sjtubeamer.tex | 40 ++++---- src/doc/sjtubeamerdevguide.tex | 48 +++++++-- src/support/step.template.tex | 12 +++ 4 files changed, 225 insertions(+), 47 deletions(-) create mode 100644 src/support/step.template.tex diff --git a/src/build.lua b/src/build.lua index 202937eb..927ef2af 100644 --- a/src/build.lua +++ b/src/build.lua @@ -6,7 +6,12 @@ sourcefiledir = "source" sourcefiles = {"*.ins","*.dtx","vi/"} installfiles = {"*.sty","vi/"} -docfiledir = "doc" +maindir = "." +docfiledir = maindir .. "/doc" +supportdir = maindir .. "/support" + +builddir = maindir .. "/build" +typesetdir = builddir .. "/doc" if os.type == "windows" then typesetexe = "pdflatex" @@ -83,12 +88,6 @@ function compile_file(dir, cmd, filename) return errorlevel end - --- NOTICE: if you want to save the tourial step pdf, --- please uncomment the following line. - --- cachedemo = true -- cache the demo - -- Generate tutorial files before compiling the doc. function typeset_demo_tasks() local errorlevel = 0 @@ -96,7 +95,7 @@ function typeset_demo_tasks() print("============================================================") print("If you want to save the previous demo files") - print("Please modify the cachedemo variable in build.lua file.") + print("Use \"l3build cache-demo\" command (" .. module .. ")") print("============================================================") print("Compiling precompiled header...") @@ -115,12 +114,6 @@ function typeset_demo_tasks() cp(file, unpackdir, tutorialdir) end local typesetcommand = typesetexe .. " " .. typesetopts -- patch l3build - local cachedemo = cachedemo or false - if not cachedemo then - -- delete the cache - rm(tutorialdir, "step*.pdf") - rm(supportdir .. "/tutorial", "step*.pdf") - end for _, p in ipairs(filelist(tutorialdir, "step*.tex")) do local pdffilename = string.gsub(p,".tex",".pdf") if p == "step0.tex" then @@ -145,7 +138,7 @@ function typeset_demo_tasks() errorlevel = compile_file(tutorialdir, typesetcommand, cachedfilename) if errorlevel ~= 0 then - print(pdffilename .. " compilation failed.") + print("!" .. pdffilename .. " compilation failed.") return errorlevel end errorlevel = ren(tutorialdir, "tmp" .. pdffilename, pdffilename) @@ -153,16 +146,12 @@ function typeset_demo_tasks() -- fallback to standard compilation. errorlevel = compile_file(tutorialdir, typesetcommand, p) if errorlevel ~= 0 then - print(pdffilename .. " compilation failed.") + print("! " .. pdffilename .. " compilation failed.") return errorlevel end end - if cachedemo then - -- cache the demo - cp(pdffilename, tutorialdir, supportdir .. "/tutorial") - end else - print(pdffilename .. " exists.") + print("Reuse: " .. pdffilename) end end end @@ -304,4 +293,145 @@ function checkinit_hook() end return 0 +end + +-- usage: l3build cache-demo +-- description: cache the demo pdf files after l3build doc. +if options["target"] == "cache-demo" then + print("Use this command after l3build doc.") + print("Use l3build clean-demo to clean the cache. (" .. module ..")") + + local function cachedemo() + local tutorialdir = typesetdir .. "/tutorial" + local targetdir = supportdir .. "/tutorial" + print("Demo files in " .. tutorialdir .. " will be cached to " .. targetdir) + local cachedcnt = 0 + local totalcnt = 0 + -- Cache the pdf corresponding to the tex file + for _, p in ipairs(filelist(tutorialdir, "step*.tex")) do + local pdffilename = string.gsub(p,".tex",".pdf") + totalcnt = totalcnt + 1 + if fileexists(tutorialdir .. "/" .. pdffilename) then + -- Move the pdf to the support dir + cp(pdffilename, tutorialdir, targetdir) + print("Cached: " .. pdffilename) + cachedcnt = cachedcnt + 1 + else + print("NO: " .. pdffilename) + end + end + print("Cached/Total: " .. cachedcnt .. "/" .. totalcnt) + end + + cachedemo() + os.exit(0) +end + +-- usage: l3build clean-demo +-- description: clean the cached demo pdf files from l3build cache-demo. +if options["target"] == "clean-demo" then + + local function cleandemo() + local tutorialdir = typesetdir .. "/tutorial" + print("Clean the cached demo in " .. tutorialdir .. ". (" .. module .. ")") + local cleancnt = 0 + for _, p in ipairs(filelist(tutorialdir, "step*.pdf")) do + -- Remove the pdf in the build dir and the support dir. + rm(tutorialdir, p) + rm(supportdir .. "/tutorial", p) + cleancnt = cleancnt + 1 + print("Clean: " .. p) + end + print("Clean: " .. cleancnt) + end + + cleandemo() + os.exit(0) +end + +-- usage: l3build add-demo [demonum] +-- description: add step[demonum].tex to the tutorial directory. +if options["target"] == "add-demo" then + if options["names"] == nil or #options["names"] > 1 then + print("Error: Please specify one and only one demo number. (" .. module .. ")") + os.exit(1) + end + + -- The added demo number. + local demonum = tonumber(options["names"][1]) + if demonum == nil then + print("Error: \"" .. options["names"][1] .. "\" is not a valid number.") + os.exit(1) + end + + local function adddemo(demonum) + local tutorialsuppdir = supportdir .. "/tutorial" + print("Add step" .. options["names"][1] .. ".tex to " .. tutorialsuppdir .. ". (" .. module .. ")") + + -- Record the demo number which is not less than the added number + local actionlist = {} + local renflag = false + for _, p in ipairs(filelist(tutorialsuppdir, "step*.tex")) do + local curdemoid = string.sub(p, 5, -5) + local curdemonum = tonumber(string.gmatch(curdemoid, "%d+")()) + if curdemonum ~= nil then -- exclude something like "stepalgo.tex" + if curdemonum >= demonum then + table.insert(actionlist, {curdemonum, curdemoid}) + end + if curdemonum == demonum then + renflag = true + end + end + end + + -- If the target added demo file exists, + -- The demo with larger demo number will be renamed in an descending order. Like a "refactor" action. + if renflag then + table.sort(actionlist, function(i,j) + if i[1] > j[1] then + return true + end + if i[1] == j[1] then + return #i[2] > #j[2] -- the longer one should be first replaced. + end + return false + end) + for _, num in ipairs(actionlist) do + local oldid = num[2] + local num = num[1] + local oldcachepdf = "step" .. oldid .. ".pdf" + if fileexists(tutorialsuppdir .. "/" .. oldcachepdf) then + rm(tutorialsuppdir, oldcachepdf) + print(oldcachepdf .. " cache is deleted.") + end + local newid = string.gsub(oldid, num, num + 1) + ren(tutorialsuppdir, "step" .. oldid .. ".tex", "step" .. newid .. ".tex") + + -- modify the number in sjtubeamer.tex + local usrdoc = docfiledir .. "/sjtubeamer.tex" + local usrdocfile = io.open(usrdoc, 'r') + local usrdoccontent = usrdocfile:read("a") + usrdocfile:close() + local cnt + usrdoccontent, cnt = string.gsub(usrdoccontent, "step" .. string.gsub(string.gsub(oldid,"%+","%%+"),"%-","%%-") .. "%.", "step" .. newid .. ".") -- avoid the magical character insertion + local usrdocfile = io.open(usrdoc, "w+") + usrdocfile:write(usrdoccontent) + usrdocfile:close() + + print("step" .. oldid .. " -> " .. "step" .. newid .. " Doc replaced: " .. cnt) + end + end + + -- The new demo file will be created. + local newdemofilename = "step" .. demonum .. ".tex" + cp("step.template.tex", supportdir, tutorialsuppdir) + ren(tutorialsuppdir, "step.template.tex", newdemofilename) + print("Create: " .. tutorialsuppdir .. "/" .. newdemofilename .. ", Edit your new demo there.") + print("You could rename the demo file for different compilation processes:") + print(" +: add 1 more (xe)latex compilation;\n -: add 1 more biber;\n _: add 1 more bibtex") + + end + + adddemo(demonum) + os.exit(0) end \ No newline at end of file diff --git a/src/doc/sjtubeamer.tex b/src/doc/sjtubeamer.tex index 5a2da31a..a2b5eb54 100644 --- a/src/doc/sjtubeamer.tex +++ b/src/doc/sjtubeamer.tex @@ -115,7 +115,7 @@ left=0pt,right=0pt,top=0pt,bottom=0pt,boxsep=0pt,boxrule=0.6pt, toptitle=1mm,bottomtitle=1mm,drop lifted shadow,center title, graphics pages={#1}] - \tcbincludepdf{tutorial/#3.pdf} + \tcbincludepdf{tutorial/#3} \end{tcbraster} }{} @@ -189,7 +189,7 @@ \section{测试模板} 下面的代码可以用于测试 \themename{} 是否可以正常使用。 -\beamerdemo[1]{step1} +\beamerdemo[1]{step1.tex} \begin{commentlist} @@ -209,13 +209,13 @@ \chapter{样式} \noindent{\ttfamily\hfil\hspace*{-.5cm} + maxplus \hfil\hfil\hspace*{-.5cm} + max \hfil\hfil + min \hfil}\par \vspace*{-.2cm} -\begin{beamerdemoraster}[1,3,5,2,4,6]{red}{step2tb} +\begin{beamerdemoraster}[1,3,5,2,4,6]{red}{step2tb.pdf} \end{beamerdemoraster} -\begin{beamerdemoraster}[1,2,3]{blue}{step2bd}\marginpar{\ttfamily\raisebox{1.8cm}{+ blue}}\marginpar{\ttfamily\raisebox{-1.8cm}{+ light}} +\begin{beamerdemoraster}[1,2,3]{blue}{step2bd.pdf}\marginpar{\ttfamily\raisebox{1.8cm}{+ blue}}\marginpar{\ttfamily\raisebox{-1.8cm}{+ light}} \end{beamerdemoraster} \vspace*{-.2cm} -\begin{beamerdemoraster}[1,2,3]{blue}{step2bl} +\begin{beamerdemoraster}[1,2,3]{blue}{step2bl.pdf} \end{beamerdemoraster} \clearpage @@ -229,29 +229,29 @@ \chapter{样式} bottom=0pt,boxsep=0pt,boxrule=0.6pt, toptitle=1mm,bottomtitle=1mm,drop lifted shadow, center title,fonttitle=\ttfamily] - {tutorial/step2#1.pdf} + {tutorial/#1} } \begin{tcbitemize}[raster columns=3, raster equal height, left=0pt,right=0pt,top=0pt, bottom=0pt,boxsep=0pt,boxrule=0pt] - \tcbitem \myincludepdf{miniframes} - \tcbitem \myincludepdf{default} - \tcbitem \myincludepdf{infolines} - \tcbitem \myincludepdf{smoothbars} - \tcbitem \myincludepdf{sidebar} - \tcbitem \myincludepdf{split} - \tcbitem \myincludepdf{shadow} - \tcbitem \myincludepdf{tree} - \tcbitem \myincludepdf{smoothtree} + \tcbitem \myincludepdf{step2miniframes.pdf} + \tcbitem \myincludepdf{step2default.pdf} + \tcbitem \myincludepdf{step2infolines.pdf} + \tcbitem \myincludepdf{step2smoothbars.pdf} + \tcbitem \myincludepdf{step2sidebar.pdf} + \tcbitem \myincludepdf{step2split.pdf} + \tcbitem \myincludepdf{step2shadow.pdf} + \tcbitem \myincludepdf{step2tree.pdf} + \tcbitem \myincludepdf{step2smoothtree.pdf} \end{tcbitemize} -\beamerdemo[1]{step2} +\beamerdemo[1]{step2.tex} \chapter{草稿} 在确定版式后,下一步就要输入文字填入内容了。由于 \LaTeX{} 的编译速度较慢,在打草稿的时候,我们推荐开启 \cls{beamer} 文档类的 \opt{draft} 模式,只关注于内容。在这种模式下,图片都不会被载入,而是使用一个占位符代替。 -\beamerdemo[1]{step3} +\beamerdemo[1]{step3.tex} \begin{commentlist} \item 使用 \env{columns} 环境分栏,也可以采用 \pkg{multicol} 宏包提供的 \env{multicols} 环境。后者还兼容 \cls{article} 文档类。 @@ -262,13 +262,13 @@ \chapter{草稿} 当然,如果演示文稿的内容过长的话,推荐分成许多个文件编写。最后通过一个主文件拼接起来。如果暂时想专心编写某一部分的内容,可以直接注释掉其他部分的入口。 -\beamerdemo[1]{step4} +\beamerdemo[1]{step4.tex} \chapter{封面} 当内容完成之后,就可以制作封面和封底了。在此之前需要先填写该文档的元数据信息:标题、副标题、作者、组织、日期。 -\beamerdemo[1,2]{step5} +\beamerdemo[1,2]{step5.tex} \begin{commentlist} \item 在载入模板时选择 \opt{maxplus}, \opt{max}, \opt{min} 以使用不同的标题页结尾页模板。 @@ -292,7 +292,7 @@ \section{节次提示} 而新式的方法是使用 \themename{} 优化后的节次页。现在节次页也会随主题的不同而有不同的样式。节次页的编号支持在加载主题之后使用 \cmd{ctexset} 来更改格式,详见 \href{https://mirrors.sjtug.sjtu.edu.cn/CTAN/language/chinese/ctex/ctex.pdf#7}{\CTeX{} 宏集手册}。 -\begin{beamerdemoraster}[1,2,3]{red}{step7s} +\begin{beamerdemoraster}[1,2,3]{red}{step7s.pdf} \end{beamerdemoraster} \beamerdemo[4]{step7+.tex} diff --git a/src/doc/sjtubeamerdevguide.tex b/src/doc/sjtubeamerdevguide.tex index 6b375d63..f892a51d 100644 --- a/src/doc/sjtubeamerdevguide.tex +++ b/src/doc/sjtubeamerdevguide.tex @@ -133,6 +133,8 @@ \subsection{l3build}\label{sec:l3build} \end{verbatim} You could operate the package by the following command. The build script is set in \verb"build.lua". +\subsubsection{Built-In Commands}\label{sec:builtincmd} + \fcmd{l3build install} This command will install current version from \verb"source" to your \TeX{} distribution. Remember to update the \verb"l3build" to the latest version to avoid misbehaving. This command requires an argument \verb"--texmfhome" option to specify the install path, which could be obtained from Mik\TeX{} Console or the \verb"tlmgr". Then, refresh the database of filenames in your TeX{} distribution. This command is useful if you want this template to be globally available for all documents on your computer. \fcmd{l3build unpack} This command will unpack the source code and create a sandbox environment in \verb"build/local". You can create your own test file to test certain features here. It is the most common command for testing a certain feature. @@ -150,9 +152,9 @@ \subsection{l3build}\label{sec:l3build} % \begin{center} % unpack $\rightarrow$ \verb"min.tex" $\rightarrow$ documentations % \end{center} -Since the doc has a lot of dependencies (or unit tests), you can cache the demo files to \verb"support/tutorial" directory. -Change the variable in \verb"build.lua": \verb"cachedemo=true" to cache the demo automatically, and remove the variable to clean the cached files. -We highly recommend that using *nix to compile the doc. +Since the doc has a lot of dependencies (or unit tests), you can cache the demo files to \verb"support/tutorial" directory. This could be done by the exclusive \verb"l3build cache-demo" in Section \ref{sec:exclcmd}. +% Change the variable in \verb"build.lua": \verb"cachedemo=true" to cache the demo automatically, and remove the variable to clean the cached files. +% We highly recommend that using *nix to compile the doc. \fcmd{l3build save color} If you make some modification to the framework (except \verb"sjtucover") and change the result. To save the current result as a reference, run this command and \verb"color" could be exchanged by any of the test units above. @@ -167,6 +169,28 @@ \subsection{l3build}\label{sec:l3build} texdoc l3build \end{verbatim} +\subsubsection{Exclusive Commands}\label{sec:exclcmd} + +We add a couple of exclusive commands to \verb"l3build" for a better development experience. These commands are not available in other projects. + +\fcmd{l3build cache-demo} This could be used after \texttt{l3build doc} mentioned in Section \ref{sec:builtincmd} to cache the generated pdf files that starts with \verb"step". After this command, these pdf's will be copied to \verb"support/tutorial" directory and will be futher reused in the next epoch of \verb"l3build doc". To clean the cached demo pdf's, use \texttt{l3build clean-demo}. + +\fcmd{l3build clean-demo} This command will clean the pdf files cached by \texttt{l3build cache-demo}. It is also recommended to clean all the cached files before \texttt{l3build add-demo [demonum]}. + +\fcmd{l3build add-demo 20} This command will add a new demo file \texttt{step20.tex} in \texttt{support/tutorial} folder. If the new filename has been occupied, all the demo files with larger number will be renamed (the number will be incremented in an descending demo number order) to leave the place for the new file. Notably, the number in the user documentation \texttt{doc/sjtubeamer.tex} will also be changed. If the corresponding pdf's are cached, they will get deleted since they are outdated. You need to insert the description of the new demo in the user documentation later in an appropriate position. + +The file will be generated based on the template \verb"support/step.template.tex". You could change the demo filename to add compilation steps in the future \verb"l3build doc" generations. For example, \verb"step20+.tex" will add another \LaTeX{}\footnote{To decrease the time of compilation, the documentaion will be compiled in \hologo{pdfLaTeX} on Windows and \hologo{XeLaTeX} on Linux and MacOS. For more pre-compilation techniques that we used in \themename{}, see Section \ref{sec:precompilation}.} compilation round. + +\begin{table}[h] + \begin{tabular}{cl} + Symbol & Description \\ + \verb"+" & add another \LaTeX{} round. \\ + \multicolumn{2}{c}{\small{\itshape (The following symbols need a premised \texttt{+})}} \\ + \verb"-" & add biber compilation before the next \LaTeX{} round. \\ + \verb"_" & add \textsc{Bib}\TeX{} compilation before the next \LaTeX{} round. + \end{tabular} +\end{table} + \subsection{Customize Generation}\label{sec:precompile} In \verb"source/beamerthemesjtubeamer.ins", you could customize what templates you want to output on the line: @@ -214,8 +238,6 @@ \subsection{Check Integration} You could download \href{https://mirrors.sjtug.sjtu.edu.cn/ctan/support/latexindent.zip}{\ttfamily latexindent} and link the executable path \verb"latex-workshop.latexindent.path" in Visual Studio Code. \end{warn} -\clearpage - \section{Coding Style} This section gives a contribution code on coding style. Every contributor should follow this coding style if you want to make a pull request to this project. And following the coding style strictly will make the Doc\TeX{} compiler for Visual Studio Code snippets run properly. @@ -415,6 +437,20 @@ \subsubsection{Macrocode} ... % \end{macrocode}\end{lstlisting} +\subsubsection{An Example} + +Notably, the contents before the \emph{first} \verb"macrocode" environment in \verb"macro" environment will be treated as the description of this macro. When generating the Visual Studio Code snippets, the description will be shown. The searching on the command in \verb"macrocode" environments will decide the parameter number and the default parameter in the code snipptes as well. If you want to add some notes to this macro, add them before the end of the \verb"macro" environment. You could use multiple \verb"macrocode" environments in order to add comments between the code lines. + +\begin{lstlisting}[showspaces=true] +% \begin{macro}{\foobar} +% +% \begin{macrocode} + +% \end{macrocode} +% +% \end{macro} +\end{lstlisting} + \section{Framework}\label{sec:framework} \themename\ is a modular presentation framework. @@ -663,7 +699,7 @@ \subsection{Old \TeX\ Distribution} Test & $\surd$ & $\surd$ & $\surd$ & $\surd$ & $\circ$ & $\circ$ & $\circ$ & $\circ$ & \\ \end{tabular} -\subsection{Pre-Compilation} +\subsection{Pre-Compilation}\label{sec:precompilation} \themename\ is relatively a large project for developers. To boost up the compilation on 20+ unit tests, we introduced \texttt{mylatexformat} to cache the precompiled common header. However, this method comes with compatibility issues in that it only supports old packages \emph{without} using \texttt{fontspec} to load OpenType fonts. diff --git a/src/support/step.template.tex b/src/support/step.template.tex new file mode 100644 index 00000000..f81abc4e --- /dev/null +++ b/src/support/step.template.tex @@ -0,0 +1,12 @@ +\documentclass{ctexbeamer} +\usetheme[]{sjtubeamer} + +% preamble... + +\begin{document} +\begin{frame} + + % content ... + +\end{frame} +\end{document} \ No newline at end of file