Merge branch 'master' into paths-from-stdin

This commit is contained in:
Théophane Hufschmitt 2023-03-02 19:20:51 +01:00 committed by GitHub
commit 1f394d2107
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 322 additions and 119 deletions

View file

@ -20,6 +20,8 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: cachix/install-nix-action@v19 - uses: cachix/install-nix-action@v19
with:
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV - run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
- uses: cachix/cachix-action@v12 - uses: cachix/cachix-action@v12
if: needs.check_secrets.outputs.cachix == 'true' if: needs.check_secrets.outputs.cachix == 'true'
@ -59,6 +61,8 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV - run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
- uses: cachix/install-nix-action@v19 - uses: cachix/install-nix-action@v19
with:
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
- uses: cachix/cachix-action@v12 - uses: cachix/cachix-action@v12
with: with:
name: '${{ env.CACHIX_NAME }}' name: '${{ env.CACHIX_NAME }}'
@ -103,6 +107,8 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: cachix/install-nix-action@v19 - uses: cachix/install-nix-action@v19
with:
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV - run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
- run: echo NIX_VERSION="$(nix --experimental-features 'nix-command flakes' eval .\#default.version | tr -d \")" >> $GITHUB_ENV - run: echo NIX_VERSION="$(nix --experimental-features 'nix-command flakes' eval .\#default.version | tr -d \")" >> $GITHUB_ENV
- uses: cachix/cachix-action@v12 - uses: cachix/cachix-action@v12

View file

@ -1 +1 @@
2.14.0 2.15.0

View file

@ -2,13 +2,10 @@ makefiles = \
mk/precompiled-headers.mk \ mk/precompiled-headers.mk \
local.mk \ local.mk \
src/libutil/local.mk \ src/libutil/local.mk \
src/libutil/tests/local.mk \
src/libstore/local.mk \ src/libstore/local.mk \
src/libstore/tests/local.mk \
src/libfetchers/local.mk \ src/libfetchers/local.mk \
src/libmain/local.mk \ src/libmain/local.mk \
src/libexpr/local.mk \ src/libexpr/local.mk \
src/libexpr/tests/local.mk \
src/libcmd/local.mk \ src/libcmd/local.mk \
src/nix/local.mk \ src/nix/local.mk \
src/resolve-system-dependencies/local.mk \ src/resolve-system-dependencies/local.mk \
@ -19,12 +16,22 @@ makefiles = \
misc/systemd/local.mk \ misc/systemd/local.mk \
misc/launchd/local.mk \ misc/launchd/local.mk \
misc/upstart/local.mk \ misc/upstart/local.mk \
doc/manual/local.mk \ doc/manual/local.mk
tests/local.mk \
tests/plugins/local.mk
-include Makefile.config -include Makefile.config
ifeq ($(tests), yes)
makefiles += \
src/libutil/tests/local.mk \
src/libstore/tests/local.mk \
src/libexpr/tests/local.mk \
tests/local.mk \
tests/plugins/local.mk
else
makefiles += \
mk/disable-tests.mk
endif
OPTIMIZE = 1 OPTIMIZE = 1
ifeq ($(OPTIMIZE), 1) ifeq ($(OPTIMIZE), 1)

View file

@ -45,3 +45,4 @@ sandbox_shell = @sandbox_shell@
storedir = @storedir@ storedir = @storedir@
sysconfdir = @sysconfdir@ sysconfdir = @sysconfdir@
system = @system@ system = @system@
tests = @tests@

View file

@ -145,6 +145,13 @@ if test "x$GCC_ATOMIC_BUILTINS_NEED_LIBATOMIC" = xyes; then
LDFLAGS="-latomic $LDFLAGS" LDFLAGS="-latomic $LDFLAGS"
fi fi
# Building without tests is useful for bootstrapping with a smaller footprint
# or running the tests in a separate derivation. Otherwise, we do compile and
# run them.
AC_ARG_ENABLE(tests, AS_HELP_STRING([--disable-tests],[Do not build the tests]),
tests=$enableval, tests=yes)
AC_SUBST(tests)
# LTO is currently broken with clang for unknown reasons; ld segfaults in the llvm plugin # LTO is currently broken with clang for unknown reasons; ld segfaults in the llvm plugin
AC_ARG_ENABLE(lto, AS_HELP_STRING([--enable-lto],[Enable LTO (only supported with GCC) [default=no]]), AC_ARG_ENABLE(lto, AS_HELP_STRING([--enable-lto],[Enable LTO (only supported with GCC) [default=no]]),
lto=$enableval, lto=no) lto=$enableval, lto=no)
@ -270,6 +277,8 @@ if test "$gc" = yes; then
fi fi
if test "$tests" = yes; then
# Look for gtest. # Look for gtest.
PKG_CHECK_MODULES([GTEST], [gtest_main]) PKG_CHECK_MODULES([GTEST], [gtest_main])
@ -282,6 +291,7 @@ dnl No good for C++ libs with mangled symbols
dnl AC_CHECK_LIB([rapidcheck], []) dnl AC_CHECK_LIB([rapidcheck], [])
AC_LANG_POP(C++) AC_LANG_POP(C++)
fi
# Look for nlohmann/json. # Look for nlohmann/json.
PKG_CHECK_MODULES([NLOHMANN_JSON], [nlohmann_json >= 3.9]) PKG_CHECK_MODULES([NLOHMANN_JSON], [nlohmann_json >= 3.9])

View file

@ -71,3 +71,8 @@
<http://libcpuid.sourceforge.net>. <http://libcpuid.sourceforge.net>.
This is an optional dependency and can be disabled This is an optional dependency and can be disabled
by providing a `--disable-cpuid` to the `configure` script. by providing a `--disable-cpuid` to the `configure` script.
- Unless `./configure --disable-tests` is specified, GoogleTest (GTest) and
RapidCheck are required, which are available at
<https://google.github.io/googletest/> and
<https://github.com/emil-e/rapidcheck> respectively.

