about summary refs log tree commit diff
path: root/corepkgs
diff options
context:
space:
mode:
Diffstat (limited to 'corepkgs')
-rw-r--r--corepkgs/buildenv.nix28
-rw-r--r--corepkgs/buildenv.pl168
-rw-r--r--corepkgs/config.nix.in17
-rw-r--r--corepkgs/derivation.nix27
-rw-r--r--corepkgs/fetchurl.nix37
-rw-r--r--corepkgs/imported-drv-to-derivation.nix21
-rw-r--r--corepkgs/local.mk5
-rw-r--r--corepkgs/nar.nix49
-rw-r--r--corepkgs/unpack-channel.nix42
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;
+}