Merge remote-tracking branch 'upstream/master' into typed-goal-maps

This commit is contained in:
John Ericson 2020-10-17 21:44:27 +00:00
commit 619d262c97
20 changed files with 310 additions and 224 deletions

View file

@ -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/.])]) [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 # Checks for libarchive
PKG_CHECK_MODULES([LIBARCHIVE], [libarchive >= 3.1.2], [CXXFLAGS="$LIBARCHIVE_CFLAGS $CXXFLAGS"]) 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. # Look for SQLite, a required dependency.
PKG_CHECK_MODULES([SQLITE3], [sqlite3 >= 3.6.19], [CXXFLAGS="$SQLITE3_CFLAGS $CXXFLAGS"]) PKG_CHECK_MODULES([SQLITE3], [sqlite3 >= 3.6.19], [CXXFLAGS="$SQLITE3_CFLAGS $CXXFLAGS"])

View file

@ -18,11 +18,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1591633336, "lastModified": 1602604700,
"narHash": "sha256-oVXv4xAnDJB03LvZGbC72vSVlIbbJr8tpjEW5o/Fdek=", "narHash": "sha256-TSfAZX0czPf1P8xnnGFXcoeoM9I5CaFjAdNP63W9DCY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "70717a337f7ae4e486ba71a500367cad697e5f09", "rev": "3a10a004bb5802d5f23c58886722e4239705e733",
"type": "github" "type": "github"
}, },
"original": { "original": {

119
flake.nix
View file

@ -16,7 +16,8 @@
officialRelease = false; 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); forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
@ -61,34 +62,41 @@
"LDFLAGS=-fuse-ld=gold" "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 bzip2 xz brotli zlib editline
openssl pkgconfig sqlite openssl sqlite
libarchive libarchive
boost boost
nlohmann_json nlohmann_json
lowdown
# Tests
git
mercurial
jq
gmock gmock
] ]
++ lib.optionals stdenv.isLinux [libseccomp utillinuxMinimal] ++ lib.optionals stdenv.isLinux [libseccomp utillinuxMinimal]
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium ++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium;
++ lib.optional (stdenv.isLinux || stdenv.isDarwin)
(aws-sdk-cpp.override { awsDeps = lib.optional (stdenv.isLinux || stdenv.isDarwin)
apis = ["s3" "transfer"]; (aws-sdk-cpp.override {
customMemoryManagement = false; apis = ["s3" "transfer"];
}); customMemoryManagement = false;
});
propagatedDeps = propagatedDeps =
[ (boehmgc.override { enableLargeConfig = true; }) [ (boehmgc.override { enableLargeConfig = true; })
@ -115,7 +123,8 @@
outputs = [ "out" "dev" "doc" ]; outputs = [ "out" "dev" "doc" ];
buildInputs = buildDeps; nativeBuildInputs = nativeBuildDeps;
buildInputs = buildDeps ++ awsDeps;
propagatedBuildInputs = propagatedDeps; propagatedBuildInputs = propagatedDeps;
@ -159,14 +168,17 @@
src = self; src = self;
nativeBuildInputs =
[ buildPackages.autoconf-archive
buildPackages.autoreconfHook
buildPackages.pkgconfig
];
buildInputs = buildInputs =
[ autoconf-archive [ nix
autoreconfHook
nix
curl curl
bzip2 bzip2
xz xz
pkgconfig
pkgs.perl pkgs.perl
boost boost
nlohmann_json nlohmann_json
@ -197,15 +209,15 @@
src = lowdown-src; src = lowdown-src;
outputs = [ "out" "dev" ]; outputs = [ "out" "bin" "dev" ];
buildInputs = [ which ]; nativeBuildInputs = [ which ];
configurePhase = configurePhase =
'' ''
./configure \ ./configure \
PREFIX=${placeholder "dev"} \ PREFIX=${placeholder "dev"} \
BINDIR=${placeholder "out"}/bin BINDIR=${placeholder "bin"}/bin
''; '';
}; };
@ -214,10 +226,12 @@
hydraJobs = { hydraJobs = {
# Binary package for various platforms. # 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. # 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 # Binary tarball for various platforms, containing a Nix store
# with the closure of 'nix' package, and the second half of # with the closure of 'nix' package, and the second half of
@ -323,7 +337,8 @@
enableParallelBuilding = true; enableParallelBuilding = true;
buildInputs = buildDeps ++ propagatedDeps; nativeBuildInputs = nativeBuildDeps;
buildInputs = buildDeps ++ propagatedDeps ++ awsDeps;
dontInstall = false; dontInstall = false;
@ -425,10 +440,47 @@
checks = forAllSystems (system: { checks = forAllSystems (system: {
binaryTarball = self.hydraJobs.binaryTarball.${system}; binaryTarball = self.hydraJobs.binaryTarball.${system};
perlBindings = self.hydraJobs.perlBindings.${system}; perlBindings = self.hydraJobs.perlBindings.${system};
} // nixpkgs.lib.optionalAttrs (builtins.elem system linuxSystems) {
buildStatic = self.hydraJobs.buildStatic.${system};
}); });
packages = forAllSystems (system: { packages = forAllSystems (system: {
inherit (nixpkgsFor.${system}) nix; 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); defaultPackage = forAllSystems (system: self.packages.${system}.nix);
@ -442,7 +494,8 @@
outputs = [ "out" "dev" "doc" ]; outputs = [ "out" "dev" "doc" ];
buildInputs = buildDeps ++ propagatedDeps ++ perlDeps; nativeBuildInputs = nativeBuildDeps;
buildInputs = buildDeps ++ propagatedDeps ++ awsDeps ++ perlDeps;
inherit configureFlags; inherit configureFlags;

View file

@ -100,7 +100,7 @@ public:
virtual void writeToStdout(std::string_view s); virtual void writeToStdout(std::string_view s);
template<typename... Args> template<typename... Args>
inline void stdout(const std::string & fs, const Args & ... args) inline void cout(const std::string & fs, const Args & ... args)
{ {
boost::format f(fs); boost::format f(fs);
formatHelper(f, args...); formatHelper(f, args...);

View file

@ -1,6 +1,7 @@
#include "util.hh" #include "util.hh"
#include "types.hh" #include "types.hh"
#include <limits.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
namespace nix { namespace nix {

View file

@ -4,6 +4,7 @@
#include <list> #include <list>
#include <set> #include <set>
#include <string>
#include <map> #include <map>
#include <vector> #include <vector>

View file

@ -83,7 +83,7 @@ struct CmdAddToStore : MixDryRun, StoreCommand
store->addToStore(info, source); store->addToStore(info, source);
} }
logger->stdout("%s", store->printStorePath(info.path)); logger->cout("%s", store->printStorePath(info.path));
} }
}; };

View file

@ -85,7 +85,7 @@ struct CmdEval : MixJSON, InstallableCommand
printValueAsJSON(*state, true, *v, jsonOut, context); printValueAsJSON(*state, true, *v, jsonOut, context);
} else { } else {
state->forceValueDeep(*v); state->forceValueDeep(*v);
logger->stdout("%s", *v); logger->cout("%s", *v);
} }
} }
}; };

