cmd_status.v

3.0 KB · raw

1//! `koh status` — what the working tree has that head does not.23module cli45import json6import src.fmt7import src.history8import src.snapshot9import src.storage1011pub fn cmd_status(raw []string) int {12	args := parse('status', raw, Options{13		flags: ['json']14	}) or { return usage_error(err.msg()) }15	store := open_store() or { return refuse(args.json(), err.msg()) }16	defer {17		store.close()18	}19	head := history.head(store) or {20		return refuse(args.json(), 'this repo has no saves yet — run "koh save \\"first save\\""')21	}22	changes := compare_with_head(store, head) or { return refuse(args.json(), err.msg()) }23	unfinished := snapshot.restore_pending(store)2425	if args.json() {26		emit_json(json.encode(StatusJson{27			head_id:            head.id28			head_msg:           head.message29			dirty:              changes.dirty30			modified:           changes.modified31			added:              changes.added32			deleted:            changes.removed33			ignore_changed:     changes.ignore_changed34			restore_unfinished: unfinished35		}))36		return 037	}38	if unfinished {39		warn(snapshot.restore_unfinished)40	}41	if !changes.dirty {42		ok('no changes')43		if changes.ignore_changed {44			note('${snapshot.ignore_file} changed since [${head.id}]')45		}46		return 047	}48	for path in changes.added {49		println('  ${fmt.green('+')} ${path}')50	}51	for path in changes.modified {52		println('  ${fmt.amber('~')} ${path}')53	}54	for path in changes.removed {55		println('  ${fmt.red('-')} ${path}')56	}57	note('${changes.added.len} added  ·  ${changes.modified.len} modified  ·  ${changes.removed.len} removed')58	if changes.ignore_changed {59		warn('${snapshot.ignore_file} changed since [${head.id}] — the next save records the new rules')60	}61	return 062}6364pub struct Changes {65pub:66	dirty          bool67	added          []string68	modified       []string69	removed        []string70	ignore_changed bool71}7273struct StatusJson {74	head_id            string75	head_msg           string76	dirty              bool77	modified           []string78	added              []string79	deleted            []string80	ignore_changed     bool81	restore_unfinished bool82}8384pub fn compare_with_head(store &storage.Store, head history.Save) !Changes {85	before := snapshot.index_files(history.files_of(store, head.id)!)86	after := snapshot.index_files(snapshot.walk(store, store.root, snapshot.load(store.root))!)87	mut added := []string{}88	mut modified := []string{}89	mut removed := []string{}90	for path in after.keys() {91		if path !in before {92			added << path93		} else if before[path].hash != after[path].hash94			|| before[path].executable != after[path].executable {95			modified << path96		}97	}98	for path in before.keys() {99		if path !in after {100			removed << path101		}102	}103	added.sort()104	modified.sort()105	removed.sort()106	ignore_changed := snapshot.ignore_file in added || snapshot.ignore_file in modified107	return Changes{108		dirty:          added.len + modified.len + removed.len > 0109		added:          added110		modified:       modified111		removed:        removed112		ignore_changed: ignore_changed113	}114}