Repository navigation
fix(paths): recover the profile a skipped or failed migration left behind and prune update staging from the cache - #88
Merged
Conversation
…e staging from the cache When both the rename and the copy fallback of a legacy directory failed, migrate_legacy_paths removed the half copy and let Colony continue on an empty new directory. relocate() now returns the directory to use, and a failure records the legacy path in a OnceLock that colony_data_dir() and colony_cache_dir() honour for the rest of the session; the next start retries the move. The migration now runs before the log file is created. On Windows the log's data directory is the config directory the first move targets, and creating it first made the move skip for good. Its log lines are captured in memory and written to the log once it is open. The boot sweep looked for update-staging in the config root while the launcher download writes it to the cache. Both are swept now, and the whole directory is emptied: a staged update that was never applied is unreachable after a restart. colony.log moves from the cache root to the data directory. External config overrides are read from the Local config directory first, with the Roaming one kept as a fallback on Windows. The dead ~/.local/share/colony/applications entry is gone; origin classification uses the shared install root instead.
v0.10.2 to v0.10.4 created the new config directory for the log file before the migration ran, so on Windows the Roaming to Local move was skipped and the profile stayed behind. The config move is now tracked by a .migrated marker: when the target exists without it, the files it lacks are copied over, never overwriting what was written there since. A half copy that cannot be removed after a failed move is renamed aside, so the next start retries instead of running on it. The migration decisions are factored out of the OnceLock setters and tested on explicit paths, scanned apps are classified as external directly, and the FAQ lists the macOS override path.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Migration fallback (FS-7). When both the rename and the copy fallback of a legacy directory failed,
migrate_legacy_pathsremoved the half copy and Colony carried on with an empty directory. The error log even said so. Nowrelocate()returns the directory to use. On failure, the legacy path goes into aOnceLockthatcolony_data_dir()andcolony_cache_dir()use for the rest of the session, and the next start tries the move again.When the Windows Roaming to Local config move fails, the cache stays in the old tree as well. On Windows the new cache root sits inside the new config directory, so creating it would make the next start treat the move as done.
When the cache move fails, the per-repo cache moves are skipped. They run on the next start where the cache move succeeds.
If the copy fallback fails and the half copy cannot be removed (for example a scanner holds a file open), it is renamed aside to
<dir>.incomplete-<timestamp>, so the next start really retries. If even that fails, an error tells the user to delete it by hand.Recovery for profiles left behind by v0.10.2 to v0.10.4 (FS-7). Those releases created the new config directory for the log file before the move ran, so on Windows the Roaming to Local move was skipped and Colony started on an empty profile. "The target exists" no longer means "moved": the config move writes an explicit
.migratedmarker in the new config directory. When the target exists without it, every legacy file the target lacks is copied over, never overwriting what was written there since, and the marker is written. The legacy directory is never deleted. Once marked, the move is never redone, so a file removed afterwards stays removed.Migration runs before the log file is created. On
mainthe log was created first. On Windows, creating it made%LOCALAPPDATA%\Colony\Colonyexist, so the Roaming move was always skipped. On Linux it made~/.cache/Colony/Colonyexist, so theconfig/cachemove was always skipped. The migration's own log lines are captured in memory and written to the log file and stderr once the log is open.Update staging sweep.
prune_staginglooked in<config>/update-staging, butdownload_launcher_assetwrites to<cache>/update-staging. Both places are swept now. The config one catches leftovers from older versions. The whole directory is emptied: the path of a downloaded update exists only in memory, so an update that was never applied can't be reached after a restart. That includes its binary and its signatures.Log location (FS-5).
colony.logmoves from the cache root to<data>/Colony/Colony/colony.logand is still truncated on every run.--helpprints this path without creating it.Config overrides (FS-2).
config.rsnow readsdirs::config_local_dir()/colony/first. On Windows it then reads the Roamingdirs::config_dir()/colony/as a fallback. On Linux and macOS the two are the same path, and it is listed once.Dead scan entry (FS-6). The
${HOME}/.local/share/colony/applicationsentry is removed fromconfig/colony.tomland fromscan.rs. Nothing has written to that path since the colony-ui layout. Scanned apps are classified as external directly: the entries Colony writes for its own apps carryX-Colony-Managedand are skipped, and no scan directory lies under the install root, so the old directory check could never match. The French comments incolony.tomlare translated.Tests. The update tests and the persistence end-to-end test had separate
ENV_LOCKs even though they set the same XDG variables. They now share oneXDG_TEST_LOCK.Docs. The log path is updated in
docs/architecture.md,docs/faq.md,docs/tutorial.md,CONTRIBUTING.mdand the bug report template. The FAQ'scategories.jsonoverride path is corrected to what the code reads (~/.config/colony/,~/Library/Application Support/colony/on macOS,%LOCALAPPDATA%\colony\on Windows).Verification
cargo test --bin colony: 156 passed. New and extended tests:a_move_an_earlier_version_skipped_is_finished_without_overwriting: a target holding onlycache/colony.logand a freshpreferences/preferences.json, plus a legacy profile. The missing legacy files arrive, the fresh file is kept, the marker is written, and a second run does not bring back a file removed since.a_completed_config_move_is_marked.a_failed_config_move_resolves_both_dirs_to_the_legacy_tree(unix): the Windows shape with the cache inside the config directory. The migration decision returns both legacy directories, nothing creates the new config directory, andresolve()with those fallbacks returns the legacy tree without consulting the layout.a_failed_cache_move_defers_the_per_repo_moves(unix).a_failed_move_keeps_using_the_legacy_directory(unix): makes the rename fail with a read-only parent and the copy fail with an unreadable file. It checks that the legacy directory is returned with its contents intact and that the half copy is removed.prune_stagingagainst the migrated layout. It checks that the cache-side staging and a config-side leftover are both removed, and that the reclaimed byte count is exact.the_local_override_wins_over_roaming: Local comes first, and Roaming appears once, right after it.relocatetests now assert the returned directory.