e45cc89462f8

3.3.0: a whole-repo steal's progress line counts files, saves and events against their totals

time
2026-10-03 14:42 UTC · 1 week ago
machine
Junes-MacBook-Pro.local
agent
claude-opus-5-5
session
steal progress totals
parent
44adaadc6a8e
5 files VERSION+1 −1src/cli/cmd_steal.v+10 −7src/cli/progress.v+29 −3src/cli/progress_test.v+32 −0v.mod+1 −1
VERSION+1 −1
@@ -1 +1 @@1-3.2.271+3.3.0

view file

src/cli/cmd_steal.v+10 −7
@@ -431,27 +431,30 @@431431 	if exchange.signed_in_to(base) {432432 		return steal_repo(repo, args)433433 	}434-	mut backend := remote.Backend(watch('stealing ${repo}', exchange.read_only('${base}/${repo}') or {435-		return refuse(args.json(), err.msg())436-	}))437-	return steal_whole(repo, args, mut backend, '${base}/${repo}')434+	backend := exchange.read_only('${base}/${repo}') or { return refuse(args.json(), err.msg()) }435+	return steal_whole(repo, args, backend, '${base}/${repo}')438436 }439437 440438 // steal_repo fetches a whole repo into ./<name>, for a machine that does not441439 // have it yet.442440 fn steal_repo(name string, args Args) int {443-	mut backend := watched_backend('stealing ${name}') or { return refuse(args.json(), err.msg()) }444-	return steal_whole(name, args, mut backend, '')441+	backend := this_machine_backend() or { return refuse(args.json(), err.msg()) }442+	return steal_whole(name, args, backend, '')445443 }446444 447445 // steal_whole is that fetch, from whichever remote was chosen: the whole history in, then the head's448446 // files onto the disk. A non-empty `source` means the repo came from a read-only address and stays449447 // local until this machine signs in there.450-fn steal_whole(name string, args Args, mut backend remote.Backend, source string) int {448+fn steal_whole(name string, args Args, inner remote.Backend, source string) int {451449 	target := os.join_path(os.getwd(), name)452450 	if os.exists(target) {453451 		return refuse(args.json(), '${name} already exists here — run steal inside it instead')454452 	}453+	mut backend := remote.Backend(Watched{454+		label: 'stealing ${name}'455+		whole: true456+		inner: inner457+	})455458 	fetched := exchange.fetch_repo(mut backend, name) or { return refuse(args.json(), err.msg()) }456459 	store := land_repo(target, name, fetched, source) or {457460 		os.rmdir_all(target) or {}

view file

src/cli/progress.v+29 −3
@@ -51,10 +51,16 @@5151 // line moves with the transfer. Exchange stays unaware of it.5252 struct Watched {5353 	label string54+	// whole is a steal of a whole repo, which fetches every key it lists, so a55+	// listing is the total for that kind: files, saves or events.56+	whole bool5457 mut:5558 	inner    remote.Backend5659 	received int5760 	sent     int61+	listed   map[string]int62+	fetched  map[string]int63+	kind     string5864 }5965 6066 // watched_backend is this machine's backend, counted on the line under `label`.@@ -71,10 +77,13 @@7177 7278 fn (mut w Watched) show() {7379 	mut text := w.label80+	if w.kind != '' {81+		text += ' · ${w.kind} ${w.fetched[w.kind]} of ${w.listed[w.kind]}'82+	}7483 	if w.sent > 0 {7584 		text += ' · ${w.sent} sent'7685 	}77-	if w.received > 0 {86+	if w.kind == '' && w.received > 0 {7887 		text += ' · ${w.received} received'7988 	}8089 	working(text)@@ -82,13 +91,30 @@8291 8392 fn (mut w Watched) get(key string) !remote.Object {8493 	object := w.inner.get(key)!85-	w.received++94+	kind := key_kind(os.dir(key))95+	if kind in w.listed {96+		w.kind = kind97+		w.fetched[kind]++98+	} else {99+		w.received++100+	}86101 	w.show()87102 	return object88103 }89104 90105 fn (mut w Watched) list(prefix string) ![]string {91-	return w.inner.list(prefix)!106+	keys := w.inner.list(prefix)!107+	if w.whole {108+		w.listed[key_kind(prefix)] += keys.len109+	}110+	return keys111+}112+113+// key_kind names what a key folder such as `repo/objects` holds, in the words114+// the person knows: an object is a file's contents.115+fn key_kind(folder string) string {116+	kind := os.base(folder)117+	return if kind == 'objects' { 'files' } else { kind }92118 }93119 94120 fn (mut w Watched) put_if_absent(key string, body []u8) !bool {

view file

src/cli/progress_test.v+32 −0
@@ -0,0 +1,32 @@1+module cli2+3+import os4+import src.remote5+6+fn test_a_whole_steal_counts_each_kind_against_its_listing() {7+	base := os.join_path(os.vtmp_dir(), 'koh-progress-${os.getpid()}')8+	defer {9+		os.rmdir_all(base) or {}10+	}11+	mut folder := remote.new_folder(base)!12+	for key in ['r/objects/a', 'r/objects/b', 'r/saves/s1'] {13+		folder.put_if_absent(key, 'x'.bytes())!14+	}15+	mut w := Watched{16+		label: 'stealing r'17+		whole: true18+		inner: remote.Backend(folder)19+	}20+	for prefix in ['r/objects', 'r/saves'] {21+		for key in w.list(prefix)! {22+			w.get(key)!23+		}24+	}25+	assert w.listed == {26+		'files': 227+		'saves': 128+	}29+	assert w.fetched == w.listed30+	assert w.kind == 'saves'31+	assert w.received == 032+}

view file

v.mod+1 −1
@@ -1,6 +1,6 @@11 Module {22 	name: 'koh3'3-	version: '3.2.27'3+	version: '3.3.0'44 	description: 'One SQLite file per repo, one line of history.'55 	license: 'MIT'66 }

view file