//! `koh peek` — put a save's tree in a temporary folder and print where. //! //! The working tree and history are untouched: a peek is a read of the object //! store into a scratch folder the user can look at, then throw away. module cli import json import os import src.fmt import src.history import src.snapshot pub fn cmd_peek(raw []string) int { args := parse('peek', raw, Options{ flags: ['json'] }) or { return usage_error(err.msg()) } store := open_store() or { return refuse(args.json(), err.msg()) } defer { store.close() } id := args.positional_at(0) if id == '' { return usage_error('peek needs a save ID') } save := history.resolve(store, id) or { return refuse(args.json(), err.msg()) } files := history.files_of(store, save.id) or { return refuse(args.json(), err.msg()) } path := peek_path(save.id) // Re-peeking the same save replaces its folder rather than merging into it. if os.exists(path) { os.rmdir_all(path) or { return refuse(args.json(), err.msg()) } } os.mkdir_all(path, os.MkdirParams{}) or { return refuse(args.json(), err.msg()) } snapshot.restore_files(store, path, snapshot.Ignore{}, files, []) or { return refuse(args.json(), err.msg()) } if args.json() { emit_json(json.encode(PeekJson{ id: save.id path: path files: files.len })) return 0 } ok('peeked [${save.id}] into') println(path) note('${fmt.plural(files.len, 'file')} — delete the folder when you are done') return 0 } // peek_path is where a save's scratch copy lives. `doctor` sweeps these folders // out of the temp directory. pub fn peek_path(save_id string) string { return os.join_path(os.temp_dir(), '${peek_prefix}${save_id}') } pub const peek_prefix = 'koh-peek-' struct PeekJson { id string path string files int }