From eb45a321a5d4f5965e52a61c1efad66d7269cd9a Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Thu, 17 Feb 2022 16:34:05 +0200 Subject: [PATCH] tools: add cmd/tools/regress.v to simplify bisecting for regression bugs/features: Support finding which commit introduced a regression: ./v run cmd/tools/regress.v --old COMMIT --command './v run /abs/path/to/regression_bug.v' Support also finding which commit introduced a feature (or made code compile/run): ./v run cmd/tools/regress.v --old COMMIT --command '! ./v run /abs/path/to/feature.v' NB: the '! ' is a POSIX shell feature. It may not work on Windows outside of WSL. Its meaning is to invert the exit code for the next command, i.e. 0 -> 1, non 0 -> 0 If it does not work for you, you need to write a more explicit script that will exit with 0 code for all commits, where the feature does NOT work, and with non 0 code for all commits, where the feature does work. --- cmd/tools/oldv.v | 2 +- cmd/tools/regress.v | 79 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 cmd/tools/regress.v diff --git a/cmd/tools/oldv.v b/cmd/tools/oldv.v index 3a085846a3..fff8d0ab1c 100644 --- a/cmd/tools/oldv.v +++ b/cmd/tools/oldv.v @@ -16,7 +16,7 @@ const ( | git checkout known_good_commit | git bisect good | ## Now git will automatically checkout a middle commit between the bad and the good -| cmd/tools/oldv HEAD --command="run commands in oldv folder, to verify if the commit is good or bad" +| cmd/tools/oldv --bisect --command="run commands in oldv folder, to verify if the commit is good or bad" | ## See what the result is, and either do: ... | git bisect good | ## ... or do: diff --git a/cmd/tools/regress.v b/cmd/tools/regress.v new file mode 100644 index 0000000000..596deef3e2 --- /dev/null +++ b/cmd/tools/regress.v @@ -0,0 +1,79 @@ +import os +import term +import flag + +const tools_folder = os.real_path(os.dir(os.executable())) + +const oldvexe = fullpath(tools_folder, 'oldv') + +const oldv_source = fullpath(tools_folder, 'oldv.v') + +const vroot = os.real_path(os.dir(tools_folder)) + +const vexe = fullpath(vroot, 'v') + +fn fullpath(folder string, fname string) string { + return os.real_path(os.join_path_single(folder, exename(fname))) +} + +fn exename(n string) string { + if n.ends_with('.v') || os.user_os() != 'windows' { + return n + } + return '${n}.exe' +} + +struct Context { +mut: + old_commit string + new_commit string + command string +} + +fn main() { + mut fp := flag.new_flag_parser(os.args) + mut context := Context{} + fp.application(os.file_name(os.executable())) + fp.version('0.0.2') + fp.description('\n Find at what commit a regression occurred. + To find when a regression happened (regression_bug.v should fail on master): + ./v run cmd/tools/regress.v --old a7019ac --command " ./v run /abs/path/to/regression_bug.v" + To find when a feature was implemented (feature.v should succeed on master): + ./v run cmd/tools/regress.v --old a7019ac --command "! ./v run /abs/path/to/feature.v"') + fp.skip_executable() + // + context.new_commit = fp.string('new', `n`, 'master', 'The new commit, by default: master.') + context.old_commit = fp.string('old', `o`, '', 'A known old commit, required (for it, COMMAND should exit with 0).') + context.command = fp.string('command', `c`, '', 'A command to execute. Should exit with 0 for the *old* commits.') + fp.finalize() or {} + if context.old_commit == '' { + eprintln('--old COMMIT is required') + exit(1) + } + if context.command == '' { + eprintln('--command "COMMAND" is required') + exit(2) + } + if !os.exists(oldvexe) { + if 0 != execute('${os.quoted_path(vexe)} -o ${os.quoted_path(oldvexe)} ${os.quoted_path(oldv_source)}') { + panic('can not compile $oldvexe') + } + } + os.execute('git checkout master') + os.execute('git bisect reset') + os.execute('git checkout $context.new_commit') + os.execute('git bisect start') + os.execute('git bisect new') + os.execute('git checkout $context.old_commit') + os.execute('git bisect old') + println(term.colorize(term.bright_yellow, term.header('', '-'))) + execute('git bisect run ${os.quoted_path(oldvexe)} --bisect -c "$context.command"') + println(term.colorize(term.bright_yellow, term.header('', '-'))) + os.execute('git bisect reset') + os.execute('git checkout master') +} + +fn execute(cmd string) int { + eprintln('### $cmd') + return os.system(cmd) +}