123module 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}