diff options
Diffstat (limited to 'corepkgs')
-rw-r--r-- | corepkgs/buildenv.nix | 28 | ||||
-rw-r--r-- | corepkgs/buildenv.pl | 168 | ||||
-rw-r--r-- | corepkgs/config.nix.in | 17 | ||||
-rw-r--r-- | corepkgs/derivation.nix | 27 | ||||
-rw-r--r-- | corepkgs/fetchurl.nix | 37 | ||||
-rw-r--r-- | corepkgs/imported-drv-to-derivation.nix | 21 | ||||
-rw-r--r-- | corepkgs/local.mk | 5 | ||||
-rw-r--r-- | corepkgs/nar.nix | 49 | ||||
-rw-r--r-- | corepkgs/unpack-channel.nix | 42 |
9 files changed, 394 insertions, 0 deletions
diff --git a/corepkgs/buildenv.nix b/corepkgs/buildenv.nix new file mode 100644 index 000000000000..c52a0ea93d35 --- /dev/null +++ b/corepkgs/buildenv.nix @@ -0,0 +1,28 @@ +with import <nix/config.nix>; + +{ derivations, manifest }: + +derivation { + name = "user-environment"; + system = builtins.currentSystem; + builder = perl; + args = [ "-w" ./buildenv.pl ]; + + manifest = manifest; + + # !!! grmbl, need structured data for passing this in a clean way. + derivations = + map (d: + [ (d.meta.active or "true") + (d.meta.priority or 5) + (builtins.length d.outputs) + ] ++ map (output: builtins.getAttr output d) d.outputs) + derivations; + + # Building user environments remotely just causes huge amounts of + # network traffic, so don't do that. + preferLocalBuild = true; + + # Don't build in a chroot because Nix's dependencies may not be there. + __noChroot = true; +} diff --git a/corepkgs/buildenv.pl b/corepkgs/buildenv.pl new file mode 100644 index 000000000000..f98cca7c8582 --- /dev/null +++ b/corepkgs/buildenv.pl @@ -0,0 +1,168 @@ +use strict; +use Cwd; +use IO::Handle; + +STDOUT->autoflush(1); + +my $out = $ENV{"out"}; +mkdir "$out", 0755 || die "error creating $out"; + + +my $symlinks = 0; + +my %priorities; + + +# For each activated package, create symlinks. + +sub createLinks { + my $srcDir = shift; + my $dstDir = shift; + my $priority = shift; + + my @srcFiles = glob("$srcDir/*"); + + foreach my $srcFile (@srcFiles) { + my $baseName = $srcFile; + $baseName =~ s/^.*\///g; # strip directory + my $dstFile = "$dstDir/$baseName"; + + # The files below are special-cased so that they don't show up + # in user profiles, either because they are useless, or + # because they would cause pointless collisions (e.g., each + # Python package brings its own + # `$out/lib/pythonX.Y/site-packages/easy-install.pth'.) + # Urgh, hacky... + if ($srcFile =~ /\/propagated-build-inputs$/ || + $srcFile =~ /\/nix-support$/ || + $srcFile =~ /\/perllocal.pod$/ || + $srcFile =~ /\/info\/dir$/ || + $srcFile =~ /\/log$/) + { + # Do nothing. + } + + elsif (-d $srcFile) { + + lstat $dstFile; + + if (-d _) { + createLinks($srcFile, $dstFile, $priority); + } + + elsif (-l _) { + my $target = readlink $dstFile or die; + if (!-d $target) { + die "collision between directory `$srcFile' and non-directory `$target'"; + } + unlink $dstFile or die "error unlinking `$dstFile': $!"; + mkdir $dstFile, 0755 || + die "error creating directory `$dstFile': $!"; + createLinks($target, $dstFile, $priorities{$dstFile}); + createLinks($srcFile, $dstFile, $priority); + } + + else { + symlink($srcFile, $dstFile) || + die "error creating link `$dstFile': $!"; + $priorities{$dstFile} = $priority; + $symlinks++; + } + } + + else { + + if (-l $dstFile) { + my $target = readlink $dstFile; + my $prevPriority = $priorities{$dstFile}; + die ( "collision between `$srcFile' and `$target'; " + . "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; + } + + symlink($srcFile, $dstFile) || + die "error creating link `$dstFile': $!"; + $priorities{$dstFile} = $priority; + $symlinks++; + } + } +} + + +my %done; +my %postponed; + +sub addPkg; +sub addPkg { + my $pkgDir = shift; + my $priority = shift; + + return if (defined $done{$pkgDir}); + $done{$pkgDir} = 1; + +# print "symlinking $pkgDir\n"; + createLinks("$pkgDir", "$out", $priority); + + my $propagatedFN = "$pkgDir/nix-support/propagated-user-env-packages"; + if (-e $propagatedFN) { + open PROP, "<$propagatedFN" or die; + my $propagated = <PROP>; + close PROP; + my @propagated = split ' ', $propagated; + foreach my $p (@propagated) { + $postponed{$p} = 1 unless defined $done{$p}; + } + } +} + + +# Convert the stuff we get from the environment back into a coherent +# data type. +my @pkgs; +my @derivations = split ' ', $ENV{"derivations"}; +while (scalar @derivations) { + my $active = shift @derivations; + my $priority = shift @derivations; + my $outputs = shift @derivations; + for (my $n = 0; $n < $outputs; $n++) { + my $path = shift @derivations; + push @pkgs, + { path => $path + , active => $active ne "false" + , priority => int($priority) }; + } +} + + +# Symlink to the packages that have been installed explicitly by the +# user. Process in priority order to reduce unnecessary +# symlink/unlink steps. +@pkgs = sort { $a->{priority} <=> $b->{priority} || $a->{path} cmp $b->{path} } @pkgs; +foreach my $pkg (@pkgs) { + #print $pkg, " ", $pkgs{$pkg}->{priority}, "\n"; + addPkg($pkg->{path}, $pkg->{priority}) if $pkg->{active}; +} + + +# Symlink to the packages that have been "propagated" by packages +# 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, $priorityCounter++); + } +} + + +print STDERR "created $symlinks symlinks in user environment\n"; + + +symlink($ENV{"manifest"}, "$out/manifest.nix") or die "cannot create manifest"; diff --git a/corepkgs/config.nix.in b/corepkgs/config.nix.in new file mode 100644 index 000000000000..a5ec83b9ea0c --- /dev/null +++ b/corepkgs/config.nix.in @@ -0,0 +1,17 @@ +let + fromEnv = var: def: + let val = builtins.getEnv var; in + if val != "" then val else def; +in { + perl = "@perl@"; + shell = "@bash@"; + coreutils = "@coreutils@"; + bzip2 = "@bzip2@"; + gzip = "@gzip@"; + xz = "@xz@"; + tar = "@tar@"; + tarFlags = "@tarFlags@"; + tr = "@tr@"; + curl = "@curl@"; + nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@"; +} diff --git a/corepkgs/derivation.nix b/corepkgs/derivation.nix new file mode 100644 index 000000000000..c0fbe8082cd3 --- /dev/null +++ b/corepkgs/derivation.nix @@ -0,0 +1,27 @@ +/* This is the implementation of the ‘derivation’ builtin function. + It's actually a wrapper around the ‘derivationStrict’ primop. */ + +drvAttrs @ { outputs ? [ "out" ], ... }: + +let + + strict = derivationStrict drvAttrs; + + commonAttrs = drvAttrs // (builtins.listToAttrs outputsList) // + { all = map (x: x.value) outputsList; + inherit drvAttrs; + }; + + outputToAttrListElement = outputName: + { name = outputName; + value = commonAttrs // { + outPath = builtins.getAttr outputName strict; + drvPath = strict.drvPath; + type = "derivation"; + inherit outputName; + }; + }; + + outputsList = map outputToAttrListElement outputs; + +in (builtins.head outputsList).value diff --git a/corepkgs/fetchurl.nix b/corepkgs/fetchurl.nix new file mode 100644 index 000000000000..39b9dd5082e3 --- /dev/null +++ b/corepkgs/fetchurl.nix @@ -0,0 +1,37 @@ +with import <nix/config.nix>; + +{system ? builtins.currentSystem, url, outputHash ? "", outputHashAlgo ? "", md5 ? "", sha1 ? "", sha256 ? "", executable ? false}: + +assert (outputHash != "" && outputHashAlgo != "") + || md5 != "" || sha1 != "" || sha256 != ""; + +let + + builder = builtins.toFile "fetchurl.sh" + ('' + echo "downloading $url into $out" + ${curl} --fail --location --max-redirs 20 --insecure "$url" > "$out" + '' + (if executable then "${coreutils}/chmod +x $out" else "")); + +in + +derivation { + name = baseNameOf (toString url); + builder = shell; + args = [ "-e" builder ]; + + # New-style output content requirements. + outputHashAlgo = if outputHashAlgo != "" then outputHashAlgo else + if sha256 != "" then "sha256" else if sha1 != "" then "sha1" else "md5"; + outputHash = if outputHash != "" then outputHash else + if sha256 != "" then sha256 else if sha1 != "" then sha1 else md5; + outputHashMode = if executable then "recursive" else "flat"; + + inherit system url; + + # No need to double the amount of network traffic + preferLocalBuild = true; + + # Don't build in a chroot because Nix's dependencies may not be there. + __noChroot = true; +} diff --git a/corepkgs/imported-drv-to-derivation.nix b/corepkgs/imported-drv-to-derivation.nix new file mode 100644 index 000000000000..bdb60169860a --- /dev/null +++ b/corepkgs/imported-drv-to-derivation.nix @@ -0,0 +1,21 @@ +attrs @ { drvPath, outputs, ... }: + +let + + commonAttrs = (builtins.listToAttrs outputsList) // + { all = map (x: x.value) outputsList; + inherit drvPath; + type = "derivation"; + }; + + outputToAttrListElement = outputName: + { name = outputName; + value = commonAttrs // { + outPath = builtins.getAttr outputName attrs; + inherit outputName; + }; + }; + + outputsList = map outputToAttrListElement outputs; + +in (builtins.head outputsList).value diff --git a/corepkgs/local.mk b/corepkgs/local.mk new file mode 100644 index 000000000000..19c1d06962c0 --- /dev/null +++ b/corepkgs/local.mk @@ -0,0 +1,5 @@ +corepkgs_FILES = nar.nix buildenv.nix buildenv.pl unpack-channel.nix derivation.nix fetchurl.nix imported-drv-to-derivation.nix + +$(foreach file,config.nix $(corepkgs_FILES),$(eval $(call install-data-in,$(d)/$(file),$(datadir)/nix/corepkgs))) + +template-files += $(d)/config.nix diff --git a/corepkgs/nar.nix b/corepkgs/nar.nix new file mode 100644 index 000000000000..04be17fb0ce2 --- /dev/null +++ b/corepkgs/nar.nix @@ -0,0 +1,49 @@ +with import <nix/config.nix>; + +let + + builder = builtins.toFile "nar.sh" + '' + export PATH=${nixBinDir}:${coreutils} + + if [ $compressionType = xz ]; then + ext=.xz + compressor="| ${xz} -7" + elif [ $compressionType = bzip2 ]; then + ext=.bz2 + compressor="| ${bzip2}" + else + ext= + compressor= + fi + + echo "packing ‘$storePath’..." + mkdir $out + dst=$out/tmp.nar$ext + + set -o pipefail + eval "nix-store --dump \"$storePath\" $compressor > $dst" + + hash=$(nix-hash --flat --type $hashAlgo --base32 $dst) + echo -n $hash > $out/nar-compressed-hash + + mv $dst $out/$hash.nar$ext + ''; + +in + +{ storePath, hashAlgo, compressionType }: + +derivation { + name = "nar"; + system = builtins.currentSystem; + builder = shell; + args = [ "-e" builder ]; + inherit storePath hashAlgo compressionType; + + # Don't build in a chroot because Nix's dependencies may not be there. + __noChroot = true; + + # Remote machines may not have ${nixBinDir} or ${coreutils} in the same prefixes + preferLocalBuild = true; +} diff --git a/corepkgs/unpack-channel.nix b/corepkgs/unpack-channel.nix new file mode 100644 index 000000000000..f7c521035428 --- /dev/null +++ b/corepkgs/unpack-channel.nix @@ -0,0 +1,42 @@ +with import <nix/config.nix>; + +let + + builder = builtins.toFile "unpack-channel.sh" + '' + mkdir $out + cd $out + xzpat="\.xz\$" + gzpat="\.gz\$" + if [[ "$src" =~ $xzpat ]]; then + ${xz} -d < $src | ${tar} xf - ${tarFlags} + elif [[ "$src" =~ $gzpat ]]; then + ${gzip} -d < $src | ${tar} xf - ${tarFlags} + else + ${bzip2} -d < $src | ${tar} xf - ${tarFlags} + fi + mv * $out/$channelName + if [ -n "$binaryCacheURL" ]; then + mkdir $out/binary-caches + echo -n "$binaryCacheURL" > $out/binary-caches/$channelName + fi + ''; + +in + +{ name, channelName, src, binaryCacheURL ? "" }: + +derivation { + system = builtins.currentSystem; + builder = shell; + args = [ "-e" builder ]; + inherit name channelName src binaryCacheURL; + + PATH = "${nixBinDir}:${coreutils}"; + + # No point in doing this remotely. + preferLocalBuild = true; + + # Don't build in a chroot because Nix's dependencies may not be there. + __noChroot = true; +} |