View file

@ -62,17 +62,17 @@ public:
static void printFlakeInfo(const Store & store, const Flake & flake) static void printFlakeInfo(const Store & store, const Flake & flake)
{ {
logger->stdout("Resolved URL: %s", flake.resolvedRef.to_string()); logger->cout("Resolved URL: %s", flake.resolvedRef.to_string());
logger->stdout("Locked URL: %s", flake.lockedRef.to_string()); logger->cout("Locked URL: %s", flake.lockedRef.to_string());
if (flake.description) if (flake.description)
logger->stdout("Description: %s", *flake.description); logger->cout("Description: %s", *flake.description);
logger->stdout("Path: %s", store.printStorePath(flake.sourceInfo->storePath)); logger->cout("Path: %s", store.printStorePath(flake.sourceInfo->storePath));
if (auto rev = flake.lockedRef.input.getRev()) 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()) if (auto revCount = flake.lockedRef.input.getRevCount())
logger->stdout("Revisions: %s", *revCount); logger->cout("Revisions: %s", *revCount);
if (auto lastModified = flake.lockedRef.input.getLastModified()) 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")); std::put_time(std::localtime(&*lastModified), "%F %T"));
} }
@ -140,7 +140,7 @@ struct CmdFlakeInfo : FlakeCommand, MixJSON
if (json) { if (json) {
auto json = flakeToJson(*store, flake); auto json = flakeToJson(*store, flake);
logger->stdout("%s", json.dump()); logger->cout("%s", json.dump());
} else } else
printFlakeInfo(*store, flake); printFlakeInfo(*store, flake);
} }
@ -158,9 +158,9 @@ struct CmdFlakeListInputs : FlakeCommand, MixJSON
auto flake = lockFlake(); auto flake = lockFlake();
if (json) if (json)
logger->stdout("%s", flake.lockFile.toJson()); logger->cout("%s", flake.lockFile.toJson());
else { else {
logger->stdout("%s", flake.flake.lockedRef); logger->cout("%s", flake.flake.lockedRef);
std::unordered_set<std::shared_ptr<Node>> visited; std::unordered_set<std::shared_ptr<Node>> visited;
@ -172,7 +172,7 @@ struct CmdFlakeListInputs : FlakeCommand, MixJSON
bool last = i + 1 == node.inputs.size(); bool last = i + 1 == node.inputs.size();
if (auto lockedNode = std::get_if<0>(&input.second)) { 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, prefix + (last ? treeLast : treeConn), input.first,
*lockedNode ? (*lockedNode)->lockedRef : flake.flake.lockedRef); *lockedNode ? (*lockedNode)->lockedRef : flake.flake.lockedRef);
@ -180,7 +180,7 @@ struct CmdFlakeListInputs : FlakeCommand, MixJSON
if (firstVisit) recurse(**lockedNode, prefix + (last ? treeNull : treeLine)); if (firstVisit) recurse(**lockedNode, prefix + (last ? treeNull : treeLine));
} else if (auto follows = std::get_if<1>(&input.second)) { } 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, prefix + (last ? treeLast : treeConn), input.first,
printInputPath(*follows)); printInputPath(*follows));
} }
@ -811,7 +811,7 @@ struct CmdFlakeShow : FlakeCommand
try { try {
auto recurse = [&]() auto recurse = [&]()
{ {
logger->stdout("%s", headerPrefix); logger->cout("%s", headerPrefix);
auto attrs = visitor.getAttrs(); auto attrs = visitor.getAttrs();
for (const auto & [i, attr] : enumerate(attrs)) { for (const auto & [i, attr] : enumerate(attrs)) {
bool last = i + 1 == attrs.size(); bool last = i + 1 == attrs.size();
@ -837,7 +837,7 @@ struct CmdFlakeShow : FlakeCommand
} }
*/ */
logger->stdout("%s: %s '%s'", logger->cout("%s: %s '%s'",
headerPrefix, headerPrefix,
attrPath.size() == 2 && attrPath[0] == "devShell" ? "development environment" : attrPath.size() == 2 && attrPath[0] == "devShell" ? "development environment" :
attrPath.size() == 3 && attrPath[0] == "checks" ? "derivation" : attrPath.size() == 3 && attrPath[0] == "checks" ? "derivation" :
@ -885,7 +885,7 @@ struct CmdFlakeShow : FlakeCommand
if (attrPath.size() == 1) if (attrPath.size() == 1)
recurse(); recurse();
else if (!showLegacy) 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 { else {
if (visitor.isDerivation()) if (visitor.isDerivation())
showDerivation(); showDerivation();
@ -902,7 +902,7 @@ struct CmdFlakeShow : FlakeCommand
auto aType = visitor.maybeGetAttr("type"); auto aType = visitor.maybeGetAttr("type");
if (!aType || aType->getString() != "app") if (!aType || aType->getString() != "app")
throw EvalError("not an app definition"); throw EvalError("not an app definition");
logger->stdout("%s: app", headerPrefix); logger->cout("%s: app", headerPrefix);
} }
else if ( else if (
@ -910,11 +910,11 @@ struct CmdFlakeShow : FlakeCommand
(attrPath.size() == 2 && attrPath[0] == "templates")) (attrPath.size() == 2 && attrPath[0] == "templates"))
{ {
auto description = visitor.getAttr("description")->getString(); 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 { else {
logger->stdout("%s: %s", logger->cout("%s: %s",
headerPrefix, headerPrefix,
attrPath.size() == 1 && attrPath[0] == "overlay" ? "Nixpkgs overlay" : attrPath.size() == 1 && attrPath[0] == "overlay" ? "Nixpkgs overlay" :
attrPath.size() == 2 && attrPath[0] == "nixosConfigurations" ? "NixOS configuration" : attrPath.size() == 2 && attrPath[0] == "nixosConfigurations" ? "NixOS configuration" :

View file

@ -74,7 +74,7 @@ struct CmdHash : Command
Hash h = hashSink->finish().first; Hash h = hashSink->finish().first;
if (truncate && h.hashSize > 20) h = compressHash(h, 20); 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 void run() override
{ {
for (auto s : args) 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));
} }
}; };

View file

@ -37,11 +37,11 @@ struct MixLs : virtual Args, MixJSON
auto line = fmt("%s %20d %s", tp, st.fileSize, relPath); auto line = fmt("%s %20d %s", tp, st.fileSize, relPath);
if (st.type == FSAccessor::Type::tSymlink) if (st.type == FSAccessor::Type::tSymlink)
line += " -> " + accessor->readLink(curPath); line += " -> " + accessor->readLink(curPath);
logger->stdout(line); logger->cout(line);
if (recursive && st.type == FSAccessor::Type::tDirectory) if (recursive && st.type == FSAccessor::Type::tDirectory)
doPath(st, curPath, relPath, false); doPath(st, curPath, relPath, false);
} else { } else {
logger->stdout(relPath); logger->cout(relPath);
if (recursive) { if (recursive) {
auto st = accessor->stat(curPath); auto st = accessor->stat(curPath);
if (st.type == FSAccessor::Type::tDirectory) if (st.type == FSAccessor::Type::tDirectory)

View file

@ -393,7 +393,7 @@ struct CmdProfileInfo : virtual EvalCommand, virtual StoreCommand, MixDefaultPro
for (size_t i = 0; i < manifest.elements.size(); ++i) { for (size_t i = 0; i < manifest.elements.size(); ++i) {
auto & element(manifest.elements[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->originalRef.to_string() + "#" + element.source->attrPath : "-",
element.source ? element.source->resolvedRef.to_string() + "#" + element.source->attrPath : "-", element.source ? element.source->resolvedRef.to_string() + "#" + element.source->attrPath : "-",
concatStringsSep(" ", store->printStorePathSet(element.storePaths))); concatStringsSep(" ", store->printStorePathSet(element.storePaths)));

View file

@ -26,7 +26,7 @@ struct CmdRegistryList : StoreCommand
for (auto & registry : registries) { for (auto & registry : registries) {
for (auto & entry : registry->entries) { for (auto & entry : registry->entries) {
// FIXME: format nicely // FIXME: format nicely
logger->stdout("%s %s %s", logger->cout("%s %s %s",
registry->type == Registry::Flag ? "flags " : registry->type == Registry::Flag ? "flags " :
registry->type == Registry::User ? "user " : registry->type == Registry::User ? "user " :
registry->type == Registry::System ? "system" : registry->type == Registry::System ? "system" :

View file

@ -147,13 +147,13 @@ struct CmdSearch : InstallableCommand, MixJSON
jsonElem.attr("description", description); jsonElem.attr("description", description);
} else { } else {
auto name2 = hilite(name.name, nameMatch, "\e[0;2m"); auto name2 = hilite(name.name, nameMatch, "\e[0;2m");
if (results > 1) logger->stdout(""); if (results > 1) logger->cout("");
logger->stdout( logger->cout(
"* %s%s", "* %s%s",
wrap("\e[0;1m", hilite(attrPath2, attrPathMatch, "\e[0;1m")), wrap("\e[0;1m", hilite(attrPath2, attrPathMatch, "\e[0;1m")),
name.version != "" ? " (" + name.version + ")" : ""); name.version != "" ? " (" + name.version + ")" : "");
if (description != "") if (description != "")
logger->stdout( logger->cout(
" %s", hilite(description, descriptionMatch, ANSI_NORMAL)); " %s", hilite(description, descriptionMatch, ANSI_NORMAL));
} }
} }

View file

@ -20,12 +20,12 @@ struct CmdShowConfig : Command, MixJSON
{ {
if (json) { if (json) {
// FIXME: use appropriate JSON types (bool, ints, etc). // FIXME: use appropriate JSON types (bool, ints, etc).
logger->stdout("%s", globalConfig.toJSON().dump()); logger->cout("%s", globalConfig.toJSON().dump());
} else { } else {
std::map<std::string, Config::SettingInfo> settings; std::map<std::string, Config::SettingInfo> settings;
globalConfig.getSettings(settings); globalConfig.getSettings(settings);
for (auto & s : settings) for (auto & s : settings)
logger->stdout("%s = %s", s.first, s.second.value); logger->cout("%s = %s", s.first, s.second.value);
} }
} }
}; };

View file

@ -156,7 +156,7 @@ struct CmdWhyDepends : SourceExprCommand
auto pathS = store->printStorePath(node.path); auto pathS = store->printStorePath(node.path);
assert(node.dist != inf); assert(node.dist != inf);
logger->stdout("%s%s%s%s" ANSI_NORMAL, logger->cout("%s%s%s%s" ANSI_NORMAL,
firstPad, firstPad,
node.visited ? "\e[38;5;244m" : "", node.visited ? "\e[38;5;244m" : "",
firstPad != "" ? "" : "", firstPad != "" ? "" : "",

View file

@ -1,6 +1,6 @@
{ nixpkgs, system, overlay }: { nixpkgs, system, overlay }:
with import (nixpkgs + "/nixos/lib/testing.nix") { with import (nixpkgs + "/nixos/lib/testing-python.nix") {
inherit system; inherit system;
extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ]; extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ];
}; };
@ -64,6 +64,7 @@ in
makeTest ( makeTest (
{ {
name = "github-flakes";
nodes = nodes =
{ # Impersonate github.com and api.github.com. { # Impersonate github.com and api.github.com.
@ -113,36 +114,37 @@ makeTest (
}; };
}; };
testScript = { nodes }: testScript = { nodes }: ''
'' # fmt: off
use POSIX qw(strftime); 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" client.succeed("nix registry pin nixpkgs")
or die "revision mismatch";
$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. info = json.loads(client.succeed("nix flake info nixpkgs --json"))
$github->succeed("systemctl stop httpd.service"); 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"); client.succeed("nix build nixpkgs#hello")
strftime("%Y%m%d%H%M%S", gmtime($date)) eq "${nixpkgs.lastModifiedDate}" or die "time mismatch";
$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).
# The build shouldn't fail even with --tarball-ttl 0 (the server client.succeed("nix build nixpkgs#fuse --tarball-ttl 0")
# being down should not be a fatal error). '';
$client->succeed("nix build nixpkgs#fuse --tarball-ttl 0");
'';
}) })

View file

@ -2,12 +2,13 @@
{ nixpkgs, system, overlay }: { nixpkgs, system, overlay }:
with import (nixpkgs + "/nixos/lib/testing.nix") { with import (nixpkgs + "/nixos/lib/testing-python.nix") {
inherit system; inherit system;
extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ]; extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ];
}; };
makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; in { makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; in {
name = "nix-copy-closure";
nodes = nodes =
{ client = { client =
@ -25,41 +26,46 @@ makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; in {
}; };
}; };
testScript = { nodes }: testScript = { nodes }: ''
'' # fmt: off
startAll; import subprocess
# Create an SSH key on the client. start_all()
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");
# Install the SSH key on the server. # Create an SSH key on the client.
$server->succeed("mkdir -m 700 /root/.ssh"); subprocess.run([
$server->copyFileFromHost("key.pub", "/root/.ssh/authorized_keys"); "${pkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
$server->waitForUnit("sshd"); ], capture_output=True, check=True)
$client->waitForUnit("network.target");
$client->succeed("ssh -o StrictHostKeyChecking=no " . $server->name() . " 'echo hello world'");
# Copy the closure of package A from the client to the server. client.succeed("mkdir -m 700 /root/.ssh")
$server->fail("nix-store --check-validity ${pkgA}"); client.copy_from_host("key", "/root/.ssh/id_ed25519")
$client->succeed("nix-copy-closure --to server --gzip ${pkgA} >&2"); client.succeed("chmod 600 /root/.ssh/id_ed25519")
$server->succeed("nix-store --check-validity ${pkgA}");
# Copy the closure of package B from the server to the client. # Install the SSH key on the server.
$client->fail("nix-store --check-validity ${pkgB}"); server.succeed("mkdir -m 700 /root/.ssh")
$client->succeed("nix-copy-closure --from server --gzip ${pkgB} >&2"); server.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
$client->succeed("nix-store --check-validity ${pkgB}"); 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. # Copy the closure of package A from the client to the server.
$client->fail("nix-store -r ${pkgC}"); server.fail("nix-store --check-validity ${pkgA}")
# FIXME client.succeed("nix-copy-closure --to server --gzip ${pkgA} >&2")
#$client->succeed( server.succeed("nix-store --check-validity ${pkgA}")
# "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 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}")
'';
}) })

View file

@ -2,7 +2,7 @@
{ nixpkgs, system, overlay }: { nixpkgs, system, overlay }:
with import (nixpkgs + "/nixos/lib/testing.nix") { with import (nixpkgs + "/nixos/lib/testing-python.nix") {
inherit system; inherit system;
extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ]; extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ];
}; };
@ -36,6 +36,7 @@ let
in in
{ {
name = "remote-builds";
nodes = nodes =
{ builder1 = builder; { builder1 = builder;
@ -66,44 +67,46 @@ in
}; };
}; };
testScript = { nodes }: testScript = { nodes }: ''
'' # fmt: off
startAll; import subprocess
# Create an SSH key on the client. start_all()
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");
# Install the SSH key on the builders. # Create an SSH key on the client.
$client->waitForUnit("network.target"); subprocess.run([
foreach my $builder ($builder1, $builder2) { "${pkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
$builder->succeed("mkdir -p -m 700 /root/.ssh"); ], capture_output=True, check=True)
$builder->copyFileFromHost("key.pub", "/root/.ssh/authorized_keys"); client.succeed("mkdir -p -m 700 /root/.ssh")
$builder->waitForUnit("sshd"); client.copy_from_host("key", "/root/.ssh/id_ed25519")
$client->succeed("ssh -o StrictHostKeyChecking=no " . $builder->name() . " 'echo hello world'"); client.succeed("chmod 600 /root/.ssh/id_ed25519")
}
# Perform a build and check that it was performed on the builder. # Install the SSH key on the builders.
my $out = $client->succeed( client.wait_for_unit("network.target")
"nix-build ${expr nodes.client.config 1} 2> build-output", for builder in [builder1, builder2]:
"grep -q Hello build-output" builder.succeed("mkdir -p -m 700 /root/.ssh")
); builder.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
$builder1->succeed("test -e $out"); builder.wait_for_unit("sshd")
client.succeed(f"ssh -o StrictHostKeyChecking=no {builder.name} 'echo hello world'")
# And a parallel build. # Perform a build and check that it was performed on the builder.
my ($out1, $out2) = split /\s/, out = client.succeed(
$client->succeed('nix-store -r $(nix-instantiate ${expr nodes.client.config 2})\!out $(nix-instantiate ${expr nodes.client.config 3})\!out'); "nix-build ${expr nodes.client.config 1} 2> build-output",
$builder1->succeed("test -e $out1 -o -e $out2"); "grep -q Hello build-output"
$builder2->succeed("test -e $out1 -o -e $out2"); )
builder1.succeed(f"test -e {out}")
# And a failing build. # And a parallel build.
$client->fail("nix-build ${expr nodes.client.config 5}"); 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. # And a failing build.
$builder1->block; client.fail("nix-build ${expr nodes.client.config 5}")
$client->succeed("nix-build ${expr nodes.client.config 4}");
'';
# Test whether the build hook automatically skips unavailable builders.
builder1.block()
client.succeed("nix-build ${expr nodes.client.config 4}")
'';
}) })

