From a5952405d2803ae0d29955fe6725cd9195327a07 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 16 Nov 2011 11:37:40 +0000 Subject: * Re-use prepared statements across insertions into the manifest cache DB. This speeds up creating the cache from 16.1s to 7.9s on my system. --- perl/lib/Nix/Manifest.pm | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'perl/lib/Nix') diff --git a/perl/lib/Nix/Manifest.pm b/perl/lib/Nix/Manifest.pm index 7790cfe3b98c..f042e1f88db3 100644 --- a/perl/lib/Nix/Manifest.pm +++ b/perl/lib/Nix/Manifest.pm @@ -286,6 +286,14 @@ EOF open MAINLOCK, ">>$lockFile" or die "unable to acquire lock ‘$lockFile’: $!\n"; flock(MAINLOCK, LOCK_EX) or die; + our $insertNAR = $dbh->prepare( + "insert into NARs(manifest, storePath, url, hash, size, narHash, " . + "narSize, refs, deriver, system) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") or die; + + our $insertPatch = $dbh->prepare( + "insert into Patches(manifest, storePath, basePath, baseHash, url, hash, " . + "size, narHash, narSize, patchType) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $dbh->begin_work; # Read each manifest in $manifestDir and add it to the database, @@ -312,20 +320,16 @@ EOF sub addNARToDB { my ($storePath, $narFile) = @_; - $dbh->do( - "insert into NARs(manifest, storePath, url, hash, size, narHash, " . - "narSize, refs, deriver, system) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - {}, $id, $storePath, $narFile->{url}, $narFile->{hash}, $narFile->{size}, + $insertNAR->execute( + $id, $storePath, $narFile->{url}, $narFile->{hash}, $narFile->{size}, $narFile->{narHash}, $narFile->{narSize}, $narFile->{references}, $narFile->{deriver}, $narFile->{system}); }; sub addPatchToDB { my ($storePath, $patch) = @_; - $dbh->do( - "insert into Patches(manifest, storePath, basePath, baseHash, url, hash, " . - "size, narHash, narSize, patchType) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - {}, $id, $storePath, $patch->{basePath}, $patch->{baseHash}, $patch->{url}, + $insertPatch->execute( + $id, $storePath, $patch->{basePath}, $patch->{baseHash}, $patch->{url}, $patch->{hash}, $patch->{size}, $patch->{narHash}, $patch->{narSize}, $patch->{patchType}); }; -- cgit 1.4.1 From 63ee5e4d2a46c3619c59307d7dbb08f25d32c3e8 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 16 Nov 2011 11:56:19 +0000 Subject: * Remove obsolete line. --- perl/lib/Nix/Manifest.pm | 1 - 1 file changed, 1 deletion(-) (limited to 'perl/lib/Nix') diff --git a/perl/lib/Nix/Manifest.pm b/perl/lib/Nix/Manifest.pm index f042e1f88db3..21c61d284faf 100644 --- a/perl/lib/Nix/Manifest.pm +++ b/perl/lib/Nix/Manifest.pm @@ -120,7 +120,6 @@ sub readManifest_ { elsif (/^\s*Hash:\s*(\S+)\s*$/) { $hash = $1; } elsif (/^\s*URL:\s*(\S+)\s*$/) { $url = $1; } elsif (/^\s*Size:\s*(\d+)\s*$/) { $size = $1; } - elsif (/^\s*SuccOf:\s*(\/\S+)\s*$/) { } # obsolete elsif (/^\s*BasePath:\s*(\/\S+)\s*$/) { $basePath = $1; } elsif (/^\s*BaseHash:\s*(\S+)\s*$/) { $baseHash = $1; } elsif (/^\s*Type:\s*(\S+)\s*$/) { $patchType = $1; } -- cgit 1.4.1 From d7d7910ba48d898bda2db92a4f16a6179c855f7d Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 16 Nov 2011 16:25:38 +0000 Subject: * Don't decompress the manifests in /nix/var/nix/manifest. This saves disk space, and, since they're typically only decompressed once (to fill the manifest cache), doesn't make things slower. --- perl/lib/Nix/Manifest.pm | 10 ++++++++-- scripts/nix-pull.in | 11 +---------- 2 files changed, 9 insertions(+), 12 deletions(-) (limited to 'perl/lib/Nix') diff --git a/perl/lib/Nix/Manifest.pm b/perl/lib/Nix/Manifest.pm index 21c61d284faf..9c891abb8bd9 100644 --- a/perl/lib/Nix/Manifest.pm +++ b/perl/lib/Nix/Manifest.pm @@ -53,8 +53,14 @@ sub addPatch { sub readManifest_ { my ($manifest, $addNAR, $addPatch) = @_; - open MANIFEST, "<$manifest" - or die "cannot open `$manifest': $!"; + # Decompress the manifest if necessary. + if ($manifest =~ /\.bz2$/) { + open MANIFEST, "$Nix::Config::bzip2 -d < $manifest |" + or die "cannot decompress `$manifest': $!"; + } else { + open MANIFEST, "<$manifest" + or die "cannot open `$manifest': $!"; + } my $inside = 0; my $type; diff --git a/scripts/nix-pull.in b/scripts/nix-pull.in index f3cba0c02619..d8352b2774bb 100755 --- a/scripts/nix-pull.in +++ b/scripts/nix-pull.in @@ -59,16 +59,7 @@ sub processURL { # First see if a bzipped manifest is available. if (system("$Nix::Config::curl --fail --silent --head '$url'.bz2 > /dev/null") == 0) { print "fetching list of Nix archives at `$url.bz2'...\n"; - my $bzipped = downloadFile "$url.bz2"; - - $manifest = "$tmpDir/MANIFEST"; - - system("$Nix::Config::bzip2 -d < $bzipped > $manifest") == 0 - or die "cannot decompress manifest"; - - $manifest = (`$Nix::Config::binDir/nix-store --add $manifest` - or die "cannot copy $manifest to the store"); - chomp $manifest; + $manifest = downloadFile "$url.bz2"; } # Otherwise, just get the uncompressed manifest. -- cgit 1.4.1 From f8e609c3413e38d403d986020079f24a2b82c063 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 16 Nov 2011 16:41:48 +0000 Subject: * nix-pull: update the Nix manifest cache if necessary. Also, don't read the manifest just to check the version and print the number of paths. This makes nix-pull very fast for the cached cache (speeding up nixos-rebuild without the ‘--no-pull’ or ‘--fast’ options). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- perl/lib/Nix/Manifest.pm | 8 ++++---- scripts/nix-pull.in | 24 +++--------------------- 2 files changed, 7 insertions(+), 25 deletions(-) (limited to 'perl/lib/Nix') diff --git a/perl/lib/Nix/Manifest.pm b/perl/lib/Nix/Manifest.pm index 9c891abb8bd9..d1717a0a8ebd 100644 --- a/perl/lib/Nix/Manifest.pm +++ b/perl/lib/Nix/Manifest.pm @@ -305,8 +305,8 @@ EOF # unless we've already done so on a previous run. my %seen; - for my $manifest (glob "$manifestDir/*.nixmanifest") { - $manifest = Cwd::abs_path($manifest); + for my $manifestLink (glob "$manifestDir/*.nixmanifest") { + my $manifest = Cwd::abs_path($manifestLink); my $timestamp = lstat($manifest)->mtime; $seen{$manifest} = 1; @@ -342,10 +342,10 @@ EOF my $version = readManifest_($manifest, \&addNARToDB, \&addPatchToDB); if ($version < 3) { - die "you have an old-style manifest `$manifest'; please delete it"; + die "you have an old-style or corrupt manifest `$manifestLink'; please delete it"; } if ($version >= 10) { - die "manifest `$manifest' is too new; please delete it or upgrade Nix"; + die "manifest `$manifestLink' is too new; please delete it or upgrade Nix"; } } diff --git a/scripts/nix-pull.in b/scripts/nix-pull.in index d8352b2774bb..74545a35004c 100755 --- a/scripts/nix-pull.in +++ b/scripts/nix-pull.in @@ -33,10 +33,6 @@ if (! -l $manifestDirLink) { # Process the URLs specified on the command line. -my %narFiles; -my %patches; - -my $skipWrongStore = 0; sub downloadFile { my $url = shift; @@ -68,20 +64,6 @@ sub processURL { $manifest = downloadFile $url; } - my $version = readManifest($manifest, \%narFiles, \%patches); - - die "`$url' is not a manifest or it is too old (i.e., for Nix <= 0.7)\n" if $version < 3; - die "manifest `$url' is too new\n" if $version >= 5; - - if ($skipWrongStore) { - foreach my $path (keys %narFiles) { - if (substr($path, 0, length($storeDir) + 1) ne "$storeDir/") { - print STDERR "warning: manifest `$url' assumes a Nix store at a different location than $storeDir, skipping...\n"; - exit 0; - } - } - } - my $baseName = "unnamed"; if ($url =~ /\/([^\/]+)\/[^\/]+$/) { # get the forelast component $baseName = $1; @@ -120,12 +102,12 @@ sub processURL { while (@ARGV) { my $url = shift @ARGV; if ($url eq "--skip-wrong-store") { - $skipWrongStore = 1; + # No-op, no longer supported. } else { processURL $url; } } -my $size = scalar (keys %narFiles); -print "$size store paths in manifest\n"; +# Update the cache. +updateManifestDB(); -- cgit 1.4.1 From 993fa94fb489f46e127ef760bea8c65ef281ef7f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 22 Nov 2011 17:28:41 +0000 Subject: * Move initialisation of variables like nixConfDir from libmain to libstore so that the Perl bindings can use it as well. It's vital that the Perl bindings use the configuration file, because otherwise nix-copy-closure will fail with a ‘database locked’ message if the value of ‘use-sqlite-wal’ is changed from the default. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- perl/lib/Nix/Store.xs | 4 +--- src/libmain/Makefile.am | 7 ------- src/libmain/shared.cc | 26 ++------------------------ src/libstore/Makefile.am | 11 ++++++++++- src/libstore/globals.cc | 30 ++++++++++++++++++++++++++++++ src/libstore/globals.hh | 4 +++- 6 files changed, 46 insertions(+), 36 deletions(-) (limited to 'perl/lib/Nix') diff --git a/perl/lib/Nix/Store.xs b/perl/lib/Nix/Store.xs index af71ad955c4f..9e51ea337c7e 100644 --- a/perl/lib/Nix/Store.xs +++ b/perl/lib/Nix/Store.xs @@ -18,10 +18,8 @@ using namespace nix; void doInit() { if (!store) { - nixStore = canonPath(getEnv("NIX_STORE_DIR", getEnv("NIX_STORE", "/nix/store"))); - nixStateDir = canonPath(getEnv("NIX_STATE_DIR", "/nix/var/nix")); - nixDBPath = getEnv("NIX_DB_DIR", nixStateDir + "/db"); try { + setDefaultsFromEnvironment(); store = openStore(); } catch (Error & e) { croak(e.what()); diff --git a/src/libmain/Makefile.am b/src/libmain/Makefile.am index ababc3595968..404353c62922 100644 --- a/src/libmain/Makefile.am +++ b/src/libmain/Makefile.am @@ -7,13 +7,6 @@ libmain_la_LIBADD = ../libstore/libstore.la @BDW_GC_LIBS@ pkginclude_HEADERS = shared.hh AM_CXXFLAGS = \ - -DNIX_STORE_DIR=\"$(storedir)\" \ - -DNIX_DATA_DIR=\"$(datadir)\" \ - -DNIX_STATE_DIR=\"$(localstatedir)/nix\" \ - -DNIX_LOG_DIR=\"$(localstatedir)/log/nix\" \ - -DNIX_CONF_DIR=\"$(sysconfdir)/nix\" \ - -DNIX_LIBEXEC_DIR=\"$(libexecdir)\" \ - -DNIX_BIN_DIR=\"$(bindir)\" \ -DNIX_VERSION=\"$(VERSION)\" \ -I$(srcdir)/.. -I$(srcdir)/../libutil \ -I$(srcdir)/../libstore diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 8532cdaadcab..f7c11ed0544e 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -120,30 +120,8 @@ static bool showTrace = false; processor. */ static void initAndRun(int argc, char * * argv) { - /* Setup Nix paths. */ - nixStore = canonPath(getEnv("NIX_STORE_DIR", getEnv("NIX_STORE", NIX_STORE_DIR))); - nixDataDir = canonPath(getEnv("NIX_DATA_DIR", NIX_DATA_DIR)); - nixLogDir = canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR)); - nixStateDir = canonPath(getEnv("NIX_STATE_DIR", NIX_STATE_DIR)); - nixDBPath = getEnv("NIX_DB_DIR", nixStateDir + "/db"); - nixConfDir = canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR)); - nixLibexecDir = canonPath(getEnv("NIX_LIBEXEC_DIR", NIX_LIBEXEC_DIR)); - nixBinDir = canonPath(getEnv("NIX_BIN_DIR", NIX_BIN_DIR)); - - string subs = getEnv("NIX_SUBSTITUTERS", "default"); - if (subs == "default") { - substituters.push_back(nixLibexecDir + "/nix/substituters/copy-from-other-stores.pl"); - substituters.push_back(nixLibexecDir + "/nix/substituters/download-using-manifests.pl"); - } else - substituters = tokenizeString(subs, ":"); - - /* Get some settings from the configuration file. */ - thisSystem = querySetting("system", SYSTEM); - maxBuildJobs = queryIntSetting("build-max-jobs", 1); - buildCores = queryIntSetting("build-cores", 1); - maxSilentTime = queryIntSetting("build-max-silent-time", 0); - buildTimeout = queryIntSetting("build-timeout", 0); - + setDefaultsFromEnvironment(); + /* Catch SIGINT. */ struct sigaction act; act.sa_handler = sigintHandler; diff --git a/src/libstore/Makefile.am b/src/libstore/Makefile.am index e19256b925ea..39a61233b4a7 100644 --- a/src/libstore/Makefile.am +++ b/src/libstore/Makefile.am @@ -15,7 +15,16 @@ libstore_la_LIBADD = ../libutil/libutil.la ../boost/format/libformat.la ${aterm_ EXTRA_DIST = schema.sql AM_CXXFLAGS = -Wall \ - ${sqlite_include} -I$(srcdir)/.. -I$(srcdir)/../libutil + ${sqlite_include} -I$(srcdir)/.. -I$(srcdir)/../libutil \ + -DNIX_STORE_DIR=\"$(storedir)\" \ + -DNIX_DATA_DIR=\"$(datadir)\" \ + -DNIX_STATE_DIR=\"$(localstatedir)/nix\" \ + -DNIX_LOG_DIR=\"$(localstatedir)/log/nix\" \ + -DNIX_CONF_DIR=\"$(sysconfdir)/nix\" \ + -DNIX_LIBEXEC_DIR=\"$(libexecdir)\" \ + -DNIX_BIN_DIR=\"$(bindir)\" \ + -I$(srcdir)/.. -I$(srcdir)/../libutil \ + -I$(srcdir)/../libstore local-store.lo: schema.sql.hh diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 2e9dc88237d1..5c22f1406649 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -1,3 +1,5 @@ +#include "config.h" + #include "globals.hh" #include "util.hh" @@ -138,5 +140,33 @@ void reloadSettings() settings.clear(); } + +void setDefaultsFromEnvironment() +{ + /* Setup Nix paths. */ + nixStore = canonPath(getEnv("NIX_STORE_DIR", getEnv("NIX_STORE", NIX_STORE_DIR))); + nixDataDir = canonPath(getEnv("NIX_DATA_DIR", NIX_DATA_DIR)); + nixLogDir = canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR)); + nixStateDir = canonPath(getEnv("NIX_STATE_DIR", NIX_STATE_DIR)); + nixDBPath = getEnv("NIX_DB_DIR", nixStateDir + "/db"); + nixConfDir = canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR)); + nixLibexecDir = canonPath(getEnv("NIX_LIBEXEC_DIR", NIX_LIBEXEC_DIR)); + nixBinDir = canonPath(getEnv("NIX_BIN_DIR", NIX_BIN_DIR)); + + string subs = getEnv("NIX_SUBSTITUTERS", "default"); + if (subs == "default") { + substituters.push_back(nixLibexecDir + "/nix/substituters/copy-from-other-stores.pl"); + substituters.push_back(nixLibexecDir + "/nix/substituters/download-using-manifests.pl"); + } else + substituters = tokenizeString(subs, ":"); + + /* Get some settings from the configuration file. */ + thisSystem = querySetting("system", SYSTEM); + maxBuildJobs = queryIntSetting("build-max-jobs", 1); + buildCores = queryIntSetting("build-cores", 1); + maxSilentTime = queryIntSetting("build-max-silent-time", 0); + buildTimeout = queryIntSetting("build-timeout", 0); +} + } diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index 231c1f8508ac..12a9b9ca15c0 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -114,7 +114,9 @@ void overrideSetting(const string & name, const Strings & value); void reloadSettings(); - +void setDefaultsFromEnvironment(); + + } -- cgit 1.4.1 From ab20af3e6f83f320232d0e5f6bcfcb279c0047c0 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 23 Nov 2011 12:21:35 +0000 Subject: * build-remote.pl: drop a hard-coded reference to /nix/etc/nix. --- perl/lib/Nix/Config.pm.in | 1 + scripts/build-remote.pl.in | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'perl/lib/Nix') diff --git a/perl/lib/Nix/Config.pm.in b/perl/lib/Nix/Config.pm.in index 658305fd9783..b657683be3f8 100644 --- a/perl/lib/Nix/Config.pm.in +++ b/perl/lib/Nix/Config.pm.in @@ -4,6 +4,7 @@ $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@"; $libexecDir = $ENV{"NIX_LIBEXEC_DIR"} || "@libexecdir@"; $manifestDir = $ENV{"NIX_MANIFESTS_DIR"} || "@localstatedir@/nix/manifests"; $logDir = $ENV{"NIX_LOG_DIR"} || "@localstatedir@/log/nix"; +$confDir = $ENV{"NIX_CONF_DIR"} || "@sysconfdir@/nix"; $bzip2 = $ENV{"NIX_BZIP2"} || "@bzip2@"; $curl = "@curl@"; diff --git a/scripts/build-remote.pl.in b/scripts/build-remote.pl.in index e8c76086dae2..110c95f223a0 100755 --- a/scripts/build-remote.pl.in +++ b/scripts/build-remote.pl.in @@ -3,6 +3,7 @@ use Fcntl ':flock'; use English '-no_match_vars'; use IO::Handle; +use Nix::Config; use Nix::SSH qw/sshOpts openSSHConnection/; no warnings('once'); @@ -208,7 +209,7 @@ print STDERR "@ build-remote $drvPath $hostName\n" if $printBuildTrace; my $maybeSign = ""; -$maybeSign = "--sign" if -e "/nix/etc/nix/signing-key.sec"; +$maybeSign = "--sign" if -e "$Nix::Config::confDir/signing-key.sec"; # Register the derivation as a temporary GC root. Note that $PPID is -- cgit 1.4.1 From 5bbd693caedd5d50994938555b3a4b535875347e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 23 Nov 2011 15:13:37 +0000 Subject: * Add an API function exportPaths() that provides the functionality of ‘nix-store --export’. * Add a Perl module that provides the functionality of ‘nix-copy-closure --to’. This is used by build-remote.pl so it no longer needs to start a separate nix-copy-closure process. Also, it uses the Perl API to do the export, so it doesn't need to start a separate nix-store process either. As a result, nix-copy-closure and build-remote.pl should no longer fail on very large closures due to an "Argument list too long" error. (Note that having very many dependencies in a single derivation can still fail because the environment can become too large. Can't be helped though.) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- perl/Makefile.am | 2 +- perl/lib/Nix/CopyClosure.pm | 46 +++++++++++++++++++++++++++++++++++++++++++++ perl/lib/Nix/Store.pm | 2 +- perl/lib/Nix/Store.xs | 13 +++++++++++++ scripts/build-remote.pl.in | 4 ++-- scripts/nix-copy-closure.in | 36 ++++++++--------------------------- src/libstore/local-store.cc | 2 +- src/libstore/store-api.cc | 11 +++++++++++ src/libstore/store-api.hh | 6 ++++++ src/nix-store/nix-store.cc | 6 +----- 10 files changed, 90 insertions(+), 38 deletions(-) create mode 100644 perl/lib/Nix/CopyClosure.pm (limited to 'perl/lib/Nix') diff --git a/perl/Makefile.am b/perl/Makefile.am index eded469f924b..93f5415c8bb6 100644 --- a/perl/Makefile.am +++ b/perl/Makefile.am @@ -2,7 +2,7 @@ perlversion := $(shell perl -e 'use Config; print $$Config{version};') perlarchname := $(shell perl -e 'use Config; print $$Config{archname};') perllibdir = $(libdir)/perl5/site_perl/$(perlversion)/$(perlarchname) -PERL_MODULES = lib/Nix/Store.pm lib/Nix/Manifest.pm lib/Nix/GeneratePatches.pm lib/Nix/SSH.pm lib/Nix/Config.pm.in +PERL_MODULES = lib/Nix/Store.pm lib/Nix/Manifest.pm lib/Nix/GeneratePatches.pm lib/Nix/SSH.pm lib/Nix/CopyClosure.pm lib/Nix/Config.pm.in all: $(PERL_MODULES:.in=) ln -sfn $(abs_builddir)/.libs/libNixStore.so lib/Store.so diff --git a/perl/lib/Nix/CopyClosure.pm b/perl/lib/Nix/CopyClosure.pm new file mode 100644 index 000000000000..045f6bfaf156 --- /dev/null +++ b/perl/lib/Nix/CopyClosure.pm @@ -0,0 +1,46 @@ +package Nix::CopyClosure; + +use strict; +use Nix::Config; +use Nix::Store; + + +sub copyTo { + my ($sshHost, $sshOpts, $storePaths, $compressor, $decompressor, $includeOutputs, $dryRun, $sign) = @_; + + $compressor = "$compressor |" if $compressor ne ""; + $decompressor = "$decompressor |" if $decompressor ne ""; + + # Get the closure of this path. + my @closure = reverse(topoSortPaths(computeFSClosure(0, $includeOutputs, + map { followLinksToStorePath $_ } @{$storePaths}))); + + # Ask the remote host which paths are invalid. Because of limits + # to the command line length, do this in chunks. Eventually, + # we'll want to use ‘--from-stdin’, but we can't rely on the + # target having this option yet. + my @missing = (); + while (scalar(@closure) > 0) { + my @ps = splice(@closure, 0, 1500); + open(READ, "set -f; ssh $sshHost @{$sshOpts} nix-store --check-validity --print-invalid @ps|"); + while () { + chomp; + push @missing, $_; + } + close READ or die; + } + + # Export the store paths and import them on the remote machine. + if (scalar @missing > 0) { + print STDERR "copying ", scalar @missing, " missing paths to ‘$sshHost’...\n"; + #print STDERR " $_\n" foreach @missing; + unless ($dryRun) { + open SSH, "| $compressor ssh $sshHost @{$sshOpts} '$decompressor nix-store --import'" or die; + exportPaths(fileno(SSH), $sign, @missing); + close SSH or die "copying store paths to remote machine `$sshHost' failed: $?"; + } + } +} + + +1; diff --git a/perl/lib/Nix/Store.pm b/perl/lib/Nix/Store.pm index bef6e7460ca7..d96f8e9ab652 100644 --- a/perl/lib/Nix/Store.pm +++ b/perl/lib/Nix/Store.pm @@ -12,7 +12,7 @@ our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); -our @EXPORT = qw(isValidPath topoSortPaths computeFSClosure followLinksToStorePath); +our @EXPORT = qw(isValidPath topoSortPaths computeFSClosure followLinksToStorePath exportPaths); our $VERSION = '0.15'; diff --git a/perl/lib/Nix/Store.xs b/perl/lib/Nix/Store.xs index 9e51ea337c7e..b50451f45f10 100644 --- a/perl/lib/Nix/Store.xs +++ b/perl/lib/Nix/Store.xs @@ -146,3 +146,16 @@ SV * followLinksToStorePath(char * path) } OUTPUT: RETVAL + + +void exportPaths(int fd, int sign, ...) + PPCODE: + try { + doInit(); + Paths paths; + for (int n = 2; n < items; ++n) paths.push_back(SvPV_nolen(ST(n))); + FdSink sink(fd); + exportPaths(*store, paths, sign, sink); + } catch (Error & e) { + croak(e.what()); + } diff --git a/scripts/build-remote.pl.in b/scripts/build-remote.pl.in index 110c95f223a0..72d09565bc25 100755 --- a/scripts/build-remote.pl.in +++ b/scripts/build-remote.pl.in @@ -5,6 +5,7 @@ use English '-no_match_vars'; use IO::Handle; use Nix::Config; use Nix::SSH qw/sshOpts openSSHConnection/; +use Nix::CopyClosure; no warnings('once'); @@ -225,8 +226,7 @@ sub removeRoots { # Copy the derivation and its dependencies to the build machine. -system("NIX_SSHOPTS=\"@sshOpts\" @bindir@/nix-copy-closure $hostName $maybeSign $drvPath @inputs") == 0 - or die "cannot copy inputs to $hostName: $?"; +Nix::CopyClosure::copyTo($hostName, [ @sshOpts ], [ $drvPath, @inputs ], "", "", 0, 0, $maybeSign ne ""); # Perform the build. diff --git a/scripts/nix-copy-closure.in b/scripts/nix-copy-closure.in index 172acd9e7da2..2eac56e3f229 100755 --- a/scripts/nix-copy-closure.in +++ b/scripts/nix-copy-closure.in @@ -3,6 +3,7 @@ use Nix::SSH; use Nix::Config; use Nix::Store; +use Nix::CopyClosure; if (scalar @ARGV < 1) { @@ -39,8 +40,8 @@ while (@ARGV) { $sign = 1; } elsif ($arg eq "--gzip") { - $compressor = "| gzip"; - $decompressor = "gunzip |"; + $compressor = "gzip"; + $decompressor = "gunzip"; } elsif ($arg eq "--from") { $toMode = 0; @@ -67,30 +68,7 @@ openSSHConnection $sshHost or die "$0: unable to start SSH\n"; if ($toMode) { # Copy TO the remote machine. - - # Get the closure of this path. - my @allStorePaths = reverse(topoSortPaths(computeFSClosure(0, $includeOutputs, map { followLinksToStorePath $_ } @storePaths))); - - # Ask the remote host which paths are invalid. - open(READ, "set -f; ssh $sshHost @sshOpts nix-store --check-validity --print-invalid @allStorePaths|"); - my @missing = (); - while () { - chomp; - push @missing, $_; - } - close READ or die; - - # Export the store paths and import them on the remote machine. - if (scalar @missing > 0) { - print STDERR "copying these missing paths:\n"; - print STDERR " $_\n" foreach @missing; - unless ($dryRun) { - my $extraOpts = $sign ? "--sign" : ""; - system("set -f; nix-store --export $extraOpts @missing $compressor | ssh $sshHost @sshOpts '$decompressor nix-store --import'") == 0 - or die "copying store paths to remote machine `$sshHost' failed: $?"; - } - } - + Nix::CopyClosure::copyTo($sshHost, [ @sshOpts ], [ @storePaths ], $compressor, $decompressor, $includeOutputs, $dryRun, $sign); } else { # Copy FROM the remote machine. @@ -112,8 +90,10 @@ else { # Copy FROM the remote machine. # Export the store paths on the remote machine and import them on locally. if (scalar @missing > 0) { - print STDERR "copying these missing paths:\n"; - print STDERR " $_\n" foreach @missing; + print STDERR "copying ", scalar @missing, " missing paths from ‘$sshHost’...\n"; + #print STDERR " $_\n" foreach @missing; + $compressor = "| $compressor" if $compressor ne ""; + $decompressor = "$decompressor |" if $decompressor ne ""; unless ($dryRun) { my $extraOpts = $sign ? "--sign" : ""; system("set -f; ssh $sshHost @sshOpts 'nix-store --export $extraOpts @missing $compressor' | $decompressor $Nix::Config::binDir/nix-store --import") == 0 diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 06cadcb0ff0e..3c1f2ecacdcb 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -1255,7 +1255,7 @@ Path LocalStore::importPath(bool requireSignature, Source & source) bool haveSignature = readInt(hashAndReadSource) == 1; if (requireSignature && !haveSignature) - throw Error("imported archive lacks a signature"); + throw Error(format("imported archive of `%1%' lacks a signature") % dstPath); if (haveSignature) { string signature = readString(hashAndReadSource); diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index d67ff2c77299..36ade2170876 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -298,6 +298,17 @@ string showPaths(const PathSet & paths) } +void exportPaths(StoreAPI & store, const Paths & paths, + bool sign, Sink & sink) +{ + foreach (Paths::const_iterator, i, paths) { + writeInt(1, sink); + store.exportPath(*i, sign, sink); + } + writeInt(0, sink); +} + + } diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index b3e67436c6c3..8bfb09880edd 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -342,6 +342,12 @@ ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven = false); +/* Export multiple paths in the format expected by ‘nix-store + --import’. */ +void exportPaths(StoreAPI & store, const Paths & paths, + bool sign, Sink & sink); + + } diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index 371ca54af07c..84d3da032c2e 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -594,11 +594,7 @@ static void opExport(Strings opFlags, Strings opArgs) else throw UsageError(format("unknown flag `%1%'") % *i); FdSink sink(STDOUT_FILENO); - for (Strings::iterator i = opArgs.begin(); i != opArgs.end(); ++i) { - writeInt(1, sink); - store->exportPath(*i, sign, sink); - } - writeInt(0, sink); + exportPaths(*store, opArgs, sign, sink); } -- cgit 1.4.1 From 216440b3ff1431beca7784c7ae76cb5e75446953 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 29 Nov 2011 12:32:55 +0000 Subject: * For consistency with "nix-store -q --hash", produce hashes in base-32. (This affects Hydra manifests.) --- perl/lib/Nix/Store.xs | 2 +- scripts/nix-push.in | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'perl/lib/Nix') diff --git a/perl/lib/Nix/Store.xs b/perl/lib/Nix/Store.xs index b50451f45f10..aac7761cbd80 100644 --- a/perl/lib/Nix/Store.xs +++ b/perl/lib/Nix/Store.xs @@ -67,7 +67,7 @@ SV * queryPathHash(char * path) try { doInit(); Hash hash = store->queryPathHash(path); - string s = "sha256:" + printHash(hash); + string s = "sha256:" + printHash32(hash); XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); } catch (Error & e) { croak(e.what()); diff --git a/scripts/nix-push.in b/scripts/nix-push.in index dcdad5721265..cf46d00dfb06 100755 --- a/scripts/nix-push.in +++ b/scripts/nix-push.in @@ -198,8 +198,8 @@ for (my $n = 0; $n < scalar @storePaths; $n++) { # In some exceptional cases (such as VM tests that use the Nix # store of the host), the database doesn't contain the hash. So # compute it. - if ($narHash eq "sha256:0000000000000000000000000000000000000000000000000000") { - $narHash = `$binDir/nix-hash --type sha256 '$storePath'`; + if ($narHash =~ /^sha256:0*$/) { + $narHash = `$binDir/nix-hash --type sha256 --base32 '$storePath'`; die "cannot hash `$storePath'" if $? != 0; chomp $narHash; $narHash = "sha256:$narHash"; -- cgit 1.4.1 From 1749a7b0ae943f6a208ffc3fd0f6e9506872c5b6 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 29 Nov 2011 13:01:24 +0000 Subject: * download-using-manifests: use the Perl bindings. --- perl/lib/Nix/Store.pm | 6 +++- perl/lib/Nix/Store.xs | 11 ++++++ scripts/download-using-manifests.pl.in | 66 +++++++++++++++------------------- 3 files changed, 45 insertions(+), 38 deletions(-) (limited to 'perl/lib/Nix') diff --git a/perl/lib/Nix/Store.pm b/perl/lib/Nix/Store.pm index d96f8e9ab652..d5fc6eec590e 100644 --- a/perl/lib/Nix/Store.pm +++ b/perl/lib/Nix/Store.pm @@ -12,7 +12,11 @@ our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); -our @EXPORT = qw(isValidPath topoSortPaths computeFSClosure followLinksToStorePath exportPaths); +our @EXPORT = qw( + isValidPath queryReferences queryPathInfo queryDeriver queryPathHash + topoSortPaths computeFSClosure followLinksToStorePath exportPaths + hashPath +); our $VERSION = '0.15'; diff --git a/perl/lib/Nix/Store.xs b/perl/lib/Nix/Store.xs index aac7761cbd80..5256d1372fe2 100644 --- a/perl/lib/Nix/Store.xs +++ b/perl/lib/Nix/Store.xs @@ -159,3 +159,14 @@ void exportPaths(int fd, int sign, ...) } catch (Error & e) { croak(e.what()); } + + +SV * hashPath(char * algo, int base32, char * path) + PPCODE: + try { + Hash h = hashPath(parseHashType(algo), path).first; + string s = base32 ? printHash32(h) : printHash(h); + XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); + } catch (Error & e) { + croak(e.what()); + } diff --git a/scripts/download-using-manifests.pl.in b/scripts/download-using-manifests.pl.in index a827a995f919..ef663dabb1ef 100755 --- a/scripts/download-using-manifests.pl.in +++ b/scripts/download-using-manifests.pl.in @@ -3,6 +3,7 @@ use strict; use Nix::Config; use Nix::Manifest; +use Nix::Store; use POSIX qw(strftime); use File::Temp qw(tempdir); @@ -19,14 +20,8 @@ my $fast = 1; my $dbh = updateManifestDB(); -sub isValidPath { - my $p = shift; - if ($fast) { - return -e $p; - } else { - return system("$Nix::Config::binDir/nix-store --check-validity '$p' 2> /dev/null") == 0; - } -} +# $hashCache->{$algo}->{$path} yields the $algo-hash of $path. +my $hashCache; sub parseHash { @@ -101,15 +96,17 @@ sub computeSmallestDownload { foreach my $patch (@{$patchList}) { if (isValidPath($patch->{basePath})) { - # !!! this should be cached my ($baseHashAlgo, $baseHash) = parseHash $patch->{baseHash}; - my $format = "--base32"; - $format = "" if $baseHashAlgo eq "md5"; - my $hash = $fast && $baseHashAlgo eq "sha256" - ? `$Nix::Config::binDir/nix-store -q --hash "$patch->{basePath}"` - : `$Nix::Config::binDir/nix-hash --type '$baseHashAlgo' $format "$patch->{basePath}"`; - chomp $hash; - $hash =~ s/.*://; + + my $hash = $hashCache->{$baseHashAlgo}->{$patch->{basePath}}; + if (!defined $hash) { + $hash = $fast && $baseHashAlgo eq "sha256" + ? queryPathHash($patch->{basePath}) + : hashPath($baseHashAlgo, $baseHashAlgo ne "md5", $patch->{basePath}); + $hash =~ s/.*://; + $hashCache->{$baseHashAlgo}->{$patch->{basePath}} = $hash; + } + next if $hash ne $baseHash; } push @queue, $patch->{basePath}; @@ -257,7 +254,7 @@ open LOGFILE, ">>$logFile" or die "cannot open log file $logFile"; my $date = strftime ("%F %H:%M:%S UTC", gmtime (time)); print LOGFILE "$$ get $targetPath $date\n"; -print "\n*** Trying to download/patch `$targetPath'\n"; +print STDERR "\n*** Trying to download/patch `$targetPath'\n"; # Compute the shortest path. @@ -281,7 +278,7 @@ sub downloadFile { $ENV{"PRINT_PATH"} = 1; $ENV{"QUIET"} = 1; my ($hash, $path) = `$Nix::Config::binDir/nix-prefetch-url '$url'`; - die "download of `$url' failed" . ($! ? ": $!" : "") unless $? == 0; + die "download of `$url' failed" . ($! ? ": $!" : "") . "\n" unless $? == 0; chomp $path; return $path; } @@ -293,17 +290,17 @@ while (scalar @path > 0) { my $u = $edge->{start}; my $v = $edge->{end}; - print "\n*** Step $curStep/$maxStep: "; + print STDERR "\n*** Step $curStep/$maxStep: "; if ($edge->{type} eq "present") { - print "using already present path `$v'\n"; + print STDERR "using already present path `$v'\n"; print LOGFILE "$$ present $v\n"; if ($curStep < $maxStep) { # Since this is not the last step, the path will be used # as a base to one or more patches. So turn the base path # into a NAR archive, to which we can apply the patch. - print " packing base path...\n"; + print STDERR " packing base path...\n"; system("$Nix::Config::binDir/nix-store --dump $v > $tmpNar") == 0 or die "cannot dump `$v'"; } @@ -311,17 +308,17 @@ while (scalar @path > 0) { elsif ($edge->{type} eq "patch") { my $patch = $edge->{info}; - print "applying patch `$patch->{url}' to `$u' to create `$v'\n"; + print STDERR "applying patch `$patch->{url}' to `$u' to create `$v'\n"; print LOGFILE "$$ patch $patch->{url} $patch->{size} $patch->{baseHash} $u $v\n"; # Download the patch. - print " downloading patch...\n"; + print STDERR " downloading patch...\n"; my $patchPath = downloadFile "$patch->{url}"; # Apply the patch to the NAR archive produced in step 1 (for # the already present path) or a later step (for patch sequences). - print " applying patch...\n"; + print STDERR " applying patch...\n"; system("$Nix::Config::libexecDir/bspatch $tmpNar $tmpNar2 $patchPath") == 0 or die "cannot apply patch `$patchPath' to $tmpNar"; @@ -331,7 +328,7 @@ while (scalar @path > 0) { } else { # This was the last patch. Unpack the final NAR archive # into the target path. - print " unpacking patched archive...\n"; + print STDERR " unpacking patched archive...\n"; system("$Nix::Config::binDir/nix-store --restore $v < $tmpNar2") == 0 or die "cannot unpack $tmpNar2 into `$v'"; } @@ -341,13 +338,13 @@ while (scalar @path > 0) { elsif ($edge->{type} eq "narfile") { my $narFile = $edge->{info}; - print "downloading `$narFile->{url}' into `$v'\n"; + print STDERR "downloading `$narFile->{url}' into `$v'\n"; my $size = $narFile->{size} || -1; print LOGFILE "$$ narfile $narFile->{url} $size $v\n"; # Download the archive. - print " downloading archive...\n"; + print STDERR " downloading archive...\n"; my $narFilePath = downloadFile "$narFile->{url}"; if ($curStep < $maxStep) { @@ -356,7 +353,7 @@ while (scalar @path > 0) { or die "cannot unpack `$narFilePath' into `$v'"; } else { # Unpack the archive into the target path. - print " unpacking archive...\n"; + print STDERR " unpacking archive...\n"; system("$Nix::Config::bzip2 -d < '$narFilePath' | $Nix::Config::binDir/nix-store --restore '$v'") == 0 or die "cannot unpack `$narFilePath' into `$v'"; } @@ -376,20 +373,15 @@ if (defined $finalNarHash) { # The hash in the manifest can be either in base-16 or base-32. # Handle both. - my $extraFlag = - ($hashAlgo eq "sha256" && length($hash) != 64) - ? "--base32" : ""; - - my $hash2 = `$Nix::Config::binDir/nix-hash --type $hashAlgo $extraFlag $targetPath` - or die "cannot compute hash of path `$targetPath'"; - chomp $hash2; + my $hash2 = hashPath($hashAlgo, $hashAlgo eq "sha256" && length($hash) != 64, $targetPath); - die "hash mismatch in downloaded path $targetPath; expected $hash, got $hash2" + die "hash mismatch in downloaded path $targetPath; expected $hash, got $hash2\n" if $hash ne $hash2; } else { - die "cannot check integrity of the downloaded path since its hash is not known"; + die "cannot check integrity of the downloaded path since its hash is not known\n"; } +print STDERR "\n"; print LOGFILE "$$ success\n"; close LOGFILE; -- cgit 1.4.1 From f35c4351e5f99f1960a6ca7a3fd6dae76dcca163 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 29 Nov 2011 22:15:07 +0000 Subject: * Don't require a specific Perl version. --- perl/lib/Nix/Store.pm | 1 - 1 file changed, 1 deletion(-) (limited to 'perl/lib/Nix') diff --git a/perl/lib/Nix/Store.pm b/perl/lib/Nix/Store.pm index d5fc6eec590e..126831105a66 100644 --- a/perl/lib/Nix/Store.pm +++ b/perl/lib/Nix/Store.pm @@ -1,6 +1,5 @@ package Nix::Store; -use 5.010001; use strict; use warnings; -- cgit 1.4.1 From 92d6a5ed73e043aebe5029c1ed75449873d327ac Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 2 Dec 2011 12:09:24 +0000 Subject: * Add some more functions to the Perl bindings. --- perl/lib/Nix/Store.pm | 3 ++- perl/lib/Nix/Store.xs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) (limited to 'perl/lib/Nix') diff --git a/perl/lib/Nix/Store.pm b/perl/lib/Nix/Store.pm index 126831105a66..4283e77a45af 100644 --- a/perl/lib/Nix/Store.pm +++ b/perl/lib/Nix/Store.pm @@ -14,7 +14,8 @@ our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw( isValidPath queryReferences queryPathInfo queryDeriver queryPathHash topoSortPaths computeFSClosure followLinksToStorePath exportPaths - hashPath + hashPath hashFile hashString + addToStore makeFixedOutputPath ); our $VERSION = '0.15'; diff --git a/perl/lib/Nix/Store.xs b/perl/lib/Nix/Store.xs index 5256d1372fe2..f8a577fce8fd 100644 --- a/perl/lib/Nix/Store.xs +++ b/perl/lib/Nix/Store.xs @@ -170,3 +170,49 @@ SV * hashPath(char * algo, int base32, char * path) } catch (Error & e) { croak(e.what()); } + + +SV * hashFile(char * algo, int base32, char * path) + PPCODE: + try { + Hash h = hashFile(parseHashType(algo), path); + string s = base32 ? printHash32(h) : printHash(h); + XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); + } catch (Error & e) { + croak(e.what()); + } + + +SV * hashString(char * algo, int base32, char * s) + PPCODE: + try { + Hash h = hashString(parseHashType(algo), s); + string s = base32 ? printHash32(h) : printHash(h); + XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); + } catch (Error & e) { + croak(e.what()); + } + + +SV * addToStore(char * srcPath, int recursive, char * algo) + PPCODE: + try { + doInit(); + Path path = store->addToStore(srcPath, recursive, parseHashType(algo)); + XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0))); + } catch (Error & e) { + croak(e.what()); + } + + +SV * makeFixedOutputPath(int recursive, char * algo, char * hash, char * name) + PPCODE: + try { + doInit(); + HashType ht = parseHashType(algo); + Path path = makeFixedOutputPath(recursive, ht, + parseHash16or32(ht, hash), name); + XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0))); + } catch (Error & e) { + croak(e.what()); + } -- cgit 1.4.1