v/cmd/tools/oldv.v

113 lines
4.1 KiB
V

import os
import flag
import scripting
import vgit
const (
tool_version = '0.0.3'
tool_description = ' Checkout an old V and compile it as it was on specific commit.
This tool is useful, when you want to discover when something broke.
It is also useful, when you just want to experiment with an older historic V.
The VCOMMIT argument can be a git commitish like HEAD or master and so on.
When oldv is used with git bisect, you probably want to give HEAD. For example:
git bisect start
git bisect bad
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"
## See what the result is, and either do: ...
git bisect good
## ... or do:
git bisect bad
## Now you just repeat the above steps, each time running oldv with the same command, then mark the result as good or bad,
## until you find the commit, where the problem first occurred.
## When you finish, do not forget to do:
git bisect reset'
)
struct Context {
mut:
vgo vgit.VGitOptions
commit_v string='master' // the commit from which you want to produce a working v compiler (this may be a commit-ish too)
commit_vc string='master' // this will be derived from commit_v
commit_v_hash string // this will be filled from the commit-ish commit_v using rev-list. It IS a commit hash.
path_v string // the full path to the v folder inside workdir.
path_vc string // the full path to the vc folder inside workdir.
cmd_to_run string // the command that you want to run *in* the oldv repo
cc string='cc' // the C compiler to use for bootstrapping.
cleanup bool // should the tool run a cleanup first
}
fn (c mut Context) compile_oldv_if_needed() {
mut vgit_context := vgit.VGitContext{
workdir: c.vgo.workdir
v_repo_url: c.vgo.v_repo_url
vc_repo_url: c.vgo.vc_repo_url
cc: c.cc
commit_v: c.commit_v
path_v: c.path_v
path_vc: c.path_vc
}
vgit_context.compile_oldv_if_needed()
c.commit_v_hash = vgit_context.commit_v__hash
if !os.exists(vgit_context.vexepath) && c.cmd_to_run.len > 0 {
// NB: 125 is a special code, that git bisect understands as 'skip this commit'.
// it is used to inform git bisect that the current commit leads to a build failure.
exit(125)
}
}
fn main() {
scripting.used_tools_must_exist(['git', 'cc'])
mut context := Context{}
mut fp := flag.new_flag_parser(os.args)
fp.application(os.file_name(os.executable()))
fp.version(tool_version)
fp.description(tool_description)
fp.arguments_description('VCOMMIT')
fp.skip_executable()
fp.limit_free_args(1, 1)
context.cleanup = fp.bool('clean', 0, true, 'Clean before running (slower).')
context.cmd_to_run = fp.string('command', `c`, '', 'Command to run in the old V repo.\n')
commits := vgit.add_common_tool_options(mut context.vgo, mut fp)
if commits.len > 0 {
context.commit_v = commits[0]
} else {
context.commit_v = scripting.run('git rev-list -n1 HEAD')
}
println('################# context.commit_v: $context.commit_v #####################')
context.path_v = vgit.normalized_workpath_for_commit(context.vgo.workdir, context.commit_v)
context.path_vc = vgit.normalized_workpath_for_commit(context.vgo.workdir, 'vc')
if !os.is_dir(context.vgo.workdir) {
eprintln('Work folder: ${context.vgo.workdir} , does not exist.')
exit(2)
}
ecc := os.getenv('CC')
if ecc != '' {
context.cc = ecc
}
if context.cleanup {
scripting.rmrf(context.path_v)
scripting.rmrf(context.path_vc)
}
context.compile_oldv_if_needed()
scripting.chdir(context.path_v)
println('# v commit hash: $context.commit_v_hash')
println('# checkout folder: $context.path_v')
if context.cmd_to_run.len > 0 {
cmdres := os.exec(context.cmd_to_run) or {
panic(err)
}
println('# command: ${context.cmd_to_run:-34s} exit code: ${cmdres.exit_code:-4d} result:')
println(cmdres.output)
exit(cmdres.exit_code)
}
}