handover.v

2.9 KB · raw

1//! The cut-over hand-off.2//!3//! While repos with an unmigrated Koh 2 `.koh/` directory still exist on this4//! machine, `koh` is Koh 3 but those repos belong to Koh 2. Rather than let a5//! command fail confusingly, Koh 3 hands it to `koh2` unchanged — same6//! arguments, same terminal. Agents always type `koh`, and every repo gets the7//! Koh that owns it.8//!9//! `migrate` is the exception: it is how such a repo stops being a Koh 2 repo.10//! Commands about the machine rather than the repo stay Koh 3's, and a command11//! Koh 2 reads differently, or lacks, is refused with the way forward.1213module cli1415import os16import src.fmt1718// hand_over reports whether this invocation belongs to Koh 2, and if so runs19// it. It never returns when the hand-off happens.20pub fn hand_over(argv []string) {21	if argv.len < 2 {22		return23	}24	command := argv[1]25	if command in ['migrate', 'man', 'help', '--help', '-h', '--version', '-v', 'remote', 'update'] {26		return27	}28	if !inside_koh2_repo(os.getwd()) {29		return30	}31	// Koh 2's `view` sets visibility, its `steal` downloads a URL, its `doctor`32	// checks something else, and it has no `build` or `strip`.33	if command in ['view', 'steal', 'doctor', 'build', 'strip'] {34		eprintln('  ${fmt.red(fmt.glyph_fail)} "koh ${command}" needs a Koh 3 repo, and this one is still Koh 2 — run "koh migrate" to convert it')35		exit(1)36	}37	target := koh2_binary()38	if target == '' {39		eprintln('  ${fmt.red(fmt.glyph_fail)} this folder holds a Koh 2 repo, and koh2 is not on PATH')40		eprintln('  install koh2, or run "koh migrate" to convert this repo')41		exit(1)42	}43	// The one notice line the document asks for, on stderr so the output koh244	// prints (JSON included) reaches the caller unchanged.45	eprintln('  ${fmt.dim('this is a Koh 2 repo — handing the command to ${os.file_name(target)}')}')46	// execvp builds argv as [path, ...cmdargs], so the arguments go without47	// our own argv[0].48	os.execvp(target, argv[1..]) or {49		eprintln('  ${fmt.red(fmt.glyph_fail)} could not hand this command to ${target}: ${err.msg()}')50		exit(1)51	}52}5354// koh2_binary finds the Koh 2 binary. Before the cutover it is still called55// `koh`, so that name is a fallback — never this binary itself, which would56// hand the command straight back to us for ever.57fn koh2_binary() string {58	if found := os.find_abs_path_of_executable('koh2') {59		return found60	}61	if legacy := os.find_abs_path_of_executable('koh') {62		if os.real_path(legacy) != os.real_path(os.executable()) {63			return legacy64		}65	}66	return ''67}6869// inside_koh2_repo looks upward for a `.koh` that is a directory. A `.koh`70// file is Koh 3's.71fn inside_koh2_repo(start string) bool {72	mut dir := os.real_path(start)73	for {74		path := os.join_path(dir, '.koh')75		if os.is_dir(path) {76			return true77		}78		if os.is_file(path) {79			return false80		}81		parent := os.dir(dir)82		if parent == dir || parent == '' {83			return false84		}85		dir = parent86	}87	return false88}