diff --git a/scripts/nix-collect-garbage.in b/scripts/nix-collect-garbage.in index 8f54ba20f..eaa706578 100755 --- a/scripts/nix-collect-garbage.in +++ b/scripts/nix-collect-garbage.in @@ -5,13 +5,27 @@ my $storedir = "@prefix@/store"; my %alive; -open HASHES, "nix --query --refs \$(cat $linkdir/*.hash) |" or die "in `nix -qrh'"; +my $keepsuccessors = 0; +my $invert = 0; + +foreach my $arg (@ARGV) { + if ($arg eq "--keep-successors") { $keepsuccessors = 1; } + if ($arg eq "--invert") { $invert = 1; } + else { die "unknown argument `$arg'" }; +} + +my $extraarg = ""; +if ($keepsuccessors) { $extraarg = "--include-successors"; }; +open HASHES, "nix --query --requisites $extraarg \$(cat $linkdir/*.id) |" or die "in `nix -qrh'"; while () { chomp; $alive{$_} = 1; + if ($invert) { print "$_\n"; }; } close HASHES; +exit 0 if ($invert); + opendir(DIR, $storedir) or die "cannot opendir $storedir: $!"; my @names = readdir(DIR); closedir DIR; diff --git a/scripts/nix-switch.in b/scripts/nix-switch.in index ddaca4e22..db0e96f3e 100755 --- a/scripts/nix-switch.in +++ b/scripts/nix-switch.in @@ -3,39 +3,56 @@ use strict; my $keep = 0; +my $sourceroot = 0; +my $srcid; -if (scalar @ARGV > 0 && $ARGV[0] eq "--keep") { - shift @ARGV; - $keep = 1; +foreach my $arg (@ARGV) { + if ($arg eq "--keep") { $keep = 1; } + elsif ($arg eq "--source-root") { $sourceroot = 1; } + elsif ($arg =~ /^([0-9a-z]{32})$/) { $srcid = $arg; } + else { die "unknown argument `$arg'" }; } -my $hash = $ARGV[0]; -$hash || die "no package hash specified"; - my $linkdir = "@localstatedir@/nix/links"; # Build the specified package, and all its dependencies. -system "nix --install $hash"; +my $nfid = `nix --install $srcid`; if ($?) { die "`nix --install' failed"; } +chomp $nfid; +die unless $nfid =~ /^([0-9a-z]{32})$/; -my $pkgdir = `nix --query --list $hash`; +my $pkgdir = `nix --query --list $nfid`; if ($?) { die "`nix --query --list' failed"; } chomp $pkgdir; # Figure out a generation number. +opendir(DIR, $linkdir); my $nr = 0; -while (-e "$linkdir/$nr") { $nr++; } +foreach my $n (sort(readdir(DIR))) { + next if (!($n =~ /^\d+$/)); + $nr = $n + 1 if ($n >= $nr); +} +closedir(DIR); + my $link = "$linkdir/$nr"; # Create a symlink from $link to $pkgdir. symlink($pkgdir, $link) or die "cannot create $link: $!"; -# Also store the hash of $pkgdir. This is useful for garbage +# Store the id of the normal form. This is useful for garbage # collection and the like. -my $hashfile = "$linkdir/$nr.hash"; -open HASH, "> $hashfile" or die "cannot create $hashfile"; -print HASH "$hash\n"; -close HASH; +my $idfile = "$linkdir/$nr.id"; +open ID, "> $idfile" or die "cannot create $idfile"; +print ID "$nfid\n"; +close ID; + +# Optionally store the source id. +if ($sourceroot) { + $idfile = "$linkdir/$nr-src.id"; + open ID, "> $idfile" or die "cannot create $idfile"; + print ID "$srcid\n"; + close ID; +} my $current = "$linkdir/current"; @@ -59,6 +76,7 @@ rename($tmplink, $current) or die "cannot rename $tmplink"; if (!$keep && defined $oldlink) { print "deleting old $oldlink\n"; - unlink($oldlink) == 1 || print "cannot delete $oldlink\n"; - unlink("$oldlink.hash") == 1 || print "cannot delete $oldlink.hash\n"; + unlink($oldlink) == 1 or print "cannot delete $oldlink\n"; + unlink("$oldlink.id") == 1 or print "cannot delete $oldlink.id\n"; + unlink("$oldlink-src.id"); } diff --git a/src/Makefile.am b/src/Makefile.am index 23e242919..cc51eff36 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,6 +43,7 @@ nix.o: nix-help.txt.hh install-data-local: $(INSTALL) -d $(localstatedir)/nix $(INSTALL) -d $(localstatedir)/nix/links + ln -sf $(localstatedir)/nix/links/current $(prefix)/current $(INSTALL) -d $(localstatedir)/log/nix $(INSTALL) -d $(prefix)/store $(bindir)/nix --init diff --git a/src/nix-help.txt b/src/nix-help.txt index ecf9b5c16..0e54d162d 100644 --- a/src/nix-help.txt +++ b/src/nix-help.txt @@ -26,7 +26,7 @@ Source selection for --install, --dump: Query flags: --list / -l: query the output paths (roots) of an fstate (default) - --refs / -r: query paths referenced by an fstate + --requisites / -r: print all paths necessary to realise expression --generators / -g: find expressions producing a subset of given ids --expansion / -e: print a path containing id --graph: print a dot graph rooted at given ids diff --git a/src/nix.cc b/src/nix.cc index a7bcf7268..68d01f2f8 100644 --- a/src/nix.cc +++ b/src/nix.cc @@ -95,18 +95,22 @@ FSId maybeNormalise(const FSId & id, bool normalise) /* Perform various sorts of queries. */ static void opQuery(Strings opFlags, Strings opArgs) { - enum { qList, qRefs, qGenerators, qExpansion, qGraph + enum { qList, qRequisites, qGenerators, qExpansion, qGraph } query = qList; bool normalise = false; + bool includeExprs = true; + bool includeSuccessors = false; for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); i++) if (*i == "--list" || *i == "-l") query = qList; - else if (*i == "--refs" || *i == "-r") query = qRefs; + else if (*i == "--requisites" || *i == "-r") query = qRequisites; else if (*i == "--generators" || *i == "-g") query = qGenerators; else if (*i == "--expansion" || *i == "-e") query = qExpansion; else if (*i == "--graph") query = qGraph; else if (*i == "--normalise" || *i == "-n") normalise = true; + else if (*i == "--exclude-exprs") includeExprs = false; + else if (*i == "--include-successors") includeSuccessors = true; else throw UsageError(format("unknown flag `%1%'") % *i); switch (query) { @@ -126,13 +130,14 @@ static void opQuery(Strings opFlags, Strings opArgs) break; } - case qRefs: { + case qRequisites: { StringSet paths; for (Strings::iterator i = opArgs.begin(); i != opArgs.end(); i++) { - Strings paths2 = fstateRefs( - maybeNormalise(argToId(*i), normalise)); + Strings paths2 = fstateRequisites( + maybeNormalise(argToId(*i), normalise), + includeExprs, includeSuccessors); paths.insert(paths2.begin(), paths2.end()); } for (StringSet::iterator i = paths.begin(); diff --git a/src/normalise.cc b/src/normalise.cc index eefb790b6..5ef4d82ac 100644 --- a/src/normalise.cc +++ b/src/normalise.cc @@ -244,7 +244,8 @@ Strings fstatePaths(const FSId & id) } -static void fstateRefsSet(const FSId & id, StringSet & paths) +static void fstateRequisitesSet(const FSId & id, + bool includeExprs, bool includeSuccessors, StringSet & paths) { FState fs = parseFState(termFromId(id)); @@ -257,17 +258,28 @@ static void fstateRefsSet(const FSId & id, StringSet & paths) else if (fs.type == FState::fsDerive) { for (FSIds::iterator i = fs.derive.inputs.begin(); i != fs.derive.inputs.end(); i++) - fstateRefsSet(*i, paths); + fstateRequisitesSet(*i, + includeExprs, includeSuccessors, paths); } else abort(); + + if (includeExprs) + paths.insert(expandId(id)); + + string idSucc; + if (includeSuccessors && + queryDB(nixDB, dbSuccessors, id, idSucc)) + fstateRequisitesSet(parseHash(idSucc), + includeExprs, includeSuccessors, paths); } -Strings fstateRefs(const FSId & id) +Strings fstateRequisites(const FSId & id, + bool includeExprs, bool includeSuccessors) { StringSet paths; - fstateRefsSet(id, paths); + fstateRequisitesSet(id, includeExprs, includeSuccessors, paths); return Strings(paths.begin(), paths.end()); } diff --git a/src/normalise.hh b/src/normalise.hh index a5b45c861..98f58783e 100644 --- a/src/normalise.hh +++ b/src/normalise.hh @@ -15,8 +15,14 @@ void realiseSlice(const FSId & id, FSIdSet pending = FSIdSet()); fstate-expression. */ Strings fstatePaths(const FSId & id); -/* Get the list of paths referenced by the given fstate-expression. */ -Strings fstateRefs(const FSId & id); +/* Get the list of paths that are required to realise the given + expression. For a derive expression, this is the union of + requisites of the inputs; for a slice expression, it is the path of + each element in the slice. If `includeExprs' is true, include the + paths of the Nix expressions themselves. If `includeSuccessors' is + true, include the requisites of successors. */ +Strings fstateRequisites(const FSId & id, + bool includeExprs, bool includeSuccessors); /* Return the list of the ids of all known fstate-expressions whose output ids are completely contained in `ids'. */