Skip to content

Commit b0da187

Browse files
authored
[check] Split github action into two stages (source, output) (#4533)
Also improve the visibility of error messages.
1 parent 1f854d8 commit b0da187

File tree

3 files changed

+113
-54
lines changed

3 files changed

+113
-54
lines changed

.github/workflows/check.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ jobs:
1717

1818
steps:
1919
- uses: actions/checkout@v2
20+
- name: check-source
21+
run: ../tools/check-source.sh
2022
- name: install
2123
run: sudo apt-get install latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended lmodern
2224
- name: make
2325
run: make quiet
24-
- name: check
25-
run: ../tools/check.sh
26+
- name: check-output
27+
run: ../tools/check-output.sh

tools/check-output.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/bin/bash
2+
3+
# This script checks the results of the LaTeX run.
4+
5+
failed=0
6+
7+
function fail() {
8+
9+
# echo "::error file=app.js,line=10,col=15::Something went wrong"
10+
11+
! sed 's/^\(.\+\.tex\):/file=\1::/;s/^/::error /' | grep .
12+
}
13+
14+
15+
# Discover "Overfull \[hv]box" and "Reference ... undefined" messages from LaTeX.
16+
sed -n '/\.tex/{s/^.*\/\([-a-z0-9]\+\.tex\).*$/\1/;h};
17+
/Overfull [\\][hv]box\|LaTeX Warning..Reference/{x;p;x;p}' std.log |
18+
sed '/^.\+\.tex$/{N;s/\n/:/}' | fail || failed=1
19+
20+
21+
# Cross references since the previous standard.
22+
function indexentries() { sed 's,\\glossaryentry{\(.*\)@.*,\1,' "$1" | LANG=C sort; }
23+
function removals() { diff -u "$1" "$2" | grep '^-' | grep -v '^---' | sed 's/^-//'; }
24+
function difference() { diff -u "$1" "$2" | grep '^[-+]' | grep -v '^\(---\|+++\)'; }
25+
XREFDELTA="$(difference <(indexentries xrefdelta.glo) <(removals <(indexentries xrefprev) <(indexentries xrefindex.glo)))"
26+
if [ -n "$XREFDELTA" ]; then
27+
echo "incorrect entries in xrefdelta.tex:" >&2
28+
echo "$XREFDELTA" | sed 's,^-,spurious ,; s,^+,missing ,;' >&2
29+
failed=1
30+
fi
31+
32+
exit $failed
Lines changed: 77 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,144 @@
11
#!/bin/bash
22

3+
# This script checks that the LaTeX sources stick to the rules.
4+
5+
failed=0
6+
37
# Ignore files where rules may be violated within macro definitions.
48
texfiles=$(ls *.tex | grep -v macros.tex | grep -v layout.tex | grep -v tables.tex)
59
texlibdesc="support.tex concepts.tex diagnostics.tex utilities.tex strings.tex containers.tex iterators.tex ranges.tex algorithms.tex numerics.tex time.tex locales.tex iostreams.tex regex.tex atomics.tex threads.tex"
610
texlib="lib-intro.tex $texlibdesc"
711

8-
# Discover "Overfull \[hv]box" and "Reference ... undefined" messages from LaTeX.
9-
sed -n '/\.tex/{s/^.*\/\([-a-z0-9]\+\.tex\).*$/\1/;h};
10-
/Overfull [\\][hv]box\|LaTeX Warning..Reference/{x;p;x;p}' std.log |
11-
sed '/^.\+\.tex$/{N;s/\n/:/}' | grep . && exit 1
12+
# Filter that reformats the error message as a "workflow command",
13+
# for native handling by github actions.
14+
# Prefixes each line of input with "$*: ".
15+
function fail() {
16+
# echo "::error file=app.js,line=10,col=15::Something went wrong"
17+
18+
# For some reason, the file/line/col information is not shown in the GUI.
19+
# Make sure to leave it in the message proper.
20+
! sed 's@^\(.\+\.tex\):\([0-9]\+\):@::error file=source/\1,line=\2::\1:\2:'"$*"': @; s@^\([^:][^:]\)@::error ::'"$*"': \1@' |
21+
grep .
22+
}
23+
1224

1325
# Find non-ASCII (Unicode) characters in the source
14-
LC_ALL=C grep -ne '[^ -~ ]' *.tex | sed 's/$/ <--- non-ASCII character/' | grep . && exit 1
26+
LC_ALL=C grep -ne '[^ -~ ]' *.tex |
27+
fail 'non-ASCII character' || failed=1
1528

1629
# Trailing whitespace in a line.
17-
grep -ne '\s$' *.tex | sed 's/$/<--- trailing whitespace/' | grep . && exit 1
30+
grep -ne '\s$' *.tex |
31+
fail 'trailing whitespace' || failed=1
1832

1933
# Trailing empty lines
20-
for f in *.tex; do [ $(tail -c 2 $f | wc -l) -eq 1 ] || (echo "$f has trailing empty lines"; exit 1 ) done
34+
for f in *.tex; do
35+
[ $(tail -c 2 $f | wc -l) -eq 1 ] ||
36+
echo "$f" | fail 'trailing empty lines' || failed=1
37+
done
2138

2239
# indented \begin{codeblock} / \end{codeblock} (causes unwanted empty space)
23-
grep -ne '^.\+\\\(begin\|end\){codeblock}' $texfiles && exit 1
40+
grep -ne '^.\+\\\(begin\|end\){codeblock}' $texfiles |
41+
fail 'indented codeblock env' || failed=1
2442

2543
# \pnum not alone on a line.
26-
grep -ne '^[^%]\+\\pnum' $texfiles && exit 1
27-
grep -ne '\\pnum.\+$' $texfiles && exit 1
44+
grep -ne '^[^%]\+\\pnum' $texfiles |
45+
fail "pnum not alone on line" || failed=1
46+
grep -ne '\\pnum.\+$' $texfiles |
47+
fail "pnum not alone on line" || failed=1
2848
# Fixup: sed '/\\pnum.\+$/s/\\pnum\s*/\\pnum\n/'
2949

3050
# Two consecutive \pnum
3151
for f in $texfiles; do
32-
awk 'prev == $0 && /^\\pnum/ { print FILENAME ":" FNR ": duplicate \\pnum on consecutive lines" } { prev = $0 }' $f
33-
done | grep . && exit 1
52+
awk 'prev == $0 && /^\\pnum/ { print FILENAME ":" FNR ":" } { prev = $0 }' $f
53+
done |
54+
fail 'two consecutive \\pnum' || failed=1
3455

3556
# punctuation after the footnote marker
36-
grep -n "\\end{footnote" $texfiles | grep -v '}[@)%]\?$' && exit 1
57+
grep -n "\\end{footnote" $texfiles | grep -v '}[@)%]\?$' |
58+
fail "punctuation after footnote marker" || failed=1
3759

3860
# \opt used incorrectly.
39-
grep -n '\\opt[^{]' $texfiles && exit 1
40-
grep -n 'opt{}' *.tex && exit 1
61+
grep -n '\\opt[^{]' $texfiles |
62+
fail '\\opt used incorrectly' || failed=1
63+
grep -n 'opt{}' *.tex |
64+
fail '\\opt used incorrectly' || failed=1
4165

4266
# Use \notdef instead of "not defined".
43-
grep -n "// not defined" $texfiles | sed 's/$/ <--- use \\notdef instead/' | grep . && exit 1
67+
grep -n "// not defined" $texfiles |
68+
fail "use \\notdef instead" || failed=1
4469

4570
# Library element introducer followed by stuff.
46-
grep -ne '^\\\(constraints\|mandates\|expects\|effects\|sync\|ensures\|returns\|throws\|complexity\|remarks\|errors\).\+$' $texlibdesc && exit 1
71+
grep -ne '^\\\(constraints\|mandates\|expects\|effects\|sync\|ensures\|returns\|throws\|complexity\|remarks\|errors\).\+$' $texlibdesc |
72+
fail 'stuff after library element' || failed=1
4773
# Fixup: sed 's/^\\\(constraints\|mandates\|expects\|effects\|sync\|ensures\|returns\|throws\|complexity\|remarks\|errors\)\s*\(.\)/\\\1\n\2/'
4874
# Fixup: sed 's/^\\ //'
4975

5076
# Change marker in [diff] followed by stuff.
51-
grep -Hne '^\\\(change\|rationale\|effect\|difficulty\|howwide\)\s.\+$' compatibility.tex && exit 1
77+
grep -Hne '^\\\(change\|rationale\|effect\|difficulty\|howwide\)\s.\+$' compatibility.tex |
78+
fail "change marker in [diff] followed by stuff" || failed=1
5279
# Fixup: sed 's/^\\\(change\|rationale\|effect\|difficulty\|howwide\)\s\(.\)/\\\1\n\2/'q
5380

5481
# "template <class" (with space) in library clause.
55-
grep -ne 'template\s<class' $texlib | sed 's/$/ <--- space between "template" and "<class"/' | grep . && exit 1
82+
grep -ne 'template\s<class' $texlib |
83+
fail 'space between "template" and "<class"' || failed=1
5684

5785
# \begin{example/note} with non-whitespace in front on the same line.
58-
grep -ne '^.*[^ ]\s*\\\(begin\|end\){\(example\|note\)}' $texfiles && exit 1
86+
grep -ne '^.*[^ ]\s*\\\(begin\|end\){\(example\|note\)}' $texfiles |
87+
fail "non-whitespace before note/example begins" || failed=1
5988
# Fixup: sed 's/^\(.*[^ ]\)\s*\(\\\(begin\|end\){\(example\|note\)}\)/\1\n\2/'
6089

6190
# \begin/end{example/note} with stuff (except %) following on the same line.
62-
grep -ne '\\\(begin\|end\){\(example\|note\)}[^%]\+$' $texfiles && exit 1
91+
grep -ne '\\\(begin\|end\){\(example\|note\)}[^%]\+$' $texfiles |
92+
fail "content following note/example env" || failed=1
6393
# Fixup: sed 's/\(\\\(begin\|end\){\(example\|note\)}\)\s*\([^ ].*\)$/\1\n\4/'
6494

6595
# \end{note} or \end{example} at the end of a table cell
6696
grep -n -A1 '\\end{\(example\|note\)}' $texfiles | grep -- '- *\(\\\\\|&\)' |
67-
sed 's/$/ <--- needs tailnote or tailexample/' | grep . && exit 1
97+
fail "needs tailnote or tailexample" || failed=1
6898

6999
# Blank line between "begin example" and "begin codeblock"
70100
for f in $texfiles; do
71101
sed -n '/\\begin{example}/{N;N;/\n\n\\begin{codeblock}$/{=;p}}' $f |
72102
# prefix output with filename and line
73103
sed '/^[0-9]\+$/{N;s/\n/:/}' | sed "s/.*/$f:&/"
74-
done | grep . && exit 1
104+
done |
105+
fail 'blank line between "begin example" and "begin codeblock"' || failed=1
75106
# Fixup: sed '/\\begin{example}/{N;s/\n$//}'
76107

77108
# Comment not aligned to multiple of four. (Ignore lines with "@".)
78109
for f in $texfiles; do
79110
sed -n '/begin{codeblock\(tu\)\?}/,/end{codeblock\(tu\)\?}/{/^[^@]*[^ @][^@]*\/\//{=;p}}' $f |
80111
# prefix output with filename and line
81112
sed '/^[0-9]\+$/{N;s/\n/:/}' | sed "s/.*/$f:&/" |
82-
awk '{ match($0,"^[-a-z0-9]*[.]tex:[0-9]*:"); n=match(substr($0,RLENGTH+1),"[ ;]//"); if (n % 4 != 0) print $0 " <--- comment starts in column " n; }'
83-
done | grep . && exit 1
113+
awk '{ match($0,"^[-a-z0-9]*[.]tex:[0-9]*:"); n=match(substr($0,RLENGTH+1),"[ ;]//"); if (n % 4 != 0) print "comment starts in column " n ": " $0; }'
114+
done |
115+
fail "comment not aligned" || failed=1
84116

85117
# Deleted special member function with a parameter name.
86-
grep -n "&[ 0-9a-z_]\+) = delete" $texfiles && exit 1
118+
grep -n "&[ 0-9a-z_]\+) = delete" $texfiles |
119+
fail 'named parameter in deleted special member' || failed=1
87120
# to fix: sed '/= delete/s/&[ 0-9a-z_]\+)/\&)/'
88121

89122
# Bad characters in label. "-" is allowed due to a single remaining offender.
90-
grep -n '^\\rSec.\[[^]]*[^-a-z.0-9][^]]*\]{' $texfiles | sed 's/$/ <--- bad character in label/' | grep . && exit 1
123+
grep -n '^\\rSec.\[[^]]*[^-a-z.0-9][^]]*\]{' $texfiles |
124+
fail 'bad character in label' || failed=1
91125

92126
# "shall", "may", or "should" inside a note
93127
for f in $texfiles; do
94128
sed -n '/begin{\(note\|footnote\)}/,/end{\(note\|footnote\)}/{/\(shall\|may\|should\)[^a-zA-Z]/{=;p}}' $f |
95129
# prefix output with filename and line
96-
sed '/^[0-9]\+$/{N;s/\n/:/}' | sed "s/.*/$f:&/" |
97-
sed 's/$/ <--- "shall", "should", or "may" inside a note/'
98-
done | grep . && exit 1
130+
sed '/^[0-9]\+$/{N;s/\n/:/}' | sed "s/.*/$f:&/"
131+
done |
132+
fail '"shall", "should", or "may" inside a note' || failed=1
99133

100134
# Hanging paragraphs
101135
for f in $texfiles; do
102136
sed -n '/^\\rSec/{=;p};/^\\pnum/{s/^.*$/x/;=;p}' $f |
103137
# prefix output with filename and line
104138
sed '/^[0-9]\+$/{N;s/\n/:/}' | sed "s/.*/$f:&/" |
105139
awk -F: 'BEGIN { prevlevel = 0 } $3 ~ /^\\rSec./ { match($3, "[0-9]"); level=substr($3, RSTART, 1); if (text && level > prevlevel) { print prevsec " <-- Hanging paragraph follows" } prevlevel = level; prevsec = $3; text = 0 } $3 == "x" { text = 1 }'
106-
done | grep . && exit 1
140+
done |
141+
fail 'hanging paragraph' || failed=1
107142

108143
# Subclauses without siblings
109144
for f in $texfiles; do
@@ -114,29 +149,30 @@ for f in $texfiles; do
114149
{
115150
match($3, "[0-9]");
116151
level = substr($3, RSTART, 1);
117-
if (level < prevlevel && secs[prevlevel] == 1) { print title[prevlevel] " <-- Subclause without siblings" }
152+
if (level < prevlevel && secs[prevlevel] == 1) { print title[prevlevel] }
118153
++secs[level];
119154
title[level] = $0;
120155
secs[level + 1] = 0;
121156
prevlevel = level;
122157
}'
123-
done | grep . && exit 1
158+
done | fail 'subclause without siblings' || failed=1
124159

125160

126161
# Library descriptive macros not immediately preceded by \pnum.
127162
for f in $texlibdesc; do
128163
sed -n '/^\\pnum/{h;:x;n;/^\\index/b x;/^\\\(constraints\|mandates\|expects\|effects\|sync\|ensures\|returns\|throws\|complexity\|remarks\|errors\)/{x;/\n/{x;=;p};d};/^\\pnum/D;H;b x}' $f |
129164
# prefix output with filename and line
130-
sed '/^[0-9]\+$/{N;s/\n/:/}' | sed "s/.*/$f:&/" |
131-
sed 's/$/ <--- \\pnum missing/'
132-
done | grep . && exit 1
165+
sed '/^[0-9]\+$/{N;s/\n/:/}' | sed "s/.*/$f:&/"
166+
done |
167+
fail '\\pnum missing' || failed=1
133168

134169
# Cross-references pointing to their own section.
135170
for f in $texfiles; do
136171
sed -n '/^\\rSec/{s/^.rSec.\[/S /;s/\].*$//;=;p};/\\iref{/{s/^.*\\.\?ref{\([-a-z.0-9]\+\)}.*/R \1/g;=;p}' $f |
137172
sed '/^[0-9]\+$/{N;s/\n/: /}' | sed "s/.*/$f:&/" |
138173
awk '$2 == "S" { seclabel = $3 } $2 == "R" && $3 == seclabel { print $1 " section self-reference to [" $3 "]" }'
139-
done | grep . && exit 1
174+
done |
175+
fail "cross-reference to its own section" || failed=1
140176

141177
# \placeholder before (
142178
#egrep 'placeholder{[-A-Za-z]*}@?\(' *.tex
@@ -155,20 +191,9 @@ done | grep . && exit 1
155191
# different files anyway. So just check the timestamp.
156192
for f in *.dot; do
157193
if [ "$f" -nt "${f%.dot}.pdf" ]; then
158-
echo -e "need to rebuild ${f%.dot}.pdf:\nmake clean-figures && make figures" >&2
159-
exit 1
194+
echo -e "need to rebuild ${f%.dot}.pdf:\nmake clean-figures && make figures"
160195
fi
161-
done
196+
done |
197+
fail 'outdated figure' || failed=1
162198

163-
# Cross references since the previous standard.
164-
function indexentries() { sed 's,\\glossaryentry{\(.*\)@.*,\1,' "$1" | LANG=C sort; }
165-
function removals() { diff -u "$1" "$2" | grep '^-' | grep -v '^---' | sed 's/^-//'; }
166-
function difference() { diff -u "$1" "$2" | grep '^[-+]' | grep -v '^\(---\|+++\)'; }
167-
XREFDELTA="$(difference <(indexentries xrefdelta.glo) <(removals <(indexentries xrefprev) <(indexentries xrefindex.glo)))"
168-
if [ -n "$XREFDELTA" ]; then
169-
echo "incorrect entries in xrefdelta.tex:" >&2
170-
echo "$XREFDELTA" | sed 's,^-,spurious ,; s,^+,missing ,;' >&2
171-
exit 1
172-
fi
173-
174-
exit 0
199+
exit $failed

0 commit comments

Comments
 (0)