v/cmd/tools/oldv.v

111 lines
4.2 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'.strip_margin()
)
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 (mut c 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')
}
scripting.cprintln('################# 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)
scripting.cprintln('# v commit hash: $context.commit_v_hash')
scripting.cprintln('# checkout folder: $context.path_v')
if context.cmd_to_run.len > 0 {
cmdres := os.exec(context.cmd_to_run) or {
panic(err)
}
scripting.cprintln('# command: ${context.cmd_to_run:-34s} exit code: ${cmdres.exit_code:-4d} result:')
println(cmdres.output)
exit(cmdres.exit_code)
}
}