OILS / soil / worker.sh View on Github | oilshell.org

640 lines, 208 significant
1#!/usr/bin/env bash
2#
3# Run continuous build tasks.
4#
5# Usage:
6# soil/worker.sh <function name>
7
8set -o nounset
9set -o pipefail
10set -o errexit
11
12REPO_ROOT=$(cd "$(dirname $0)/.."; pwd) # tsv-lib.sh uses this
13readonly REPO_ROOT
14
15source soil/common.sh
16source test/tsv-lib.sh
17
18py-all-and-ninja() {
19 ### baseline for most tasks
20
21 build/py.sh all
22 ./NINJA-config.sh
23}
24
25ninja-config() {
26 ./NINJA-config.sh
27}
28
29dummy-tasks() {
30 ### Print tasks that execute quickly
31
32 # (task_name, script, action, result_html)
33 cat <<EOF
34os-info soil/diagnose.sh os-info -
35dump-env soil/diagnose.sh dump-env -
36EOF
37}
38
39raw-vm-tasks() {
40 # The perf tool depends on a specific version of a kernel, so run it outside
41 # a container.
42
43 # (task_name, script, action, result_html)
44 cat <<EOF
45os-info soil/diagnose.sh os-info -
46dump-env soil/diagnose.sh dump-env -
47perf-install benchmarks/perf.sh soil-install -
48wait-for-tarball soil/wait.sh for-cpp-tarball -
49test-install-tar devtools/release-native.sh test-install-tar -
50perf-profiles benchmarks/perf.sh soil-run _tmp/perf/index.html
51EOF
52}
53
54# Oh there is a large list of pre-installed software
55# https://github.com/actions/runner-images#available-images
56# https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2004-Readme.md
57# https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md
58#
59# 1. System deps for building wedges - ninja, cmake, libreadline-dev, etc.
60# 2. fetch wedges - re2c, cmark, python2, python3, MyPy, pyflakes
61# - Python 3.10 desired for "pea"
62# 3. build them
63# 4. build Oils with them
64
65dev-setup-for() {
66 local distro=$1
67 # (task_name, script, action, result_html)
68
69 cat <<EOF
70os-info soil/diagnose.sh os-info -
71dump-env soil/diagnose.sh dump-env -
72wedge-deps build/deps.sh wedge-deps-$distro -
73fetch build/deps.sh fetch -
74install-wedges build/deps.sh install-wedges-fast _build/wedge/logs/index.html
75py-all-and-ninja soil/worker.sh py-all-and-ninja -
76smoke-test build/dev-setup-test.sh smoke-test -
77wedge-report build/deps.sh wedge-report -
78EOF
79}
80
81spec-bin-for() {
82 local distro=$1
83 cat <<EOF
84os-info soil/diagnose.sh os-info -
85dump-env soil/diagnose.sh dump-env -
86wedge-deps build/deps.sh wedge-deps-$distro -
87fetch build/deps.sh fetch -
88spec-bin build/deps.sh install-spec-bin-fast _build/wedge/logs/index.html
89EOF
90}
91
92dev-setup-debian-tasks() {
93 # (task_name, script, action, result_html)
94
95 dev-setup-for debian
96 #spec-bin-for debian
97}
98
99dev-setup-fedora-tasks() {
100 # (task_name, script, action, result_html)
101
102 dev-setup-for fedora
103}
104
105dev-setup-alpine-tasks() {
106 # (task_name, script, action, result_html)
107
108 dev-setup-for alpine
109 #spec-bin-for alpine
110}
111
112pea-tasks() {
113 ### Print tasks for the 'pea' build
114
115 # We need a later version of Python 3 / MyPy both to type check and
116 # to parse
117
118 # Run py-source so we can type check generated code
119 # We need to type check more than we translate
120
121 # (task_name, script, action, result_html)
122 cat <<EOF
123os-info soil/diagnose.sh os-info -
124dump-env soil/diagnose.sh dump-env -
125py-source build/py.sh py-source -
126check-types pea/TEST.sh check-types -
127run-tests pea/TEST.sh run-tests -
128parse-all pea/TEST.sh parse-all -
129EOF
130}
131
132dev-minimal-tasks() {
133 ### Print tasks for the 'dev-minimal' build
134
135 # repo overview is suggested by README.md
136
137 # (task_name, script, action, result_html)
138 cat <<EOF
139os-info soil/diagnose.sh os-info -
140dump-env soil/diagnose.sh dump-env -
141build-minimal build/py.sh minimal -
142repo-overview metrics/source-code.sh overview -
143lint test/lint.sh soil-run -
144asdl-types asdl/TEST.sh check-types -
145oil-types devtools/types.sh soil-run -
146unit test/unit.sh minimal _test/py-unit/
147lossless test/lossless.sh soil-run -
148parse-errors test/parse-errors.sh soil-run-py -
149runtime-errors test/runtime-errors.sh soil-run-py -
150ysh-parse-errors test/ysh-parse-errors.sh soil-run-py -
151ysh-runtime-errors test/ysh-runtime-errors.sh soil-run-py -
152ysh-every-string test/ysh-every-string.sh soil-run-py -
153ysh-large ysh/run.sh soil-run -
154j8-errors data_lang/j8-errors.sh soil-run-py -
155link-busybox-ash test/spec-bin.sh link-busybox-ash -
156osh-minimal test/spec-py.sh osh-minimal _tmp/spec/osh-minimal/index.html
157headless client/run.sh soil-run-py -
158EOF
159}
160
161interactive-tasks() {
162 ### Print tasks for the 'interactive' build
163
164 # TODO: also run interactive suite with osh-cpp
165
166# TODO: Why does the needs-terminal suite hang in Docker? It doesn't hang in an interactive Docker session.
167#
168# needs-terminal test/spec-py.sh needs-terminal-all _tmp/spec/needs-terminal-py/index.html
169#
170# https://oilshell.zulipchat.com/#narrow/stream/121539-oil-dev/topic/Spec.20Tests.20for.20Interactive.20Parsing
171
172 cat <<EOF
173os-info soil/diagnose.sh os-info -
174dump-env soil/diagnose.sh dump-env -
175py-all-and-ninja soil/worker.sh py-all-and-ninja -
176interactive-osh test/spec-py.sh interactive-osh _tmp/spec/interactive-osh/index.html
177nohup test/nohup.sh soil-run -
178process-table test/process-table.sh soil-run _tmp/process-table/index.html
179stateful test/stateful.sh soil-run _tmp/spec/stateful/index.html
180EOF
181
182}
183
184wild-tasks() {
185 ### Print tasks for the 'wild' build
186
187 # (task_name, script, action, result_html)
188 cat <<EOF
189os-info soil/diagnose.sh os-info -
190dump-env soil/diagnose.sh dump-env -
191wait-for-tarball soil/wait.sh for-cpp-tarball -
192test-tar devtools/release-native.sh test-tar -
193linecount metrics/tarball.sh linecount-oils-cpp -
194wild test/wild.sh soil-run _tmp/wild-www/index.html
195EOF
196}
197
198benchmarks-tasks() {
199 # (task_name, script, action, result_html)
200
201 cat <<EOF
202os-info soil/diagnose.sh os-info -
203dump-env soil/diagnose.sh dump-env -
204py-all-and-ninja soil/worker.sh py-all-and-ninja -
205dev-shell-test build/dev-shell-test.sh soil-run -
206id-test benchmarks/id-test.sh soil-run -
207osh-parser benchmarks/osh-parser.sh soil-run _tmp/osh-parser/index.html
208osh-runtime benchmarks/osh-runtime.sh soil-run _tmp/osh-runtime/index.html
209vm-baseline benchmarks/vm-baseline.sh soil-run _tmp/vm-baseline/index.html
210compute benchmarks/compute.sh soil-run _tmp/compute/index.html
211gc benchmarks/gc.sh soil-run _tmp/gc/index.html
212mycpp-benchmarks benchmarks/mycpp.sh soil-run _tmp/mycpp-examples/-wwz-index
213EOF
214}
215
216bloaty-tasks() {
217 cat <<EOF
218os-info soil/diagnose.sh os-info -
219dump-env soil/diagnose.sh dump-env -
220wait-for-tarball soil/wait.sh for-cpp-tarball -
221test-tar devtools/release-native.sh test-tar -
222native-code metrics/native-code.sh oils-for-unix _tmp/metrics/oils-for-unix/
223EOF
224}
225
226benchmarks2-tasks() {
227 # Note: id-test doesn't run in 'other-tests' because 'gawk' isn't in that image
228 cat <<EOF
229os-info soil/diagnose.sh os-info -
230dump-env soil/diagnose.sh dump-env -
231wait-for-tarball soil/wait.sh for-cpp-tarball -
232test-tar devtools/release-native.sh test-tar -
233gc-cachegrind benchmarks/gc-cachegrind.sh soil-run _tmp/gc-cachegrind/index.html
234EOF
235# TODO: uftrace wedge with debian-12
236#uftrace benchmarks/uftrace.sh soil-run _tmp/uftrace/index.html
237}
238
239cpp-spec-tasks() {
240 # (task_name, script, action, result_html)
241
242 cat <<EOF
243os-info soil/diagnose.sh os-info -
244dump-env soil/diagnose.sh dump-env -
245py-all-and-ninja soil/worker.sh py-all-and-ninja -
246oils-cpp-smoke build/native.sh soil-run -
247osh-all test/spec-cpp.sh osh-all _tmp/spec/osh-cpp/compare.html
248ysh-all test/spec-cpp.sh ysh-all _tmp/spec/ysh-cpp/compare.html
249ysh-py test/spec-py.sh ysh-all-serial _tmp/spec/ysh-py/index.html
250EOF
251}
252
253cpp-tarball-tasks() {
254
255 # Note: build-times task requires _build/oils.sh
256 # It's a bit redundant with test-tar
257
258 cat <<EOF
259os-info soil/diagnose.sh os-info -
260dump-env soil/diagnose.sh dump-env -
261py-all-and-ninja soil/worker.sh py-all-and-ninja -
262oils-cpp-smoke build/native.sh soil-run -
263make-tar devtools/release-native.sh make-tar _release/oils-for-unix.tar
264xshar-hello devtools/xshar.sh soil-run-hello _release/hello-xshar.xshar
265xshar-test-oils devtools/xshar.sh soil-run-test-oils _release/test-oils.xshar
266build-times build/native.sh measure-build-times -
267EOF
268
269# build-times is a good enough test
270# test-tar devtools/release-native.sh test-tar -
271#
272# Note: tarball is deployed outside the container
273
274}
275
276cpp-small-tasks() {
277
278 # yaks could be moved to pea/ image once it has python2-dev
279 cat <<EOF
280os-info soil/diagnose.sh os-info -
281dump-env soil/diagnose.sh dump-env -
282py-all-and-ninja soil/worker.sh py-all-and-ninja -
283py-unit test/unit.sh all _test/py-unit/
284yaks yaks/TEST.sh soil-run -
285oils-cpp-smoke build/native.sh soil-run -
286cpp-unit test/cpp-unit.sh soil-run _test/-wwz-index
287headless client/run.sh soil-run-cpp -
288asan test/asan.sh soil-run -
289ltrace test/ltrace.sh soil-run -
290micro-syntax doctools/micro-syntax.sh soil-run -
291src-tree doctools/src-tree.sh soil-run _tmp/src-tree-www/index.html
292line-counts metrics/source-code.sh write-reports _tmp/metrics/line-counts/-wwz-index
293preprocessed metrics/source-code.sh preprocessed _tmp/metrics/preprocessed/-wwz-index
294mycpp-examples mycpp/TEST.sh soil-run _test/-wwz-index
295parse-errors test/parse-errors.sh soil-run-cpp -
296runtime-errors test/runtime-errors.sh soil-run-cpp -
297ysh-parse-errors test/ysh-parse-errors.sh soil-run-cpp -
298ysh-runtime-errors test/ysh-runtime-errors.sh soil-run-cpp -
299ysh-every-string test/ysh-every-string.sh soil-run-cpp -
300ysh-large ysh/run.sh soil-run-cpp -
301j8-errors data_lang/j8-errors.sh soil-run-cpp -
302houston-fp demo/houston-fp/run.sh soil-run -
303souffle-smoke-test test/souffle-smoke.sh soil-run -
304EOF
305}
306
307cpp-coverage-tasks() {
308 # dep notes: hnode_asdl.h required by expr_asdl.h in mycpp/examples
309
310 cat <<EOF
311os-info soil/diagnose.sh os-info -
312dump-env soil/diagnose.sh dump-env -
313py-all-and-ninja soil/worker.sh py-all-and-ninja -
314extract-clang deps/from-binary.sh extract-clang-in-container -
315mycpp-unit-coverage mycpp/TEST.sh unit-test-coverage _test/clang-coverage/mycpp/html/index.html
316mycpp-examples-coverage mycpp/TEST.sh examples-coverage _test/clang-coverage/mycpp/examples/html/index.html
317cpp-coverage cpp/TEST.sh coverage _test/clang-coverage/cpp/html/index.html
318unified-coverage test/coverage.sh unified-report _test/clang-coverage/unified/html/index.html
319compare-gcc-clang metrics/native-code.sh compare-gcc-clang _tmp/metrics/compare-gcc-clang.txt
320EOF
321}
322
323ovm-tarball-tasks() {
324 ### Print tasks for the 'ovm-tarball' build
325
326 # notes:
327 # - py-all needed to crawl dependencies to make tarball.
328
329 # (task_name, script, action, result_html)
330 cat <<EOF
331os-info soil/diagnose.sh os-info -
332dump-env soil/diagnose.sh dump-env -
333py-all build/py.sh all -
334syscall-by-code test/syscall.sh by-code _tmp/syscall/by-code.txt
335syscall-by-input test/syscall.sh by-input _tmp/syscall/by-input.txt
336osh-spec test/spec-py.sh osh-all-serial _tmp/spec/osh-py/index.html
337gold test/gold.sh soil-run -
338osh-usage test/osh-usage.sh soil-run -
339tools-deps test/tools-deps.sh soil-run -
340make-tarball devtools/release.sh py-tarball _release/oil.tar
341ysh-ovm-tarball test/spec-py.sh ysh-ovm-tarball _tmp/spec/ysh-py/index.html
342docs build/doc.sh soil-run _release/VERSION/index.html
343doc-metrics echo no-op _release/VERSION/doc/metrics.txt
344EOF
345
346# doc-metrics is a no-op, just for the link. Because soil-run just runs the
347# release, which creates metrics.
348}
349
350# Reuse ovm-tarball container
351app-tests-tasks() {
352
353 cat <<EOF
354os-info soil/diagnose.sh os-info -
355dump-env soil/diagnose.sh dump-env -
356py-all build/py.sh all -
357ble-clone test/ble.sh clone -
358ble-build test/ble.sh build -
359ble-bash-suite test/ble.sh bash-suite -
360ble-test-osh-py test/ble.sh run-tests-osh-py -
361wait-for-tarball soil/wait.sh for-cpp-tarball -
362test-tar devtools/release-native.sh test-tar -
363ble-test-osh-cpp test/ble.sh run-tests-osh-cpp -
364EOF
365
366# This doesn't work
367# ble-test-osh-bash test/ble.sh run-tests-osh-bash -
368}
369
370# TODO: Most of these should be Ninja tasks.
371# Other tests:
372# find-test, xargs-test, pgen2-test, web/table/csv2html-test.sh
373# Probably should start using a shell test framework too.
374other-tests-tasks() {
375 cat <<EOF
376os-info soil/diagnose.sh os-info -
377dump-env soil/diagnose.sh dump-env -
378build-minimal build/py.sh minimal -
379configure-test ./configure-test.sh soil_run -
380time-test benchmarks/time-test.sh soil-run -
381tsv-lib-test test/tsv-lib-test.sh soil-run -
382ysh-ify test/ysh-ify.sh soil-run -
383R-test devtools/R-test.sh soil-run -
384xargs-test test/other.sh xargs-test -
385csv2html-test test/other.sh csv2html-test -
386oil-python-symbols metrics/source-code.sh oil-python-symbols -
387opyc test/opyc.sh soil-run -
388opy-count-lines opy/soil.sh count-lines -
389test-gold opy/soil.sh test-gold -
390build-oil-repo opy/soil.sh build-oil-repo -
391regtest-compile opy/soil.sh regtest-compile -
392EOF
393}
394
395tests-todo() {
396 ### More tests to add
397 find . -name '_*' -a -prune -o -name '*-test.sh' -a -print
398
399 # pgen2/pgen2-test.sh seems mostly broken
400}
401
402# Redefinition for quicker cloud debugging
403maybe-merge-tasks() {
404 cat <<EOF
405os-info soil/diagnose.sh os-info -
406dump-env soil/diagnose.sh dump-env -
407maybe-merge soil/maybe-merge.sh soil-run -
408EOF
409}
410
411run-tasks() {
412 ### Run the tasks on stdin and write _tmp/soil/INDEX.tsv.
413 local job_name=$1
414 local out_dir=$2 # should already exist
415 local tty=$3
416
417 mkdir -p $out_dir/logs
418
419 # So we can run benchmarks/time_.py.
420 # 2023-02-28: Images like soil-wild based off the new soil-common no longer
421 # have 'cc'. Instead they use a wedge.
422 if command -v cc > /dev/null; then
423 build/py.sh time-helper
424 else
425 echo 'test time-tsv3'
426 time-tsv3 -o /tmp/echo.tsv --append -- echo hi
427
428 echo '/tmp/echo.tsv:'
429 cat /tmp/echo.tsv
430 fi
431
432 # For the later deploy step to pick up
433 date +%s > $out_dir/task-run-start-time.txt
434
435 # This data can go on the dashboard index
436 local tsv=$out_dir/INDEX.tsv
437 rm -f $tsv
438
439 local status
440 local max_status=0
441
442 while read task_name script action result_html; do
443 log "--- task: $task_name ---"
444
445 local log_path=$out_dir/logs/$task_name.txt
446
447 # 15 minutes per task
448 # One of the longest tasks is test/spec-cpp, which takes around 420 seconds
449 # TODO: should have a configurable timeout
450 local -a timeout=(timeout 900)
451 local stdin_tty=''
452
453 case $script in
454 test/process-table.sh)
455 # Workaround for weird interaction, see
456 # $ test/process-table.sh timeout-issue
457 timeout=()
458 ;;
459 test/nohup.sh)
460 # Only run test/nohup.sh with TTY. For some reason build/py.sh all hangs
461 # with $tty?
462 stdin_tty=$tty
463 ;;
464 esac
465
466 local -a argv=(
467 time-tsv3 -o $tsv --append
468 --field $task_name --field $script --field $action
469 --field $result_html --
470 "${timeout[@]}" "$script" "$action"
471 )
472
473 # Run task and save status
474 set +o errexit
475 if test -n "$stdin_tty"; then
476 # explicitly connect TTY, e.g. for soil/interactive
477 "${argv[@]}" > $log_path 2>&1 < $stdin_tty
478 else
479 "${argv[@]}" > $log_path 2>&1
480 fi
481 status=$?
482 set -o errexit
483
484 if test "$status" -gt "$max_status"; then
485 max_status=$status
486 fi
487
488 # Show the last line
489 echo
490 tsv-row status elapsed task script action result_html
491 tail -n 1 $tsv
492 echo
493 log "status=$status max_status=$max_status"
494 done
495
496 log '--- done ---'
497 ls -l $out_dir
498 wc -l $out_dir/logs/*
499
500 # This suppressed the deployment of logs, which we don't want. So all our
501 # Travis builds succeed? But then we can't use their failure notifications
502 # (which might be OK).
503 if false; then
504 # exit with the maximum exit code.
505 awk '
506 BEGIN { max = 0 }
507 { if ($1 > max) { max = $1 } }
508 END { exit(max) }
509 ' $tsv
510 fi
511
512 # To fail later. Important: this dir persists across jobs; it's NOT removed
513 # by 'host-shim.sh job-reset'.
514 mkdir -p _soil-jobs
515
516 # Hack: Assign job_id and write it to the status file. Other jobs can poll
517 # for completion of this job and access its resources.
518
519 local job_id
520 job_id="$(date +%Y-%m-%d__%H-%M-%S)"
521
522 # e.g. _soil-jobs/dummy.status.txt
523 echo "$max_status $job_id" > _soil-jobs/$job_name.status.txt
524}
525
526save-metadata() {
527 ### Write metadata files to be saved as JSON
528
529 # NOTE: host-shim.sh also writes image-pull-time.txt
530
531 local job_name=$1
532 local meta_dir=$2
533
534 echo "$job_name" > $meta_dir/job-name.txt
535
536 # command to show current branch
537 # This does NOT work in detached HEAD! Travis puts the branch in an env
538 # variable, but sr.ht doesn't.
539 # git rev-parse --abbrev-ref HEAD > $meta_dir/git-branch.txt
540
541 git log -n 1 --pretty='format:%H' > $meta_dir/commit-hash.txt
542
543 # ISO 8601 format
544 # Note: this can get confused with rebases. Two different commits can have
545 # the same date.
546 git log -n 1 --pretty='format:%aI' > $meta_dir/commit-date.txt
547
548 git log -n 1 --pretty='format:%s' > $meta_dir/commit-line.txt # "subject"
549}
550
551disable-git-errors() {
552
553 # 2023-02: The build started failing because of the permissions we set in
554 # soil/host-shim.sh mount-perms.
555 #
556 # The issue is that the guest needs to be able to write to the Docker mount
557 # of the repo. I think it may have been related to podman vs. Docker.
558 # Should check if mount-perms is necessary in both places.
559 #
560 # git fails unless we have this workaround.
561
562 # https://stackoverflow.com/questions/72978485/git-submodule-update-failed-with-fatal-detected-dubious-ownership-in-repositor
563
564 # https://github.blog/2022-04-12-git-security-vulnerability-announced/
565
566 #git config --global --add safe.directory '*'
567
568 git config --global --add safe.directory /home/uke/oil
569}
570
571job-main() {
572 local job_name=$1
573
574 local out_dir=_tmp/soil
575
576 # Report for debugging
577 export EXTRA_MYCPP_ARGS='--stack-roots-warn 16'
578
579 log-context 'job-main'
580 mkdir -v -p $out_dir
581 ls -l -d $out_dir
582
583 disable-git-errors
584
585 save-metadata $job_name $out_dir
586
587 local captured
588
589 set +o errexit
590 captured=$(tty)
591 status=$?
592 set -o errexit
593
594 if test $status -eq 0; then
595 echo "TTY = $captured"
596 local tty=$captured
597 else
598 echo "captured = $captured"
599 local tty='' # clear the output
600 fi
601 echo
602
603 ${job_name}-tasks | run-tasks $job_name $out_dir "$tty"
604}
605
606JOB-dummy() { job-main 'dummy'; }
607JOB-raw-vm() { job-main 'raw-vm'; }
608JOB-dev-setup-debian() { job-main 'dev-setup-debian'; }
609JOB-dev-setup-fedora() { job-main 'dev-setup-fedora'; }
610JOB-dev-setup-alpine() { job-main 'dev-setup-alpine'; }
611
612JOB-dev-minimal() { job-main 'dev-minimal'; }
613JOB-interactive() { job-main 'interactive'; }
614
615JOB-other-tests() { job-main 'other-tests'; }
616
617JOB-pea() { job-main 'pea'; }
618
619JOB-ovm-tarball() { job-main 'ovm-tarball'; }
620JOB-app-tests() { job-main 'app-tests'; }
621
622JOB-cpp-coverage() { job-main 'cpp-coverage'; }
623JOB-cpp-small() { job-main 'cpp-small'; }
624JOB-cpp-tarball() { job-main 'cpp-tarball'; }
625JOB-cpp-spec() { job-main 'cpp-spec'; }
626
627JOB-bloaty() { job-main 'bloaty'; }
628JOB-benchmarks() { job-main 'benchmarks'; }
629JOB-benchmarks2() { job-main 'benchmarks2'; }
630
631JOB-wild() { job-main 'wild'; }
632
633JOB-maybe-merge() { job-main 'maybe-merge'; }
634
635list-jobs() {
636 # dev-setup-fedora for Fedora, disable
637 compgen -A function | grep -- '^JOB-' | sed 's/^JOB-//g' | egrep -v 'maybe-merge|dev-setup-fedora|dev-setup-alpine'
638}
639
640"$@"