View file

@ -3,3 +3,20 @@
* Commands which take installables on the command line can now read them from the standard input if * Commands which take installables on the command line can now read them from the standard input if
passed the `--stdin` flag. This is primarily useful when you have a large amount of paths which passed the `--stdin` flag. This is primarily useful when you have a large amount of paths which
exceed the OS arg limit. exceed the OS arg limit.
* The special handling of an [installable](../command-ref/new-cli/nix.md#installables) with `.drv` suffix being interpreted as all of the given [store derivation](../glossary.md#gloss-store-derivation)'s output paths is removed, and instead taken as the literal store path that it represents.
The new `^` syntax for store paths introduced in Nix 2.13 allows explicitly referencing output paths of a derivation.
Using this is better and more clear than relying on the now-removed `.drv` special handling.
For example,
```shell-session
$ nix path-info /nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv
```
now gives info about the derivation itself, while
```shell-session
$ nix path-info /nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^*
```
provides information about each of its outputs.

View file

@ -89,9 +89,7 @@
}); });
configureFlags = configureFlags =
[ lib.optionals stdenv.isLinux [
"CXXFLAGS=-I${lib.getDev rapidcheck}/extras/gtest/include"
] ++ lib.optionals stdenv.isLinux [
"--with-boost=${boost}/lib" "--with-boost=${boost}/lib"
"--with-sandbox-shell=${sh}/bin/busybox" "--with-sandbox-shell=${sh}/bin/busybox"
] ]
@ -99,6 +97,10 @@
"LDFLAGS=-fuse-ld=gold" "LDFLAGS=-fuse-ld=gold"
]; ];
testConfigureFlags = [
"CXXFLAGS=-I${lib.getDev rapidcheck}/extras/gtest/include"
];
nativeBuildDeps = nativeBuildDeps =
[ [
buildPackages.bison buildPackages.bison
@ -124,13 +126,16 @@
libarchive libarchive
boost boost
lowdown-nix lowdown-nix
gtest
rapidcheck
] ]
++ lib.optionals stdenv.isLinux [libseccomp] ++ lib.optionals stdenv.isLinux [libseccomp]
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium ++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium
++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid; ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid;
checkDeps = [
gtest
rapidcheck
];
awsDeps = lib.optional (stdenv.isLinux || stdenv.isDarwin) awsDeps = lib.optional (stdenv.isLinux || stdenv.isDarwin)
(aws-sdk-cpp.override { (aws-sdk-cpp.override {
apis = ["s3" "transfer"]; apis = ["s3" "transfer"];
@ -200,7 +205,7 @@
VERSION_SUFFIX = versionSuffix; VERSION_SUFFIX = versionSuffix;
nativeBuildInputs = nativeBuildDeps; nativeBuildInputs = nativeBuildDeps;
buildInputs = buildDeps ++ awsDeps; buildInputs = buildDeps ++ awsDeps ++ checkDeps;
propagatedBuildInputs = propagatedDeps; propagatedBuildInputs = propagatedDeps;
enableParallelBuilding = true; enableParallelBuilding = true;
@ -305,7 +310,7 @@
}; };
let let
canRunInstalled = currentStdenv.buildPlatform.canExecute currentStdenv.hostPlatform; canRunInstalled = currentStdenv.buildPlatform.canExecute currentStdenv.hostPlatform;
in currentStdenv.mkDerivation { in currentStdenv.mkDerivation (finalAttrs: {
name = "nix-${version}"; name = "nix-${version}";
inherit version; inherit version;
@ -318,7 +323,8 @@
nativeBuildInputs = nativeBuildDeps; nativeBuildInputs = nativeBuildDeps;
buildInputs = buildDeps buildInputs = buildDeps
# There have been issues building these dependencies # There have been issues building these dependencies
++ lib.optionals (currentStdenv.hostPlatform == currentStdenv.buildPlatform) awsDeps; ++ lib.optionals (currentStdenv.hostPlatform == currentStdenv.buildPlatform) awsDeps
++ lib.optionals finalAttrs.doCheck checkDeps;
propagatedBuildInputs = propagatedDeps; propagatedBuildInputs = propagatedDeps;
@ -348,6 +354,8 @@
configureFlags = configureFlags ++ configureFlags = configureFlags ++
[ "--sysconfdir=/etc" ] ++ [ "--sysconfdir=/etc" ] ++
lib.optional stdenv.hostPlatform.isStatic "--enable-embedded-sandbox-shell" ++ lib.optional stdenv.hostPlatform.isStatic "--enable-embedded-sandbox-shell" ++
[ (lib.enableFeature finalAttrs.doCheck "tests") ] ++
lib.optionals finalAttrs.doCheck testConfigureFlags ++
lib.optional (!canRunInstalled) "--disable-doc-gen"; lib.optional (!canRunInstalled) "--disable-doc-gen";
enableParallelBuilding = true; enableParallelBuilding = true;
@ -369,7 +377,7 @@
''} ''}
''; '';
doInstallCheck = true; doInstallCheck = finalAttrs.doCheck;
installCheckFlags = "sysconfdir=$(out)/etc"; installCheckFlags = "sysconfdir=$(out)/etc";
separateDebugInfo = !currentStdenv.hostPlatform.isStatic; separateDebugInfo = !currentStdenv.hostPlatform.isStatic;
@ -411,7 +419,7 @@
}); });
meta.platforms = lib.platforms.unix; meta.platforms = lib.platforms.unix;
}; });
lowdown-nix = with final; currentStdenv.mkDerivation rec { lowdown-nix = with final; currentStdenv.mkDerivation rec {
name = "lowdown-0.9.0"; name = "lowdown-0.9.0";
@ -462,6 +470,14 @@
buildNoGc = forAllSystems (system: self.packages.${system}.nix.overrideAttrs (a: { configureFlags = (a.configureFlags or []) ++ ["--enable-gc=no"];})); buildNoGc = forAllSystems (system: self.packages.${system}.nix.overrideAttrs (a: { configureFlags = (a.configureFlags or []) ++ ["--enable-gc=no"];}));
buildNoTests = forAllSystems (system:
self.packages.${system}.nix.overrideAttrs (a: {
doCheck =
assert ! a?dontCheck;
false;
})
);
# Perl bindings for various platforms. # Perl bindings for various platforms.
perlBindings = forAllSystems (system: nixpkgsFor.${system}.native.nix.perl-bindings); perlBindings = forAllSystems (system: nixpkgsFor.${system}.native.nix.perl-bindings);
@ -634,9 +650,9 @@
nativeBuildInputs = nativeBuildDeps nativeBuildInputs = nativeBuildDeps
++ (lib.optionals stdenv.cc.isClang [ pkgs.bear pkgs.clang-tools ]); ++ (lib.optionals stdenv.cc.isClang [ pkgs.bear pkgs.clang-tools ]);
buildInputs = buildDeps ++ propagatedDeps ++ awsDeps; buildInputs = buildDeps ++ propagatedDeps ++ awsDeps ++ checkDeps;
inherit configureFlags; configureFlags = configureFlags ++ testConfigureFlags;
enableParallelBuilding = true; enableParallelBuilding = true;

View file

@ -123,6 +123,7 @@ release:
`/home/eelco/Dev/nixpkgs-pristine`. `/home/eelco/Dev/nixpkgs-pristine`.
TODO: trigger nixos.org netlify: https://docs.netlify.com/configure-builds/build-hooks/ TODO: trigger nixos.org netlify: https://docs.netlify.com/configure-builds/build-hooks/
* Prepare for the next point release by editing `.version` to * Prepare for the next point release by editing `.version` to
e.g. e.g.
@ -152,7 +153,7 @@ release:
from the previous milestone, and close the previous milestone. Set from the previous milestone, and close the previous milestone. Set
the date for the next milestone 6 weeks from now. the date for the next milestone 6 weeks from now.
* Create a backport label * Create a backport label.
* Post an [announcement on Discourse](https://discourse.nixos.org/c/announcements/8), including the contents of * Post an [announcement on Discourse](https://discourse.nixos.org/c/announcements/8), including the contents of
`rl-$VERSION.md`. `rl-$VERSION.md`.

12
mk/disable-tests.mk Normal file
View file

@ -0,0 +1,12 @@
# This file is only active for `./configure --disable-tests`.
# Running `make check` or `make installcheck` would indicate a mistake in the
# caller.
installcheck:
@echo "Tests are disabled. Configure without '--disable-tests', or avoid calling 'make installcheck'."
@exit 1
# This currently has little effect.
check:
@echo "Tests are disabled. Configure without '--disable-tests', or avoid calling 'make check'."
@exit 1

View file

@ -8,7 +8,7 @@ if [ -n "${XDG_STATE_HOME-}" ]; then
else else
NIX_LINK_NEW=$HOME/.local/state/nix/profile NIX_LINK_NEW=$HOME/.local/state/nix/profile
fi fi
if ! [ -e "$NIX_LINK" ]; then if [ -e "$NIX_LINK_NEW" ]; then
NIX_LINK="$NIX_LINK_NEW" NIX_LINK="$NIX_LINK_NEW"
else else
if [ -t 2 ] && [ -e "$NIX_LINK_NEW" ]; then if [ -t 2 ] && [ -e "$NIX_LINK_NEW" ]; then

View file

@ -8,7 +8,7 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then
else else
NIX_LINK_NEW="$HOME/.local/state/nix/profile" NIX_LINK_NEW="$HOME/.local/state/nix/profile"
fi fi
if ! [ -e "$NIX_LINK" ]; then if [ -e "$NIX_LINK_NEW" ]; then
NIX_LINK="$NIX_LINK_NEW" NIX_LINK="$NIX_LINK_NEW"
else else
if [ -t 2 ] && [ -e "$NIX_LINK_NEW" ]; then if [ -t 2 ] && [ -e "$NIX_LINK_NEW" ]; then

View file

@ -31,25 +31,22 @@ InstallableDerivedPath InstallableDerivedPath::parse(
ExtendedOutputsSpec extendedOutputsSpec) ExtendedOutputsSpec extendedOutputsSpec)
{ {
auto derivedPath = std::visit(overloaded { auto derivedPath = std::visit(overloaded {
// If the user did not use ^, we treat the output more liberally. // If the user did not use ^, we treat the output more
// liberally: we accept a symlink chain or an actual
// store path.
[&](const ExtendedOutputsSpec::Default &) -> DerivedPath { [&](const ExtendedOutputsSpec::Default &) -> DerivedPath {
// First, we accept a symlink chain or an actual store path.
auto storePath = store->followLinksToStorePath(prefix); auto storePath = store->followLinksToStorePath(prefix);
// Second, we see if the store path ends in `.drv` to decide what sort // Remove this prior to stabilizing the new CLI.
// of derived path they want. if (storePath.isDerivation()) {
// auto oldDerivedPath = DerivedPath::Built {
// This handling predates the `^` syntax. The `^*` in .drvPath = storePath,
// `/nix/store/hash-foo.drv^*` unambiguously means "do the .outputs = OutputsSpec::All { },
// `DerivedPath::Built` case", so plain `/nix/store/hash-foo.drv` could };
// also unambiguously mean "do the DerivedPath::Opaque` case". warn(
// "The interpretation of store paths arguments ending in `.drv` recently changed. If this command is now failing try again with '%s'",
// Issue #7261 tracks reconsidering this `.drv` dispatching. oldDerivedPath.to_string(*store));
return storePath.isDerivation() };
? (DerivedPath) DerivedPath::Built { return DerivedPath::Opaque {
.drvPath = std::move(storePath),
.outputs = OutputsSpec::All {},
}
: (DerivedPath) DerivedPath::Opaque {
.path = std::move(storePath), .path = std::move(storePath),
}; };
}, },

View file

@ -677,9 +677,12 @@ StorePathSet Installable::toDerivations(
for (const auto & b : i->toDerivedPaths()) for (const auto & b : i->toDerivedPaths())
std::visit(overloaded { std::visit(overloaded {
[&](const DerivedPath::Opaque & bo) { [&](const DerivedPath::Opaque & bo) {
if (!useDeriver) drvPaths.insert(
throw Error("argument '%s' did not evaluate to a derivation", i->what()); bo.path.isDerivation()
drvPaths.insert(getDeriver(store, *i, bo.path)); ? bo.path
: useDeriver
? getDeriver(store, *i, bo.path)
: throw Error("argument '%s' did not evaluate to a derivation", i->what()));
}, },
[&](const DerivedPath::Built & bfd) { [&](const DerivedPath::Built & bfd) {
drvPaths.insert(bfd.drvPath); drvPaths.insert(bfd.drvPath);

View file

@ -63,6 +63,11 @@ public:
one that contains a commit hash or content hash. */ one that contains a commit hash or content hash. */
bool isLocked() const { return locked; } bool isLocked() const { return locked; }
/* Check whether the input carries all necessary info required
for cache insertion and substitution.
These fields are used to uniquely identify cached trees
within the "tarball TTL" window without necessarily
indicating that the input's origin is unchanged. */
bool hasAllInfo() const; bool hasAllInfo() const;
bool operator ==(const Input & other) const; bool operator ==(const Input & other) const;

View file

@ -92,13 +92,11 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
if (S_ISLNK(dstSt.st_mode)) { if (S_ISLNK(dstSt.st_mode)) {
auto prevPriority = state.priorities[dstFile]; auto prevPriority = state.priorities[dstFile];
if (prevPriority == priority) if (prevPriority == priority)
throw Error( throw BuildEnvFileConflictError(
"files '%1%' and '%2%' have the same priority %3%; " readLink(dstFile),
"use 'nix-env --set-flag priority NUMBER INSTALLED_PKGNAME' " srcFile,
"or type 'nix profile install --help' if using 'nix profile' to find out how " priority
"to change the priority of one of the conflicting packages" );
" (0 being the highest priority)",
srcFile, readLink(dstFile), priority);
if (prevPriority < priority) if (prevPriority < priority)
continue; continue;
if (unlink(dstFile.c_str()) == -1) if (unlink(dstFile.c_str()) == -1)

View file

@ -12,6 +12,32 @@ struct Package {
Package(const Path & path, bool active, int priority) : path{path}, active{active}, priority{priority} {} Package(const Path & path, bool active, int priority) : path{path}, active{active}, priority{priority} {}
}; };
class BuildEnvFileConflictError : public Error
{
public:
const Path fileA;
const Path fileB;
int priority;
BuildEnvFileConflictError(
const Path fileA,
const Path fileB,
int priority
)
: Error(
"Unable to build profile. There is a conflict for the following files:\n"
"\n"
" %1%\n"
" %2%",
fileA,
fileB
)
, fileA(fileA)
, fileB(fileB)
, priority(priority)
{}
};
typedef std::vector<Package> Packages; typedef std::vector<Package> Packages;
void buildProfile(const Path & out, Packages && pkgs); void buildProfile(const Path & out, Packages && pkgs);

View file

@ -88,6 +88,10 @@ struct curlFileTransfer : public FileTransfer
{request.uri}, request.parentAct) {request.uri}, request.parentAct)
, callback(std::move(callback)) , callback(std::move(callback))
, finalSink([this](std::string_view data) { , finalSink([this](std::string_view data) {
if (errorSink) {
(*errorSink)(data);
}
if (this->request.dataCallback) { if (this->request.dataCallback) {
auto httpStatus = getHTTPStatus(); auto httpStatus = getHTTPStatus();
@ -163,8 +167,6 @@ struct curlFileTransfer : public FileTransfer
} }
} }
if (errorSink)
(*errorSink)({(char *) contents, realSize});
(*decompressionSink)({(char *) contents, realSize}); (*decompressionSink)({(char *) contents, realSize});
return realSize; return realSize;

View file

@ -38,8 +38,6 @@ class RemoteStore : public virtual RemoteStoreConfig,
{ {
public: public:
virtual bool sameMachine() = 0;
RemoteStore(const Params & params); RemoteStore(const Params & params);
/* Implementations of abstract store API methods. */ /* Implementations of abstract store API methods. */

View file

@ -49,9 +49,6 @@ public:
return *uriSchemes().begin() + "://" + host; return *uriSchemes().begin() + "://" + host;
} }
bool sameMachine() override
{ return false; }
// FIXME extend daemon protocol, move implementation to RemoteStore // FIXME extend daemon protocol, move implementation to RemoteStore
std::optional<std::string> getBuildLogExact(const StorePath & path) override std::optional<std::string> getBuildLogExact(const StorePath & path) override
{ unsupported("getBuildLogExact"); } { unsupported("getBuildLogExact"); }

View file

@ -855,6 +855,7 @@ json Store::pathInfoToJSON(const StorePathSet & storePaths,
auto info = queryPathInfo(storePath); auto info = queryPathInfo(storePath);
jsonPath["path"] = printStorePath(info->path); jsonPath["path"] = printStorePath(info->path);
jsonPath["valid"] = true;
jsonPath["narHash"] = info->narHash.to_string(hashBase, true); jsonPath["narHash"] = info->narHash.to_string(hashBase, true);
jsonPath["narSize"] = info->narSize; jsonPath["narSize"] = info->narSize;

View file

@ -29,9 +29,6 @@ public:
static std::set<std::string> uriSchemes() static std::set<std::string> uriSchemes()
{ return {"unix"}; } { return {"unix"}; }
bool sameMachine() override
{ return true; }
ref<FSAccessor> getFSAccessor() override ref<FSAccessor> getFSAccessor() override
{ return LocalFSStore::getFSAccessor(); } { return LocalFSStore::getFSAccessor(); }

View file

@ -32,7 +32,8 @@ void Logger::warn(const std::string & msg)
void Logger::writeToStdout(std::string_view s) void Logger::writeToStdout(std::string_view s)
{ {
std::cout << s << "\n"; writeFull(STDOUT_FILENO, s);
writeFull(STDOUT_FILENO, "\n");
} }
class SimpleLogger : public Logger class SimpleLogger : public Logger

View file

@ -102,11 +102,9 @@ public:
virtual void writeToStdout(std::string_view s); virtual void writeToStdout(std::string_view s);
template<typename... Args> template<typename... Args>
inline void cout(const std::string & fs, const Args & ... args) inline void cout(const Args & ... args)
{ {
boost::format f(fs); writeToStdout(fmt(args...));
formatHelper(f, args...);
writeToStdout(f.str());
} }
virtual std::optional<char> ask(std::string_view s) virtual std::optional<char> ask(std::string_view s)

View file

@ -139,11 +139,11 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
for (auto & buildable : buildables) { for (auto & buildable : buildables) {
std::visit(overloaded { std::visit(overloaded {
[&](const BuiltPath::Opaque & bo) { [&](const BuiltPath::Opaque & bo) {
std::cout << store->printStorePath(bo.path) << std::endl; logger->cout(store->printStorePath(bo.path));
}, },
[&](const BuiltPath::Built & bfd) { [&](const BuiltPath::Built & bfd) {
for (auto & output : bfd.outputs) { for (auto & output : bfd.outputs) {
std::cout << store->printStorePath(output.second) << std::endl; logger->cout(store->printStorePath(output.second));
} }
}, },
}, buildable.path.raw()); }, buildable.path.raw());

View file

@ -17,7 +17,7 @@ struct MixCat : virtual Args
if (st.type != FSAccessor::Type::tRegular) if (st.type != FSAccessor::Type::tRegular)
throw Error("path '%1%' is not a regular file", path); throw Error("path '%1%' is not a regular file", path);
std::cout << accessor->readFile(path); writeFull(STDOUT_FILENO, accessor->readFile(path));
} }
}; };

View file

@ -25,7 +25,7 @@ struct CmdDescribeStores : Command, MixJSON
res[storeName] = storeConfig->toJSON(); res[storeName] = storeConfig->toJSON();
} }
if (json) { if (json) {
std::cout << res; logger->cout("%s", res);
} else { } else {
for (auto & [storeName, storeConfig] : res.items()) { for (auto & [storeName, storeConfig] : res.items()) {
std::cout << "## " << storeName << std::endl << std::endl; std::cout << "## " << storeName << std::endl << std::endl;

View file

@ -97,7 +97,7 @@ void printClosureDiff(
items.push_back(fmt("%s → %s", showVersions(removed), showVersions(added))); items.push_back(fmt("%s → %s", showVersions(removed), showVersions(added)));
if (showDelta) if (showDelta)
items.push_back(fmt("%s%+.1f KiB" ANSI_NORMAL, sizeDelta > 0 ? ANSI_RED : ANSI_GREEN, sizeDelta / 1024.0)); items.push_back(fmt("%s%+.1f KiB" ANSI_NORMAL, sizeDelta > 0 ? ANSI_RED : ANSI_GREEN, sizeDelta / 1024.0));
std::cout << fmt("%s%s: %s\n", indent, name, concatStringsSep(", ", items)); logger->cout("%s%s: %s", indent, name, concatStringsSep(", ", items));
} }
} }
} }

View file

@ -112,11 +112,11 @@ struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
else if (raw) { else if (raw) {
stopProgressBar(); stopProgressBar();
std::cout << *state->coerceToString(noPos, *v, context, "while generating the eval command output"); writeFull(STDOUT_FILENO, *state->coerceToString(noPos, *v, context, "while generating the eval command output"));
} }
else if (json) { else if (json) {
std::cout << printValueAsJSON(*state, true, *v, pos, context, false).dump() << std::endl; logger->cout("%s", printValueAsJSON(*state, true, *v, pos, context, false));
} }
else { else {

View file

@ -952,7 +952,7 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun
{"path", store->printStorePath(flake.flake.sourceInfo->storePath)}, {"path", store->printStorePath(flake.flake.sourceInfo->storePath)},
{"inputs", traverse(*flake.lockFile.root)}, {"inputs", traverse(*flake.lockFile.root)},
}; };
std::cout << jsonRoot.dump() << std::endl; logger->cout("%s", jsonRoot);
} else { } else {
traverse(*flake.lockFile.root); traverse(*flake.lockFile.root);
} }

View file

@ -53,7 +53,7 @@ struct CmdLog : InstallableCommand
if (!log) continue; if (!log) continue;
stopProgressBar(); stopProgressBar();
printInfo("got build log for '%s' from '%s'", installable->what(), logSub.getUri()); printInfo("got build log for '%s' from '%s'", installable->what(), logSub.getUri());
std::cout << *log; writeFull(STDOUT_FILENO, *log);
return; return;
} }

View file

@ -93,7 +93,7 @@ struct MixLs : virtual Args, MixJSON
if (json) { if (json) {
if (showDirectory) if (showDirectory)
throw UsageError("'--directory' is useless with '--json'"); throw UsageError("'--directory' is useless with '--json'");
std::cout << listNar(accessor, path, recursive); logger->cout("%s", listNar(accessor, path, recursive));
} else } else
listText(accessor); listText(accessor);
} }

View file

@ -292,7 +292,7 @@ void mainWrapped(int argc, char * * argv)
NixArgs args; NixArgs args;
if (argc == 2 && std::string(argv[1]) == "__dump-args") { if (argc == 2 && std::string(argv[1]) == "__dump-args") {
std::cout << args.toJSON().dump() << "\n"; logger->cout("%s", args.toJSON());
return; return;
} }
@ -312,7 +312,7 @@ void mainWrapped(int argc, char * * argv)
b["doc"] = trim(stripIndentation(primOp->doc)); b["doc"] = trim(stripIndentation(primOp->doc));
res[state.symbols[builtin.name]] = std::move(b); res[state.symbols[builtin.name]] = std::move(b);
} }
std::cout << res.dump() << "\n"; logger->cout("%s", res);
return; return;
} }
@ -321,14 +321,14 @@ void mainWrapped(int argc, char * * argv)
if (completions) { if (completions) {
switch (completionType) { switch (completionType) {
case ctNormal: case ctNormal:
std::cout << "normal\n"; break; logger->cout("normal"); break;
case ctFilenames: case ctFilenames:
std::cout << "filenames\n"; break; logger->cout("filenames"); break;
case ctAttrs: case ctAttrs:
std::cout << "attrs\n"; break; logger->cout("attrs"); break;
} }
for (auto & s : *completions) for (auto & s : *completions)
std::cout << s.completion << "\t" << trim(s.description) << "\n"; logger->cout(s.completion + "\t" + trim(s.description));
} }
}); });

