ci/linux_ci.vsh
Rama master · réplica de lectura del repositorio original.
import common { Task, exec_args }
import crypto.sha256
import os
// Shared tasks/helpers
fn all_code_is_formatted() {
if common.is_github_job {
exec_args(['v', '-silent', 'test-cleancode'])
} else {
exec_args(['v', '-progress', 'test-cleancode'])
}
}
fn verify_v_test_works() {
println(os.getenv('VFLAGS'))
exec_args(['v', 'cmd/tools/test_if_v_test_system_works.v'])
exec_args(['./cmd/tools/test_if_v_test_system_works'])
}
fn test_pure_v_math_module() {
exec_args(['v', '-d', 'pure_v_math', '-exclude', '@vlib/math/*.c.v', 'test', 'vlib/math/'])
}
fn self_tests() {
// Never select the V1 compatibility compiler here. It is a separate V 0.5.2
// installation, so `test-self vlib` would resolve `vlib` under *its* VROOT and
// test the release's own standard library instead of this repository's.
if common.is_github_job {
exec_args(['v', '-W', '-silent', 'test-self', 'vlib'])
} else {
exec_args(['v', '-progress', 'test-self', 'vlib'])
}
}
fn build_examples() {
if common.is_github_job {
// The exhaustive CI matrix includes a few deliberately large examples.
// Keep the user-facing V3 memory guard while allowing CI to validate them.
exec_args(['v', '-no-memory-limit', '-W', 'build-examples'])
} else {
exec_args(['v', '-progress', 'build-examples'])
}
}
fn v_doctor() {
exec_args(['v', 'doctor'])
}
fn build_v_with_prealloc() {
exec_args(['v', '-cg', '-cstrict', '-o', 'vstrict1', 'cmd/v'])
// -prealloc uses _Thread_local for g_memory_block; bundled tcc does not support it.
prealloc_cc_flag := if os.getenv('VFLAGS').contains('-cc tcc') { ' -cc cc' } else { '' }
exec_args(['./vstrict1', ...(os.split_args(prealloc_cc_flag) or { panic(err) }), '-o', 'vprealloc',
'-prealloc', 'cmd/v'])
exec_args(['./vprealloc', 'run', 'examples/hello_world.v'])
exec_args(['./vprealloc', '-o', 'v3', 'cmd/v'])
exec_args(['./v3', '-o', 'v4', 'cmd/v'])
exec_args(['./v4', '-d', 'debug_malloc', '-d', 'debug_realloc', '-o', 'vdebug1', 'cmd/v'])
}
// TCC job tasks
fn install_dependencies_for_examples_and_tools_tcc() {
if common.is_github_job && os.exists('/etc/apt/apt-mirrors.txt') {
exec_args(['.github/workflows/disable_azure_mirror.sh'])
}
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'update'])
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libssl-dev', 'sqlite3',
'libsqlite3-dev', 'valgrind', 'nodejs'])
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libfreetype6-dev',
'libxi-dev', 'libxcursor-dev', 'libgl-dev', 'libxrandr-dev', 'libasound2-dev', 'libegl-dev',
'libx11-xcb-dev'])
// Wayland development libraries for sokol Wayland support
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libwayland-dev',
'libxkbcommon-dev', 'libwayland-egl1', 'libxkbcommon-x11-dev'])
// The following is needed for examples/c_interop_wkhtmltopdf.v.
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'xfonts-75dpi',
'xfonts-base', 'expect'])
exec_args(['v', 'retry', '--', 'sh', 'ci/install_wkhtmltox.sh'])
}
fn test_v_to_c_tcc() {
exec_args(['thirdparty/tcc/tcc.exe', '-version'])
exec_args(['v', '-cg', '-o', 'vtcc', 'cmd/v']) // ensure vtcc can build itself twice
}
fn v_self_compilation_tcc() {
exec_args(['v', '-o', 'v2', 'cmd/v'])
exec_args(['./v2', '-o', 'v3', 'cmd/v'])
exec_args(['./v3', '-o', 'v4', 'cmd/v'])
}
fn v_doctor_tcc() {
v_doctor()
}
fn verify_v_test_works_tcc() {
verify_v_test_works()
}
fn test_pure_v_math_module_tcc() {
test_pure_v_math_module()
}
fn self_tests_tcc() {
exec_args(['v', '-keepc', '-cc', 'tcc', '-g', 'self'])
self_tests()
}
fn self_tests_vprod_tcc() {
// Keep the optimized test compiler while still checking a TCC debug self-build.
exec_args(['v', '-keepc', '-cc', 'tcc', '-g', '-o', 'v_tcc_debug', 'self'])
exec_args(['./v_tcc_debug', 'run', 'examples/hello_world.v'])
// Emit a separate result line for every file instead of hiding successes.
exec_args(['v', '-W', 'test-self', 'vlib'])
}
fn build_examples_tcc() {
build_examples()
}
fn run_submodule_example_tcc() {
exec_args(['v', '-W', 'run', 'examples/submodule'])
}
fn build_tools_tcc() {
if common.is_github_job {
exec_args(['v', '-N', '-W', 'build-tools'])
} else {
exec_args(['v', '-progress', '-N', '-W', 'build-tools'])
}
}
fn build_vbinaries_tcc() {
exec_args(['v', '-N', '-W', 'build-vbinaries'])
}
fn build_benches_tcc() {
exec_args(['v', 'should-compile-all', 'vlib/v/tests/bench/'])
}
fn run_vsh_script_tcc() {
exec_args(['v', 'run', 'examples/v_script.vsh'])
}
fn test_v_tutorials_tcc() {
exec_args(['v', 'tutorials/building_a_simple_web_blog_with_veb/code/blog'])
}
fn build_fast_tcc() {
os.chdir('cmd/tools/fast') or { panic(err) }
exec_args(['v', '-o', 'fast', '.'])
os.chdir('../../..') or { panic(err) }
os.chdir('cmd/tools/fast') or { panic(err) }
exec_args(['./fast', 'help'])
os.chdir('../../..') or { panic(err) }
}
fn v_self_compilation_usecache_tcc() {
$if !enable_usecache_test ? {
eprintln('> ${@LOCATION} use `-d enable_usecache_test` in VFLAGS to enable this task')
return
}
exec_args(['v', 'wipe-cache'])
exec_args(['v', 'examples/hello_world.v'])
exec_args(['./examples/hello_world'])
exec_args(['v', 'wipe-cache'])
exec_args(['v', '-o', 'v2', 'cmd/v'])
exec_args(['./v2', '-o', 'v3', 'cmd/v'])
exec_args(['./v3', 'version'])
exec_args(['v', 'wipe-cache'])
exec_args(['./v3', '-o', 'tetris', 'examples/tetris/tetris.v'])
exec_args(['rm', '-f', './examples/hello_world', 'v2', 'v3', 'tetris'])
}
fn test_password_input_tcc() {
exec_args(['v', 'test', 'examples/password/'])
}
fn test_readline_tcc() {
exec_args(['v', 'test', 'examples/readline/'])
}
fn test_leak_detector_tcc() {
exec_args(['v', '-gc', 'boehm_leak', '-o', 'testcase_leak', 'vlib/v/tests/testcase_leak.vv'])
exec_args(['sh', '-c', './testcase_leak 2>leaks.txt'])
exec_args(['grep', 'Found 1 leaked object', 'leaks.txt'])
exec_args(['grep', '-P', ', sz=\\s?1000,', 'leaks.txt'])
}
fn test_leak_detector_not_active_tcc() {
exec_args(['v', '-o', 'testcase_leak', 'vlib/v/tests/testcase_leak.vv'])
exec_args(['sh', '-c', './testcase_leak 2>leaks.txt'])
assert os.file_size('leaks.txt') == 0, os.read_file('leaks.txt') or { err.msg() }
}
// GCC job tasks
fn all_code_is_formatted_gcc() {
all_code_is_formatted()
}
fn install_dependencies_for_examples_and_tools_gcc() {
if common.is_github_job && os.exists('/etc/apt/apt-mirrors.txt') {
exec_args(['.github/workflows/disable_azure_mirror.sh'])
}
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'update'])
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'postgresql', 'libpq-dev',
'libssl-dev', 'sqlite3', 'libsqlite3-dev', 'valgrind', 'nodejs'])
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libfreetype6-dev',
'libxi-dev', 'libxcursor-dev', 'libgl-dev', 'libxrandr-dev', 'libasound2-dev'])
// Wayland development libraries for sokol Wayland support
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libwayland-dev',
'libxkbcommon-dev', 'libwayland-egl1', 'libxkbcommon-x11-dev', 'wayland-protocols', 'libegl-dev'])
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libx11-dev',
'libx11-xcb-dev', 'libgl1-mesa-dri', 'xauth', 'xvfb'])
}
fn recompile_v_with_cstrict_gcc() {
exec_args(['v', '-cc', 'gcc', '-cg', '-cstrict', '-o', 'vstrict', 'cmd/v'])
}
fn valgrind_v_c_gcc() {
exec_args(['valgrind', '--error-exitcode=1', 'v', '-o', 'v.c', 'cmd/v'])
}
fn run_sanitizers_gcc() {
exec_args(['v', '-o', 'v2', 'cmd/v', '-cflags', '-fsanitize=thread'])
exec_args(['v', '-o', 'v3', 'cmd/v', '-cflags', '-fsanitize=undefined -fno-sanitize=alignment'])
exec_args(['env', 'UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1', './v2', '-o', 'v.c',
'cmd/v'])
exec_args(['env', 'UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1', './v3', '-o', 'v.c',
'cmd/v'])
}
fn v_self_compilation_gcc() {
exec_args(['v', '-o', 'v2', 'cmd/v'])
exec_args(['./v2', '-o', 'v3', 'cmd/v'])
exec_args(['./v3', '-o', 'v4', 'cmd/v'])
}
fn v_self_compilation_usecache_gcc() {
$if !enable_usecache_test ? {
eprintln('> ${@LOCATION} use `-d enable_usecache_test` in VFLAGS to enable this task')
return
}
exec_args(['v', 'wipe-cache'])
exec_args(['v', 'examples/hello_world.v'])
exec_args(['examples/hello_world'])
exec_args(['v', 'wipe-cache'])
exec_args(['v', '-o', 'v2', 'cmd/v'])
exec_args(['./v2', '-o', 'v3', 'cmd/v'])
exec_args(['./v3', 'version'])
exec_args(['v', 'wipe-cache'])
exec_args(['./v3', '-o', 'tetris', 'examples/tetris/tetris.v'])
exec_args(['rm', '-f', './examples/hello_world', 'v2', 'v3', 'tetris'])
}
fn verify_v_test_works_gcc() {
verify_v_test_works()
}
fn test_pure_v_math_module_gcc() {
test_pure_v_math_module()
}
fn self_tests_gcc() {
self_tests()
}
fn self_tests_prod_gcc() {
exec_args(['v', '-o', 'vprod', '-prod', 'cmd/v'])
exec_args(['./vprod', '-silent', 'test-self', 'vlib'])
}
fn self_tests_cstrict_gcc() {
exec_args(['env', 'VTEST_JUST_ESSENTIAL=1', 'V_CI_CSTRICT=1', 'v', '-cc', 'gcc', '-cstrict',
'-silent', 'test-self', 'vlib'])
}
fn skip_ownership_autofree_test() bool {
return common.is_github_job || os.getenv('VTEST_SKIP_OWNERSHIP') == '1'
}
fn report_skipped_ownership_autofree_test() {
eprintln('> skipping ownership/autofree test')
}
fn build_examples_gcc() {
build_examples()
}
fn build_tetris_autofree_gcc() {
if skip_ownership_autofree_test() {
report_skipped_ownership_autofree_test()
return
}
exec_args(['v', '-autofree', '-o', 'tetris', 'examples/tetris/tetris.v'])
exec_args(['rm', '-f', 'tetris'])
}
fn build_blog_autofree_gcc() {
if skip_ownership_autofree_test() {
report_skipped_ownership_autofree_test()
return
}
exec_args(['v', '-autofree', '-o', 'blog', 'tutorials/building_a_simple_web_blog_with_veb/code/blog'])
exec_args(['rm', '-f', 'blog'])
}
fn build_option_test_autofree_gcc() {
if skip_ownership_autofree_test() {
report_skipped_ownership_autofree_test()
return
}
exec_args(['v', '-autofree', 'vlib/v/tests/options/option_test.c.v'])
}
fn v_self_compilation_parallel_cc_gcc() {
exec_args(['v', '-o', 'v2', '-parallel-cc', 'cmd/v'])
exec_args(['rm', '-f', 'v2'])
}
fn build_modules_gcc() {
exec_args(['v', 'build-module', 'vlib/os'])
exec_args(['v', 'build-module', 'vlib/builtin'])
exec_args(['v', 'build-module', 'vlib/strconv'])
exec_args(['v', 'build-module', 'vlib/time'])
exec_args(['v', 'build-module', 'vlib/term'])
exec_args(['v', 'build-module', 'vlib/math'])
exec_args(['v', 'build-module', 'vlib/strings'])
exec_args(['v', 'build-module', 'vlib/v/token'])
exec_args(['v', 'build-module', 'vlib/v/parser'])
exec_args(['v', 'build-module', 'vlib/v/gen/c'])
exec_args(['v', 'build-module', 'vlib/os/cmdline'])
}
fn compile_vdoctor_prod_gcc() {
exec_args(['v', '-showcc', '-cc', 'gcc', '-prod', 'cmd/tools/vdoctor.v'])
}
fn compile_vup_prod_gcc() {
exec_args(['v', '-showcc', '-cc', 'gcc', '-prod', 'cmd/tools/vup.v'])
}
// Clang job tasks
fn all_code_is_formatted_clang() {
all_code_is_formatted()
}
fn install_dependencies_for_examples_and_tools_clang() {
if common.is_github_job && os.exists('/etc/apt/apt-mirrors.txt') {
exec_args(['.github/workflows/disable_azure_mirror.sh'])
}
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'update'])
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'postgresql', 'libpq-dev',
'libssl-dev', 'sqlite3', 'libsqlite3-dev', 'valgrind', 'nodejs'])
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libfreetype6-dev',
'libxi-dev', 'libxcursor-dev', 'libgl-dev', 'libxrandr-dev', 'libasound2-dev'])
// Wayland development libraries for sokol Wayland support
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libwayland-dev',
'libxkbcommon-dev', 'libwayland-egl1', 'libxkbcommon-x11-dev', 'wayland-protocols', 'libegl-dev'])
exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'clang', 'libx11-xcb-dev'])
}
fn recompile_v_with_cstrict_clang() {
exec_args(['v', '-cc', 'clang', '-cg', '-cstrict', '-o', 'vstrict', 'cmd/v'])
exec_args(['rm', '-f', 'vstrict'])
}
fn valgrind_clang() {
exec_args(['valgrind', '--error-exitcode=1', 'v', '-o', 'v.c', 'cmd/v'])
exec_args(['rm', '-f', 'v.c'])
}
fn run_sanitizers_clang() {
exec_args(['.github/workflows/run_sanitizers.sh'])
}
fn v_self_compilation_clang() {
exec_args(['v', '-o', 'v2', 'cmd/v'])
exec_args(['./v2', '-o', 'v3', 'cmd/v'])
exec_args(['./v3', '-o', 'v4', 'cmd/v'])
}
fn v_self_compilation_usecache_clang() {
$if !enable_usecache_test ? {
eprintln('> ${@LOCATION} use `-d enable_usecache_test` in VFLAGS to enable this task')
return
}
exec_args(['v', 'wipe-cache'])
exec_args(['v', 'examples/hello_world.v'])
exec_args(['./examples/hello_world'])
exec_args(['v', 'wipe-cache'])
exec_args(['v', '-o', 'v2', 'cmd/v'])
exec_args(['./v2', '-o', 'v3', 'cmd/v'])
exec_args(['./v3', 'version'])
exec_args(['v', 'wipe-cache'])
exec_args(['./v3', '-o', 'tetris', 'examples/tetris/tetris.v'])
exec_args(['rm', '-f', './examples/hello_world', 'v2', 'v3', 'tetris'])
}
fn verify_v_test_works_clang() {
verify_v_test_works()
}
fn test_pure_v_math_module_clang() {
test_pure_v_math_module()
}
fn self_tests_clang() {
self_tests()
}
fn self_tests_vprod_clang() {
exec_args(['v', '-o', 'vprod', '-prod', 'cmd/v'])
exec_args(['./vprod', '-silent', 'test-self', 'vlib'])
}
fn self_tests_cstrict_clang() {
exec_args(['env', 'VTEST_JUST_ESSENTIAL=1', 'V_CI_CSTRICT=1', './vprod', '-cstrict', '-silent',
'test-self', 'vlib'])
}
fn build_examples_clang() {
build_examples()
}
fn build_examples_autofree_clang() {
if skip_ownership_autofree_test() {
report_skipped_ownership_autofree_test()
return
}
exec_args(['v', '-N', '-W', '-autofree', '-experimental', '-o', 'tetris', 'examples/tetris/tetris.v'])
exec_args(['rm', '-f', 'tetris'])
}
fn build_modules_clang() {
exec_args(['v', 'build-module', 'vlib/os'])
exec_args(['v', 'build-module', 'vlib/builtin'])
exec_args(['v', 'build-module', 'vlib/strconv'])
exec_args(['v', 'build-module', 'vlib/time'])
exec_args(['v', 'build-module', 'vlib/term'])
exec_args(['v', 'build-module', 'vlib/math'])
exec_args(['v', 'build-module', 'vlib/strings'])
exec_args(['v', 'build-module', 'vlib/v/token'])
exec_args(['v', 'build-module', 'vlib/v/parser'])
exec_args(['v', 'build-module', 'vlib/v/gen/c'])
exec_args(['v', 'build-module', 'vlib/os/cmdline'])
}
fn test_inline_assembly() {
exec_args(['v', 'test', 'vlib/v/slow_tests/assembly'])
}
// Keep this list in the same order as the active tasks in
// .github/workflows/linux_ci.yml. The aggregate runner changes compiler flags at
// the same boundaries as the three workflow jobs.
// Order is deliberate on both sides: the cheapest check that can prove a checkout
// broken runs first, and `build_v_with_prealloc`, which is five compiler builds,
// runs last so a red run reports the cheap signal before paying for it.
const ci_tasks = [
'all_code_is_formatted_tcc',
'install_dependencies_for_examples_and_tools_tcc',
'test_v_to_c_tcc',
'v_self_compilation_tcc',
'v_doctor_tcc',
'verify_v_test_works_tcc',
'test_pure_v_math_module_tcc',
'test_inline_assembly',
'self_tests_vprod_tcc',
'build_examples_tcc',
'run_submodule_example_tcc',
'build_tools_tcc',
'build_vbinaries_tcc',
'build_benches_tcc',
'run_vsh_script_tcc',
'test_v_tutorials_tcc',
'build_fast_tcc',
'v_self_compilation_usecache_tcc',
'test_password_input_tcc',
'test_readline_tcc',
'test_leak_detector_tcc',
'test_leak_detector_not_active_tcc',
'build_v_with_prealloc',
'all_code_is_formatted_gcc',
'install_dependencies_for_examples_and_tools_gcc',
'recompile_v_with_cstrict_gcc',
'valgrind_v_c_gcc',
'run_sanitizers_gcc',
'v_self_compilation_gcc',
'v_self_compilation_usecache_gcc',
'verify_v_test_works_gcc',
'test_pure_v_math_module_gcc',
'self_tests_gcc',
'self_tests_prod_gcc',
'self_tests_cstrict_gcc',
'build_examples_gcc',
'build_tetris_autofree_gcc',
'build_blog_autofree_gcc',
'build_option_test_autofree_gcc',
'v_self_compilation_parallel_cc_gcc',
'build_modules_gcc',
'compile_vdoctor_prod_gcc',
'compile_vup_prod_gcc',
'all_code_is_formatted_clang',
'install_dependencies_for_examples_and_tools_clang',
'recompile_v_with_cstrict_clang',
'valgrind_clang',
'run_sanitizers_clang',
'v_self_compilation_clang',
'v_self_compilation_usecache_clang',
'verify_v_test_works_clang',
'test_pure_v_math_module_clang',
'self_tests_clang',
'self_tests_vprod_clang',
'self_tests_cstrict_clang',
'build_examples_clang',
'build_examples_autofree_clang',
'build_modules_clang',
]
// Keep progress across edits/rebuilds, but isolate users and checkout directories.
fn ci_progress_path() string {
checkout := sha256.hexhash(os.real_path(os.getwd()))
return os.join_path(os.cache_dir(), 'v-linux-ci-${os.getuid()}-${checkout}.progress')
}
fn ci_progress_contents(task_name string) string {
// Record the whole ordered task list so changed plans restart safely.
return 'linux-ci-v1\n${task_name}\n${ci_tasks.join('\n')}\n'
}
fn ci_resume_index(path string) !int {
if !os.exists(path) {
return -1
}
if !os.is_file(path) {
return error('CI progress path is not a file: ${path}')
}
saved := os.read_file(path)!
for i, task_name in ci_tasks {
if saved == ci_progress_contents(task_name) {
return i
}
}
eprintln('Ignoring invalid or outdated CI progress; restarting from the first task.')
return -1
}
fn save_ci_progress(path string, task_name string) ! {
// Write privately, then rename on the same filesystem. An interrupted write
// leaves the previous checkpoint intact, never a partially written cursor.
if os.exists(path) && !os.is_file(path) {
return error('CI progress path is not a file: ${path}')
}
tmp_dir := '${path}.${os.getpid()}.tmp'
os.mkdir(tmp_dir, mode: 0o700)!
defer {
os.rmdir_all(tmp_dir) or {}
}
tmp_path := os.join_path(tmp_dir, 'progress')
os.write_file(tmp_path, ci_progress_contents(task_name))!
os.rename(tmp_path, path)!
}
fn ci_vflags(task_index int) string {
if task_index < ci_tasks.index('all_code_is_formatted_gcc') {
return '-cc tcc -no-retry-compilation'
}
if task_index < ci_tasks.index('all_code_is_formatted_clang') {
return '-cc gcc'
}
return '-cc clang'
}
// run_ci_tasks mirrors the active ci/linux_ci.vsh steps in
// .github/workflows/linux_ci.yml. The generic `all` mode intentionally remains
// exhaustive, including tasks that are currently disabled in the workflow.
fn run_ci_tasks(reset bool) ! {
// Match the GitHub Actions environment that changes test behavior.
os.setenv('CI', 'true', true)
os.setenv('GITHUB_ACTIONS', 'true', true)
os.setenv('RUNNER_OS', 'Linux', true)
os.setenv('V_MACOS_V3_NO_FALLBACK', '1', true)
// Stop test/build sessions promptly while retaining Linux CI's normal worker count.
os.setenv('VTEST_FAIL_FAST', '1', true)
os.setenv('VTEST_SHOW_LONGEST_BY_RUNTIME', '3', true)
os.setenv('VTEST_SHOW_LONGEST_BY_COMPTIME', '3', true)
os.setenv('VTEST_SHOW_LONGEST_BY_TOTALTIME', '3', true)
os.setenv('VTEST_SKIP_OWNERSHIP', '1', true)
progress_path := ci_progress_path()
progress_dir := '${progress_path}.d'
saved_index := if reset { -1 } else { ci_resume_index(progress_path)! }
// No valid cursor means none of its finer-grained records may be reused.
if saved_index < 0 && os.exists(progress_dir) {
os.rmdir_all(progress_dir)!
}
if !os.exists(progress_dir) {
os.mkdir(progress_dir, mode: 0o700)!
}
start := if saved_index < 0 { 0 } else { saved_index }
os.unsetenv('VTEST_RESUME_OWNER')
eprintln('CI progress: ${progress_path}')
eprintln('Use `v run ci/linux_ci.vsh ci --reset` to restart from the first task.')
if start > 0 {
eprintln('Resuming at ${ci_tasks[start]}; skipping ${start} completed CI tasks.')
}
for i in start .. ci_tasks.len {
task_name := ci_tasks[i]
// Save BEFORE execution: a failure or interruption must retry this task.
save_ci_progress(progress_path, task_name)!
os.setenv('V_CI_TASK_PROGRESS', os.join_path(progress_dir, task_name), true)
os.setenv('VFLAGS', ci_vflags(i), true)
if task_name.ends_with('_tcc') || task_name in ['build_v_with_prealloc', 'test_inline_assembly'] {
os.setenv('GITHUB_JOB', 'tcc-linux', true)
} else if task_name.ends_with('_gcc') {
os.setenv('GITHUB_JOB', 'gcc-linux', true)
} else {
os.setenv('GITHUB_JOB', 'clang-linux', true)
}
eprintln('CI task ${i + 1}/${ci_tasks.len}: ${task_name}')
exec_args(['v', 'run', 'ci/linux_ci.vsh', '${task_name}'])
}
os.rmdir_all(progress_dir)!
os.rm(progress_path)!
eprintln('CI tasks complete; progress cleared.')
}
// Collect all tasks
const all_tasks = {
'build_v_with_prealloc': Task{build_v_with_prealloc, 'Build V with prealloc'}
// tcc tasks
'all_code_is_formatted_tcc': Task{all_code_is_formatted, 'All code is formatted (tcc)'}
'install_dependencies_for_examples_and_tools_tcc': Task{install_dependencies_for_examples_and_tools_tcc, 'Install deps for examples/tools (tcc)'}
'test_v_to_c_tcc': Task{test_v_to_c_tcc, 'Test v->c with tcc'}
'v_self_compilation_tcc': Task{v_self_compilation_tcc, 'V self compilation (tcc)'}
'v_doctor_tcc': Task{v_doctor_tcc, 'v doctor (tcc)'}
'verify_v_test_works_tcc': Task{verify_v_test_works_tcc, 'Verify `v test` works (tcc)'}
'test_pure_v_math_module_tcc': Task{test_pure_v_math_module_tcc, 'Test pure V math module (tcc)'}
'self_tests_tcc': Task{self_tests_tcc, 'Self tests (tcc)'}
'self_tests_vprod_tcc': Task{self_tests_vprod_tcc, 'Self tests using the optimized compiler (tcc)'}
'build_examples_tcc': Task{build_examples_tcc, 'Build examples (tcc)'}
'run_submodule_example_tcc': Task{run_submodule_example_tcc, 'Run submodule example (tcc)'}
'build_tools_tcc': Task{build_tools_tcc, 'Build V tools (tcc)'}
'build_vbinaries_tcc': Task{build_vbinaries_tcc, 'Build V binaries (tcc)'}
'build_benches_tcc': Task{build_benches_tcc, 'Build benches (tcc)'}
'run_vsh_script_tcc': Task{run_vsh_script_tcc, 'Run a VSH script (tcc)'}
'test_v_tutorials_tcc': Task{test_v_tutorials_tcc, 'Test V tutorials (tcc)'}
'build_fast_tcc': Task{build_fast_tcc, 'Build cmd/tools/fast (tcc)'}
'v_self_compilation_usecache_tcc': Task{v_self_compilation_usecache_tcc, 'V self compilation with default caching (tcc)'}
'test_password_input_tcc': Task{test_password_input_tcc, 'Test password input (tcc)'}
'test_readline_tcc': Task{test_readline_tcc, 'Test readline (tcc)'}
'test_leak_detector_tcc': Task{test_leak_detector_tcc, 'Test leak detector (tcc)'}
'test_leak_detector_not_active_tcc': Task{test_leak_detector_not_active_tcc, 'Test leak detector not active (tcc)'}
// gcc tasks
'all_code_is_formatted_gcc': Task{all_code_is_formatted_gcc, 'All code is formatted (gcc)'}
'install_dependencies_for_examples_and_tools_gcc': Task{install_dependencies_for_examples_and_tools_gcc, 'Install deps for examples/tools (gcc)'}
'recompile_v_with_cstrict_gcc': Task{recompile_v_with_cstrict_gcc, 'Recompile V with -cstrict and gcc'}
'valgrind_v_c_gcc': Task{valgrind_v_c_gcc, 'Valgrind v.c (gcc)'}
'run_sanitizers_gcc': Task{run_sanitizers_gcc, 'Run sanitizers (gcc)'}
'v_self_compilation_gcc': Task{v_self_compilation_gcc, 'V self compilation (gcc)'}
'v_self_compilation_usecache_gcc': Task{v_self_compilation_usecache_gcc, 'V self compilation with default caching (gcc)'}
'verify_v_test_works_gcc': Task{verify_v_test_works_gcc, 'Verify `v test` works (gcc)'}
'test_pure_v_math_module_gcc': Task{test_pure_v_math_module_gcc, 'Test pure V math module (gcc)'}
'self_tests_gcc': Task{self_tests_gcc, 'Self tests (gcc)'}
'self_tests_prod_gcc': Task{self_tests_prod_gcc, 'Self tests (-prod) (gcc)'}
'self_tests_cstrict_gcc': Task{self_tests_cstrict_gcc, 'Self tests (-cstrict) (gcc)'}
'build_examples_gcc': Task{build_examples_gcc, 'Build examples (gcc)'}
'build_tetris_autofree_gcc': Task{build_tetris_autofree_gcc, 'Build tetris with -autofree (gcc)'}
'build_blog_autofree_gcc': Task{build_blog_autofree_gcc, 'Build blog tutorial with -autofree (gcc)'}
'build_option_test_autofree_gcc': Task{build_option_test_autofree_gcc, 'Build option_test.c.v with -autofree (gcc)'}
'v_self_compilation_parallel_cc_gcc': Task{v_self_compilation_parallel_cc_gcc, 'V self compilation with -parallel-cc (gcc)'}
'build_modules_gcc': Task{build_modules_gcc, 'Build modules (gcc)'}
'compile_vdoctor_prod_gcc': Task{compile_vdoctor_prod_gcc, 'compile vdoctor with -prod (gcc)'}
'compile_vup_prod_gcc': Task{compile_vup_prod_gcc, 'compile vup with -prod (gcc)'}
// clang tasks
'all_code_is_formatted_clang': Task{all_code_is_formatted_clang, 'All code is formatted (clang)'}
'install_dependencies_for_examples_and_tools_clang': Task{install_dependencies_for_examples_and_tools_clang, 'Install deps for examples/tools (clang)'}
'recompile_v_with_cstrict_clang': Task{recompile_v_with_cstrict_clang, 'Recompile V with -cstrict and clang'}
'valgrind_clang': Task{valgrind_clang, 'Valgrind (clang)'}
'run_sanitizers_clang': Task{run_sanitizers_clang, 'Run sanitizers (clang)'}
'v_self_compilation_clang': Task{v_self_compilation_clang, 'V self compilation (clang)'}
'v_self_compilation_usecache_clang': Task{v_self_compilation_usecache_clang, 'V self compilation with default caching (clang)'}
'verify_v_test_works_clang': Task{verify_v_test_works_clang, 'Verify `v test` works (clang)'}
'test_pure_v_math_module_clang': Task{test_pure_v_math_module_clang, 'Test pure V math module (clang)'}
'self_tests_clang': Task{self_tests_clang, 'Self tests (clang)'}
'self_tests_vprod_clang': Task{self_tests_vprod_clang, 'Self tests (vprod) (clang)'}
'self_tests_cstrict_clang': Task{self_tests_cstrict_clang, 'Self tests (-cstrict) (clang)'}
'build_examples_clang': Task{build_examples_clang, 'Build examples (clang)'}
'build_examples_autofree_clang': Task{build_examples_autofree_clang, 'Build examples with -autofree (clang)'}
'build_modules_clang': Task{build_modules_clang, 'Build modules (clang)'}
'test_inline_assembly': Task{test_inline_assembly, 'Test inline assembly'}
}
if os.args.len > 1 && os.args[1] == 'ci' {
if os.args.len > 3 || (os.args.len == 3 && os.args[2] != '--reset') {
eprintln('Usage: v run ci/linux_ci.vsh ci [--reset]')
exit(1)
}
run_ci_tasks(os.args.len == 3) or {
eprintln('Could not update CI progress: ${err.msg()}')
exit(1)
}
exit(0)
}
common.run(all_tasks)