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

901 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
358### community
359
360- [2025-10-08-comm](2025-10-08-comm.wwz/_tmp/aports-report/2025-10-08-comm/diff_merged.html) - **86** disagreements
361 - [2025-10-16-comm-disagree](2025-10-16-comm-disagree.wwz/_tmp/aports-report/2025-10-16-comm-disagree/diff_merged.html) - **71** disagreements
362 - [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
363 - [2025-10-26-comm-cause](2025-10-26-comm-cause.wwz/_tmp/aports-report/2025-10-26-comm-cause/diff_merged.html) - updated causes
364 - [2025-11-01-comm-cause](2025-11-01-comm-cause.wwz/_tmp/aports-report/2025-11-01-comm-cause/diff_merged.html) - updated causes
365 - [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
366 - [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
367
368';
369 } | cmark
370
371 echo '
372 </body>
373</html>
374'
375}
376
377typed-tsv-to-sql() {
378 local tsv=${1:-$BASE_DIR/big/tasks.tsv}
379 local name
380 name=${2:-$(basename $tsv .tsv)}
381
382 local schema="${tsv%'.tsv'}.schema.tsv"
383 #echo $name $schema
384
385 echo "CREATE TABLE $name ("
386 web/table/schema2sqlite.py $schema
387 echo ');'
388
389 echo "
390-- use this temp import because we already created the table, and
391-- '.headers on' is not expected in that case
392
393.import $tsv temp_import
394insert into $name select * from temp_import;
395drop table temp_import;
396
397-- select * from $name limit 5;
398 "
399}
400
401my-rsync() {
402 #rsync --archive --verbose --dry-run "$@"
403 rsync --archive --verbose "$@"
404}
405
406readonly EPOCH=${EPOCH:-'2025-07-28-100'}
407readonly BUILD_HOST=he.oils.pub
408#readonly BUILD_HOST=lenny.local
409
410sync-results() {
411 local host=${1:-$BUILD_HOST}
412 local prefix=${2:-}
413 mkdir -p $REPORT_DIR
414
415 # Exclude .apk files, because they are large. We only need the metadata
416 my-rsync \
417 --exclude '*.apk' \
418 "$host:~/git/oils-for-unix/oils/_tmp/aports-build/$prefix*" \
419 $REPORT_DIR/
420}
421
422local-sync() {
423 mkdir -p $REPORT_DIR
424
425 #my-rsync --dry-run $BASE_DIR/ $REPORT_DIR/
426 my-rsync $BASE_DIR/ $REPORT_DIR/
427}
428
429make-package-table() {
430 local base_dir=${1:-$REPORT_DIR/$EPOCH}
431 local config=${2:-baseline}
432
433 local db=$PWD/$base_dir/$config/tables.db
434 rm -f $db
435
436 typed-tsv-to-sql $base_dir/$config/tasks.tsv | sqlite-tabs-headers $db
437
438 sqlite3 -cmd '.mode columns' $db < regtest/aports/tasks.sql
439
440 pushd $base_dir/$config > /dev/null
441
442 db-to-tsv $db packages
443
444 # Set precision
445 echo "
446 alter table packages_schema add column precision;
447
448 update packages_schema set precision = 1 where column_name = 'elapsed_secs';
449 update packages_schema set precision = 1 where column_name = 'user_elapsed_ratio';
450 update packages_schema set precision = 1 where column_name = 'user_sys_ratio';
451 update packages_schema set precision = 1 where column_name = 'max_rss_MB';
452 " | sqlite3 $db
453
454 # Count .apk for this config
455 # Note: we could also create an 'apk' table, in addition to 'packages', and diff
456 # But that's a bunch of overhead
457
458 local num_apk
459 num_apk=$(cat apk.txt | wc -l)
460
461 sqlite3 $db >metrics.txt <<EOF
462update metrics
463set num_apk = $num_apk
464where id = 1;
465
466.mode column
467select * from metrics;
468EOF
469
470 popd > /dev/null
471
472 #cat $base_dir/$config/packages.schema.tsv
473}
474
475tasks-schema() {
476 here-schema-tsv-4col <<EOF
477column_name type precision strftime
478status integer 0 -
479elapsed_secs float 1 -
480start_time float 1 %H:%M:%S
481end_time float 1 %H:%M:%S
482user_secs float 1 -
483sys_secs float 1 -
484max_rss_KiB integer 0 -
485xargs_slot integer 0 -
486pkg string 0 -
487pkg_HREF string 0 -
488EOF
489}
490
491write-tables-for-config() {
492 local base_dir=${1:-$REPORT_DIR/$EPOCH}
493 local config=${2:-baseline}
494
495 local tasks_tsv=$base_dir/$config/tasks.tsv
496 mkdir -p $base_dir/$config
497
498 tasks-schema >$base_dir/$config/tasks.schema.tsv
499
500 local out=$base_dir/$config/tasks.html
501 tasks-html $tasks_tsv "tasks: $config" > $out
502 log "Wrote $out"
503
504 make-package-table "$base_dir" "$config"
505
506 local packages_tsv=$base_dir/$config/packages.tsv
507
508 local out=$base_dir/$config/packages.html
509 tasks-html $packages_tsv "packages: $config" > $out
510 log "Wrote $out"
511}
512
513make-diff-db() {
514 local base_dir=$1
515 local name=${2:-diff_baseline}
516
517 local db=$name.db
518
519 local diff_sql=$PWD/regtest/aports/diff.sql
520 local cause_awk=$PWD/regtest/aports/cause.awk
521 local cause_sql=$PWD/regtest/aports/cause.sql
522
523 pushd $base_dir > /dev/null
524
525 rm -f $db
526 sqlite3 $db < $diff_sql
527
528 #
529 # Now make diffs
530 #
531
532 sqlite3 $db >failed-packages.txt <<EOF
533.mode tabs
534-- this is a text file, so headers are OFF
535.headers off
536
537select pkg from diff_baseline;
538EOF
539
540 mkdir -p error
541 cat failed-packages.txt | while read -r pkg; do
542 #local left=baseline/log/$pkg.log.txt
543 local right=osh-as-sh/log/$pkg.log.txt
544
545 # lower case 'error fail' are more noisy, e.g. command line flags
546 egrep 'Error|ERROR|Fail|FAIL|test-suite.log' $right > error/$pkg.txt || true
547 done
548
549 { echo "pkg${TAB}cause${TAB}suite${TAB}suite_HREF"
550 cat failed-packages.txt | while read -r pkg; do
551 local right=osh-as-sh/log/$pkg.log.txt
552
553 local cause
554 cause=$(awk -f $cause_awk $right)
555
556 local suite=''
557 local suite_HREF=''
558 local suite_path="osh-as-sh/test-suite/$pkg/test-suite.log.txt"
559 if test -f "$suite_path"; then
560 suite='suite'
561 suite_HREF=$suite_path # shard added in regtest/aports/merge.sql
562 fi
563
564 echo "${pkg}${TAB}${cause}${TAB}${suite}${TAB}${suite_HREF}"
565 done
566 } > causes.tsv
567
568 # Import causes.tsv and add columns
569 sqlite-tabs-headers \
570 -cmd '.import causes.tsv causes' \
571 $db < $cause_sql
572
573 # The DB is diff_baseline.db, with table diff_baseline
574 db-to-tsv $db diff_baseline
575
576 popd > /dev/null
577}
578
579db-to-tsv() {
580 local db=$1
581 local table_name=$2
582 local order_by=${3:-}
583
584 echo "
585 select * from ${table_name} ${order_by};
586 " | sqlite-tabs-headers $db >$table_name.tsv
587
588 echo "
589 create table ${table_name}_schema as
590 select
591 name as column_name,
592 case
593 when UPPER(type) like '%INT%' then 'integer'
594 when UPPER(type) = 'REAL' then 'float'
595 when UPPER(type) = 'TEXT' then 'string'
596 else LOWER(type)
597 end as type
598 from PRAGMA_TABLE_INFO('${table_name}');
599
600 select * from ${table_name}_schema;
601 " | sqlite-tabs-headers $db >$table_name.schema.tsv
602}
603
604merge-diffs-sql() {
605 local -a SHARDS=( "$@" )
606
607 local is_first_shard=T
608
609 # Now insert data from all the shards
610 for ((i=0; i<${#SHARDS[@]}; i++)); do
611 local shard_dir="${SHARDS[i]}"
612 shard_name=$(basename $shard_dir)
613
614 # Handle incomplete shard
615 if ! test -d $shard_dir/baseline || ! test -d $shard_dir/osh-as-sh; then
616 continue
617 fi
618
619 echo "ATTACH DATABASE '$shard_dir/diff_baseline.db' AS temp_shard;"
620
621 if test -n "$is_first_shard"; then
622 # Create table from first shard
623 echo "
624 CREATE TABLE diff_merged AS
625 SELECT *, CAST('' as TEXT) as shard FROM temp_shard.diff_baseline where 1=0;
626
627 CREATE TABLE metrics AS
628 SELECT *, CAST('' as TEXT) as shard FROM temp_shard.metrics where 1=0;
629 "
630 is_first_shard='' # don't create table next time
631 fi
632
633 # Now insert data
634 echo "
635 INSERT INTO diff_merged
636 SELECT *, '$shard_name' as shard FROM temp_shard.diff_baseline;
637
638 INSERT INTO metrics
639 SELECT *, '$shard_name' as shard FROM temp_shard.metrics;
640
641 DETACH DATABASE temp_shard;
642 "
643 done
644
645 # Does not involve metaprogramming
646 cat regtest/aports/merge.sql
647}
648
649merge-diffs() {
650 local epoch_dir=${1:-_tmp/aports-report/2025-10-15-main}
651 local do_disagree=${2:-}
652
653 local db=$PWD/$epoch_dir/diff_merged.db
654 rm -f $db
655
656 local -a shards
657 if test -n "$do_disagree"; then
658 # Hack: distinguish disagree-2025 from disagree-packages.txt
659 shards=( $epoch_dir/disagree-2* ) # Usually 1 shard
660 else
661 shards=( $epoch_dir/shard* )
662 fi
663
664 echo SHARDS "${shards[@]}"
665
666 merge-diffs-sql "${shards[@]}" | sqlite3 $db
667 #echo $db
668
669 # copied from above
670 pushd $epoch_dir > /dev/null
671
672 db-to-tsv $db diff_merged 'order by pkg'
673 db-to-tsv $db metrics
674
675 db-to-tsv $db notable_disagree 'order by pkg'
676 db-to-tsv $db timeout_disagree 'order by pkg'
677 db-to-tsv $db baseline_only 'order by pkg'
678 db-to-tsv $db both_fail 'order by pkg'
679 db-to-tsv $db both_timeout 'order by pkg'
680
681 db-to-tsv $db cause_hist
682
683 # For re-running failures
684 sqlite3 diff_merged.db >disagree-packages.txt <<EOF
685.headers off
686select pkg from diff_merged where disagree = 1 and timeout = 0;
687EOF
688 #wc -l disagree-packages.txt
689
690 popd > /dev/null
691
692 local title1='OSH Disagreements - regtest/aports'
693 local out=$epoch_dir/diff_merged.html
694 merge-diff-html $epoch_dir '../../../web' "$title1" > $out
695 echo "Wrote $out"
696
697 local name2=metrics
698 local title2='Metrics - regtest/aports'
699 local out=$epoch_dir/$name2.html
700 table-page-html $epoch_dir $name2 '../../../web' "$title2" > $out
701 echo "Wrote $out"
702
703 # After merging, regenerate other stuff too
704
705 html-tree "$epoch_dir"
706
707 update-published # also done in deploy-published
708}
709
710write-shard-reports() {
711 local base_dir=$1 # e.g. _tmp/aports-report/2025-08-02/shard3
712
713 index-html > $base_dir/index.html
714
715 for config in baseline osh-as-sh; do
716 # Incomplete shard
717 if ! test -d "$base_dir/$config"; then
718 return
719 fi
720 write-tables-for-config "$base_dir" "$config"
721 done
722
723 local name=diff_baseline
724 local title="$base_dir differences"
725 make-diff-db $base_dir
726 table-page-html $base_dir $name '' "$title" > $base_dir/$name.html
727 echo "Wrote $base_dir/$name.html"
728}
729
730write-all-reports() {
731 local epoch_dir=${1:-_tmp/aports-report/2025-08-03}
732
733 for shard_dir in $epoch_dir/shard*; do
734 write-shard-reports "$shard_dir"
735 done
736
737 merge-diffs "$epoch_dir"
738}
739
740write-disagree-reports() {
741 local epoch_dir=${1:-_tmp/aports-build/2025-09-27}
742
743 # Hack: distinguish disagree-2025 from disagree-packages.txt
744 for shard_dir in $epoch_dir/disagree-2*; do
745 write-shard-reports "$shard_dir"
746 done
747
748 merge-diffs "$epoch_dir" T
749}
750
751html-tree() {
752 local epoch_dir=${1:-_tmp/aports-report/2025-08-07-fix}
753
754 local epoch
755 epoch=$(basename $epoch_dir)
756
757 pushd $epoch_dir
758 # -L 3 goes 3 levels deeps, omitting logs
759 tree \
760 -H './' \
761 -T "regtest/aports - $epoch" \
762 -L 3 \
763 --charset=ascii \
764 > tree.html
765 popd
766
767 echo "Wrote $epoch_dir/tree.html"
768}
769
770update-published() {
771 local out=$REPORT_DIR/published.html
772 published-html > $out
773 echo "Wrote $out"
774}
775
776remove-apk() {
777 local base_dir=${1:-$REPORT_DIR/2025-09-07}
778 # temporary
779
780 find $base_dir -name '*.apk' -o -name 'APKINDEX*' | xargs -d $'\n' --verbose -- rm -v
781}
782
783make-wwz() {
784 local base_dir=${1:-$REPORT_DIR/2025-08-03}
785
786 # must not end with slash
787 base_dir=${base_dir%'/'}
788
789 local wwz=$base_dir.wwz
790 rm -f -v $wwz
791
792 zip -r $wwz $base_dir web/
793
794 echo "Wrote $wwz"
795}
796
797readonly WEB_HOST=op.oils.pub
798
799deploy-wwz-op() {
800 local wwz=${1:-$REPORT_DIR/2025-08-03.wwz}
801
802 local dest_dir=$WEB_HOST/aports-build
803
804 update-published # slightly redundant
805
806 ssh $WEB_HOST mkdir -p $dest_dir
807
808 scp $wwz $REPORT_DIR/published.html \
809 $WEB_HOST:$dest_dir/
810
811 echo "Visit https://$dest_dir/published.html"
812 echo " https://$dest_dir/$(basename $wwz)/"
813}
814
815deploy-published() {
816 local dest_dir=$WEB_HOST/aports-build
817
818 update-published # slightly redundant
819
820 scp $REPORT_DIR/published.html \
821 $WEB_HOST:$dest_dir/
822
823 echo "Visit https://$dest_dir/published.html"
824}
825
826#
827# For editing
828#
829
830readonly EDIT_DIR=_tmp/aports-edit
831
832readonly EDITING_APORTS_EPOCH='2025-11-02-main-patch.wwz'
833
834sync-old-wwz() {
835 local wwz=${1:-$EDITING_APORTS_EPOCH}
836
837 mkdir -p $EDIT_DIR
838 rm -f -v $EDIT_DIR/$wwz
839
840 wget --directory-prefix $EDIT_DIR \
841 "https://$WEB_HOST/aports-build/$wwz"
842
843 ls -l $EDIT_DIR
844 #echo "Wrote $wwz"
845}
846
847extract-old-wwz() {
848 local new_epoch=$1
849 local wwz=${2:-$EDITING_APORTS_EPOCH}
850
851 # Extract the whole thing into a temp dir
852 local tmp_dir=$EDIT_DIR/$new_epoch
853 rm -r -f $tmp_dir
854 mkdir -p $tmp_dir
855
856 pushd $tmp_dir
857 unzip ../$wwz
858 popd
859
860 # Now re-create the old structure under _tmp/aports-report/2025-09-06-edit
861
862 local dest_dir=$REPORT_DIR/$new_epoch
863 mkdir -p $dest_dir
864
865 local old_epoch
866 old_epoch=$(basename $wwz .wwz)
867 mv -v --no-target-directory $tmp_dir/_tmp/aports-report/$old_epoch $dest_dir
868}
869
870rebuild-both() {
871 for a_repo in main comm; do
872 local old=2025-11-02-${a_repo}-patch.wwz
873 sync-old-wwz $old
874 local new=2025-11-09-${a_repo}-cause
875
876 rm -r -f _tmp/aports-report/$new
877
878 extract-old-wwz $new $old
879
880 write-disagree-reports _tmp/aports-report/$new
881
882 make-wwz _tmp/aports-report/$new
883
884 deploy-wwz-op _tmp/aports-report/$new.wwz
885 done
886}
887
888#
889# Dev tools
890#
891
892out-of-vm() {
893 local dest=~/vm-shared/$EPOCH
894 mkdir -p $dest
895 cp $REPORT_DIR/$EPOCH.wwz $dest
896 pushd ~/vm-shared/$EPOCH
897 unzip $EPOCH.wwz
898 popd
899}
900
901task-five "$@"