aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcmd/common-eval-args.cc32
-rw-r--r--src/libcmd/common-eval-args.hh22
-rw-r--r--src/libcmd/installable-flake.cc9
-rw-r--r--src/libcmd/lix-cmd.pc.in10
-rw-r--r--src/libcmd/meson.build10
-rw-r--r--src/libcmd/nix-cmd.pc.in9
-rw-r--r--src/libcmd/repl-interacter.cc33
-rw-r--r--src/libcmd/repl-interacter.hh5
-rw-r--r--src/libcmd/repl.cc11
-rw-r--r--src/libexpr/eval.cc2
-rw-r--r--src/libexpr/flake/meson.build2
-rw-r--r--src/libexpr/lix-expr.pc.in10
-rw-r--r--src/libexpr/meson.build14
-rw-r--r--src/libexpr/nix-expr.pc.in10
-rw-r--r--src/libexpr/primops.cc2
-rw-r--r--src/libexpr/primops/context.cc6
-rw-r--r--src/libfetchers/cache.cc11
-rw-r--r--src/libfetchers/fetchers.cc4
-rw-r--r--src/libfetchers/lix-fetchers.pc.in10
-rw-r--r--src/libfetchers/meson.build18
-rw-r--r--src/libmain/lix-main.pc.in10
-rw-r--r--src/libmain/meson.build8
-rw-r--r--src/libmain/nix-main.pc.in9
-rw-r--r--src/libstore/build/derivation-goal.cc11
-rw-r--r--src/libstore/build/local-derivation-goal.cc52
-rw-r--r--src/libstore/daemon.cc6
-rw-r--r--src/libstore/globals.hh23
-rw-r--r--src/libstore/linux/fchmodat2-compat.hh28
-rw-r--r--src/libstore/lix-store.pc.in10
-rw-r--r--src/libstore/meson.build11
-rw-r--r--src/libstore/nix-store.pc.in9
-rw-r--r--src/libstore/store-api.cc8
-rw-r--r--src/libstore/store-api.hh3
-rw-r--r--src/libutil/archive.cc9
-rw-r--r--src/libutil/archive.hh2
-rw-r--r--src/libutil/lix-util.pc.in10
-rw-r--r--src/libutil/meson.build18
-rw-r--r--src/libutil/util.cc8
-rw-r--r--src/libutil/util.hh7
-rw-r--r--src/lix-base.pc.in8
-rw-r--r--src/nix/main.cc5
-rw-r--r--src/nix/upgrade-nix.cc18
42 files changed, 309 insertions, 194 deletions
diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc
index 94a4b7922..9beea5aa2 100644
--- a/src/libcmd/common-eval-args.cc
+++ b/src/libcmd/common-eval-args.cc
@@ -164,28 +164,30 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
return res.finish();
}
-SourcePath lookupFileArg(EvalState & state, std::string_view s)
+SourcePath lookupFileArg(EvalState & state, std::string_view fileArg)
{
- if (EvalSettings::isPseudoUrl(s)) {
- auto storePath = fetchers::downloadTarball(
- state.store, EvalSettings::resolvePseudoUrl(s), "source", false).tree.storePath;
+ if (EvalSettings::isPseudoUrl(fileArg)) {
+ auto const url = EvalSettings::resolvePseudoUrl(fileArg);
+ auto const downloaded = fetchers::downloadTarball(
+ state.store,
+ url,
+ /* name */ "source",
+ /* locked */ false
+ );
+ StorePath const storePath = downloaded.tree.storePath;
return state.rootPath(CanonPath(state.store->toRealPath(storePath)));
- }
-
- else if (s.starts_with("flake:")) {
+ } else if (fileArg.starts_with("flake:")) {
experimentalFeatureSettings.require(Xp::Flakes);
- auto flakeRef = parseFlakeRef(std::string(s.substr(6)), {}, true, false);
+ static constexpr size_t FLAKE_LEN = std::string_view("flake:").size();
+ auto flakeRef = parseFlakeRef(std::string(fileArg.substr(FLAKE_LEN)), {}, true, false);
auto storePath = flakeRef.resolve(state.store).fetchTree(state.store).first.storePath;
return state.rootPath(CanonPath(state.store->toRealPath(storePath)));
- }
-
- else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {
- Path p(s.substr(1, s.size() - 2));
+ } else if (fileArg.size() > 2 && fileArg.at(0) == '<' && fileArg.at(fileArg.size() - 1) == '>') {
+ Path p(fileArg.substr(1, fileArg.size() - 2));
return state.findFile(p);
+ } else {
+ return state.rootPath(CanonPath::fromCwd(fileArg));
}
-
- else
- return state.rootPath(CanonPath::fromCwd(s));
}
}
diff --git a/src/libcmd/common-eval-args.hh b/src/libcmd/common-eval-args.hh
index 6359b2579..08a4b65e4 100644
--- a/src/libcmd/common-eval-args.hh
+++ b/src/libcmd/common-eval-args.hh
@@ -28,6 +28,26 @@ private:
std::map<std::string, std::string> autoArgs;
};
-SourcePath lookupFileArg(EvalState & state, std::string_view s);
+/** @brief Resolve an argument that is generally a file, but could be something that
+ * is easy to resolve to a file, like a <lookup path> or a tarball URL.
+ *
+ * In particular, this will resolve and fetch pseudo-URLs starting with
+ * @c channel:, flakerefs starting with @c flake:, and anything that
+ * @ref nix::fetchers::downloadTarball() can take.
+ *
+ * Non-absolute files are looked up relative to the current directory(?)
+ * FIXME: the process's current directory or EvalState's current directory?
+ *
+ * @param state The nix::EvalState to base settings, store, and nixPath from.
+ *
+ * @param fileArg The the path-ish to resolve.
+ *
+ * @return A nix::SourcePath to the resolved and fetched file.
+ *
+ * @exception nix::FileTransferError from nix::fetchers::downloadTarball(). Probably others.
+ *
+ * @exception nix::ThrownError for failed search path lookup. Probably others.
+ */
+SourcePath lookupFileArg(EvalState & state, std::string_view fileArg);
}
diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc
index 615f70945..46bdd411b 100644
--- a/src/libcmd/installable-flake.cc
+++ b/src/libcmd/installable-flake.cc
@@ -105,9 +105,14 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
fmt("while evaluating the flake output attribute '%s'", attrPath)))
{
return { *derivedPathWithInfo };
+ } else {
+ throw Error(
+ "expected flake output attribute '%s' to be a derivation or path but found %s: %s",
+ attrPath,
+ showType(v),
+ ValuePrinter(*this->state, v, errorPrintOptions)
+ );
}
- else
- throw Error("flake output attribute '%s' is not a derivation or path", attrPath);
}
auto drvPath = attr->forceDerivation();
diff --git a/src/libcmd/lix-cmd.pc.in b/src/libcmd/lix-cmd.pc.in
new file mode 100644
index 000000000..f2e3f9d5e
--- /dev/null
+++ b/src/libcmd/lix-cmd.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Lix (libcmd)
+Description: Lix Package Manager (libcmd)
+Version: @PACKAGE_VERSION@
+Requires: lix-base lix-util
+Libs: -L${libdir} -llixcmd
+Cflags: -I${includedir}/lix/libcmd
diff --git a/src/libcmd/meson.build b/src/libcmd/meson.build
index 5a0e61503..4da1b496b 100644
--- a/src/libcmd/meson.build
+++ b/src/libcmd/meson.build
@@ -39,7 +39,7 @@ libcmd_generated_headers = [
]
libcmd = library(
- 'nixcmd',
+ 'lixcmd',
libcmd_generated_headers,
libcmd_sources,
dependencies : [
@@ -59,13 +59,13 @@ libcmd = library(
install_rpath : libdir,
)
-install_headers(libcmd_headers, subdir : 'nix', preserve_path : true)
+install_headers(libcmd_headers, subdir : 'lix/libcmd', preserve_path : true)
custom_target(
command : [ 'cp', '@INPUT@', '@OUTPUT@' ],
input : libcmd_generated_headers,
output : '@PLAINNAME@',
install : true,
- install_dir : includedir / 'nix',
+ install_dir : includedir / 'lix/libcmd',
)
liblixcmd = declare_dependency(
@@ -76,8 +76,8 @@ liblixcmd = declare_dependency(
# FIXME: not using the pkg-config module because it creates way too many deps
# while meson migration is in progress, and we want to not include boost here
configure_file(
- input : 'nix-cmd.pc.in',
- output : 'nix-cmd.pc',
+ input : 'lix-cmd.pc.in',
+ output : 'lix-cmd.pc',
install_dir : libdir / 'pkgconfig',
configuration : {
'prefix' : prefix,
diff --git a/src/libcmd/nix-cmd.pc.in b/src/libcmd/nix-cmd.pc.in
deleted file mode 100644
index 39575f222..000000000
--- a/src/libcmd/nix-cmd.pc.in
+++ /dev/null
@@ -1,9 +0,0 @@
-prefix=@prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Nix
-Description: Nix Package Manager
-Version: @PACKAGE_VERSION@
-Libs: -L${libdir} -lnixcmd
-Cflags: -I${includedir}/nix -std=c++2a
diff --git a/src/libcmd/repl-interacter.cc b/src/libcmd/repl-interacter.cc
index d3567e021..41589cda1 100644
--- a/src/libcmd/repl-interacter.cc
+++ b/src/libcmd/repl-interacter.cc
@@ -1,6 +1,8 @@
#include <cstdio>
#include <iostream>
#include <string>
+#include <string_view>
+#include <cerrno>
#ifdef READLINE
#include <readline/history.h>
@@ -176,15 +178,42 @@ bool ReadlineLikeInteracter::getLine(std::string & input, ReplPromptType promptT
if (!s)
return false;
- write_history(historyFile.c_str());
+ this->writeHistory();
input += s;
input += '\n';
return true;
}
+void ReadlineLikeInteracter::writeHistory()
+{
+ int ret = write_history(historyFile.c_str());
+ int writeHistErr = errno;
+
+ if (ret == 0) {
+ return;
+ }
+
+ // If the open fails, editline returns EOF. If the close fails, editline
+ // forwards the return value of fclose(), which is EOF on error.
+ // readline however, returns the errno.
+ // So if we didn't get exactly EOF, then consider the return value the error
+ // code; otherwise use the errno we saved above.
+ // https://github.com/troglobit/editline/issues/66
+ if (ret != EOF) {
+ writeHistErr = ret;
+ }
+
+ // In any of these cases, we should explicitly ignore the error, but log
+ // them so the user isn't confused why their history is getting eaten.
+
+ std::string_view const errMsg(std::strerror(writeHistErr));
+ warn("ignoring error writing repl history to %s: %s", this->historyFile, errMsg);
+
+}
+
ReadlineLikeInteracter::~ReadlineLikeInteracter()
{
- write_history(historyFile.c_str());
+ this->writeHistory();
}
AutomationInteracter::Guard AutomationInteracter::init(detail::ReplCompleterMixin *)
diff --git a/src/libcmd/repl-interacter.hh b/src/libcmd/repl-interacter.hh
index c31b1a1e6..8f815fceb 100644
--- a/src/libcmd/repl-interacter.hh
+++ b/src/libcmd/repl-interacter.hh
@@ -42,6 +42,11 @@ public:
}
virtual Guard init(detail::ReplCompleterMixin * repl) override;
virtual bool getLine(std::string & input, ReplPromptType promptType) override;
+ /** Writes the current history to the history file.
+ *
+ * This function logs but ignores errors from readline's write_history().
+ */
+ virtual void writeHistory();
virtual ~ReadlineLikeInteracter() override;
};
diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc
index 525c25560..46b6d57ed 100644
--- a/src/libcmd/repl.cc
+++ b/src/libcmd/repl.cc
@@ -90,7 +90,8 @@ struct NixRepl
Strings loadedFiles;
std::function<AnnotatedValues()> getValues;
- const static int envSize = 32768;
+ // Uses 8MiB of memory. It's fine.
+ const static int envSize = 1 << 20;
std::shared_ptr<StaticEnv> staticEnv;
Env * env;
int displ;
@@ -375,6 +376,9 @@ StringSet NixRepl::completePrefix(const std::string & prefix)
// Quietly ignore evaluation errors.
} catch (BadURL & e) {
// Quietly ignore BadURL flake-related errors.
+ } catch (SysError & e) {
+ // Quietly ignore system errors which can for example be raised by
+ // a non-existent file being `import`-ed.
}
}
@@ -854,6 +858,11 @@ void NixRepl::loadReplOverlays()
replInitFilesFunction->determinePos(noPos)
);
+ // n.b. this does in fact load the stuff into the environment twice (once
+ // from the superset of the environment returned by repl-overlays and once
+ // from the thing itself), but it's not fixable because clearEnv here could
+ // lead to dangling references to the old environment in thunks.
+ // https://git.lix.systems/lix-project/lix/issues/337#issuecomment-3745
addAttrsToScope(newAttrs);
}
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 65f0a7938..a8b37325b 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -1115,7 +1115,7 @@ void EvalState::evalFile(const SourcePath & path_, Value & v, bool mustBeTrivial
return;
}
- printTalkative("evaluating file '%1%'", resolvedPath);
+ debug("evaluating file '%1%'", resolvedPath);
Expr * e = nullptr;
auto j = fileParseCache.find(resolvedPath);
diff --git a/src/libexpr/flake/meson.build b/src/libexpr/flake/meson.build
index 3ecc30f4e..cce1b0c75 100644
--- a/src/libexpr/flake/meson.build
+++ b/src/libexpr/flake/meson.build
@@ -4,5 +4,5 @@ libexpr_generated_headers += custom_target(
output : '@PLAINNAME@.gen.hh',
capture : true,
install : true,
- install_dir : includedir / 'nix/flake',
+ install_dir : includedir / 'lix/libexpr/flake',
)
diff --git a/src/libexpr/lix-expr.pc.in b/src/libexpr/lix-expr.pc.in
new file mode 100644
index 000000000..5e850976d
--- /dev/null
+++ b/src/libexpr/lix-expr.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Lix libexpr
+Description: Lix Package Manager (libexpr)
+Version: @PACKAGE_VERSION@
+Requires: lix-base lix-util lix-fetchers lix-store bdw-gc
+Libs: -L${libdir} -llixexpr
+Cflags: -I${includedir}/lix/libexpr
diff --git a/src/libexpr/meson.build b/src/libexpr/meson.build
index 099279d56..fda6fde2c 100644
--- a/src/libexpr/meson.build
+++ b/src/libexpr/meson.build
@@ -15,7 +15,7 @@ parser_tab = custom_target(
# NOTE(Qyriad): Meson doesn't support installing only part of a custom target, so we add
# an install script below which removes parser-tab.cc.
install : true,
- install_dir : includedir / 'nix',
+ install_dir : includedir / 'lix/libexpr',
)
lexer_tab = custom_target(
@@ -37,7 +37,7 @@ lexer_tab = custom_target(
# NOTE(Qyriad): Meson doesn't support installing only part of a custom target, so we add
# an install script below which removes lexer-tab.cc.
install : true,
- install_dir : includedir / 'nix',
+ install_dir : includedir / 'lix/libexpr',
)
# TODO(Qyriad): When the parser and lexer are rewritten this should be removed.
@@ -59,7 +59,7 @@ foreach header : [ 'imported-drv-to-derivation.nix', 'fetchurl.nix' ]
output : '@PLAINNAME@.gen.hh',
capture : true,
install : true,
- install_dir : includedir / 'nix',
+ install_dir : includedir / 'lix/libexpr',
)
endforeach
subdir('flake')
@@ -127,7 +127,7 @@ libexpr_headers = files(
)
libexpr = library(
- 'nixexpr',
+ 'lixexpr',
libexpr_sources,
parser_tab,
lexer_tab,
@@ -152,7 +152,7 @@ libexpr = library(
install_headers(
libexpr_headers,
- subdir : 'nix',
+ subdir : 'lix/libexpr',
preserve_path : true,
)
@@ -164,8 +164,8 @@ liblixexpr = declare_dependency(
# FIXME: not using the pkg-config module because it creates way too many deps
# while meson migration is in progress, and we want to not include boost here
configure_file(
- input : 'nix-expr.pc.in',
- output : 'nix-expr.pc',
+ input : 'lix-expr.pc.in',
+ output : 'lix-expr.pc',
install_dir : libdir / 'pkgconfig',
configuration : {
'prefix' : prefix,
diff --git a/src/libexpr/nix-expr.pc.in b/src/libexpr/nix-expr.pc.in
deleted file mode 100644
index 60ffb5dba..000000000
--- a/src/libexpr/nix-expr.pc.in
+++ /dev/null
@@ -1,10 +0,0 @@
-prefix=@prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Nix
-Description: Nix Package Manager
-Version: @PACKAGE_VERSION@
-Requires: nix-store bdw-gc
-Libs: -L${libdir} -lnixexpr
-Cflags: -I${includedir}/nix -std=c++2a
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 77e7cf22b..64a52dfd6 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -242,7 +242,7 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
// No need to call staticEnv.sort(), because
// args[0]->attrs is already sorted.
- printTalkative("evaluating file '%1%'", path);
+ debug("evaluating file '%1%'", path);
Expr * e = state.parseExprFromFile(resolveExprPath(path), staticEnv);
e->eval(state, *env, v);
diff --git a/src/libexpr/primops/context.cc b/src/libexpr/primops/context.cc
index 1eec8b316..36692aafb 100644
--- a/src/libexpr/primops/context.cc
+++ b/src/libexpr/primops/context.cc
@@ -36,7 +36,7 @@ static RegisterPrimOp primop_hasContext({
> **Example**
>
- > Many operations require a string context to be empty because they are intended only to work with "regular" strings, and also to help users avoid unintentionally loosing track of string context elements.
+ > Many operations require a string context to be empty because they are intended only to work with "regular" strings, and also to help users avoid unintentionally losing track of string context elements.
> `builtins.hasContext` can help create better domain-specific errors in those case.
>
> ```nix
@@ -137,14 +137,14 @@ static RegisterPrimOp primop_addDrvOutputDependencies({
.name = "__addDrvOutputDependencies",
.args = {"s"},
.doc = R"(
- Create a copy of the given string where a single consant string context element is turned into a "derivation deep" string context element.
+ Create a copy of the given string where a single constant string context element is turned into a "derivation deep" string context element.
The store path that is the constant string context element should point to a valid derivation, and end in `.drv`.
The original string context element must not be empty or have multiple elements, and it must not have any other type of element other than a constant or derivation deep element.
The latter is supported so this function is idempotent.
- This is the opposite of [`builtins.unsafeDiscardOutputDependency`](#builtins-addDrvOutputDependencies).
+ This is the opposite of [`builtins.unsafeDiscardOutputDependency`](#builtins-unsafeDiscardOutputDependency).
)",
.fun = prim_addDrvOutputDependencies
});
diff --git a/src/libfetchers/cache.cc b/src/libfetchers/cache.cc
index 0c8ecac9d..672e1e0bc 100644
--- a/src/libfetchers/cache.cc
+++ b/src/libfetchers/cache.cc
@@ -34,7 +34,16 @@ struct CacheImpl : Cache
auto state(_state.lock());
auto dbPath = getCacheDir() + "/nix/fetcher-cache-v1.sqlite";
- createDirs(dirOf(dbPath));
+ // It would be silly to fail fetcher operations if e.g. the user has no
+ // XDG_CACHE_HOME and their HOME directory doesn't exist.
+ // We'll warn the user if that happens, but fallback to an in-memory
+ // backend for the SQLite database.
+ try {
+ createDirs(dirOf(dbPath));
+ } catch (SysError const & ex) {
+ warn("ignoring error initializing Lix fetcher cache: %s", ex.what());
+ dbPath = ":memory:";
+ }
state->db = SQLite(dbPath);
state->db.isCache();
diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc
index dc8df2217..210912cb6 100644
--- a/src/libfetchers/fetchers.cc
+++ b/src/libfetchers/fetchers.cc
@@ -133,6 +133,10 @@ std::pair<Tree, Input> Input::fetch(ref<Store> store) const
}
auto [storePath, input] = [&]() -> std::pair<StorePath, Input> {
+ // *sighs*, we print the base URL, rather than the full URL because the Nixpkgs
+ // fileset lib tests assume that fetching shallow and non-shallow prints exactly the
+ // same stderr...
+ printInfo("fetching %s input '%s'", this->getType(), this->toURL().base);
try {
return scheme->fetch(store, *this);
} catch (Error & e) {
diff --git a/src/libfetchers/lix-fetchers.pc.in b/src/libfetchers/lix-fetchers.pc.in
new file mode 100644
index 000000000..fa213b769
--- /dev/null
+++ b/src/libfetchers/lix-fetchers.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Lix libfetchers
+Description: Lix Package Manager (libfetchers)
+Version: @PACKAGE_VERSION@
+Requires: lix-base lix-util
+Libs: -L${libdir} -llixfetchers
+Cflags: -I${includedir}/lix/libfetchers
diff --git a/src/libfetchers/meson.build b/src/libfetchers/meson.build
index 3809701b7..dbb85b84c 100644
--- a/src/libfetchers/meson.build
+++ b/src/libfetchers/meson.build
@@ -23,7 +23,7 @@ libfetchers_headers = files(
)
libfetchers = library(
- 'nixfetchers',
+ 'lixfetchers',
libfetchers_sources,
dependencies : [
liblixstore,
@@ -35,7 +35,21 @@ libfetchers = library(
install_rpath : libdir,
)
-install_headers(libfetchers_headers, subdir : 'nix', preserve_path : true)
+install_headers(libfetchers_headers, subdir : 'lix/libfetchers', preserve_path : true)
+
+# FIXME: not using the pkg-config module because it creates way too many deps
+# while meson migration is in progress, and we want to not include boost here
+configure_file(
+ input : 'lix-fetchers.pc.in',
+ output : 'lix-fetchers.pc',
+ install_dir : libdir / 'pkgconfig',
+ configuration : {
+ 'prefix' : prefix,
+ 'libdir' : libdir,
+ 'includedir' : includedir,
+ 'PACKAGE_VERSION' : meson.project_version(),
+ },
+)
liblixfetchers = declare_dependency(
include_directories : include_directories('.'),
diff --git a/src/libmain/lix-main.pc.in b/src/libmain/lix-main.pc.in
new file mode 100644
index 000000000..0ceaec393
--- /dev/null
+++ b/src/libmain/lix-main.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Lix libmain
+Description: Lix Package Manager (libmain)
+Version: @PACKAGE_VERSION@
+Requires: lix-base lix-util
+Libs: -L${libdir} -llixmain
+Cflags: -I${includedir}/lix/libmain
diff --git a/src/libmain/meson.build b/src/libmain/meson.build
index 3f50b158d..b17247a9d 100644
--- a/src/libmain/meson.build
+++ b/src/libmain/meson.build
@@ -14,7 +14,7 @@ libmain_headers = files(
)
libmain = library(
- 'nixmain',
+ 'lixmain',
libmain_sources,
dependencies : [
liblixutil,
@@ -25,7 +25,7 @@ libmain = library(
install_rpath : libdir,
)
-install_headers(libmain_headers, subdir : 'nix', preserve_path : true)
+install_headers(libmain_headers, subdir : 'lix/libmain', preserve_path : true)
liblixmain = declare_dependency(
include_directories : include_directories('.'),
@@ -35,8 +35,8 @@ liblixmain = declare_dependency(
# FIXME: not using the pkg-config module because it creates way too many deps
# while meson migration is in progress, and we want to not include boost here
configure_file(
- input : 'nix-main.pc.in',
- output : 'nix-main.pc',
+ input : 'lix-main.pc.in',
+ output : 'lix-main.pc',
install_dir : libdir / 'pkgconfig',
configuration : {
'prefix' : prefix,
diff --git a/src/libmain/nix-main.pc.in b/src/libmain/nix-main.pc.in
deleted file mode 100644
index fb3ead6fa..000000000
--- a/src/libmain/nix-main.pc.in
+++ /dev/null
@@ -1,9 +0,0 @@
-prefix=@prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Nix
-Description: Nix Package Manager
-Version: @PACKAGE_VERSION@
-Libs: -L${libdir} -lnixmain
-Cflags: -I${includedir}/nix -std=c++2a
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index 3f24da276..5fa5deb7c 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -786,13 +786,6 @@ void DerivationGoal::tryLocalBuild() {
}
-static void chmod_(const Path & path, mode_t mode)
-{
- if (chmod(path.c_str(), mode) == -1)
- throw SysError("setting permissions on '%s'", path);
-}
-
-
/* Move/rename path 'src' to 'dst'. Temporarily make 'src' writable if
it's a directory and we're not root (to be able to update the
directory's parent link ".."). */
@@ -803,12 +796,12 @@ static void movePath(const Path & src, const Path & dst)
bool changePerm = (geteuid() && S_ISDIR(st.st_mode) && !(st.st_mode & S_IWUSR));
if (changePerm)
- chmod_(src, st.st_mode | S_IWUSR);
+ chmodPath(src, st.st_mode | S_IWUSR);
renameFile(src, dst);
if (changePerm)
- chmod_(dst, st.st_mode);
+ chmodPath(dst, st.st_mode);
}
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index cdbd0f5a7..9be780212 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -34,7 +34,6 @@
/* Includes required for chroot support. */
#if __linux__
#include <sys/ioctl.h>
-#include "linux/fchmodat2-compat.hh"
#include <net/if.h>
#include <netinet/ip.h>
#include <sys/mman.h>
@@ -44,6 +43,7 @@
#include <sys/prctl.h>
#include <sys/syscall.h>
#if HAVE_SECCOMP
+#include "linux/fchmodat2-compat.hh"
#include <seccomp.h>
#endif
#define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
@@ -272,12 +272,6 @@ void LocalDerivationGoal::tryLocalBuild()
started();
}
-static void chmod_(const Path & path, mode_t mode)
-{
- if (chmod(path.c_str(), mode) == -1)
- throw SysError("setting permissions on '%s'", path);
-}
-
/* Move/rename path 'src' to 'dst'. Temporarily make 'src' writable if
it's a directory and we're not root (to be able to update the
@@ -289,12 +283,12 @@ static void movePath(const Path & src, const Path & dst)
bool changePerm = (geteuid() && S_ISDIR(st.st_mode) && !(st.st_mode & S_IWUSR));
if (changePerm)
- chmod_(src, st.st_mode | S_IWUSR);
+ chmodPath(src, st.st_mode | S_IWUSR);
renameFile(src, dst);
if (changePerm)
- chmod_(dst, st.st_mode);
+ chmodPath(dst, st.st_mode);
}
@@ -696,7 +690,7 @@ void LocalDerivationGoal::startBuilder()
instead.) */
Path chrootTmpDir = chrootRootDir + "/tmp";
createDirs(chrootTmpDir);
- chmod_(chrootTmpDir, 01777);
+ chmodPath(chrootTmpDir, 01777);
/* Create a /etc/passwd with entries for the build user and the
nobody account. The latter is kind of a hack to support
@@ -721,7 +715,7 @@ void LocalDerivationGoal::startBuilder()
build user. */
Path chrootStoreDir = chrootRootDir + worker.store.storeDir;
createDirs(chrootStoreDir);
- chmod_(chrootStoreDir, 01775);
+ chmodPath(chrootStoreDir, 01775);
if (buildUser && chown(chrootStoreDir.c_str(), 0, buildUser->getGID()) == -1)
throw SysError("cannot change ownership of '%1%'", chrootStoreDir);
@@ -1618,7 +1612,6 @@ void LocalDerivationGoal::chownToBuilder(const Path & path)
void setupSeccomp()
{
#if __linux__
- if (!settings.filterSyscalls) return;
#if HAVE_SECCOMP
scmp_filter_ctx ctx;
@@ -1684,15 +1677,18 @@ void setupSeccomp()
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(fsetxattr), 0) != 0)
throw SysError("unable to add seccomp rule");
- if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, settings.allowNewPrivileges ? 0 : 1) != 0)
+ // Set the NO_NEW_PRIVS prctl flag.
+ // This both makes loading seccomp filters work for unprivileged users,
+ // and is an additional security measure in its own right.
+ if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 1) != 0)
throw SysError("unable to set 'no new privileges' seccomp attribute");
if (seccomp_load(ctx) != 0)
throw SysError("unable to load seccomp BPF program");
#else
- throw Error(
- "seccomp is not supported on this platform; "
- "you can bypass this error by setting the option 'filter-syscalls' to false, but note that untrusted builds can then create setuid binaries!");
+ // Still set the no-new-privileges flag if libseccomp is not available.
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
+ throw SysError("PR_SET_NO_NEW_PRIVS failed");
#endif
#endif
}
@@ -1862,7 +1858,7 @@ void LocalDerivationGoal::runChild()
auto dst = chrootRootDir + i.first;
createDirs(dirOf(dst));
writeFile(dst, std::string_view((const char *) sh, sizeof(sh)));
- chmod_(dst, 0555);
+ chmodPath(dst, 0555);
} else
#endif
doBind(i.second.source, chrootRootDir + i.first, i.second.optional);
@@ -1900,7 +1896,7 @@ void LocalDerivationGoal::runChild()
/* Make sure /dev/pts/ptmx is world-writable. With some
Linux versions, it is created with permissions 0. */
- chmod_(chrootRootDir + "/dev/pts/ptmx", 0666);
+ chmodPath(chrootRootDir + "/dev/pts/ptmx", 0666);
} else {
if (errno != EINVAL)
throw SysError("mounting /dev/pts");
@@ -1911,7 +1907,7 @@ void LocalDerivationGoal::runChild()
/* Make /etc unwritable */
if (!parsedDrv->useUidRange())
- chmod_(chrootRootDir + "/etc", 0555);
+ chmodPath(chrootRootDir + "/etc", 0555);
/* Unshare this mount namespace. This is necessary because
pivot_root() below changes the root of the mount
@@ -1960,10 +1956,6 @@ void LocalDerivationGoal::runChild()
throw SysError("setuid failed");
setUser = false;
-
- // Make sure we can't possibly gain new privileges in the sandbox
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
- throw SysError("PR_SET_NO_NEW_PRIVS failed");
}
#endif
@@ -2016,8 +2008,6 @@ void LocalDerivationGoal::runChild()
/* Fill in the arguments. */
Strings args;
- std::string builder = "invalid";
-
#if __APPLE__
/* This has to appear before import statements. */
std::string sandboxProfile = "(version 1)\n";
@@ -2138,15 +2128,9 @@ void LocalDerivationGoal::runChild()
_exit(1);
}
}
+#endif
- builder = drv->builder;
args.push_back(std::string(baseNameOf(drv->builder)));
-#else
- if (!drv->isBuiltin()) {
- builder = drv->builder;
- args.push_back(std::string(baseNameOf(drv->builder)));
- }
-#endif
for (auto & i : drv->args)
args.push_back(rewriteStrings(i, inputRewrites));
@@ -2201,9 +2185,9 @@ void LocalDerivationGoal::runChild()
posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL);
}
- posix_spawn(NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
+ posix_spawn(NULL, drv->builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
#else
- execve(builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
+ execve(drv->builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
#endif
throw SysError("executing '%1%'", drv->builder);
diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc
index 242b4ddc6..420fc8bfe 100644
--- a/src/libstore/daemon.cc
+++ b/src/libstore/daemon.cc
@@ -527,7 +527,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
auto drvs = WorkerProto::Serialise<DerivedPaths>::read(*store, rconn);
BuildMode mode = bmNormal;
if (GET_PROTOCOL_MINOR(clientVersion) >= 15) {
- mode = (BuildMode) readInt(from);
+ mode = buildModeFromInteger(readInt(from));
/* Repairing is not atomic, so disallowed for "untrusted"
clients.
@@ -551,7 +551,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
case WorkerProto::Op::BuildPathsWithResults: {
auto drvs = WorkerProto::Serialise<DerivedPaths>::read(*store, rconn);
BuildMode mode = bmNormal;
- mode = (BuildMode) readInt(from);
+ mode = buildModeFromInteger(readInt(from));
/* Repairing is not atomic, so disallowed for "untrusted"
clients.
@@ -582,7 +582,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
* correctly.
*/
readDerivation(from, *store, drv, Derivation::nameFromPath(drvPath));
- BuildMode buildMode = (BuildMode) readInt(from);
+ BuildMode buildMode = buildModeFromInteger(readInt(from));
logger->startWork();
auto drvType = drv.type();
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 8856d8fae..85789f6b5 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -912,29 +912,6 @@ public:
)"};
#if __linux__
- Setting<bool> filterSyscalls{
- this, true, "filter-syscalls",
- R"(
- Whether to prevent certain dangerous system calls, such as
- creation of setuid/setgid files or adding ACLs or extended
- attributes. Only disable this if you're aware of the
- security implications.
- )"};
-
- Setting<bool> allowNewPrivileges{
- this, false, "allow-new-privileges",
- R"(
- (Linux-specific.) By default, builders on Linux cannot acquire new
- privileges by calling setuid/setgid programs or programs that have
- file capabilities. For example, programs such as `sudo` or `ping`
- will fail. (Note that in sandbox builds, no such programs are
- available unless you bind-mount them into the sandbox via the
- `sandbox-paths` option.) You can allow the use of such programs by
- enabling this option. This is impure and usually undesirable, but
- may be useful in certain scenarios (e.g. to spin up containers or
- set up userspace network interfaces in tests).
- )"};
-
Setting<StringSet> ignoredAcls{
this, {"security.selinux", "system.nfs4_acl", "security.csm"}, "ignored-acls",
R"(
diff --git a/src/libstore/linux/fchmodat2-compat.hh b/src/libstore/linux/fchmodat2-compat.hh
index b05da6786..6ad8a5578 100644
--- a/src/libstore/linux/fchmodat2-compat.hh
+++ b/src/libstore/linux/fchmodat2-compat.hh
@@ -20,18 +20,16 @@
#pragma once
///@file
-#if HAVE_SECCOMP
-# if defined(__alpha__)
-# define NIX_SYSCALL_FCHMODAT2 562
-# elif defined(__x86_64__) && SIZE_MAX == 0xFFFFFFFF // x32
-# define NIX_SYSCALL_FCHMODAT2 1073742276
-# elif defined(__mips__) && defined(__mips64) && defined(_ABIN64) // mips64/n64
-# define NIX_SYSCALL_FCHMODAT2 5452
-# elif defined(__mips__) && defined(__mips64) && defined(_ABIN32) // mips64/n32
-# define NIX_SYSCALL_FCHMODAT2 6452
-# elif defined(__mips__) && defined(_ABIO32) // mips32
-# define NIX_SYSCALL_FCHMODAT2 4452
-# else
-# define NIX_SYSCALL_FCHMODAT2 452
-# endif
-#endif // HAVE_SECCOMP
+#if defined(__alpha__)
+# define NIX_SYSCALL_FCHMODAT2 562
+#elif defined(__x86_64__) && SIZE_MAX == 0xFFFFFFFF // x32
+# define NIX_SYSCALL_FCHMODAT2 1073742276
+#elif defined(__mips__) && defined(__mips64) && defined(_ABIN64) // mips64/n64
+# define NIX_SYSCALL_FCHMODAT2 5452
+#elif defined(__mips__) && defined(__mips64) && defined(_ABIN32) // mips64/n32
+# define NIX_SYSCALL_FCHMODAT2 6452
+#elif defined(__mips__) && defined(_ABIO32) // mips32
+# define NIX_SYSCALL_FCHMODAT2 4452
+#else
+# define NIX_SYSCALL_FCHMODAT2 452
+#endif
diff --git a/src/libstore/lix-store.pc.in b/src/libstore/lix-store.pc.in
new file mode 100644
index 000000000..69c323a28
--- /dev/null
+++ b/src/libstore/lix-store.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Lix libstore
+Description: Lix Package Manager (libstore)
+Version: @PACKAGE_VERSION@
+Requires: lix-base lix-util
+Libs: -L${libdir} -llixstore -llixutil
+Cflags: -I${includedir}/lix/libstore
diff --git a/src/libstore/meson.build b/src/libstore/meson.build
index 5fde92dd0..98549f6d9 100644
--- a/src/libstore/meson.build
+++ b/src/libstore/meson.build
@@ -6,7 +6,7 @@ foreach header : [ 'schema.sql', 'ca-specific-schema.sql' ]
output : '@PLAINNAME@.gen.hh',
capture : true,
install : true,
- install_dir : includedir / 'nix',
+ install_dir : includedir / 'lix/libstore',
)
endforeach
@@ -201,7 +201,7 @@ foreach name, value : cpp_str_defines
endforeach
libstore = library(
- 'nixstore',
+ 'lixstore',
libstore_generated_headers,
libstore_sources,
dependencies : [
@@ -210,7 +210,6 @@ libstore = library(
seccomp,
sqlite,
sodium,
- seccomp,
curl,
openssl,
aws_sdk,
@@ -224,7 +223,7 @@ libstore = library(
install_rpath : libdir,
)
-install_headers(libstore_headers, subdir : 'nix', preserve_path : true)
+install_headers(libstore_headers, subdir : 'lix/libstore', preserve_path : true)
# Used by libfetchers.
liblixstore = declare_dependency(
@@ -235,8 +234,8 @@ liblixstore = declare_dependency(
# FIXME: not using the pkg-config module because it creates way too many deps
# while meson migration is in progress, and we want to not include boost here
configure_file(
- input : 'nix-store.pc.in',
- output : 'nix-store.pc',
+ input : 'lix-store.pc.in',
+ output : 'lix-store.pc',
install_dir : libdir / 'pkgconfig',
configuration : {
'prefix' : prefix,
diff --git a/src/libstore/nix-store.pc.in b/src/libstore/nix-store.pc.in
deleted file mode 100644
index dc42d0bca..000000000
--- a/src/libstore/nix-store.pc.in
+++ /dev/null
@@ -1,9 +0,0 @@
-prefix=@prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Nix
-Description: Nix Package Manager
-Version: @PACKAGE_VERSION@
-Libs: -L${libdir} -lnixstore -lnixutil
-Cflags: -I${includedir}/nix -std=c++2a
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 509b0fa68..ed3566f5e 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -22,6 +22,14 @@ using json = nlohmann::json;
namespace nix {
+BuildMode buildModeFromInteger(int raw) {
+ switch (raw) {
+ case bmNormal: return bmNormal;
+ case bmRepair: return bmRepair;
+ case bmCheck: return bmCheck;
+ default: throw Error("Invalid BuildMode");
+ }
+}
bool Store::isInStore(PathView path) const
{
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 47e644fed..745fce594 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -90,6 +90,9 @@ const uint32_t exportMagic = 0x4558494e;
enum BuildMode { bmNormal, bmRepair, bmCheck };
+/** Checks that a build mode is a valid one, then returns it */
+BuildMode buildModeFromInteger(int);
+
enum TrustedFlag : bool { NotTrusted = false, Trusted = true };
struct BuildResult;
diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc
index 00536c1e1..a18c54ebf 100644
--- a/src/libutil/archive.cc
+++ b/src/libutil/archive.cc
@@ -389,13 +389,4 @@ void copyNAR(Source & source, Sink & sink)
}
-void copyPath(const Path & from, const Path & to)
-{
- auto source = sinkToSource([&](Sink & sink) {
- dumpPath(from, sink);
- });
- restorePath(to, *source);
-}
-
-
}
diff --git a/src/libutil/archive.hh b/src/libutil/archive.hh
index 2cf164a41..017b6633c 100644
--- a/src/libutil/archive.hh
+++ b/src/libutil/archive.hh
@@ -124,8 +124,6 @@ void restorePath(const Path & path, Source & source);
*/
void copyNAR(Source & source, Sink & sink);
-void copyPath(const Path & from, const Path & to);
-
inline constexpr std::string_view narVersionMagic1 = "nix-archive-1";
diff --git a/src/libutil/lix-util.pc.in b/src/libutil/lix-util.pc.in
new file mode 100644
index 000000000..cd749aabb
--- /dev/null
+++ b/src/libutil/lix-util.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Lix libutil
+Description: Lix Package Manager (libutil)
+Version: @PACKAGE_VERSION@
+Requires: lix-base lix-util
+Libs: -L${libdir} -llixutil
+Cflags: -I${includedir}/lix/libutil
diff --git a/src/libutil/meson.build b/src/libutil/meson.build
index 13266f6bd..58e0bd062 100644
--- a/src/libutil/meson.build
+++ b/src/libutil/meson.build
@@ -100,7 +100,7 @@ libutil_headers = files(
)
libutil = library(
- 'nixutil',
+ 'lixutil',
libutil_sources,
dependencies : [
aws_sdk,
@@ -118,7 +118,21 @@ libutil = library(
install : true,
)
-install_headers(libutil_headers, subdir : 'nix', preserve_path : true)
+install_headers(libutil_headers, subdir : 'lix/libutil', preserve_path : true)
+
+# FIXME: not using the pkg-config module because it creates way too many deps
+# while meson migration is in progress, and we want to not include boost here
+configure_file(
+ input : 'lix-util.pc.in',
+ output : 'lix-util.pc',
+ install_dir : libdir / 'pkgconfig',
+ configuration : {
+ 'prefix' : prefix,
+ 'libdir' : libdir,
+ 'includedir' : includedir,
+ 'PACKAGE_VERSION' : meson.project_version(),
+ },
+)
# Used by libstore and libfetchers.
liblixutil = declare_dependency(
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index bc2dd1802..2c0fcc897 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -184,6 +184,11 @@ Path canonPath(PathView path, bool resolveSymlinks)
return s.empty() ? "/" : std::move(s);
}
+void chmodPath(const Path & path, mode_t mode)
+{
+ if (chmod(path.c_str(), mode) == -1)
+ throw SysError("setting permissions on '%s'", path);
+}
Path dirOf(const PathView path)
{
@@ -1799,8 +1804,7 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode)
bind(fdSocket.get(), path);
- if (chmod(path.c_str(), mode) == -1)
- throw SysError("changing permissions on '%1%'", path);
+ chmodPath(path.c_str(), mode);
if (listen(fdSocket.get(), 100) == -1)
throw SysError("cannot listen on socket '%1%'", path);
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 914d6cce0..14868776c 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -78,6 +78,13 @@ Path absPath(Path path,
Path canonPath(PathView path, bool resolveSymlinks = false);
/**
+ * 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
+ */
+void chmodPath(const Path & path, mode_t mode);
+
+/**
* @return The directory part of the given canonical path, i.e.,
* everything before the final `/`. If the path is the root or an
* immediate child thereof (e.g., `/foo`), this means `/`
diff --git a/src/lix-base.pc.in b/src/lix-base.pc.in
new file mode 100644
index 000000000..925a7753a
--- /dev/null
+++ b/src/lix-base.pc.in
@@ -0,0 +1,8 @@
+prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Lix base
+Description: Lix Package Manager (config.hh fixup)
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}/lix
diff --git a/src/nix/main.cc b/src/nix/main.cc
index 64755d445..83d697326 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -363,11 +363,6 @@ void mainWrapped(int argc, char * * argv)
setLogFormat("bar");
settings.verboseBuild = false;
- if (isatty(STDERR_FILENO)) {
- verbosity = lvlNotice;
- } else {
- verbosity = lvlInfo;
- }
NixArgs args;
diff --git a/src/nix/upgrade-nix.cc b/src/nix/upgrade-nix.cc
index 55f833833..3e47fc8f0 100644
--- a/src/nix/upgrade-nix.cc
+++ b/src/nix/upgrade-nix.cc
@@ -111,7 +111,23 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand
if (pathExists(canonProfileDir + "/manifest.nix")) {
- std::string nixEnvCmd = settings.nixBinDir + "/nix-env";
+ // {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
+ // to be "the same package" by nix-env's logic (e.g., if their pnames differ).
+ Strings removeArgs = {
+ "--uninstall",
+ nixEnvCmd,
+ "--profile",
+ this->profileDir,
+ };
+ printTalkative("running %s %s", nixEnvCmd, concatStringsSep(" ", removeArgs));
+ runProgram(nixEnvCmd, false, removeArgs);
+
Strings upgradeArgs = {
"--profile",
this->profileDir,