v/tools/oldv.v

121 lines
4.6 KiB
V

import (
os
flag
filepath
scripting
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
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 occured.
## When you finish, do not forget to do:
git bisect reset'
)
struct Context {
mut:
v_repo_url string // the url of the V repository. It can be a local folder path, if you want to eliminate network operations...
vc_repo_url string // the url of the vc repository. It can be a local folder path, if you want to eliminate network operations...
workdir string // the working folder (typically /tmp), where the tool will write
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
verbose bool // should the tool be much more verbose
show_help bool // whether to show the usage screen
}
fn (c mut Context) compile_oldv_if_needed() {
mut vgit_context := vgit.VGitContext{
cc: c.cc
workdir: c.workdir
commit_v: c.commit_v
path_v: c.path_v
path_vc: c.path_vc
v_repo_url: c.v_repo_url
vc_repo_url: c.vc_repo_url
}
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(filepath.filename(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', 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, 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.workdir, context.commit_v)
context.path_vc = vgit.normalized_workpath_for_commit(context.workdir, 'vc')
if !os.is_dir(context.workdir) {
msg := 'Work folder: ' + context.workdir + ' , does not exist.'
eprintln(msg)
exit(2)
}
ecc := os.getenv('CC')
if ecc != '' {
context.cc = ecc
}
if context.cleanup {
scripting.run('rm -rf $context.path_v')
scripting.run('rm -rf $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)
}
}