OILS / regtest / aports-html.sh View on Github | oils.pub

902 lines, 393 significant
1#!/usr/bin/env bash
2#
3# Make HTML reports
4#
5# Usage:
6# regtest/aports-html.sh <function name>
7#
8# Examples:
9# $0 sync-results he.oils.pub
10# $0 write-all-reports
11# $0 make-wwz _tmp/aports-report/2025-08-03
12# $0 deploy-wwz-op _tmp/aports-report/2025-08-03.wwz # deploy to op.oils.pub
13
14: ${LIB_OSH=stdlib/osh}
15source $LIB_OSH/bash-strict.sh
16source $LIB_OSH/task-five.sh
17
18source regtest/aports-common.sh
19
20REPO_ROOT=$(cd "$(dirname $0)/.."; pwd)
21source test/tsv-lib.sh # tsv2html3
22source web/table/html.sh # table-sort-{begin,end}
23source benchmarks/common.sh # cmark
24source build/dev-shell.sh # python2
25
26sqlite-tabs-headers() {
27 sqlite3 \
28 -cmd '.mode tabs' \
29 -cmd '.headers on' \
30 "$@"
31}
32
33html-head() {
34 # python3 because we're outside containers
35 PYTHONPATH=. python3 doctools/html_head.py "$@"
36}
37
38index-html() {
39 local base_url='../../../../web'
40 html-head --title "aports Build" \
41 "$base_url/base.css"
42
43 cmark <<'EOF'
44<body class="width35">
45
46<p id="home-link">
47 <a href="/">Home</a>
48</p>
49
50# aports Build
51
52Configurations:
53
54- [baseline](baseline/packages.html) - [raw tasks](baseline/tasks.html) - [metrics](baseline/metrics.txt)
55- [osh-as-sh](osh-as-sh/packages.html) - [raw tasks](osh-as-sh/tasks.html) - [metrics](osh-as-sh/metrics.txt)
56
57## Baseline versus osh-as-sh
58
59- [diff_baseline](diff_baseline.html)
60
61## osh-as-sh versus osh-as-bash
62
63TODO
64
65</body>
66EOF
67}
68
69diff-summary-html() {
70 local db=${1:-_tmp/aports-report/2025-08-03/diff_merged.db}
71
72 sqlite3 $db < regtest/aports/summary.sql
73
74 echo '
75 <p></p>
76
77 <div class="side-by-side">
78 <section>
79 <h3>Task Summary</h3>
80 '
81 sqlite3 $db < regtest/aports/summary2.sql
82
83 cmark << 'EOF'
84</section>
85
86<section>
87
88### Common Causes of Disagreements
89EOF
90
91 tsv2html3 $base_dir/cause_hist.tsv
92
93 sqlite3 $db << 'EOF'
94select
95 printf(
96 '<p>Unique causes: %d </p>',
97 count(distinct cause)
98 )
99from notable_disagree
100where cause != 'unknown';
101EOF
102
103 cmark <<'EOF'
104Source: [regtest/aports/cause.awk](https://github.com/oils-for-unix/oils/blob/master/regtest/aports/cause.awk)
105EOF
106
107 echo '
108 </section>
109 </div> <!-- side-by-side -->
110 '
111}
112
113table-page-html() {
114 local base_dir=${1:-$REPORT_DIR/$EPOCH}
115 local name=${2:-diff_baseline}
116 local base_url=${3:-'../../../../web'}
117 local title=${4:-'OSH Disagreements - regtest/aports'}
118
119 html-head --title "$title" \
120 "$base_url/ajax.js" \
121 "$base_url/table/table-sort.js" \
122 "$base_url/table/table-sort.css" \
123 "$base_url/base.css"
124
125 table-sort-begin 'width60'
126
127 cmark <<EOF
128<p id="home-link">
129 <a href="../index.html">Up</a> |
130 <a href="/">Home</a>
131</p>
132
133# $title
134
135EOF
136
137 tsv2html3 $base_dir/$name.tsv
138
139 cmark <<EOF
140
141[$name.tsv]($name.tsv)
142EOF
143
144 table-sort-end "$name" # ID for sorting
145}
146
147merge-diff-html() {
148 local base_dir=${1:-$REPORT_DIR/$EPOCH}
149 local base_url=${2:-'../../../../web'}
150 local title=${3:-'OSH Disagreements - regtest/aports'}
151
152 html-head --title "$title" \
153 "$base_url/ajax.js" \
154 "$base_url/table/table-sort.js" \
155 "$base_url/table/table-sort.css" \
156 "$base_url/base.css"
157
158 table-sort-begin 'width60' # <body> <p>
159
160 # Put two parts side-by-side with flexbox
161 echo '
162 <style>
163 .side-by-side {
164 display: flex;
165 gap: 1em;
166
167 padding-left: 1em;
168 padding-right: 1em;
169 background-color: #eee;
170 }
171
172 .side-by-side section {
173 flex: 1;
174 }
175 </style>
176 '
177
178 cmark <<EOF
179<p id="home-link">
180 <a href="../index.html">Up</a> |
181 <a href="/">Home</a>
182</p>
183
184# $title
185
186EOF
187
188 diff-summary-html $base_dir/diff_merged.db
189
190 # TODO:
191 # - separate fetch-failed causes
192 # - separate OSH timeouts from other timeouts -- in case OSH being slow is a root cause
193 # - show the number of table rows above each section
194 # - make a unified table of all packages and times
195 # - this might come after removing shards?
196
197 cmark << 'EOF'
198[tree](tree.html) &nbsp;&nbsp; [metrics](metrics.html) &nbsp;&nbsp; [disagree-packages.txt](disagree-packages.txt)
199
200## Notable OSH Disagreements
201
202<div style="color: #666;">
203
204(Hint: **click** on the cause column header to sort)
205
206</div>
207
208EOF
209
210 local name=notable_disagree
211 tsv2html3 $base_dir/$name.tsv
212
213 cmark <<EOF
214[$name.tsv]($name.tsv)
215
216## All Disagreements with Timeout
217EOF
218
219 local name=timeout_disagree
220 tsv2html3 $base_dir/$name.tsv
221
222 cmark <<EOF
223[$name.tsv]($name.tsv)
224
225## Baseline-Only Failures
226EOF
227
228 name=baseline_only
229 table-sort-begin 'width60'
230 tsv2html3 $base_dir/$name.tsv
231
232 cmark <<EOF
233
234[$name.tsv]($name.tsv)
235
236## Both Timed Out
237EOF
238
239 name=both_timeout
240 table-sort-begin 'width60'
241 tsv2html3 $base_dir/$name.tsv
242
243 cmark <<EOF
244
245[$name.tsv]($name.tsv)
246
247## Both Failed
248EOF
249
250 name=both_fail
251 table-sort-begin 'width60'
252 tsv2html3 $base_dir/$name.tsv
253
254 cmark <<EOF
255[$name.tsv]($name.tsv)
256
257EOF
258
259 # Sort these tables
260 table-sort-end-many \
261 notable_disagree timeout_disagree baseline_only both_fail both_timeout
262}
263
264tasks-html() {
265 local tsv=$1
266 # note: escaping problems with title
267 # it gets interpolated into markdown and html
268 local title=$2
269
270 local base_url='../../../../../web'
271 html-head --title "$title" \
272 "$base_url/ajax.js" \
273 "$base_url/table/table-sort.js" \
274 "$base_url/table/table-sort.css" \
275 "$base_url/base.css"
276
277 table-sort-begin 'width60'
278
279 cmark <<EOF
280<p id="home-link">
281 <a href="../index.html">Up</a> |
282 <a href="/">Home</a>
283</p>
284
285# $title
286EOF
287
288 tsv2html3 $tsv
289
290 local id=$(basename $tsv .tsv)
291 cmark <<EOF
292
293[$id.tsv]($id.tsv)
294EOF
295
296 table-sort-end "$id" # ID for sorting
297}
298
299published-html() {
300 local base_url='../../web'
301
302 local title='regtest/aports'
303
304 html-head --title "$title" \
305 "$base_url/base.css"
306
307 echo '
308 <body class="width35">
309 <style>
310 code { color: green; }
311 </style>
312
313 <p id="home-link">
314 <a href="/">Home</a> |
315 <a href="https://oils.pub/">oils.pub</a>
316 </p>
317 '
318
319 { echo "## $title"
320 echo '
321Testing OSH on decades worth of shell scripts. [Source code](https://github.com/oils-for-unix/oils/tree/master/regtest).
322
323The `aports/main` repo has 1595 `APKBUILD` files, and `aports/community` has
3247168. A disagreement is when the package succeeds normally, but fails when
325`osh` becomes the system shell. Caveats: timeouts and flakiness.
326
327### main
328
329- [2025-08-07-fix](2025-08-07-fix.wwz/_tmp/aports-report/2025-08-07-fix/diff_merged.html) - **131** disagreements
330- [2025-08-14-fix](2025-08-14-fix.wwz/_tmp/aports-report/2025-08-14-fix/diff_merged.html)
331- [2025-08-26-ifs](2025-08-26-ifs.wwz/_tmp/aports-report/2025-08-26-ifs/diff_merged.html) - **62** after `IFS` fix
332 - new causes: [2025-09-06-edit](2025-09-06-edit.wwz/_tmp/aports-report/2025-09-06-edit/diff_merged.html)
333- [2025-09-07](2025-09-07.wwz/_tmp/aports-report/2025-09-07/diff_merged.html)
334- [2025-09-08](2025-09-08.wwz/_tmp/aports-report/2025-09-08/diff_merged.html)
335 - [2025-09-08-edit](2025-09-08-edit.wwz/_tmp/aports-report/2025-09-08-edit/diff_merged.html)
336 - [2025-09-08-notable](2025-09-08-notable.wwz/_tmp/aports-report/2025-09-08-notable/diff_merged.html)
337- [2025-09-10-overlayfs](2025-09-10-overlayfs.wwz/_tmp/aports-report/2025-09-10-overlayfs/diff_merged.html)
338- [2025-09-11-match](2025-09-11-match.wwz/_tmp/aports-report/2025-09-11-match/diff_merged.html)
339- [2025-09-15-order](2025-09-15-order.wwz/_tmp/aports-report/2025-09-15-order/diff_merged.html) - **32** disagreements with `osh` as `/bin/sh`
340
341After this success, we expanded our testing:
342
343- [2025-09-17-ash2](2025-09-17-ash2.wwz/_tmp/aports-report/2025-09-17-ash2/diff_merged.html) - **37**, after adding `osh` as `/bin/ash`
344- [2025-09-18-bash](2025-09-18-bash.wwz/_tmp/aports-report/2025-09-18-bash/diff_merged.html) - **43**, after adding `osh` as `/bin/bash`
345 - only run on packages that disagree: [2025-09-27-disagree](2025-09-27-disagree.wwz/_tmp/aports-report/2025-09-27-disagree/diff_merged.html)
346 - new causes: [2025-10-03-causes](2025-10-03-causes.wwz/_tmp/aports-report/2025-10-03-causes/diff_merged.html)
347- [2025-10-15-main](2025-10-15-main.wwz/_tmp/aports-report/2025-10-15-main/diff_merged.html) - **38** disagreements
348 - [2025-10-16](2025-10-16.wwz/_tmp/aports-report/2025-10-16/diff_merged.html) - down to **35** after `x=1>` and `cd x y` fixes
349 - [2025-10-22](2025-10-22.wwz/_tmp/aports-report/2025-10-22/diff_merged.html) - down to **24** after `((` and `$(false)` fixes
350 - [2025-10-26-cause](2025-10-26-cause.wwz/_tmp/aports-report/2025-10-26-cause/diff_merged.html) - updated causes
351 - [2025-11-01-main-cause](2025-11-01-main-cause.wwz/_tmp/aports-report/2025-11-01-main-cause/diff_merged.html) - updated causes
352 - [2025-11-01-main-again](2025-11-01-main-again.wwz/_tmp/aports-report/2025-11-01-main-again/diff_merged.html) - **18** disagreements
353 - [2025-11-02-main-patch](2025-11-02-main-patch.wwz/_tmp/aports-report/2025-11-02-main-patch/diff_merged.html) - **14** disagreements
354 - [2025-11-09-main-cause](2025-11-09-main-cause.wwz/_tmp/aports-report/2025-11-09-main-cause/diff_merged.html) - updated causes
355- [2025-11-11-main-full](2025-11-11-main-full.wwz/_tmp/aports-report/2025-11-11-main-full/diff_merged.html) - full run with 10 package builds in parallel, 2 cores each
356- [2025-11-16-main-full](2025-11-16-main-full.wwz/_tmp/aports-report/2025-11-16-main-full/diff_merged.html) - **17** disagreements - regression after `$[]` change
357- [2025-11-18](2025-11-18.wwz/_tmp/aports-report/2025-11-18/diff_merged.html) - **12** disagreements - fixed regression
358
359### community
360
361- [2025-10-08-comm](2025-10-08-comm.wwz/_tmp/aports-report/2025-10-08-comm/diff_merged.html) - **86** disagreements
362 - [2025-10-16-comm-disagree](2025-10-16-comm-disagree.wwz/_tmp/aports-report/2025-10-16-comm-disagree/diff_merged.html) - **71** disagreements
363 - [2025-10-22-comm](2025-10-22-comm.wwz/_tmp/aports-report/2025-10-22-comm/diff_merged.html) - down to **65** after `((` and `$(false)` fixes
364 - [2025-10-26-comm-cause](2025-10-26-comm-cause.wwz/_tmp/aports-report/2025-10-26-comm-cause/diff_merged.html) - updated causes
365 - [2025-11-01-comm-cause](2025-11-01-comm-cause.wwz/_tmp/aports-report/2025-11-01-comm-cause/diff_merged.html) - updated causes
366 - [2025-11-02-comm-patch](2025-11-02-comm-patch.wwz/_tmp/aports-report/2025-11-02-comm-patch/diff_merged.html) - **64** disagreements, **45** of unknown cause
367 - [2025-11-09-comm-cause](2025-11-09-comm-cause.wwz/_tmp/aports-report/2025-11-09-comm-cause/diff_merged.html) - updated causes, **20** of unknown cause
368 - [2025-11-18-comm-disagree](2025-11-18-comm-disagree.wwz/_tmp/aports-report/2025-11-18-comm-disagree/diff_merged.html) - **60** disagreements
369';
370 } | cmark
371
372 echo '
373 </body>
374</html>
375'
376}
377
378typed-tsv-to-sql() {
379 local tsv=${1:-$BASE_DIR/big/tasks.tsv}
380 local name
381 name=${2:-$(basename $tsv .tsv)}
382
383 local schema="${tsv%'.tsv'}.schema.tsv"
384 #echo $name $schema
385
386 echo "CREATE TABLE $name ("
387 web/table/schema2sqlite.py $schema
388 echo ');'
389
390 echo "
391-- use this temp import because we already created the table, and
392-- '.headers on' is not expected in that case
393
394.import $tsv temp_import
395insert into $name select * from temp_import;
396drop table temp_import;
397
398-- select * from $name limit 5;
399 "
400}
401
402my-rsync() {
403 #rsync --archive --verbose --dry-run "$@"
404 rsync --archive --verbose "$@"
405}
406
407readonly EPOCH=${EPOCH:-'2025-07-28-100'}
408readonly BUILD_HOST=he.oils.pub
409#readonly BUILD_HOST=lenny.local
410
411sync-results() {
412 local host=${1:-$BUILD_HOST}
413 local prefix=${2:-}
414 mkdir -p $REPORT_DIR
415
416 # Exclude .apk files, because they are large. We only need the metadata
417 my-rsync \
418 --exclude '*.apk' \
419 "$host:~/git/oils-for-unix/oils/_tmp/aports-build/$prefix*" \
420 $REPORT_DIR/
421}
422
423local-sync() {
424 mkdir -p $REPORT_DIR
425
426 #my-rsync --dry-run $BASE_DIR/ $REPORT_DIR/
427 my-rsync $BASE_DIR/ $REPORT_DIR/
428}
429
430make-package-table() {
431 local base_dir=${1:-$REPORT_DIR/$EPOCH}
432 local config=${2:-baseline}
433
434 local db=$PWD/$base_dir/$config/tables.db
435 rm -f $db
436
437 typed-tsv-to-sql $base_dir/$config/tasks.tsv | sqlite-tabs-headers $db
438
439 sqlite3 -cmd '.mode columns' $db < regtest/aports/tasks.sql
440
441 pushd $base_dir/$config > /dev/null
442
443 db-to-tsv $db packages
444
445 # Set precision
446 echo "
447 alter table packages_schema add column precision;
448
449 update packages_schema set precision = 1 where column_name = 'elapsed_secs';
450 update packages_schema set precision = 1 where column_name = 'user_elapsed_ratio';
451 update packages_schema set precision = 1 where column_name = 'user_sys_ratio';
452 update packages_schema set precision = 1 where column_name = 'max_rss_MB';
453 " | sqlite3 $db
454
455 # Count .apk for this config
456 # Note: we could also create an 'apk' table, in addition to 'packages', and diff
457 # But that's a bunch of overhead
458
459 local num_apk
460 num_apk=$(cat apk.txt | wc -l)
461
462 sqlite3 $db >metrics.txt <<EOF
463update metrics
464set num_apk = $num_apk
465where id = 1;
466
467.mode column
468select * from metrics;
469EOF
470
471 popd > /dev/null
472
473 #cat $base_dir/$config/packages.schema.tsv
474}
475
476tasks-schema() {
477 here-schema-tsv-4col <<EOF
478column_name type precision strftime
479status integer 0 -
480elapsed_secs float 1 -
481start_time float 1 %H:%M:%S
482end_time float 1 %H:%M:%S
483user_secs float 1 -
484sys_secs float 1 -
485max_rss_KiB integer 0 -
486xargs_slot integer 0 -
487pkg string 0 -
488pkg_HREF string 0 -
489EOF
490}
491
492write-tables-for-config() {
493 local base_dir=${1:-$REPORT_DIR/$EPOCH}
494 local config=${2:-baseline}
495
496 local tasks_tsv=$base_dir/$config/tasks.tsv
497 mkdir -p $base_dir/$config
498
499 tasks-schema >$base_dir/$config/tasks.schema.tsv
500
501 local out=$base_dir/$config/tasks.html
502 tasks-html $tasks_tsv "tasks: $config" > $out
503 log "Wrote $out"
504
505 make-package-table "$base_dir" "$config"
506
507 local packages_tsv=$base_dir/$config/packages.tsv
508
509 local out=$base_dir/$config/packages.html
510 tasks-html $packages_tsv "packages: $config" > $out
511 log "Wrote $out"
512}
513
514make-diff-db() {
515 local base_dir=$1
516 local name=${2:-diff_baseline}
517
518 local db=$name.db
519
520 local diff_sql=$PWD/regtest/aports/diff.sql
521 local cause_awk=$PWD/regtest/aports/cause.awk
522 local cause_sql=$PWD/regtest/aports/cause.sql
523
524 pushd $base_dir > /dev/null
525
526 rm -f $db
527 sqlite3 $db < $diff_sql
528
529 #
530 # Now make diffs
531 #
532
533 sqlite3 $db >failed-packages.txt <<EOF
534.mode tabs
535-- this is a text file, so headers are OFF
536.headers off
537
538select pkg from diff_baseline;
539EOF
540
541 mkdir -p error
542 cat failed-packages.txt | while read -r pkg; do
543 #local left=baseline/log/$pkg.log.txt
544 local right=osh-as-sh/log/$pkg.log.txt
545
546 # lower case 'error fail' are more noisy, e.g. command line flags
547 egrep 'Error|ERROR|Fail|FAIL|test-suite.log' $right > error/$pkg.txt || true
548 done
549
550 { echo "pkg${TAB}cause${TAB}suite${TAB}suite_HREF"
551 cat failed-packages.txt | while read -r pkg; do
552 local right=osh-as-sh/log/$pkg.log.txt
553
554 local cause
555 cause=$(awk -f $cause_awk $right)
556
557 local suite=''
558 local suite_HREF=''
559 local suite_path="osh-as-sh/test-suite/$pkg/test-suite.log.txt"
560 if test -f "$suite_path"; then
561 suite='suite'
562 suite_HREF=$suite_path # shard added in regtest/aports/merge.sql
563 fi
564
565 echo "${pkg}${TAB}${cause}${TAB}${suite}${TAB}${suite_HREF}"
566 done
567 } > causes.tsv
568
569 # Import causes.tsv and add columns
570 sqlite-tabs-headers \
571 -cmd '.import causes.tsv causes' \
572 $db < $cause_sql
573
574 # The DB is diff_baseline.db, with table diff_baseline
575 db-to-tsv $db diff_baseline
576
577 popd > /dev/null
578}
579
580db-to-tsv() {
581 local db=$1
582 local table_name=$2
583 local order_by=${3:-}
584
585 echo "
586 select * from ${table_name} ${order_by};
587 " | sqlite-tabs-headers $db >$table_name.tsv
588
589 echo "
590 create table ${table_name}_schema as
591 select
592 name as column_name,
593 case
594 when UPPER(type) like '%INT%' then 'integer'
595 when UPPER(type) = 'REAL' then 'float'
596 when UPPER(type) = 'TEXT' then 'string'
597 else LOWER(type)
598 end as type
599 from PRAGMA_TABLE_INFO('${table_name}');
600
601 select * from ${table_name}_schema;
602 " | sqlite-tabs-headers $db >$table_name.schema.tsv
603}
604
605merge-diffs-sql() {
606 local -a SHARDS=( "$@" )
607
608 local is_first_shard=T
609
610 # Now insert data from all the shards
611 for ((i=0; i<${#SHARDS[@]}; i++)); do
612 local shard_dir="${SHARDS[i]}"
613 shard_name=$(basename $shard_dir)
614
615 # Handle incomplete shard
616 if ! test -d $shard_dir/baseline || ! test -d $shard_dir/osh-as-sh; then
617 continue
618 fi
619
620 echo "ATTACH DATABASE '$shard_dir/diff_baseline.db' AS temp_shard;"
621
622 if test -n "$is_first_shard"; then
623 # Create table from first shard
624 echo "
625 CREATE TABLE diff_merged AS
626 SELECT *, CAST('' as TEXT) as shard FROM temp_shard.diff_baseline where 1=0;
627
628 CREATE TABLE metrics AS
629 SELECT *, CAST('' as TEXT) as shard FROM temp_shard.metrics where 1=0;
630 "
631 is_first_shard='' # don't create table next time
632 fi
633
634 # Now insert data
635 echo "
636 INSERT INTO diff_merged
637 SELECT *, '$shard_name' as shard FROM temp_shard.diff_baseline;
638
639 INSERT INTO metrics
640 SELECT *, '$shard_name' as shard FROM temp_shard.metrics;
641
642 DETACH DATABASE temp_shard;
643 "
644 done
645
646 # Does not involve metaprogramming
647 cat regtest/aports/merge.sql
648}
649
650merge-diffs() {
651 local epoch_dir=${1:-_tmp/aports-report/2025-10-15-main}
652 local do_disagree=${2:-}
653
654 local db=$PWD/$epoch_dir/diff_merged.db
655 rm -f $db
656
657 local -a shards
658 if test -n "$do_disagree"; then
659 # Hack: distinguish disagree-2025 from disagree-packages.txt
660 shards=( $epoch_dir/disagree-2* ) # Usually 1 shard
661 else
662 shards=( $epoch_dir/shard* )
663 fi
664
665 echo SHARDS "${shards[@]}"
666
667 merge-diffs-sql "${shards[@]}" | sqlite3 $db
668 #echo $db
669
670 # copied from above
671 pushd $epoch_dir > /dev/null
672
673 db-to-tsv $db diff_merged 'order by pkg'
674 db-to-tsv $db metrics
675
676 db-to-tsv $db notable_disagree 'order by pkg'
677 db-to-tsv $db timeout_disagree 'order by pkg'
678 db-to-tsv $db baseline_only 'order by pkg'
679 db-to-tsv $db both_fail 'order by pkg'
680 db-to-tsv $db both_timeout 'order by pkg'
681
682 db-to-tsv $db cause_hist
683
684 # For re-running failures
685 sqlite3 diff_merged.db >disagree-packages.txt <<EOF
686.headers off
687select pkg from diff_merged where disagree = 1 and timeout = 0;
688EOF
689 #wc -l disagree-packages.txt
690
691 popd > /dev/null
692
693 local title1='OSH Disagreements - regtest/aports'
694 local out=$epoch_dir/diff_merged.html
695 merge-diff-html $epoch_dir '../../../web' "$title1" > $out
696 echo "Wrote $out"
697
698 local name2=metrics
699 local title2='Metrics - regtest/aports'
700 local out=$epoch_dir/$name2.html
701 table-page-html $epoch_dir $name2 '../../../web' "$title2" > $out
702 echo "Wrote $out"
703
704 # After merging, regenerate other stuff too
705
706 html-tree "$epoch_dir"
707
708 update-published # also done in deploy-published
709}
710
711write-shard-reports() {
712 local base_dir=$1 # e.g. _tmp/aports-report/2025-08-02/shard3
713
714 index-html > $base_dir/index.html
715
716 for config in baseline osh-as-sh; do
717 # Incomplete shard
718 if ! test -d "$base_dir/$config"; then
719 return
720 fi
721 write-tables-for-config "$base_dir" "$config"
722 done
723
724 local name=diff_baseline
725 local title="$base_dir differences"
726 make-diff-db $base_dir
727 table-page-html $base_dir $name '' "$title" > $base_dir/$name.html
728 echo "Wrote $base_dir/$name.html"
729}
730
731write-all-reports() {
732 local epoch_dir=${1:-_tmp/aports-report/2025-08-03}
733
734 for shard_dir in $epoch_dir/shard*; do
735 write-shard-reports "$shard_dir"
736 done
737
738 merge-diffs "$epoch_dir"
739}
740
741write-disagree-reports() {
742 local epoch_dir=${1:-_tmp/aports-build/2025-09-27}
743
744 # Hack: distinguish disagree-2025 from disagree-packages.txt
745 for shard_dir in $epoch_dir/disagree-2*; do
746 write-shard-reports "$shard_dir"
747 done
748
749 merge-diffs "$epoch_dir" T
750}
751
752html-tree() {
753 local epoch_dir=${1:-_tmp/aports-report/2025-08-07-fix}
754
755 local epoch
756 epoch=$(basename $epoch_dir)
757
758 pushd $epoch_dir
759 # -L 3 goes 3 levels deeps, omitting logs
760 tree \
761 -H './' \
762 -T "regtest/aports - $epoch" \
763 -L 3 \
764 --charset=ascii \
765 > tree.html
766 popd
767
768 echo "Wrote $epoch_dir/tree.html"
769}
770
771update-published() {
772 local out=$REPORT_DIR/published.html
773 published-html > $out
774 echo "Wrote $out"
775}
776
777remove-apk() {
778 local base_dir=${1:-$REPORT_DIR/2025-09-07}
779 # temporary
780
781 find $base_dir -name '*.apk' -o -name 'APKINDEX*' | xargs -d $'\n' --verbose -- rm -v
782}
783
784make-wwz() {
785 local base_dir=${1:-$REPORT_DIR/2025-08-03}
786
787 # must not end with slash
788 base_dir=${base_dir%'/'}
789
790 local wwz=$base_dir.wwz
791 rm -f -v $wwz
792
793 zip -r $wwz $base_dir web/
794
795 echo "Wrote $wwz"
796}
797
798readonly WEB_HOST=op.oils.pub
799
800deploy-wwz-op() {
801 local wwz=${1:-$REPORT_DIR/2025-08-03.wwz}
802
803 local dest_dir=$WEB_HOST/aports-build
804
805 update-published # slightly redundant
806
807 ssh $WEB_HOST mkdir -p $dest_dir
808
809 scp $wwz $REPORT_DIR/published.html \
810 $WEB_HOST:$dest_dir/
811
812 echo "Visit https://$dest_dir/published.html"
813 echo " https://$dest_dir/$(basename $wwz)/"
814}
815
816deploy-published() {
817 local dest_dir=$WEB_HOST/aports-build
818
819 update-published # slightly redundant
820
821 scp $REPORT_DIR/published.html \
822 $WEB_HOST:$dest_dir/
823
824 echo "Visit https://$dest_dir/published.html"
825}
826
827#
828# For editing
829#
830
831readonly EDIT_DIR=_tmp/aports-edit
832
833readonly EDITING_APORTS_EPOCH='2025-11-02-main-patch.wwz'
834
835sync-old-wwz() {
836 local wwz=${1:-$EDITING_APORTS_EPOCH}
837
838 mkdir -p $EDIT_DIR
839 rm -f -v $EDIT_DIR/$wwz
840
841 wget --directory-prefix $EDIT_DIR \
842 "https://$WEB_HOST/aports-build/$wwz"
843
844 ls -l $EDIT_DIR
845 #echo "Wrote $wwz"
846}
847
848extract-old-wwz() {
849 local new_epoch=$1
850 local wwz=${2:-$EDITING_APORTS_EPOCH}
851
852 # Extract the whole thing into a temp dir
853 local tmp_dir=$EDIT_DIR/$new_epoch
854 rm -r -f $tmp_dir
855 mkdir -p $tmp_dir
856
857 pushd $tmp_dir
858 unzip ../$wwz
859 popd
860
861 # Now re-create the old structure under _tmp/aports-report/2025-09-06-edit
862
863 local dest_dir=$REPORT_DIR/$new_epoch
864 mkdir -p $dest_dir
865
866 local old_epoch
867 old_epoch=$(basename $wwz .wwz)
868 mv -v --no-target-directory $tmp_dir/_tmp/aports-report/$old_epoch $dest_dir
869}
870
871rebuild-both() {
872 for a_repo in main comm; do
873 local old=2025-11-02-${a_repo}-patch.wwz
874 sync-old-wwz $old
875 local new=2025-11-09-${a_repo}-cause
876
877 rm -r -f _tmp/aports-report/$new
878
879 extract-old-wwz $new $old
880
881 write-disagree-reports _tmp/aports-report/$new
882
883 make-wwz _tmp/aports-report/$new
884
885 deploy-wwz-op _tmp/aports-report/$new.wwz
886 done
887}
888
889#
890# Dev tools
891#
892
893out-of-vm() {
894 local dest=~/vm-shared/$EPOCH
895 mkdir -p $dest
896 cp $REPORT_DIR/$EPOCH.wwz $dest
897 pushd ~/vm-shared/$EPOCH
898 unzip $EPOCH.wwz
899 popd
900}
901
902task-five "$@"