WIP: automatically migrate client-side profiles back to /nix/var/nix

Change-Id: I430dbfabfa091417f0883975a0c1611ab62655d1
This commit is contained in:
Qyriad 2024-05-12 21:15:54 -06:00
parent acf379e5af
commit 67a431fa2f
2 changed files with 66 additions and 1 deletions

View file

@ -336,6 +336,18 @@ Path ensureDefaultProfile()
replaceSymlink(defaultProfile, profileLink); replaceSymlink(defaultProfile, profileLink);
} }
Path const profileLinkTarget = readLink(profileLink);
std::cerr << "profileLinkTarget: " << profileLinkTarget << "\n";
// Note: getStateDir() is XDG_STATE_DIR, not NIX_STATE_DIR.
if (profileLinkTarget.starts_with(createNixStateDir())) {
notice("migrating client-side profiles to %s", profilesDir());
Path const cspDir = createNixStateDir() + "/profiles";
Path const dspDir = profilesDir();
migrateProfiles(cspDir, dspDir);
std::cerr << fmt("replaceSymlink(%s, %s)\n", defaultProfile, profileLink);
replaceSymlink(defaultProfile, profileLink);
}
// Backwards compatibiliy measure: Make root's profile available as // Backwards compatibiliy measure: Make root's profile available as
// `.../default` as it's what NixOS and most of the init scripts expect // `.../default` as it's what NixOS and most of the init scripts expect
Path const globalProfileLink = settings.nixStateDir + "/profiles/default"; Path const globalProfileLink = settings.nixStateDir + "/profiles/default";
@ -343,7 +355,7 @@ Path ensureDefaultProfile()
replaceSymlink(defaultProfile, globalProfileLink); replaceSymlink(defaultProfile, globalProfileLink);
} }
return absPath(readLink(profileLink), dirOf(profileLink)); return absPath(profileLinkTarget, dirOf(profileLink));
} }
Path getDefaultProfile() Path getDefaultProfile()
@ -363,6 +375,51 @@ Path getDefaultProfile()
return profileLink; return profileLink;
} }
void migrateProfiles(Path const & profilesFrom, Path const & profilesTo)
{
notice("migrating from profiles from %s to be in %s", profilesFrom, profilesTo);
auto const oldProfiles = readDirectory(profilesFrom);
for (DirEntry const & oldProfileEnt : oldProfiles) {
auto const oldGenPath = fmt("%s/%s", profilesFrom, oldProfileEnt.name);
if (!isLink(oldGenPath)) {
// This is not a profile and we should not touch it.
continue;
}
auto const newGenPath = fmt("%s/%s", profilesTo, oldProfileEnt.name);
auto const genTarget = readLink(oldGenPath);
notice("migrating profile '%s' to '%s'", oldGenPath, newGenPath);
std::cerr << fmt("replaceSymlink(%s, %s)", genTarget, newGenPath);
//replaceSymlink(genTarget, newGenPath);
//deletePath(oldGenPath);
}
// Now that we've deleted all the profile symlinks in ~/.local/state/nix/profiles,
// it's time to make ~/.local/state/nix/profiles itself a symlink.
if (readDirectory(profilesFrom).empty()) {
removeFile(profilesFrom);
replaceSymlink(profilesTo, profilesFrom);
} else {
// But if that directory stuff other than profiles in it, we shouldn't delete that.
// Back them up for the user.
warn("non-profiles found in '%s'; backing up instead of deleting", profilesFrom);
Path backupName = profilesFrom + ".bak";
if (pathExists(backupName)) {
unsigned suffix = 0;
do {
assert(suffix < UINT_MAX);
suffix += 1;
backupName = fmt("%s.bak-%u", profilesFrom, suffix);
} while (pathExists(backupName));
}
renameFile(profilesFrom, backupName);
notice("backed up as '%s'", backupName);
}
}
Path defaultChannelsDir() Path defaultChannelsDir()
{ {
return profilesDir() + "/channels"; return profilesDir() + "/channels";

View file

@ -245,4 +245,12 @@ Path getDefaultProfile();
*/ */
Path ensureDefaultProfile(); Path ensureDefaultProfile();
/**
* Migrates a set of profiles from one directory to another.
*
* Intended for migration from ~/.local/state/nix/profiles/
* to /nix/var/nix/profiles/per-user/foo/
*/
void migrateProfiles(Path const & profilesFrom, Path const & profilesTo);
} }