View file

@ -45,7 +45,7 @@ struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand,
} }
auto json = json::object(); auto json = json::object();
json["rewrites"] = jsonRewrites; json["rewrites"] = jsonRewrites;
std::cout << json.dump(); logger->cout("%s", json);
} else { } else {
for (auto & path : storePaths) { for (auto & path : storePaths) {
auto i = remappings.find(path); auto i = remappings.find(path);

View file

@ -234,9 +234,9 @@ static int main_nix_prefetch_url(int argc, char * * argv)
if (!printPath) if (!printPath)
printInfo("path is '%s'", store->printStorePath(storePath)); printInfo("path is '%s'", store->printStorePath(storePath));
std::cout << printHash16or32(hash) << std::endl; logger->cout(printHash16or32(hash));
if (printPath) if (printPath)
std::cout << store->printStorePath(storePath) << std::endl; logger->cout(store->printStorePath(storePath));
return 0; return 0;
} }

View file

@ -228,12 +228,12 @@ struct ProfileManifest
while (i != prevElems.end() || j != curElems.end()) { while (i != prevElems.end() || j != curElems.end()) {
if (j != curElems.end() && (i == prevElems.end() || i->describe() > j->describe())) { if (j != curElems.end() && (i == prevElems.end() || i->describe() > j->describe())) {
std::cout << fmt("%s%s: ∅ -> %s\n", indent, j->describe(), j->versions()); logger->cout("%s%s: ∅ -> %s", indent, j->describe(), j->versions());
changes = true; changes = true;
++j; ++j;
} }
else if (i != prevElems.end() && (j == curElems.end() || i->describe() < j->describe())) { else if (i != prevElems.end() && (j == curElems.end() || i->describe() < j->describe())) {
std::cout << fmt("%s%s: %s -> ∅\n", indent, i->describe(), i->versions()); logger->cout("%s%s: %s -> ∅", indent, i->describe(), i->versions());
changes = true; changes = true;
++i; ++i;
} }
@ -241,7 +241,7 @@ struct ProfileManifest
auto v1 = i->versions(); auto v1 = i->versions();
auto v2 = j->versions(); auto v2 = j->versions();
if (v1 != v2) { if (v1 != v2) {
std::cout << fmt("%s%s: %s -> %s\n", indent, i->describe(), v1, v2); logger->cout("%s%s: %s -> %s", indent, i->describe(), v1, v2);
changes = true; changes = true;
} }
++i; ++i;
@ -250,7 +250,7 @@ struct ProfileManifest
} }
if (!changes) if (!changes)
std::cout << fmt("%sNo changes.\n", indent); logger->cout("%sNo changes.", indent);
} }
}; };
@ -330,7 +330,63 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
manifest.elements.push_back(std::move(element)); manifest.elements.push_back(std::move(element));
} }
try {
updateProfile(manifest.build(store)); updateProfile(manifest.build(store));
} catch (BuildEnvFileConflictError & conflictError) {
// FIXME use C++20 std::ranges once macOS has it
// See https://github.com/NixOS/nix/compare/3efa476c5439f8f6c1968a6ba20a31d1239c2f04..1fe5d172ece51a619e879c4b86f603d9495cc102
auto findRefByFilePath = [&]<typename Iterator>(Iterator begin, Iterator end) {
for (auto it = begin; it != end; it++) {
auto profileElement = *it;
for (auto & storePath : profileElement.storePaths) {
if (conflictError.fileA.starts_with(store->printStorePath(storePath))) {
return std::pair(conflictError.fileA, profileElement.source->originalRef);
}
if (conflictError.fileB.starts_with(store->printStorePath(storePath))) {
return std::pair(conflictError.fileB, profileElement.source->originalRef);
}
}
}
throw conflictError;
};
// There are 2 conflicting files. We need to find out which one is from the already installed package and
// which one is the package that is the new package that is being installed.
// The first matching package is the one that was already installed (original).
auto [originalConflictingFilePath, originalConflictingRef] = findRefByFilePath(manifest.elements.begin(), manifest.elements.end());
// The last matching package is the one that was going to be installed (new).
auto [newConflictingFilePath, newConflictingRef] = findRefByFilePath(manifest.elements.rbegin(), manifest.elements.rend());
throw Error(
"An existing package already provides the following file:\n"
"\n"
" %1%\n"
"\n"
"This is the conflicting file from the new package:\n"
"\n"
" %2%\n"
"\n"
"To remove the existing package:\n"
"\n"
" nix profile remove %3%\n"
"\n"
"The new package can also be installed next to the existing one by assigning a different priority.\n"
"The conflicting packages have a priority of %5%.\n"
"To prioritise the new package:\n"
"\n"
" nix profile install %4% --priority %6%\n"
"\n"
"To prioritise the existing package:\n"
"\n"
" nix profile install %4% --priority %7%\n",
originalConflictingFilePath,
newConflictingFilePath,
originalConflictingRef.to_string(),
newConflictingRef.to_string(),
conflictError.priority,
conflictError.priority - 1,
conflictError.priority + 1
);
}
} }
}; };
@ -584,9 +640,9 @@ struct CmdProfileDiffClosures : virtual StoreCommand, MixDefaultProfile
for (auto & gen : gens) { for (auto & gen : gens) {
if (prevGen) { if (prevGen) {
if (!first) std::cout << "\n"; if (!first) logger->cout("");
first = false; first = false;
std::cout << fmt("Version %d -> %d:\n", prevGen->number, gen.number); logger->cout("Version %d -> %d:", prevGen->number, gen.number);
printClosureDiff(store, printClosureDiff(store,
store->followLinksToStorePath(prevGen->path), store->followLinksToStorePath(prevGen->path),
store->followLinksToStorePath(gen.path), store->followLinksToStorePath(gen.path),
@ -622,10 +678,10 @@ struct CmdProfileHistory : virtual StoreCommand, EvalCommand, MixDefaultProfile
for (auto & gen : gens) { for (auto & gen : gens) {
ProfileManifest manifest(*getEvalState(), gen.path); ProfileManifest manifest(*getEvalState(), gen.path);
if (!first) std::cout << "\n"; if (!first) logger->cout("");
first = false; first = false;
std::cout << fmt("Version %s%d" ANSI_NORMAL " (%s)%s:\n", logger->cout("Version %s%d" ANSI_NORMAL " (%s)%s:",
gen.number == curGen ? ANSI_GREEN : ANSI_BOLD, gen.number == curGen ? ANSI_GREEN : ANSI_BOLD,
gen.number, gen.number,
std::put_time(std::gmtime(&gen.creationTime), "%Y-%m-%d"), std::put_time(std::gmtime(&gen.creationTime), "%Y-%m-%d"),

View file

@ -65,18 +65,16 @@ struct CmdRealisationInfo : BuiltPathsCommand, MixJSON
res.push_back(currentPath); res.push_back(currentPath);
} }
std::cout << res.dump(); logger->cout("%s", res);
} }
else { else {
for (auto & path : realisations) { for (auto & path : realisations) {
if (auto realisation = std::get_if<Realisation>(&path.raw)) { if (auto realisation = std::get_if<Realisation>(&path.raw)) {
std::cout << logger->cout("%s %s",
realisation->id.to_string() << " " << realisation->id.to_string(),
store->printStorePath(realisation->outPath); store->printStorePath(realisation->outPath));
} else } else
std::cout << store->printStorePath(path.path()); logger->cout("%s", store->printStorePath(path.path()));
std::cout << std::endl;
} }
} }
} }

View file

@ -196,9 +196,8 @@ struct CmdSearch : InstallableCommand, MixJSON
for (auto & cursor : installable->getCursors(*state)) for (auto & cursor : installable->getCursors(*state))
visit(*cursor, cursor->getAttrPath(), true); visit(*cursor, cursor->getAttrPath(), true);
if (json) { if (json)
std::cout << jsonOut->dump() << std::endl; logger->cout("%s", *jsonOut);
}
if (!json && !results) if (!json && !results)
throw Error("no results for the given search term(s)!"); throw Error("no results for the given search term(s)!");

View file

@ -57,7 +57,7 @@ struct CmdShowDerivation : InstallablesCommand
jsonRoot[store->printStorePath(drvPath)] = jsonRoot[store->printStorePath(drvPath)] =
store->readDerivation(drvPath).toJSON(*store); store->readDerivation(drvPath).toJSON(*store);
} }
std::cout << jsonRoot.dump(2) << std::endl; logger->cout(jsonRoot.dump(2));
} }
}; };