View file

@ -2,12 +2,13 @@
{ nixpkgs, system, overlay }: { nixpkgs, system, overlay }:
with import (nixpkgs + "/nixos/lib/testing.nix") { with import (nixpkgs + "/nixos/lib/testing-python.nix") {
inherit system; inherit system;
extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ]; extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ];
}; };
makeTest { makeTest {
name = "setuid";
machine = machine =
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
@ -17,94 +18,109 @@ makeTest {
virtualisation.pathsInNixDB = [ pkgs.stdenv pkgs.pkgsi686Linux.stdenv ]; virtualisation.pathsInNixDB = [ pkgs.stdenv pkgs.pkgsi686Linux.stdenv ];
}; };
testScript = { nodes }: testScript = { nodes }: ''
'' # fmt: off
startAll; start_all()
# Copying to /tmp should succeed. # Copying to /tmp should succeed.
$machine->succeed('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" {} " machine.succeed(r"""
mkdir -p $out nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" {} "
cp ${pkgs.coreutils}/bin/id /tmp/id 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. # Creating a setuid binary should fail.
$machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" {} " machine.fail(r"""
mkdir -p $out nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" {} "
cp ${pkgs.coreutils}/bin/id /tmp/id mkdir -p $out
chmod 4755 /tmp/id 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. # Creating a setgid binary should fail.
$machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" {} " machine.fail(r"""
mkdir -p $out nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" {} "
cp ${pkgs.coreutils}/bin/id /tmp/id mkdir -p $out
chmod 2755 /tmp/id 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. # The checks should also work on 32-bit binaries.
$machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> { system = "i686-linux"; }; runCommand "foo" {} " machine.fail(r"""
mkdir -p $out nix-build --no-sandbox -E '(with import <nixpkgs> { system = "i686-linux"; }; runCommand "foo" {} "
cp ${pkgs.coreutils}/bin/id /tmp/id mkdir -p $out
chmod 2755 /tmp/id 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. # The tests above use fchmodat(). Test chmod() as well.
$machine->succeed('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } " machine.succeed(r"""
mkdir -p $out nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
cp ${pkgs.coreutils}/bin/id /tmp/id mkdir -p $out
perl -e \"chmod 0666, qw(/tmp/id) or die\" 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 <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } " machine.fail(r"""
mkdir -p $out nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
cp ${pkgs.coreutils}/bin/id /tmp/id mkdir -p $out
perl -e \"chmod 04755, qw(/tmp/id) or die\" 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(). # And test fchmod().
$machine->succeed('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } " machine.succeed(r"""
mkdir -p $out nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
cp ${pkgs.coreutils}/bin/id /tmp/id mkdir -p $out
perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 01750, \\\$x or die\" 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 <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } " machine.fail(r"""
mkdir -p $out nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } "
cp ${pkgs.coreutils}/bin/id /tmp/id mkdir -p $out
perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 04777, \\\$x or die\" 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('[[ $(stat -c %a /tmp/id) = 555 ]]')
$machine->succeed("rm /tmp/id");
'';
machine.succeed("rm /tmp/id")
'';
} }