diff options
Diffstat (limited to 'v_windows/v/cmd/tools/oldv.v')
-rw-r--r-- | v_windows/v/cmd/tools/oldv.v | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/v_windows/v/cmd/tools/oldv.v b/v_windows/v/cmd/tools/oldv.v new file mode 100644 index 0000000..03eaf83 --- /dev/null +++ b/v_windows/v/cmd/tools/oldv.v @@ -0,0 +1,176 @@ +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 + vgcontext vgit.VGitContext + commit_v string = 'master' // the commit from which you want to produce a working v compiler (this may be a commit-ish too) + 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 + use_cache bool // use local cached copies for --vrepo and --vcrepo in + fresh_tcc bool // do use `make fresh_tcc` +} + +fn (mut c Context) compile_oldv_if_needed() { + c.vgcontext = 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 + make_fresh_tcc: c.fresh_tcc + } + c.vgcontext.compile_oldv_if_needed() + c.commit_v_hash = c.vgcontext.commit_v__hash + if !os.exists(c.vgcontext.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) + } +} + +const cache_oldv_folder = os.join_path(os.cache_dir(), 'oldv') + +const cache_oldv_folder_v = os.join_path(cache_oldv_folder, 'v') + +const cache_oldv_folder_vc = os.join_path(cache_oldv_folder, 'vc') + +fn sync_cache() { + scripting.verbose_trace(@FN, 'start') + if !os.exists(cache_oldv_folder) { + scripting.verbose_trace(@FN, 'creating $cache_oldv_folder') + scripting.mkdir_all(cache_oldv_folder) or { + scripting.verbose_trace(@FN, '## failed.') + exit(1) + } + } + scripting.chdir(cache_oldv_folder) + for reponame in ['v', 'vc'] { + repofolder := os.join_path(cache_oldv_folder, reponame) + if !os.exists(repofolder) { + scripting.verbose_trace(@FN, 'cloning to $repofolder') + scripting.exec('git clone --quiet https://github.com/vlang/$reponame $repofolder') or { + scripting.verbose_trace(@FN, '## error during clone: $err') + exit(1) + } + } + scripting.chdir(repofolder) + scripting.exec('git pull --quiet') or { + scripting.verbose_trace(@FN, 'pulling to $repofolder') + scripting.verbose_trace(@FN, '## error during pull: $err') + exit(1) + } + } + scripting.verbose_trace(@FN, 'done') +} + +fn main() { + scripting.used_tools_must_exist(['git', 'cc']) + // + // Resetting VEXE here allows for `v run cmd/tools/oldv.v'. + // the parent V would have set VEXE, which later will + // affect the V's run from the tool itself. + os.setenv('VEXE', '', true) + // + mut context := Context{} + context.vgo.workdir = cache_oldv_folder + 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() + context.use_cache = fp.bool('cache', `u`, true, 'Use a cache of local repositories for --vrepo and --vcrepo in \$HOME/.cache/oldv/') + if context.use_cache { + context.vgo.v_repo_url = cache_oldv_folder_v + context.vgo.vc_repo_url = cache_oldv_folder_vc + } else { + context.vgo.v_repo_url = 'https://github.com/vlang/v' + context.vgo.vc_repo_url = 'https://github.com/vlang/vc' + } + should_sync := fp.bool('cache-sync', `s`, false, 'Update the local cache') + if !should_sync { + fp.limit_free_args(1, 1) + } + //// + context.cleanup = fp.bool('clean', 0, false, 'Clean before running (slower).') + context.fresh_tcc = fp.bool('fresh_tcc', 0, true, 'Do `make fresh_tcc` when preparing a V compiler.') + 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 should_sync { + sync_cache() + exit(0) + } + if context.use_cache { + if !os.is_dir(cache_oldv_folder_v) || !os.is_dir(cache_oldv_folder_vc) { + sync_cache() + } + } + 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) + shorter_hash := context.commit_v_hash[0..10] + scripting.cprintln('# v commit hash: $shorter_hash | folder: $context.path_v') + if context.cmd_to_run.len > 0 { + scripting.cprintln_strong('# command: ${context.cmd_to_run:-34s}') + cmdres := os.execute_or_exit(context.cmd_to_run) + if cmdres.exit_code != 0 { + scripting.cprintln_strong('# exit code: ${cmdres.exit_code:-4d}') + } + scripting.cprint_strong('# result: ') + print(cmdres.output) + exit(cmdres.exit_code) + } +} |