View file

@ -173,7 +173,7 @@ struct CmdKeyGenerateSecret : Command
if (!keyName) if (!keyName)
throw UsageError("required argument '--key-name' is missing"); throw UsageError("required argument '--key-name' is missing");
std::cout << SecretKey::generate(*keyName).to_string(); writeFull(STDOUT_FILENO, SecretKey::generate(*keyName).to_string());
} }
}; };
@ -194,7 +194,7 @@ struct CmdKeyConvertSecretToPublic : Command
void run() override void run() override
{ {
SecretKey secretKey(drainFD(STDIN_FILENO)); SecretKey secretKey(drainFD(STDIN_FILENO));
std::cout << secretKey.toPublicKey().to_string(); writeFull(STDOUT_FILENO, secretKey.toPublicKey().to_string());
} }
}; };

View file

@ -23,7 +23,7 @@ nix log $outPath 2>&1 | grep 'is not available'
nix log --substituters file://$cacheDir $outPath | grep FOO nix log --substituters file://$cacheDir $outPath | grep FOO
# Test copying build logs from the binary cache. # Test copying build logs from the binary cache.
nix store copy-log --from file://$cacheDir $(nix-store -qd $outPath) nix store copy-log --from file://$cacheDir $(nix-store -qd $outPath)^'*'
nix log $outPath | grep FOO nix log $outPath | grep FOO
basicDownloadTests() { basicDownloadTests() {

View file

@ -2,14 +2,14 @@
source common.sh source common.sh
drv=$(nix-instantiate --experimental-features ca-derivations ./content-addressed.nix -A rootCA --arg seed 1) drv=$(nix-instantiate ./content-addressed.nix -A rootCA --arg seed 1)
nix --experimental-features 'nix-command ca-derivations' show-derivation "$drv" --arg seed 1 nix show-derivation "$drv" --arg seed 1
buildAttr () { buildAttr () {
local derivationPath=$1 local derivationPath=$1
local seedValue=$2 local seedValue=$2
shift; shift shift; shift
local args=("--experimental-features" "ca-derivations" "./content-addressed.nix" "-A" "$derivationPath" --arg seed "$seedValue" "--no-out-link") local args=("./content-addressed.nix" "-A" "$derivationPath" --arg seed "$seedValue" "--no-out-link")
args+=("$@") args+=("$@")
nix-build "${args[@]}" nix-build "${args[@]}"
} }
@ -46,17 +46,17 @@ testCutoff () {
} }
testGC () { testGC () {
nix-instantiate --experimental-features ca-derivations ./content-addressed.nix -A rootCA --arg seed 5 nix-instantiate ./content-addressed.nix -A rootCA --arg seed 5
nix-collect-garbage --experimental-features ca-derivations --option keep-derivations true nix-collect-garbage --option keep-derivations true
clearStore clearStore
buildAttr rootCA 1 --out-link $TEST_ROOT/rootCA buildAttr rootCA 1 --out-link $TEST_ROOT/rootCA
nix-collect-garbage --experimental-features ca-derivations nix-collect-garbage
buildAttr rootCA 1 -j0 buildAttr rootCA 1 -j0
} }
testNixCommand () { testNixCommand () {
clearStore clearStore
nix build --experimental-features 'nix-command ca-derivations' --file ./content-addressed.nix --no-link nix build --file ./content-addressed.nix --no-link
} }
# Regression test for https://github.com/NixOS/nix/issues/4775 # Regression test for https://github.com/NixOS/nix/issues/4775

View file

@ -28,6 +28,12 @@ nix realisation info --file ./content-addressed.nix transitivelyDependentCA
nix realisation info --file ./content-addressed.nix dependentCA nix realisation info --file ./content-addressed.nix dependentCA
# nix realisation info --file ./content-addressed.nix rootCA --outputs out # nix realisation info --file ./content-addressed.nix rootCA --outputs out
if isDaemonNewer "2.13"; then
pushToStore="../push-to-store.sh"
else
pushToStore="../push-to-store-old.sh"
fi
# Same thing, but # Same thing, but
# 1. With non-ca derivations # 1. With non-ca derivations
# 2. Erasing the realisations on the remote store # 2. Erasing the realisations on the remote store
@ -37,7 +43,7 @@ nix realisation info --file ./content-addressed.nix dependentCA
# #
# Regression test for #4725 # Regression test for #4725
clearStore clearStore
nix build --file ../simple.nix -L --no-link --post-build-hook ../push-to-store.sh nix build --file ../simple.nix -L --no-link --post-build-hook "$pushToStore"
clearStore clearStore
rm -r "$REMOTE_STORE_DIR/realisations" rm -r "$REMOTE_STORE_DIR/realisations"
nix build --file ../simple.nix -L --no-link --substitute --substituters "$REMOTE_STORE" --no-require-sigs -j0 nix build --file ../simple.nix -L --no-link --substitute --substituters "$REMOTE_STORE" --no-require-sigs -j0
@ -52,7 +58,7 @@ if [[ -z "$(ls "$REMOTE_STORE_DIR/realisations")" ]]; then
fi fi
# Test the local realisation disk cache # Test the local realisation disk cache
buildDrvs --post-build-hook ../push-to-store.sh buildDrvs --post-build-hook "$pushToStore"
clearStore clearStore
# Add the realisations of rootCA to the cachecache # Add the realisations of rootCA to the cachecache
clearCacheCache clearCacheCache

View file

@ -140,6 +140,36 @@ printf World2 > $flake2Dir/who
nix profile install $flake1Dir nix profile install $flake1Dir
[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]] [[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]]
expect 1 nix profile install $flake2Dir
diff -u <(
nix --offline profile install $flake2Dir 2>&1 1> /dev/null \
| grep -vE "^warning: " \
|| true
) <(cat << EOF
error: An existing package already provides the following file:
$(nix build --no-link --print-out-paths ${flake1Dir}"#default.out")/bin/hello
This is the conflicting file from the new package:
$(nix build --no-link --print-out-paths ${flake2Dir}"#default.out")/bin/hello
To remove the existing package:
nix profile remove path:${flake1Dir}
The new package can also be installed next to the existing one by assigning a different priority.
The conflicting packages have a priority of 5.
To prioritise the new package:
nix profile install path:${flake2Dir} --priority 4
To prioritise the existing package:
nix profile install path:${flake2Dir} --priority 6
EOF
)
[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]]
nix profile install $flake2Dir --priority 100 nix profile install $flake2Dir --priority 100
[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]] [[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]]
nix profile install $flake2Dir --priority 0 nix profile install $flake2Dir --priority 0

