diff --git a/configure.ac b/configure.ac index b72b47f00..5af239cbd 100644 --- a/configure.ac +++ b/configure.ac @@ -9,14 +9,14 @@ STABLE=0 # Put the revision number in the version. if test "$STABLE" != "1"; then - if REVISION=`test -d $srcdir/.svn && svnversion $srcdir 2> /dev/null`; then + if REVISION=`test -d $srcdir/.svn && svnversion -n $srcdir 2> /dev/null`; then VERSION=${VERSION}pre${REVISION} elif REVISION=`cat $srcdir/svn-revision 2> /dev/null`; then VERSION=${VERSION}pre${REVISION} fi fi -AC_DEFINE_UNQUOTED(NIX_VERSION, ["$(echo $VERSION)"], [version]) +AC_DEFINE_UNQUOTED(NIX_VERSION, ["$VERSION"], [version]) AC_PREFIX_DEFAULT(/nix) diff --git a/corepkgs/buildenv/builder.pl.in b/corepkgs/buildenv/builder.pl.in index 590d31ad6..7b9f0ed7d 100755 --- a/corepkgs/buildenv/builder.pl.in +++ b/corepkgs/buildenv/builder.pl.in @@ -13,9 +13,9 @@ mkdir "$out", 0755 || die "error creating $out"; sub readlink_or_StateWrapper; my $symlinks = 0; -my %path_state_identifier; -my %path_runtimeArgs; +my %path_state_identifier = (); +my %priorities; my $nixBinDir = $ENV{"nixBinDir"}; my $nixStore = $ENV{"nixStore"}; @@ -30,13 +30,12 @@ sub createLinks { my @srcDirParts = split /\// , substr($srcDir, length ($nixStore), length ($srcDir)); my $srcDirRoot = $nixStore . "/" . $srcDirParts[1]; # print "srcDirRoot $srcDirRoot \n"; - my $pkgStateIdentifier = $path_state_identifier{$srcDirRoot}; - my $pkgRuntimeStateArgs = $path_runtimeArgs{$srcDirRoot}; my $dstDir = shift; - my $ignoreCollisions = shift; + my $priority = shift; + my $pkgStateIdentifier = $path_state_identifier{$srcDirRoot}; # We have to look it up each time since recursion can change the $srcDir, but not the identifier - # print "createLinks $srcDir to $dstDir with iden $pkgStateIdentifier \n"; + #print "createLinks $srcDir to $dstDir with iden $pkgStateIdentifier \n"; my @srcFiles = glob("$srcDir/*"); @@ -61,7 +60,7 @@ sub createLinks { #go recursive on directorys if (-d _) { - createLinks($srcFile, $dstFile, $ignoreCollisions); + createLinks($srcFile, $dstFile, $priority); } elsif (-l _) { @@ -71,16 +70,17 @@ sub createLinks { } unlink $dstFile or die "error unlinking `$dstFile': $!"; mkdir $dstFile, 0755 || die "error creating directory `$dstFile': $!"; - createLinks($target, $dstFile, $ignoreCollisions); - createLinks($srcFile, $dstFile, $ignoreCollisions); + createLinks($target, $dstFile, $priority); # !!! <- priority isn't right + createLinks($srcFile, $dstFile, $priority); } else { - # print "1STLINK $srcFile to $dstFile with iden $pkgStateIdentifier \n"; + #print "1ST DIR LINK $srcFile to $dstFile with iden $pkgStateIdentifier \n"; symlink($srcFile, $dstFile) || die "error creating link `$dstFile': $!"; + $priorities{$dstFile} = $priority; $symlinks++; } } @@ -89,7 +89,7 @@ sub createLinks { # print "ELSE LINK $srcFile to $dstFile with iden $pkgStateIdentifier \n"; - # if we have ..... + # if we have a state component with a identifier different then "" if($pkgStateIdentifier ne "__NOSTATE__" && $pkgStateIdentifier ne ""){ my @pathparts = split /\// , $srcFile; @@ -112,38 +112,42 @@ sub createLinks { # We also check with -e if the wrapperscript-file exists, and if is it a symlink (with -l) if (-l $new_dstFile || -e $new_dstFile) { - if (!$ignoreCollisions) { my $target = readlink_or_StateWrapper $new_dstFile; die "(state) collission between `$srcFile' and `$target' (over $new_dstFile)"; - } } sysopen (DSTFILEHANDLE, $new_dstFile, O_RDWR|O_EXCL|O_CREAT, 0755); printf DSTFILEHANDLE "#! @shell@ \n"; - - if($pkgRuntimeStateArgs eq "__NOARGS__"){ - printf DSTFILEHANDLE "$nixBinDir/nix-state --run --identifier=$new_stateIdentifier $srcFile \"\$@\" \n"; - } - else{ - printf DSTFILEHANDLE "$nixBinDir/nix-state --run --identifier=$new_stateIdentifier $srcFile \"\$@\" $pkgRuntimeStateArgs \n"; - } # TODO, maybe first R.T.A. then other args ? - + printf DSTFILEHANDLE "$nixBinDir/nix-state --run --identifier=$new_stateIdentifier $srcFile \"\$@\" \n"; close (DSTFILEHANDLE); } - } - else{ - if (-l $dstFile || -e $dstFile) { - if (!$ignoreCollisions) { - my $target = readlink_or_StateWrapper $dstFile; - die "collission between `$srcFile' and `$target'"; - } - } + } + elsif($pkgStateIdentifier ne "__NOSTATE__" && $pkgStateIdentifier eq ""){ #TODO we now dont create symlinks for state packages with a empty identifier + #TODO but we must do it if there is no normal non-state pacakge + } + + else { + + if (-l $dstFile || -e $dstFile) { + my $target = readlink_or_StateWrapper $dstFile; + my $prevPriority = $priorities{$dstFile}; + die ( "Collission between `$srcFile' and `$target'. " + . "Suggested solution: use `nix-env --set-flag " + . "priority NUMBER PKGNAME' to change the priority of " + . "one of the conflicting packages.\n" ) + if $prevPriority == $priority; + next if $prevPriority < $priority; + unlink $dstFile or die; + } + + # print "2ND LINK $srcFile to $dstFile with iden $pkgStateIdentifier \n"; symlink($srcFile, $dstFile) || die "error creating link `$dstFile': $!"; + $priorities{$dstFile} = $priority; $symlinks++; - } - } + } + } } } @@ -154,13 +158,13 @@ my %postponed; sub addPkg; sub addPkg { my $pkgDir = shift; - my $ignoreCollisions = shift; + my $priority = shift; return if (defined $done{$pkgDir}); $done{$pkgDir} = 1; # print "symlinking $pkgDir\n"; - createLinks("$pkgDir", "$out", $ignoreCollisions); + createLinks("$pkgDir", "$out", $priority); my $propagatedFN = "$pkgDir/nix-support/propagated-user-env-packages"; if (-e $propagatedFN) { @@ -190,23 +194,39 @@ sub readlink_or_StateWrapper { return $target } -# Symlink to the packages that have been installed explicitly by the user. -my @storePaths = split ' ', $ENV{"derivations"}; my @stateIdentifiers = split ' ', $ENV{"stateIdentifiers"}; -my @runtimeStateArgs = split ' ', $ENV{"runtimeStateArgs_arg"}; my $si_counter = 0; -foreach my $pkgDir (@storePaths) { #Commented the sort out +# Convert the stuff we get from the environment back into a coherent +# data type. +my @paths = split ' ', $ENV{"paths"}; +my @active = split ' ', $ENV{"active"}; +my @priority = split ' ', $ENV{"priority"}; - #Link each $pkgDir to a $stateIdentifiers in $path_state_identifier - $path_state_identifier{$pkgDir} = $stateIdentifiers[$si_counter]; - $path_runtimeArgs{$pkgDir} = $runtimeStateArgs[$si_counter]; +die if scalar @paths != scalar @active; +die if scalar @paths != scalar @priority; - # print "SP: $pkgDir \n"; - # print "SI: $path_state_identifier{$pkgDir} \n"; - # print "RT: $path_runtimeArgs{$pkgDir} \n"; - - addPkg($pkgDir, 0); +my %pkgs; + +for (my $n = 0; $n < scalar @paths; $n++) { + $pkgs{$paths[$n]} = + { active => $active[$n] + , priority => $priority[$n] + , stateidentifier => $stateIdentifiers[$n] + }; + + $path_state_identifier{$paths[$n]} = $stateIdentifiers[$n]; +} + +# Symlink to the packages that have been installed explicitly by the +# user. +foreach my $pkg (sort (keys %pkgs)) { + + #print "SP: $pkg \n"; + #print "SI: $pkgs{$pkg}->{stateidentifier} \n"; + #print "PR: $pkgs{$pkg}->{priority} \n"; + + addPkg($pkg, $pkgs{$pkg}->{priority}) if $pkgs{$pkg}->{active} ne "false"; $si_counter++; } @@ -215,15 +235,17 @@ foreach my $pkgDir (@storePaths) { #Commented the sort out # installed by the user (i.e., package X declares that it want Y # installed as well). We do these later because they have a lower # priority in case of collisions. +my $priorityCounter = 1000; # don't care about collisions while (scalar(keys %postponed) > 0) { my @pkgDirs = keys %postponed; %postponed = (); - foreach my $pkgDir (sort @pkgDirs) { - addPkg($pkgDir, 1); + foreach my $pkgDir (sort @pkgDirs) { + addPkg($pkgDir, $priorityCounter++); } } print STDERR "created $symlinks symlinks in user environment\n"; symlink($ENV{"manifest"}, "$out/manifest") or die "cannot create manifest"; + diff --git a/corepkgs/buildenv/default.nix b/corepkgs/buildenv/default.nix index 4804304ae..9a90821bd 100644 --- a/corepkgs/buildenv/default.nix +++ b/corepkgs/buildenv/default.nix @@ -1,12 +1,16 @@ -{system, derivations, stateIdentifiers, runtimeStateArgs, manifest, nixBinDir, nixStore}: +{system, derivations, stateIdentifiers, manifest, nixBinDir, nixStore}: derivation { name = "user-environment"; system = system; builder = ./builder.pl; - derivations = derivations; - runtimeStateArgs_arg = runtimeStateArgs; + stateIdentifiers = stateIdentifiers; manifest = manifest; inherit nixBinDir nixStore; + + # !!! grmbl, need structured data for passing this in a clean way. + paths = derivations; + active = map (x: if x ? meta && x.meta ? active then x.meta.active else "true") derivations; + priority = map (x: if x ? meta && x.meta ? priority then x.meta.priority else "5") derivations; } diff --git a/doc/manual/installation.xml b/doc/manual/installation.xml index b9358efd1..2642bca1d 100644 --- a/doc/manual/installation.xml +++ b/doc/manual/installation.xml @@ -57,14 +57,15 @@ repository. To build the parser, very recent versions of Bison and Flex are required. (This is because Nix needs GLR support in Bison and reentrancy support in Flex.) For Bison, you need -version 1.875c or higher (1.875 does not work), -which can be obtained from the GNU FTP server. -For Flex, you need version 2.5.31, which is available on SourceForge. Slightly -older versions may also work, but ancient versions like the ubiquitous -2.5.4a won't. Note that these are only required if you modify the -parser or when you are building from the Subversion repository. +version 2.3 or higher (1.875 does not work), +which can be obtained from +the GNU FTP +server. For Flex, you need version 2.5.33, which is available +on SourceForge. +Slightly older versions may also work, but ancient versions like the +ubiquitous 2.5.4a won't. Note that these are only required if you +modify the parser or when you are building from the Subversion +repository. Nix uses Sleepycat's Berkeley DB and CWI's ATerm library. These are included in the Nix source distribution. If you build from the @@ -75,7 +76,7 @@ these packages. Alternatively, if you already have them installed, you can use configure's and options to point to their respective locations. Note that Berkeley DB must be version -4.4; other versions may not have compatible database formats. +4.5; other versions may not have compatible database formats. diff --git a/doc/manual/release-notes.xml b/doc/manual/release-notes.xml index 4830b323e..da8c47588 100644 --- a/doc/manual/release-notes.xml +++ b/doc/manual/release-notes.xml @@ -67,11 +67,22 @@ TODO: nix-env now maintains meta - info about installed packages in user - environments. + info about installed packages in user environments. to show all meta info. TODO: nix-env - . + . Specific flags: + active, priority, + keep. + + + nix-env -q now has a flag + () that causes + nix-env to show only those derivations whose + output is already in the Nix store or that can be substituted (i.e., + downloaded from somewhere). In other words, it shows the packages + that can be installed “quickly”, i.e., don’t need to be built from + source. TODO: new built-ins diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 456bc25f3..552b58625 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -616,6 +616,9 @@ static char * deepestStack = (char *) -1; /* for measuring stack usage */ Expr evalExpr2(EvalState & state, Expr e) { + /* When changing this function, make sure that you don't cause a + (large) increase in stack consumption! */ + char x; if (&x < deepestStack) deepestStack = &x; diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 420911a87..dabbaa323 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -12,6 +12,7 @@ namespace nix { MakeError(EvalError, Error) MakeError(AssertionError, EvalError) +MakeError(ThrownError, AssertionError) MakeError(Abort, EvalError) MakeError(TypeError, EvalError) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index fdb77901f..b004a3c26 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -271,6 +271,14 @@ static Expr prim_abort(EvalState & state, const ATermVector & args) } +static Expr prim_throw(EvalState & state, const ATermVector & args) +{ + PathSet context; + throw ThrownError(format("user-thrown exception: `%1%'") % + evalString(state, args[0], context)); +} + + /* Return an environment variable. Use with care. */ static Expr prim_getEnv(EvalState & state, const ATermVector & args) { @@ -1026,6 +1034,7 @@ void EvalState::addPrimOps() addPrimOp("isNull", 1, prim_isNull); addPrimOp("dependencyClosure", 1, prim_dependencyClosure); addPrimOp("abort", 1, prim_abort); + addPrimOp("throw", 1, prim_throw); addPrimOp("__getEnv", 1, prim_getEnv); addPrimOp("relativise", 2, prim_relativise); diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index f360b73fe..a902a19df 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -1466,6 +1466,7 @@ void verifyStore(bool checkContents) nixDB.enumTable(txn, dbValidPaths, paths); for (Paths::iterator i = paths.begin(); i != paths.end(); ++i) { + checkInterrupt(); if (!pathExists(*i)) { printMsg(lvlError, format("store path `%1%' disappeared") % *i); invalidateStorePath(txn, *i); diff --git a/src/nix-env/help.txt b/src/nix-env/help.txt index 534d16ad3..b10c4b492 100644 --- a/src/nix-env/help.txt +++ b/src/nix-env/help.txt @@ -45,8 +45,14 @@ Upgrade flags: --eq: "upgrade" if the current version is equal --always: upgrade regardless of current version -Query types: +Query sources: + --installed: use installed derivations (default) + --available / -a: use derivations available in Nix expression + +Query flags: + + --xml: show output in XML format --status / -s: print installed/present status --no-name: hide derivation names --attr / -A: shows the unambiguous attribute name of the @@ -55,11 +61,10 @@ Query types: --compare-versions / -c: compare version to available or installed --drv-path: print path of derivation --out-path: print path of derivation output - -Query sources: - - --installed: use installed derivations (default) - --available / -a: use derivations available in Nix expression + --description: print description + --meta: print all meta attributes (only with --xml) + --prebuilt-only: only show derivations whose prebuilt binaries are + available on this machine or are downloadable Options: diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 9e6bec730..3a1fbba8b 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -163,7 +163,6 @@ static void createUserEnv(EvalState & state, const DrvInfos & elems, ATermList manifest = ATempty; ATermList inputs = ATempty; ATermList stateIdentifiers = ATempty; - ATermList runtimeStateArgs = ATempty; for (DrvInfos::const_iterator i = elems.begin(); i != elems.end(); ++i) { @@ -195,8 +194,6 @@ static void createUserEnv(EvalState & state, const DrvInfos & elems, //Insert the new stateIdentifier into the stateIdentifiers Atermlist stateIdentifiers = ATinsert(stateIdentifiers, makeStr(i->queryStateIdentifier(state))); - //Insert the new runtime state args into the runtimeStateArgs Atermlist - runtimeStateArgs = ATinsert(runtimeStateArgs, makeStr(i->queryRuntimeStateArgs(state))); inputs = ATinsert(inputs, makeStr(i->queryOutPath(state))); @@ -220,15 +217,13 @@ static void createUserEnv(EvalState & state, const DrvInfos & elems, Expr topLevel = makeCall(envBuilder, makeAttrs( ATinsert( - ATmakeList6( + ATmakeList5( makeBind(toATerm("system"), makeStr(thisSystem), makeNoPos()), makeBind(toATerm("derivations"), makeList(ATreverse(manifest)), makeNoPos()), makeBind(toATerm("stateIdentifiers"), makeList(ATreverse(stateIdentifiers)), makeNoPos()), - makeBind(toATerm("runtimeStateArgs"), - makeList(ATreverse(runtimeStateArgs)), makeNoPos()), makeBind(toATerm("manifest"), makeStr(manifestFile, singleton(manifestFile)), makeNoPos()), makeBind(toATerm("nixBinDir"), @@ -536,9 +531,13 @@ static void installDerivations(Globals & globals, for (DrvInfos::iterator i = installedElems.begin(); i != installedElems.end(); ++i) { DrvName drvName(i->name); + MetaInfo meta = i->queryMetaInfo(globals.state); //We may need to share state - if (!globals.preserveInstalled && newNames.find(drvName.name) != newNames.end()){ + if (!globals.preserveInstalled && + newNames.find(drvName.name) != newNames.end() && + meta["keep"] != "true" + ){ //******** We're gonna check if the component and state indentifiers are the same, // since we may need to share state in that case. @@ -709,6 +708,9 @@ static void upgradeDerivations(Globals & globals, { DrvName drvName(i->name); + MetaInfo meta = i->queryMetaInfo(globals.state); + if (meta["keep"] == "true") continue; + /* Find the derivation in the input Nix expression with the same name and satisfying the version constraints specified by upgradeType. If there are multiple matches, take the @@ -997,6 +999,8 @@ static void opQuery(Globals & globals, bool printDrvPath = false; bool printOutPath = false; bool printDescription = false; + bool printMeta = false; + bool prebuiltOnly = false; bool compareVersions = false; bool xmlOutput = false; @@ -1013,8 +1017,10 @@ static void opQuery(Globals & globals, else if (*i == "--compare-versions" || *i == "-c") compareVersions = true; else if (*i == "--drv-path") printDrvPath = true; else if (*i == "--out-path") printOutPath = true; + else if (*i == "--meta") printMeta = true; else if (*i == "--installed") source = sInstalled; else if (*i == "--available" || *i == "-a") source = sAvailable; + else if (*i == "--prebuilt-only" || *i == "-b") prebuiltOnly = true; else if (*i == "--xml") xmlOutput = true; else throw UsageError(format("unknown flag `%1%'") % *i); @@ -1080,6 +1086,12 @@ static void opQuery(Globals & globals, /* For XML output. */ XMLAttrs attrs; + + if (prebuiltOnly) { + if (!store->isValidPath(i->queryOutPath(globals.state)) && + !store->hasSubstitutes(i->queryOutPath(globals.state))) + continue; + } if (printStatus) { bool hasSubs = store->hasSubstitutes(i->queryOutPath(globals.state)); @@ -1167,7 +1179,18 @@ static void opQuery(Globals & globals, } if (xmlOutput) - xml.writeEmptyElement("item", attrs); + if (printMeta) { + XMLOpenElement item(xml, "item", attrs); + MetaInfo meta = i->queryMetaInfo(globals.state); + for (MetaInfo::iterator j = meta.begin(); j != meta.end(); ++j) { + XMLAttrs attrs2; + attrs2["name"] = j->first; + attrs2["value"] = j->second; + xml.writeEmptyElement("meta", attrs2); + } + } + else + xml.writeEmptyElement("item", attrs); else table.push_back(columns); diff --git a/src/nix-setuid-helper/nix-setuid-helper.cc b/src/nix-setuid-helper/nix-setuid-helper.cc index 37347cd28..26c457fd9 100644 --- a/src/nix-setuid-helper/nix-setuid-helper.cc +++ b/src/nix-setuid-helper/nix-setuid-helper.cc @@ -36,7 +36,7 @@ static void secureChown(uid_t uidFrom, gid_t gidFrom, to. */ throw Error(error); - if (uidFrom != -1) { + if (uidFrom != (uid_t) -1) { assert(uidFrom != 0); if (st.st_uid != uidFrom) throw Error(error);