Merge changes I8d87c0e9,I25937702 into main
* changes: nix3-upgrade-nix: always use the /new/ nix-env to perform the installation libutil: implement a realPath() utility
This commit is contained in:
commit
c052716edd
|
@ -1,4 +1,5 @@
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <cstdlib>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
|
@ -106,6 +107,24 @@ Path canonPath(PathView path, bool resolveSymlinks)
|
||||||
return s.empty() ? "/" : std::move(s);
|
return s.empty() ? "/" : std::move(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Path realPath(Path const & path)
|
||||||
|
{
|
||||||
|
// With nullptr, realpath() malloc's and returns a new c-string.
|
||||||
|
char * resolved = realpath(path.c_str(), nullptr);
|
||||||
|
int saved = errno;
|
||||||
|
if (resolved == nullptr) {
|
||||||
|
throw SysError(saved, "cannot get realpath for '%s'", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Finally const _free([&] { free(resolved); });
|
||||||
|
|
||||||
|
// There's not really a from_raw_parts() for std::string.
|
||||||
|
// The copy is not a big deal.
|
||||||
|
Path ret(resolved);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void chmodPath(const Path & path, mode_t mode)
|
void chmodPath(const Path & path, mode_t mode)
|
||||||
{
|
{
|
||||||
if (chmod(path.c_str(), mode) == -1)
|
if (chmod(path.c_str(), mode) == -1)
|
||||||
|
|
|
@ -46,6 +46,22 @@ Path absPath(Path path,
|
||||||
*/
|
*/
|
||||||
Path canonPath(PathView path, bool resolveSymlinks = false);
|
Path canonPath(PathView path, bool resolveSymlinks = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a file path to a fully absolute path with no symbolic links.
|
||||||
|
*
|
||||||
|
* @param path The path to resolve. If it is relative, it will be resolved relative
|
||||||
|
* to the process's current directory.
|
||||||
|
*
|
||||||
|
* @note This is not a pure function; it performs this resolution by querying
|
||||||
|
* the filesystem.
|
||||||
|
*
|
||||||
|
* @note @ref path sadly must be (a reference to) an owned string, as std::string_view
|
||||||
|
* are not valid C strings...
|
||||||
|
*
|
||||||
|
* @return The fully resolved path.
|
||||||
|
*/
|
||||||
|
Path realPath(Path const & path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the permissions of a path
|
* Change the permissions of a path
|
||||||
* Not called `chmod` as it shadows and could be confused with
|
* Not called `chmod` as it shadows and could be confused with
|
||||||
|
|
|
@ -97,12 +97,19 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand
|
||||||
store->ensurePath(storePath);
|
store->ensurePath(storePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// {profileDir}/bin/nix-env is a symlink to {profileDir}/bin/nix, which *then*
|
||||||
|
// is a symlink to /nix/store/meow-nix/bin/nix.
|
||||||
|
// We want /nix/store/meow-nix/bin/nix-env.
|
||||||
|
Path const oldNixInStore = realPath(canonProfileDir + "/bin/nix");
|
||||||
|
Path const oldNixEnv = dirOf(oldNixInStore) + "/nix-env";
|
||||||
|
|
||||||
|
Path const newNixEnv = store->printStorePath(storePath) + "/bin/nix-env";
|
||||||
|
|
||||||
{
|
{
|
||||||
Activity act(*logger, lvlInfo, actUnknown, fmt("verifying that '%s' works...", store->printStorePath(storePath)));
|
Activity act(*logger, lvlInfo, actUnknown, fmt("verifying that '%s' works...", store->printStorePath(storePath)));
|
||||||
auto program = store->printStorePath(storePath) + "/bin/nix-env";
|
auto s = runProgram(newNixEnv, false, {"--version"});
|
||||||
auto s = runProgram(program, false, {"--version"});
|
|
||||||
if (s.find("Nix") == std::string::npos)
|
if (s.find("Nix") == std::string::npos)
|
||||||
throw Error("could not verify that '%s' works", program);
|
throw Error("could not verify that '%s' works", newNixEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger->pause();
|
logger->pause();
|
||||||
|
@ -110,23 +117,17 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand
|
||||||
auto const fullStorePath = store->printStorePath(storePath);
|
auto const fullStorePath = store->printStorePath(storePath);
|
||||||
|
|
||||||
if (pathExists(canonProfileDir + "/manifest.nix")) {
|
if (pathExists(canonProfileDir + "/manifest.nix")) {
|
||||||
|
// First remove the existing Nix, then use the *new* Nix by absolute path to
|
||||||
// {settings.nixBinDir}/nix-env is a symlink to a {settings.nixBinDir}/nix, which *then*
|
|
||||||
// is a symlink to /nix/store/meow-nix/bin/nix. We want /nix/store/meow-nix/bin/nix-env.
|
|
||||||
Path const nixInStore = canonPath(settings.nixBinDir + "/nix-env", true);
|
|
||||||
Path const nixEnvCmd = dirOf(nixInStore) + "/nix-env";
|
|
||||||
|
|
||||||
// First remove the existing Nix, then use that Nix by absolute path to
|
|
||||||
// install the new one, in case the new and old versions aren't considered
|
// install the new one, in case the new and old versions aren't considered
|
||||||
// to be "the same package" by nix-env's logic (e.g., if their pnames differ).
|
// to be "the same package" by nix-env's logic (e.g., if their pnames differ).
|
||||||
Strings removeArgs = {
|
Strings removeArgs = {
|
||||||
"--uninstall",
|
"--uninstall",
|
||||||
nixEnvCmd,
|
oldNixEnv,
|
||||||
"--profile",
|
"--profile",
|
||||||
this->profileDir,
|
this->profileDir,
|
||||||
};
|
};
|
||||||
printTalkative("running %s %s", nixEnvCmd, concatStringsSep(" ", removeArgs));
|
printTalkative("running %s %s", newNixEnv, concatStringsSep(" ", removeArgs));
|
||||||
runProgram(nixEnvCmd, false, removeArgs);
|
runProgram(newNixEnv, false, removeArgs);
|
||||||
|
|
||||||
Strings upgradeArgs = {
|
Strings upgradeArgs = {
|
||||||
"--profile",
|
"--profile",
|
||||||
|
@ -136,8 +137,8 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand
|
||||||
"--no-sandbox",
|
"--no-sandbox",
|
||||||
};
|
};
|
||||||
|
|
||||||
printTalkative("running %s %s", nixEnvCmd, concatStringsSep(" ", upgradeArgs));
|
printTalkative("running %s %s", newNixEnv, concatStringsSep(" ", upgradeArgs));
|
||||||
runProgram(nixEnvCmd, false, upgradeArgs);
|
runProgram(newNixEnv, false, upgradeArgs);
|
||||||
} else if (pathExists(canonProfileDir + "/manifest.json")) {
|
} else if (pathExists(canonProfileDir + "/manifest.json")) {
|
||||||
this->upgradeNewStyleProfile(store, storePath);
|
this->upgradeNewStyleProfile(store, storePath);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -35,9 +35,8 @@ in {
|
||||||
|
|
||||||
machine.succeed("nix --version >&2")
|
machine.succeed("nix --version >&2")
|
||||||
|
|
||||||
# Install Lix into the default profile, overriding /run/current-system/sw/bin/nix,
|
# Use Lix to install CppNix into the default profile, overriding /run/current-system/sw/bin/nix
|
||||||
# and thus making Lix think we're not on NixOS.
|
machine.succeed("nix-env --install '${lib.getBin newNix}' --profile /nix/var/nix/profiles/default")
|
||||||
machine.succeed("nix-env --install '${lib.getBin lix}' --profile /nix/var/nix/profiles/default >&2")
|
|
||||||
|
|
||||||
# Make sure that correctly got inserted into our PATH.
|
# Make sure that correctly got inserted into our PATH.
|
||||||
default_profile_nix_path = machine.succeed("command -v nix")
|
default_profile_nix_path = machine.succeed("command -v nix")
|
||||||
|
@ -45,16 +44,15 @@ in {
|
||||||
assert default_profile_nix_path.strip() == "/nix/var/nix/profiles/default/bin/nix", \
|
assert default_profile_nix_path.strip() == "/nix/var/nix/profiles/default/bin/nix", \
|
||||||
f"{default_profile_nix_path.strip()=} != /nix/var/nix/profiles/default/bin/nix"
|
f"{default_profile_nix_path.strip()=} != /nix/var/nix/profiles/default/bin/nix"
|
||||||
|
|
||||||
# And that it's the Nix we specified.
|
# And that it's the Nix we specified
|
||||||
default_profile_version = machine.succeed("nix --version")
|
default_profile_version = machine.succeed("nix --version")
|
||||||
assert "${lixVersion}" in default_profile_version, f"${lixVersion} not in {default_profile_version}"
|
assert "${newNixVersion}" in default_profile_version, f"${newNixVersion} not in {default_profile_version}"
|
||||||
|
|
||||||
# Upgrade to a different version of Nix, and make sure that also worked.
|
# Now upgrade to Lix, and make sure that worked.
|
||||||
|
machine.succeed("${lib.getExe lix} upgrade-nix --debug --store-path ${lix} 2>&1")
|
||||||
machine.succeed("nix upgrade-nix --store-path ${newNix} >&2")
|
|
||||||
default_profile_version = machine.succeed("nix --version")
|
default_profile_version = machine.succeed("nix --version")
|
||||||
print(default_profile_version)
|
print(default_profile_version)
|
||||||
assert "${newNixVersion}" in default_profile_version, f"${newNixVersion} not in {default_profile_version}"
|
assert "${lixVersion}" in default_profile_version, f"${lixVersion} not in {default_profile_version}"
|
||||||
|
|
||||||
# Now 'break' this profile -- use nix profile on it so nix-env will no longer work on it.
|
# Now 'break' this profile -- use nix profile on it so nix-env will no longer work on it.
|
||||||
machine.succeed(
|
machine.succeed(
|
||||||
|
|
Loading…
Reference in a new issue