View file

@ -9,8 +9,14 @@ echo 'require-sigs = false' >> $NIX_CONF_DIR/nix.conf
restartDaemon restartDaemon
if isDaemonNewer "2.13"; then
pushToStore="$PWD/push-to-store.sh"
else
pushToStore="$PWD/push-to-store-old.sh"
fi
# Build the dependencies and push them to the remote store. # Build the dependencies and push them to the remote store.
nix-build -o $TEST_ROOT/result dependencies.nix --post-build-hook $PWD/push-to-store.sh nix-build -o $TEST_ROOT/result dependencies.nix --post-build-hook "$pushToStore"
clearStore clearStore

10
tests/push-to-store-old.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/sh
set -x
set -e
[ -n "$OUT_PATHS" ]
[ -n "$DRV_PATH" ]
echo Pushing "$OUT_PATHS" to "$REMOTE_STORE"
printf "%s" "$DRV_PATH" | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs

View file

@ -7,4 +7,4 @@ set -e
[ -n "$DRV_PATH" ] [ -n "$DRV_PATH" ]
echo Pushing "$OUT_PATHS" to "$REMOTE_STORE" echo Pushing "$OUT_PATHS" to "$REMOTE_STORE"
printf "%s" "$DRV_PATH" | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs printf "%s" "$DRV_PATH"^'*' | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs