diff --git a/configure.ac b/configure.ac index eecb107d7..39306b953 100644 --- a/configure.ac +++ b/configure.ac @@ -179,6 +179,10 @@ AC_CHECK_HEADERS([bzlib.h], [true], [AC_MSG_ERROR([Nix requires libbz2, which is part of bzip2. See https://web.archive.org/web/20180624184756/http://www.bzip.org/.])]) # Checks for libarchive PKG_CHECK_MODULES([LIBARCHIVE], [libarchive >= 3.1.2], [CXXFLAGS="$LIBARCHIVE_CFLAGS $CXXFLAGS"]) +# Workaround until https://github.com/libarchive/libarchive/issues/1446 is fixed +if test "$shared" != yes; then + LIBARCHIVE_LIBS+=' -lz' +fi # Look for SQLite, a required dependency. PKG_CHECK_MODULES([SQLITE3], [sqlite3 >= 3.6.19], [CXXFLAGS="$SQLITE3_CFLAGS $CXXFLAGS"]) diff --git a/flake.lock b/flake.lock index 822a73332..ddff58979 100644 --- a/flake.lock +++ b/flake.lock @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1591633336, - "narHash": "sha256-oVXv4xAnDJB03LvZGbC72vSVlIbbJr8tpjEW5o/Fdek=", + "lastModified": 1602604700, + "narHash": "sha256-TSfAZX0czPf1P8xnnGFXcoeoM9I5CaFjAdNP63W9DCY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "70717a337f7ae4e486ba71a500367cad697e5f09", + "rev": "3a10a004bb5802d5f23c58886722e4239705e733", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 200417c3e..0602861fa 100644 --- a/flake.nix +++ b/flake.nix @@ -16,7 +16,8 @@ officialRelease = false; - systems = [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ]; + linuxSystems = [ "x86_64-linux" "i686-linux" "aarch64-linux" ]; + systems = linuxSystems ++ [ "x86_64-darwin" ]; forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system); @@ -61,34 +62,41 @@ "LDFLAGS=-fuse-ld=gold" ]; - buildDeps = - [ bison - flex - mdbook - lowdown - autoconf-archive - autoreconfHook - curl + nativeBuildDeps = + [ + buildPackages.bison + buildPackages.flex + (lib.getBin buildPackages.lowdown) + buildPackages.mdbook + buildPackages.autoconf-archive + buildPackages.autoreconfHook + buildPackages.pkgconfig + + # Tests + buildPackages.git + buildPackages.mercurial + buildPackages.jq + ]; + + buildDeps = + [ curl bzip2 xz brotli zlib editline - openssl pkgconfig sqlite + openssl sqlite libarchive boost nlohmann_json - - # Tests - git - mercurial - jq + lowdown gmock ] ++ lib.optionals stdenv.isLinux [libseccomp utillinuxMinimal] - ++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium - ++ lib.optional (stdenv.isLinux || stdenv.isDarwin) - (aws-sdk-cpp.override { - apis = ["s3" "transfer"]; - customMemoryManagement = false; - }); + ++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium; + + awsDeps = lib.optional (stdenv.isLinux || stdenv.isDarwin) + (aws-sdk-cpp.override { + apis = ["s3" "transfer"]; + customMemoryManagement = false; + }); propagatedDeps = [ (boehmgc.override { enableLargeConfig = true; }) @@ -115,7 +123,8 @@ outputs = [ "out" "dev" "doc" ]; - buildInputs = buildDeps; + nativeBuildInputs = nativeBuildDeps; + buildInputs = buildDeps ++ awsDeps; propagatedBuildInputs = propagatedDeps; @@ -159,14 +168,17 @@ src = self; + nativeBuildInputs = + [ buildPackages.autoconf-archive + buildPackages.autoreconfHook + buildPackages.pkgconfig + ]; + buildInputs = - [ autoconf-archive - autoreconfHook - nix + [ nix curl bzip2 xz - pkgconfig pkgs.perl boost nlohmann_json @@ -197,15 +209,15 @@ src = lowdown-src; - outputs = [ "out" "dev" ]; + outputs = [ "out" "bin" "dev" ]; - buildInputs = [ which ]; + nativeBuildInputs = [ which ]; configurePhase = '' ./configure \ PREFIX=${placeholder "dev"} \ - BINDIR=${placeholder "out"}/bin + BINDIR=${placeholder "bin"}/bin ''; }; @@ -214,10 +226,12 @@ hydraJobs = { # Binary package for various platforms. - build = nixpkgs.lib.genAttrs systems (system: nixpkgsFor.${system}.nix); + build = nixpkgs.lib.genAttrs systems (system: self.packages.${system}.nix); + + buildStatic = nixpkgs.lib.genAttrs linuxSystems (system: self.packages.${system}.nix-static); # Perl bindings for various platforms. - perlBindings = nixpkgs.lib.genAttrs systems (system: nixpkgsFor.${system}.nix.perl-bindings); + perlBindings = nixpkgs.lib.genAttrs systems (system: self.packages.${system}.nix.perl-bindings); # Binary tarball for various platforms, containing a Nix store # with the closure of 'nix' package, and the second half of @@ -323,7 +337,8 @@ enableParallelBuilding = true; - buildInputs = buildDeps ++ propagatedDeps; + nativeBuildInputs = nativeBuildDeps; + buildInputs = buildDeps ++ propagatedDeps ++ awsDeps; dontInstall = false; @@ -425,10 +440,47 @@ checks = forAllSystems (system: { binaryTarball = self.hydraJobs.binaryTarball.${system}; perlBindings = self.hydraJobs.perlBindings.${system}; + } // nixpkgs.lib.optionalAttrs (builtins.elem system linuxSystems) { + buildStatic = self.hydraJobs.buildStatic.${system}; }); packages = forAllSystems (system: { inherit (nixpkgsFor.${system}) nix; + } // nixpkgs.lib.optionalAttrs (builtins.elem system linuxSystems) { + nix-static = let + nixpkgs = nixpkgsFor.${system}.pkgsStatic; + in with commonDeps nixpkgs; nixpkgs.stdenv.mkDerivation { + name = "nix-${version}"; + + src = self; + + VERSION_SUFFIX = versionSuffix; + + outputs = [ "out" "dev" "doc" ]; + + nativeBuildInputs = nativeBuildDeps; + buildInputs = buildDeps ++ propagatedDeps; + + configureFlags = [ "--sysconfdir=/etc" ]; + + enableParallelBuilding = true; + + makeFlags = "profiledir=$(out)/etc/profile.d"; + + doCheck = true; + + installFlags = "sysconfdir=$(out)/etc"; + + postInstall = '' + mkdir -p $doc/nix-support + echo "doc manual $doc/share/doc/nix/manual" >> $doc/nix-support/hydra-build-products + ''; + + doInstallCheck = true; + installCheckFlags = "sysconfdir=$(out)/etc"; + + stripAllList = ["bin"]; + }; }); defaultPackage = forAllSystems (system: self.packages.${system}.nix); @@ -442,7 +494,8 @@ outputs = [ "out" "dev" "doc" ]; - buildInputs = buildDeps ++ propagatedDeps ++ perlDeps; + nativeBuildInputs = nativeBuildDeps; + buildInputs = buildDeps ++ propagatedDeps ++ awsDeps ++ perlDeps; inherit configureFlags; diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh index 63cb2b268..e3fe613e8 100644 --- a/src/libutil/logging.hh +++ b/src/libutil/logging.hh @@ -100,7 +100,7 @@ public: virtual void writeToStdout(std::string_view s); template - inline void stdout(const std::string & fs, const Args & ... args) + inline void cout(const std::string & fs, const Args & ... args) { boost::format f(fs); formatHelper(f, args...); diff --git a/src/libutil/tests/tests.cc b/src/libutil/tests/tests.cc index 8e77ccbe1..ffba832d8 100644 --- a/src/libutil/tests/tests.cc +++ b/src/libutil/tests/tests.cc @@ -1,6 +1,7 @@ #include "util.hh" #include "types.hh" +#include #include namespace nix { diff --git a/src/libutil/types.hh b/src/libutil/types.hh index 55d02bcf9..6c4c5ab74 100644 --- a/src/libutil/types.hh +++ b/src/libutil/types.hh @@ -4,6 +4,7 @@ #include #include +#include #include #include diff --git a/src/nix/add-to-store.cc b/src/nix/add-to-store.cc index 7fe87d757..df51e72d5 100644 --- a/src/nix/add-to-store.cc +++ b/src/nix/add-to-store.cc @@ -83,7 +83,7 @@ struct CmdAddToStore : MixDryRun, StoreCommand store->addToStore(info, source); } - logger->stdout("%s", store->printStorePath(info.path)); + logger->cout("%s", store->printStorePath(info.path)); } }; diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 43ce46546..8da81d667 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -85,7 +85,7 @@ struct CmdEval : MixJSON, InstallableCommand printValueAsJSON(*state, true, *v, jsonOut, context); } else { state->forceValueDeep(*v); - logger->stdout("%s", *v); + logger->cout("%s", *v); } } }; diff --git a/src/nix/flake.cc b/src/nix/flake.cc index d45f13029..43176d887 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -62,17 +62,17 @@ public: static void printFlakeInfo(const Store & store, const Flake & flake) { - logger->stdout("Resolved URL: %s", flake.resolvedRef.to_string()); - logger->stdout("Locked URL: %s", flake.lockedRef.to_string()); + logger->cout("Resolved URL: %s", flake.resolvedRef.to_string()); + logger->cout("Locked URL: %s", flake.lockedRef.to_string()); if (flake.description) - logger->stdout("Description: %s", *flake.description); - logger->stdout("Path: %s", store.printStorePath(flake.sourceInfo->storePath)); + logger->cout("Description: %s", *flake.description); + logger->cout("Path: %s", store.printStorePath(flake.sourceInfo->storePath)); if (auto rev = flake.lockedRef.input.getRev()) - logger->stdout("Revision: %s", rev->to_string(Base16, false)); + logger->cout("Revision: %s", rev->to_string(Base16, false)); if (auto revCount = flake.lockedRef.input.getRevCount()) - logger->stdout("Revisions: %s", *revCount); + logger->cout("Revisions: %s", *revCount); if (auto lastModified = flake.lockedRef.input.getLastModified()) - logger->stdout("Last modified: %s", + logger->cout("Last modified: %s", std::put_time(std::localtime(&*lastModified), "%F %T")); } @@ -140,7 +140,7 @@ struct CmdFlakeInfo : FlakeCommand, MixJSON if (json) { auto json = flakeToJson(*store, flake); - logger->stdout("%s", json.dump()); + logger->cout("%s", json.dump()); } else printFlakeInfo(*store, flake); } @@ -158,9 +158,9 @@ struct CmdFlakeListInputs : FlakeCommand, MixJSON auto flake = lockFlake(); if (json) - logger->stdout("%s", flake.lockFile.toJson()); + logger->cout("%s", flake.lockFile.toJson()); else { - logger->stdout("%s", flake.flake.lockedRef); + logger->cout("%s", flake.flake.lockedRef); std::unordered_set> visited; @@ -172,7 +172,7 @@ struct CmdFlakeListInputs : FlakeCommand, MixJSON bool last = i + 1 == node.inputs.size(); if (auto lockedNode = std::get_if<0>(&input.second)) { - logger->stdout("%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s", + logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s", prefix + (last ? treeLast : treeConn), input.first, *lockedNode ? (*lockedNode)->lockedRef : flake.flake.lockedRef); @@ -180,7 +180,7 @@ struct CmdFlakeListInputs : FlakeCommand, MixJSON if (firstVisit) recurse(**lockedNode, prefix + (last ? treeNull : treeLine)); } else if (auto follows = std::get_if<1>(&input.second)) { - logger->stdout("%s" ANSI_BOLD "%s" ANSI_NORMAL " follows input '%s'", + logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL " follows input '%s'", prefix + (last ? treeLast : treeConn), input.first, printInputPath(*follows)); } @@ -811,7 +811,7 @@ struct CmdFlakeShow : FlakeCommand try { auto recurse = [&]() { - logger->stdout("%s", headerPrefix); + logger->cout("%s", headerPrefix); auto attrs = visitor.getAttrs(); for (const auto & [i, attr] : enumerate(attrs)) { bool last = i + 1 == attrs.size(); @@ -837,7 +837,7 @@ struct CmdFlakeShow : FlakeCommand } */ - logger->stdout("%s: %s '%s'", + logger->cout("%s: %s '%s'", headerPrefix, attrPath.size() == 2 && attrPath[0] == "devShell" ? "development environment" : attrPath.size() == 3 && attrPath[0] == "checks" ? "derivation" : @@ -885,7 +885,7 @@ struct CmdFlakeShow : FlakeCommand if (attrPath.size() == 1) recurse(); else if (!showLegacy) - logger->stdout("%s: " ANSI_YELLOW "omitted" ANSI_NORMAL " (use '--legacy' to show)", headerPrefix); + logger->cout("%s: " ANSI_YELLOW "omitted" ANSI_NORMAL " (use '--legacy' to show)", headerPrefix); else { if (visitor.isDerivation()) showDerivation(); @@ -902,7 +902,7 @@ struct CmdFlakeShow : FlakeCommand auto aType = visitor.maybeGetAttr("type"); if (!aType || aType->getString() != "app") throw EvalError("not an app definition"); - logger->stdout("%s: app", headerPrefix); + logger->cout("%s: app", headerPrefix); } else if ( @@ -910,11 +910,11 @@ struct CmdFlakeShow : FlakeCommand (attrPath.size() == 2 && attrPath[0] == "templates")) { auto description = visitor.getAttr("description")->getString(); - logger->stdout("%s: template: " ANSI_BOLD "%s" ANSI_NORMAL, headerPrefix, description); + logger->cout("%s: template: " ANSI_BOLD "%s" ANSI_NORMAL, headerPrefix, description); } else { - logger->stdout("%s: %s", + logger->cout("%s: %s", headerPrefix, attrPath.size() == 1 && attrPath[0] == "overlay" ? "Nixpkgs overlay" : attrPath.size() == 2 && attrPath[0] == "nixosConfigurations" ? "NixOS configuration" : diff --git a/src/nix/hash.cc b/src/nix/hash.cc index 1d23bb0e2..7f3d5717a 100644 --- a/src/nix/hash.cc +++ b/src/nix/hash.cc @@ -74,7 +74,7 @@ struct CmdHash : Command Hash h = hashSink->finish().first; if (truncate && h.hashSize > 20) h = compressHash(h, 20); - logger->stdout(h.to_string(base, base == SRI)); + logger->cout(h.to_string(base, base == SRI)); } } }; @@ -108,7 +108,7 @@ struct CmdToBase : Command void run() override { for (auto s : args) - logger->stdout(Hash::parseAny(s, ht).to_string(base, base == SRI)); + logger->cout(Hash::parseAny(s, ht).to_string(base, base == SRI)); } }; diff --git a/src/nix/ls.cc b/src/nix/ls.cc index baca54431..f39fdb2fd 100644 --- a/src/nix/ls.cc +++ b/src/nix/ls.cc @@ -37,11 +37,11 @@ struct MixLs : virtual Args, MixJSON auto line = fmt("%s %20d %s", tp, st.fileSize, relPath); if (st.type == FSAccessor::Type::tSymlink) line += " -> " + accessor->readLink(curPath); - logger->stdout(line); + logger->cout(line); if (recursive && st.type == FSAccessor::Type::tDirectory) doPath(st, curPath, relPath, false); } else { - logger->stdout(relPath); + logger->cout(relPath); if (recursive) { auto st = accessor->stat(curPath); if (st.type == FSAccessor::Type::tDirectory) diff --git a/src/nix/profile.cc b/src/nix/profile.cc index 01aef2f9b..75426b2e3 100644 --- a/src/nix/profile.cc +++ b/src/nix/profile.cc @@ -393,7 +393,7 @@ struct CmdProfileInfo : virtual EvalCommand, virtual StoreCommand, MixDefaultPro for (size_t i = 0; i < manifest.elements.size(); ++i) { auto & element(manifest.elements[i]); - logger->stdout("%d %s %s %s", i, + logger->cout("%d %s %s %s", i, element.source ? element.source->originalRef.to_string() + "#" + element.source->attrPath : "-", element.source ? element.source->resolvedRef.to_string() + "#" + element.source->attrPath : "-", concatStringsSep(" ", store->printStorePathSet(element.storePaths))); diff --git a/src/nix/registry.cc b/src/nix/registry.cc index 8e8983ad0..9352e00a7 100644 --- a/src/nix/registry.cc +++ b/src/nix/registry.cc @@ -26,7 +26,7 @@ struct CmdRegistryList : StoreCommand for (auto & registry : registries) { for (auto & entry : registry->entries) { // FIXME: format nicely - logger->stdout("%s %s %s", + logger->cout("%s %s %s", registry->type == Registry::Flag ? "flags " : registry->type == Registry::User ? "user " : registry->type == Registry::System ? "system" : diff --git a/src/nix/search.cc b/src/nix/search.cc index d4326dc84..47770e128 100644 --- a/src/nix/search.cc +++ b/src/nix/search.cc @@ -147,13 +147,13 @@ struct CmdSearch : InstallableCommand, MixJSON jsonElem.attr("description", description); } else { auto name2 = hilite(name.name, nameMatch, "\e[0;2m"); - if (results > 1) logger->stdout(""); - logger->stdout( + if (results > 1) logger->cout(""); + logger->cout( "* %s%s", wrap("\e[0;1m", hilite(attrPath2, attrPathMatch, "\e[0;1m")), name.version != "" ? " (" + name.version + ")" : ""); if (description != "") - logger->stdout( + logger->cout( " %s", hilite(description, descriptionMatch, ANSI_NORMAL)); } } diff --git a/src/nix/show-config.cc b/src/nix/show-config.cc index 1ef54a33a..91721219b 100644 --- a/src/nix/show-config.cc +++ b/src/nix/show-config.cc @@ -20,12 +20,12 @@ struct CmdShowConfig : Command, MixJSON { if (json) { // FIXME: use appropriate JSON types (bool, ints, etc). - logger->stdout("%s", globalConfig.toJSON().dump()); + logger->cout("%s", globalConfig.toJSON().dump()); } else { std::map settings; globalConfig.getSettings(settings); for (auto & s : settings) - logger->stdout("%s = %s", s.first, s.second.value); + logger->cout("%s = %s", s.first, s.second.value); } } }; diff --git a/src/nix/why-depends.cc b/src/nix/why-depends.cc index 63bf087e6..57b9a2208 100644 --- a/src/nix/why-depends.cc +++ b/src/nix/why-depends.cc @@ -156,7 +156,7 @@ struct CmdWhyDepends : SourceExprCommand auto pathS = store->printStorePath(node.path); assert(node.dist != inf); - logger->stdout("%s%s%s%s" ANSI_NORMAL, + logger->cout("%s%s%s%s" ANSI_NORMAL, firstPad, node.visited ? "\e[38;5;244m" : "", firstPad != "" ? "→ " : "", diff --git a/tests/github-flakes.nix b/tests/github-flakes.nix index a47610d9a..7ac397d81 100644 --- a/tests/github-flakes.nix +++ b/tests/github-flakes.nix @@ -1,6 +1,6 @@ { nixpkgs, system, overlay }: -with import (nixpkgs + "/nixos/lib/testing.nix") { +with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ]; }; @@ -64,6 +64,7 @@ in makeTest ( { + name = "github-flakes"; nodes = { # Impersonate github.com and api.github.com. @@ -113,36 +114,37 @@ makeTest ( }; }; - testScript = { nodes }: - '' - use POSIX qw(strftime); + testScript = { nodes }: '' + # fmt: off + import json + import time - startAll; + start_all() - $github->waitForUnit("httpd.service"); + github.wait_for_unit("httpd.service") - $client->succeed("curl -v https://github.com/ >&2"); + client.succeed("curl -v https://github.com/ >&2") + client.succeed("nix registry list | grep nixpkgs") - $client->succeed("nix registry list | grep nixpkgs"); + rev = client.succeed("nix flake info nixpkgs --json | jq -r .revision") + assert rev.strip() == "${nixpkgs.rev}", "revision mismatch" - $client->succeed("nix flake info nixpkgs --json | jq -r .revision") eq "${nixpkgs.rev}\n" - or die "revision mismatch"; + client.succeed("nix registry pin nixpkgs") - $client->succeed("nix registry pin nixpkgs"); + client.succeed("nix flake info nixpkgs --tarball-ttl 0 >&2") - $client->succeed("nix flake info nixpkgs --tarball-ttl 0 >&2"); + # Shut down the web server. The flake should be cached on the client. + github.succeed("systemctl stop httpd.service") - # Shut down the web server. The flake should be cached on the client. - $github->succeed("systemctl stop httpd.service"); + info = json.loads(client.succeed("nix flake info nixpkgs --json")) + date = time.strftime("%Y%m%d%H%M%S", time.gmtime(info['lastModified'])) + assert date == "${nixpkgs.lastModifiedDate}", "time mismatch" - my $date = $client->succeed("nix flake info nixpkgs --json | jq -M .lastModified"); - strftime("%Y%m%d%H%M%S", gmtime($date)) eq "${nixpkgs.lastModifiedDate}" or die "time mismatch"; + client.succeed("nix build nixpkgs#hello") - $client->succeed("nix build nixpkgs#hello"); - - # The build shouldn't fail even with --tarball-ttl 0 (the server - # being down should not be a fatal error). - $client->succeed("nix build nixpkgs#fuse --tarball-ttl 0"); - ''; + # The build shouldn't fail even with --tarball-ttl 0 (the server + # being down should not be a fatal error). + client.succeed("nix build nixpkgs#fuse --tarball-ttl 0") + ''; }) diff --git a/tests/nix-copy-closure.nix b/tests/nix-copy-closure.nix index 9c9d119b7..e5f6a0f12 100644 --- a/tests/nix-copy-closure.nix +++ b/tests/nix-copy-closure.nix @@ -2,12 +2,13 @@ { nixpkgs, system, overlay }: -with import (nixpkgs + "/nixos/lib/testing.nix") { +with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ]; }; makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; in { + name = "nix-copy-closure"; nodes = { client = @@ -25,41 +26,46 @@ makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; in { }; }; - testScript = { nodes }: - '' - startAll; + testScript = { nodes }: '' + # fmt: off + import subprocess - # Create an SSH key on the client. - my $key = `${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f key -N ""`; - $client->succeed("mkdir -m 700 /root/.ssh"); - $client->copyFileFromHost("key", "/root/.ssh/id_ed25519"); - $client->succeed("chmod 600 /root/.ssh/id_ed25519"); + start_all() - # Install the SSH key on the server. - $server->succeed("mkdir -m 700 /root/.ssh"); - $server->copyFileFromHost("key.pub", "/root/.ssh/authorized_keys"); - $server->waitForUnit("sshd"); - $client->waitForUnit("network.target"); - $client->succeed("ssh -o StrictHostKeyChecking=no " . $server->name() . " 'echo hello world'"); + # Create an SSH key on the client. + subprocess.run([ + "${pkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", "" + ], capture_output=True, check=True) - # Copy the closure of package A from the client to the server. - $server->fail("nix-store --check-validity ${pkgA}"); - $client->succeed("nix-copy-closure --to server --gzip ${pkgA} >&2"); - $server->succeed("nix-store --check-validity ${pkgA}"); + client.succeed("mkdir -m 700 /root/.ssh") + client.copy_from_host("key", "/root/.ssh/id_ed25519") + client.succeed("chmod 600 /root/.ssh/id_ed25519") - # Copy the closure of package B from the server to the client. - $client->fail("nix-store --check-validity ${pkgB}"); - $client->succeed("nix-copy-closure --from server --gzip ${pkgB} >&2"); - $client->succeed("nix-store --check-validity ${pkgB}"); + # Install the SSH key on the server. + server.succeed("mkdir -m 700 /root/.ssh") + server.copy_from_host("key.pub", "/root/.ssh/authorized_keys") + server.wait_for_unit("sshd") + client.wait_for_unit("network.target") + client.succeed(f"ssh -o StrictHostKeyChecking=no {server.name} 'echo hello world'") - # Copy the closure of package C via the SSH substituter. - $client->fail("nix-store -r ${pkgC}"); - # FIXME - #$client->succeed( - # "nix-store --option use-ssh-substituter true" - # . " --option ssh-substituter-hosts root\@server" - # . " -r ${pkgC} >&2"); - #$client->succeed("nix-store --check-validity ${pkgC}"); - ''; + # Copy the closure of package A from the client to the server. + server.fail("nix-store --check-validity ${pkgA}") + client.succeed("nix-copy-closure --to server --gzip ${pkgA} >&2") + server.succeed("nix-store --check-validity ${pkgA}") + # Copy the closure of package B from the server to the client. + client.fail("nix-store --check-validity ${pkgB}") + client.succeed("nix-copy-closure --from server --gzip ${pkgB} >&2") + client.succeed("nix-store --check-validity ${pkgB}") + + # Copy the closure of package C via the SSH substituter. + client.fail("nix-store -r ${pkgC}") + # FIXME + # client.succeed( + # "nix-store --option use-ssh-substituter true" + # " --option ssh-substituter-hosts root\@server" + # " -r ${pkgC} >&2" + # ) + # client.succeed("nix-store --check-validity ${pkgC}") + ''; }) diff --git a/tests/remote-builds.nix b/tests/remote-builds.nix index 153956619..b9e7352c0 100644 --- a/tests/remote-builds.nix +++ b/tests/remote-builds.nix @@ -2,7 +2,7 @@ { nixpkgs, system, overlay }: -with import (nixpkgs + "/nixos/lib/testing.nix") { +with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ]; }; @@ -36,6 +36,7 @@ let in { + name = "remote-builds"; nodes = { builder1 = builder; @@ -66,44 +67,46 @@ in }; }; - testScript = { nodes }: - '' - startAll; + testScript = { nodes }: '' + # fmt: off + import subprocess - # Create an SSH key on the client. - my $key = `${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f key -N ""`; - $client->succeed("mkdir -p -m 700 /root/.ssh"); - $client->copyFileFromHost("key", "/root/.ssh/id_ed25519"); - $client->succeed("chmod 600 /root/.ssh/id_ed25519"); + start_all() - # Install the SSH key on the builders. - $client->waitForUnit("network.target"); - foreach my $builder ($builder1, $builder2) { - $builder->succeed("mkdir -p -m 700 /root/.ssh"); - $builder->copyFileFromHost("key.pub", "/root/.ssh/authorized_keys"); - $builder->waitForUnit("sshd"); - $client->succeed("ssh -o StrictHostKeyChecking=no " . $builder->name() . " 'echo hello world'"); - } + # Create an SSH key on the client. + subprocess.run([ + "${pkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", "" + ], capture_output=True, check=True) + client.succeed("mkdir -p -m 700 /root/.ssh") + client.copy_from_host("key", "/root/.ssh/id_ed25519") + client.succeed("chmod 600 /root/.ssh/id_ed25519") - # Perform a build and check that it was performed on the builder. - my $out = $client->succeed( - "nix-build ${expr nodes.client.config 1} 2> build-output", - "grep -q Hello build-output" - ); - $builder1->succeed("test -e $out"); + # Install the SSH key on the builders. + client.wait_for_unit("network.target") + for builder in [builder1, builder2]: + builder.succeed("mkdir -p -m 700 /root/.ssh") + builder.copy_from_host("key.pub", "/root/.ssh/authorized_keys") + builder.wait_for_unit("sshd") + client.succeed(f"ssh -o StrictHostKeyChecking=no {builder.name} 'echo hello world'") - # And a parallel build. - my ($out1, $out2) = split /\s/, - $client->succeed('nix-store -r $(nix-instantiate ${expr nodes.client.config 2})\!out $(nix-instantiate ${expr nodes.client.config 3})\!out'); - $builder1->succeed("test -e $out1 -o -e $out2"); - $builder2->succeed("test -e $out1 -o -e $out2"); + # Perform a build and check that it was performed on the builder. + out = client.succeed( + "nix-build ${expr nodes.client.config 1} 2> build-output", + "grep -q Hello build-output" + ) + builder1.succeed(f"test -e {out}") - # And a failing build. - $client->fail("nix-build ${expr nodes.client.config 5}"); + # And a parallel build. + paths = client.succeed(r'nix-store -r $(nix-instantiate ${expr nodes.client.config 2})\!out $(nix-instantiate ${expr nodes.client.config 3})\!out') + out1, out2 = paths.split() + builder1.succeed(f"test -e {out1} -o -e {out2}") + builder2.succeed(f"test -e {out1} -o -e {out2}") - # Test whether the build hook automatically skips unavailable builders. - $builder1->block; - $client->succeed("nix-build ${expr nodes.client.config 4}"); - ''; + # And a failing build. + client.fail("nix-build ${expr nodes.client.config 5}") + # Test whether the build hook automatically skips unavailable builders. + builder1.block() + client.succeed("nix-build ${expr nodes.client.config 4}") + ''; }) diff --git a/tests/setuid.nix b/tests/setuid.nix index 6f2f7d392..35eb304ed 100644 --- a/tests/setuid.nix +++ b/tests/setuid.nix @@ -2,12 +2,13 @@ { nixpkgs, system, overlay }: -with import (nixpkgs + "/nixos/lib/testing.nix") { +with import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ]; }; makeTest { + name = "setuid"; machine = { config, lib, pkgs, ... }: @@ -17,94 +18,109 @@ makeTest { virtualisation.pathsInNixDB = [ pkgs.stdenv pkgs.pkgsi686Linux.stdenv ]; }; - testScript = { nodes }: - '' - startAll; + testScript = { nodes }: '' + # fmt: off + start_all() - # Copying to /tmp should succeed. - $machine->succeed('nix-build --no-sandbox -E \'(with import {}; runCommand "foo" {} " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - ")\' '); + # Copying to /tmp should succeed. + machine.succeed(r""" + nix-build --no-sandbox -E '(with import {}; runCommand "foo" {} " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + ")' + """.strip()) - $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]'); + machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]') - $machine->succeed("rm /tmp/id"); + machine.succeed("rm /tmp/id") - # Creating a setuid binary should fail. - $machine->fail('nix-build --no-sandbox -E \'(with import {}; runCommand "foo" {} " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - chmod 4755 /tmp/id - ")\' '); + # Creating a setuid binary should fail. + machine.fail(r""" + nix-build --no-sandbox -E '(with import {}; runCommand "foo" {} " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + chmod 4755 /tmp/id + ")' + """.strip()) - $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]'); + machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]') - $machine->succeed("rm /tmp/id"); + machine.succeed("rm /tmp/id") - # Creating a setgid binary should fail. - $machine->fail('nix-build --no-sandbox -E \'(with import {}; runCommand "foo" {} " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - chmod 2755 /tmp/id - ")\' '); + # Creating a setgid binary should fail. + machine.fail(r""" + nix-build --no-sandbox -E '(with import {}; runCommand "foo" {} " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + chmod 2755 /tmp/id + ")' + """.strip()) - $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]'); + machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]') - $machine->succeed("rm /tmp/id"); + machine.succeed("rm /tmp/id") - # The checks should also work on 32-bit binaries. - $machine->fail('nix-build --no-sandbox -E \'(with import { system = "i686-linux"; }; runCommand "foo" {} " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - chmod 2755 /tmp/id - ")\' '); + # The checks should also work on 32-bit binaries. + machine.fail(r""" + nix-build --no-sandbox -E '(with import { system = "i686-linux"; }; runCommand "foo" {} " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + chmod 2755 /tmp/id + ")' + """.strip()) - $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]'); + machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]') - $machine->succeed("rm /tmp/id"); + machine.succeed("rm /tmp/id") - # The tests above use fchmodat(). Test chmod() as well. - $machine->succeed('nix-build --no-sandbox -E \'(with import {}; runCommand "foo" { buildInputs = [ perl ]; } " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - perl -e \"chmod 0666, qw(/tmp/id) or die\" - ")\' '); + # The tests above use fchmodat(). Test chmod() as well. + machine.succeed(r""" + nix-build --no-sandbox -E '(with import {}; runCommand "foo" { buildInputs = [ perl ]; } " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + perl -e \"chmod 0666, qw(/tmp/id) or die\" + ")' + """.strip()) - $machine->succeed('[[ $(stat -c %a /tmp/id) = 666 ]]'); + machine.succeed('[[ $(stat -c %a /tmp/id) = 666 ]]') - $machine->succeed("rm /tmp/id"); + machine.succeed("rm /tmp/id") - $machine->fail('nix-build --no-sandbox -E \'(with import {}; runCommand "foo" { buildInputs = [ perl ]; } " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - perl -e \"chmod 04755, qw(/tmp/id) or die\" - ")\' '); + machine.fail(r""" + nix-build --no-sandbox -E '(with import {}; runCommand "foo" { buildInputs = [ perl ]; } " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + perl -e \"chmod 04755, qw(/tmp/id) or die\" + ")' + """.strip()) - $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]'); + machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]') - $machine->succeed("rm /tmp/id"); + machine.succeed("rm /tmp/id") - # And test fchmod(). - $machine->succeed('nix-build --no-sandbox -E \'(with import {}; runCommand "foo" { buildInputs = [ perl ]; } " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 01750, \\\$x or die\" - ")\' '); + # And test fchmod(). + machine.succeed(r""" + nix-build --no-sandbox -E '(with import {}; runCommand "foo" { buildInputs = [ perl ]; } " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 01750, \\\$x or die\" + ")' + """.strip()) - $machine->succeed('[[ $(stat -c %a /tmp/id) = 1750 ]]'); + machine.succeed('[[ $(stat -c %a /tmp/id) = 1750 ]]') - $machine->succeed("rm /tmp/id"); + machine.succeed("rm /tmp/id") - $machine->fail('nix-build --no-sandbox -E \'(with import {}; runCommand "foo" { buildInputs = [ perl ]; } " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 04777, \\\$x or die\" - ")\' '); + machine.fail(r""" + nix-build --no-sandbox -E '(with import {}; runCommand "foo" { buildInputs = [ perl ]; } " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 04777, \\\$x or die\" + ")' + """.strip()) - $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]'); - - $machine->succeed("rm /tmp/id"); - ''; + machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]') + machine.succeed("rm /tmp/id") + ''; }