cbbdbce05674
3.4.3: migrate verifies a save's files by path, so a Koh 2 manifest listing them out of order no longer fails
- time
- 2026-10-03 18:24 UTC · 1 week ago
- machine
- Junes-MacBook-Pro.local
- agent
- claude-opus-5-5
- session
- fix nina migrate
- parent
- 1b380cba71f7
↓ koh-cbbdbce0.tar.gzatlas at this save
files changed4 files
VERSION+1 −1src/migrate/migrate.v+8 −3src/migrate/migrate_test.v+21 −0v.mod+1 −1src/migrate/migrate.v+8 −3
@@ -530,10 +530,15 @@530530 if files.len != manifest.files.len {531531 return error('save ${manifest.id} has ${files.len} files, its manifest has ${manifest.files.len}')532532 }533- for i, file in manifest.files {533+ // By path, not by position: Koh 2 did not always list a manifest's files in order.534+ mut stored := map[string]string{}535+ for file in files {536+ stored[file.path] = file.hash537+ }538+ for file in manifest.files {534539 hash := bare_hash(file.hash)535- if files[i].path != file.path || files[i].hash != hash {536- return error('save ${manifest.id}: ${files[i].path} does not match its manifest')540+ if stored[file.path] or { '' } != hash {541+ return error('save ${manifest.id}: ${file.path} does not match its manifest')537542 }538543 store.get_object(hash) or {539544 return error('save ${manifest.id} needs object ${hash}: ${err.msg()}')src/migrate/migrate_test.v+21 −0
@@ -388,3 +388,24 @@388388 assert !os.exists(os.join_path(fixture.dir, draft_file))389389 assert os.is_dir(os.join_path(fixture.dir, '.koh'))390390 }391+392+// Koh 2 did not always write a manifest's files in path order (nina has one such save).393+fn test_a_manifest_listing_its_files_out_of_order_migrates() {394+ koh2 := koh2_binary() or { return }395+ fixture := make_fixture(koh2)!396+ defer {397+ os.rmdir_all(fixture.dir) or {}398+ }399+ path := os.join_path(fixture.dir, '.koh', 'snapshots', '${fixture.first}.json')400+ mut raw := json2.decode[json2.Any](os.read_file(path)!)!.as_map()401+ mut files := raw['files']!.as_array()402+ files.reverse_in_place()403+ raw['files'] = json2.Any(files)404+ os.write_file(path, json2.encode(raw))!405+ run(prepare(fixture.dir, default_lane, [])!, quiet)!406+ store := storage.open(fixture.dir)!407+ defer {408+ store.close()409+ }410+ assert history.files_of(store, fixture.first)!.map(it.path) == ['big.txt', 'small.txt']411+}v.mod+1 −1
@@ -1,6 +1,6 @@11 Module {22 name: 'koh3'3- version: '3.4.2'3+ version: '3.4.3'44 description: 'One SQLite file per repo, one line of history.'55 license: 'MIT'66 }