aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorQyriad <qyriad@qyriad.me>2024-07-15 23:18:03 +0000
committerGerrit Code Review <gerrit@localhost>2024-07-15 23:18:03 +0000
commitc052716edddc94cb027791cc572bcbd22edff590 (patch)
tree9931d4a2f9130dbe30c33ddd98851ed168721e09 /src
parent3447dbfb2c0f3bf7e31577bf2d5908b14ba59601 (diff)
parentae7eab49b952895b3aa88192768843bccabe1ea2 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/libutil/file-system.cc19
-rw-r--r--src/libutil/file-system.hh16
-rw-r--r--src/nix/upgrade-nix.cc31
3 files changed, 51 insertions, 15 deletions
diff --git a/src/libutil/file-system.cc b/src/libutil/file-system.cc
index 278e5187c..f0199d36f 100644
--- a/src/libutil/file-system.cc
+++ b/src/libutil/file-system.cc
@@ -1,4 +1,5 @@
#include <sys/time.h>
+#include <cstdlib>
#include <filesystem>
#include <atomic>
@@ -106,6 +107,24 @@ Path canonPath(PathView path, bool resolveSymlinks)
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)
{
if (chmod(path.c_str(), mode) == -1)
diff --git a/src/libutil/file-system.hh b/src/libutil/file-system.hh
index 636c13f13..e49323e84 100644
--- a/src/libutil/file-system.hh
+++ b/src/libutil/file-system.hh
@@ -47,6 +47,22 @@ Path absPath(Path path,
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
* Not called `chmod` as it shadows and could be confused with
* `int chmod(char *, mode_t)`, which does not handle errors
diff --git a/src/nix/upgrade-nix.cc b/src/nix/upgrade-nix.cc
index 371879791..15c5960d4 100644
--- a/src/nix/upgrade-nix.cc
+++ b/src/nix/upgrade-nix.cc
@@ -97,12 +97,19 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand
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)));
- auto program = store->printStorePath(storePath) + "/bin/nix-env";
- auto s = runProgram(program, false, {"--version"});
+ auto s = runProgram(newNixEnv, false, {"--version"});
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();
@@ -110,23 +117,17 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand
auto const fullStorePath = store->printStorePath(storePath);
if (pathExists(canonProfileDir + "/manifest.nix")) {
-
- // {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
+ // First remove the existing Nix, then use the *new* Nix by absolute path to
// 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).
Strings removeArgs = {
"--uninstall",
- nixEnvCmd,
+ oldNixEnv,
"--profile",
this->profileDir,
};
- printTalkative("running %s %s", nixEnvCmd, concatStringsSep(" ", removeArgs));
- runProgram(nixEnvCmd, false, removeArgs);
+ printTalkative("running %s %s", newNixEnv, concatStringsSep(" ", removeArgs));
+ runProgram(newNixEnv, false, removeArgs);
Strings upgradeArgs = {
"--profile",
@@ -136,8 +137,8 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand
"--no-sandbox",
};
- printTalkative("running %s %s", nixEnvCmd, concatStringsSep(" ", upgradeArgs));
- runProgram(nixEnvCmd, false, upgradeArgs);
+ printTalkative("running %s %s", newNixEnv, concatStringsSep(" ", upgradeArgs));
+ runProgram(newNixEnv, false, upgradeArgs);
} else if (pathExists(canonProfileDir + "/manifest.json")) {
this->upgradeNewStyleProfile(store, storePath);
} else {