cmd_migrate.v

4.3 KB · raw

1//! `koh migrate` — one-time conversion from Koh 2.23module cli45import json26import os7import src.fmt8import src.machine9import src.migrate10import src.snapshot11import time1213pub fn cmd_migrate(raw []string) int {14	args := parse('migrate', raw, Options{15		values: ['lane', 'with']16		flags:  ['json', 'yes']17	}) or { return usage_error(err.msg()) }18	mut lane := args.value('lane')19	if lane == '' {20		lane = migrate.default_lane21	}22	if lane !in ['dev', 'main'] {23		return usage_error('--lane takes dev or main, not "${lane}"')24	}25	plan := migrate.prepare(os.getwd(), lane, args.values_of('with')) or { return refuse(args.json(), err.msg()) }26	if !args.json() {27		note('Koh 2 repo · lane ${plan.lane} · ${fmt.plural(plan.saves, 'save')} (${fmt.plural(plan.checkpoints, 'checkpoint')}) · ${fmt.plural(plan.objects, 'object')} · last save ${time.unix(plan.last_saved).ymmdd()}')28		show_lost(plan.lost)29		note('this will:')30		note('  · copy the history into one .koh file and check every save')31		if plan.renames_build {32			note('  · rename kepr.build to koh.build, as its own save')33		}34		note('  · keep the Koh 2 data as ${migrate.archive_dir}/ — move it back to undo')35	}36	approved := confirm(args.flag('yes')) or { return refuse(args.json(), err.msg()) }37	if !approved {38		return refuse(args.json(), 'not migrating, then — nothing changed')39	}40	report := migrate.run(plan, fn (stage string, done int, total int) {41		working('${stage} ${done} / ${total} saves')42	}) or { return refuse(args.json(), err.msg()) }43	if args.json() {44		emit_json(json2.encode(MigrateJson{45			repo:         report.root46			lane:         report.lane47			saves:        report.saves48			checkpoints:  report.checkpoints49			flags:        report.flags50			objects:      report.objects51			head:         report.head52			ignore_moved: report.ignore_carried53			build_file:   report.build_renamed54			lost:         plan.lost.map(it.path)55			unsafe_paths: report.unsafe_paths56		}))57		return 058	}59	ok('migrated ${fmt.plural(report.saves, 'save')} from Koh 2 (lane ${report.lane})')60	note('${fmt.plural(report.checkpoints, 'checkpoint')} · ${fmt.plural(report.flags, 'flag')} · ${fmt.plural(report.objects, 'object')}')61	warn_unsafe_paths(report.unsafe_paths)62	note('the Koh 2 data is untouched in ${migrate.archive_dir}/ — move it back to go back')63	if report.ignore_carried {64		note('carried the ignore rules to ${snapshot.ignore_file}')65	}66	if report.build_renamed {67		note('renamed kepr.build to koh.build, and saved that')68	}69	if report.log_md_was_tracked {70		warn('LOG.md was tracked by Koh 2; koh writes it itself now, so it is no longer snapshotted')71	}72	note('run "koh status" to see what the migration left, then "koh save"')73	if machine.has_remote() {74		note('this machine has a remote — run "koh offer" to publish the migrated history')75	}76	return 077}7879struct MigrateJson {80	repo         string81	lane         string82	saves        int83	checkpoints  int84	flags        int85	objects      int86	head         string87	ignore_moved bool88	build_file   bool89	lost         []string90	unsafe_paths []string91}9293// show_lost names each file Koh 2 lost versions of, where they were, and what94// can still be done about it before anything is written.95fn show_lost(lost []migrate.Lost) {96	if lost.len == 0 {97		return98	}99	mut paths := []string{}100	for gone in lost {101		if gone.path !in paths {102			paths << gone.path103		}104	}105	warn('Koh 2 has lost ${fmt.plural(lost.len, 'file version')} its saves still list:')106	for path in paths {107		versions := lost.filter(it.path == path)108		mut saves := 0109		mut first := versions[0].first110		mut last := versions[0].last111		for gone in versions {112			saves += gone.saves.len113			first = if gone.first < first { gone.first } else { first }114			last = if gone.last > last { gone.last } else { last }115		}116		mut when := time.unix(first).ymmdd()117		if time.unix(last).ymmdd() != when {118			when += ' to ${time.unix(last).ymmdd()}'119		}120		note('    ${path} · ${fmt.plural(versions.len, 'version')} · in ${fmt.plural(saves, 'save')} · ${when}')121	}122	one := lost.len == 1123	them := if one { 'that version' } else { 'any of those versions' }124	it := if one { 'it' } else { 'them' }125	note("  if you have ${them} — a backup, Time Machine, another machine's copy —")126	note('  hand ${it} back and Koh uses ${it} instead: koh migrate --with <file> …')127	note('  continuing brings those saves over without ${if one { 'it' } else { 'what was lost' }}, each one flagged')128}