summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nixos/modules/system/boot/modprobe.nix1
-rwxr-xr-xpkgs/build-support/buildenv/builder.pl70
-rw-r--r--pkgs/build-support/buildenv/default.nix10
-rw-r--r--pkgs/os-specific/linux/firmware/firmware-linux-nonfree/default.nix1
-rw-r--r--pkgs/os-specific/linux/nvidia-x11/default.nix1
-rw-r--r--pkgs/os-specific/linux/util-linux/default.nix1
-rw-r--r--pkgs/tools/archivers/cpio/default.nix1
7 files changed, 53 insertions, 32 deletions
diff --git a/nixos/modules/system/boot/modprobe.nix b/nixos/modules/system/boot/modprobe.nix
index a3b616ff3eff..c49380899664 100644
--- a/nixos/modules/system/boot/modprobe.nix
+++ b/nixos/modules/system/boot/modprobe.nix
@@ -35,6 +35,7 @@ with lib;
             fi
 
           '';
+        meta.priority = 4;
       };
       description = ''
         Wrapper around modprobe that sets the path to the modules
diff --git a/pkgs/build-support/buildenv/builder.pl b/pkgs/build-support/buildenv/builder.pl
index 08331b178f4f..798fca6572ea 100755
--- a/pkgs/build-support/buildenv/builder.pl
+++ b/pkgs/build-support/buildenv/builder.pl
@@ -5,6 +5,7 @@ use Cwd 'abs_path';
 use IO::Handle;
 use File::Path;
 use File::Basename;
+use JSON::PP;
 
 STDOUT->autoflush(1);
 
@@ -17,7 +18,7 @@ sub isInPathsToLink {
     $path = "/" if $path eq "";
     foreach my $elem (@pathsToLink) {
         return 1 if
-            $elem eq "/" || 
+            $elem eq "/" ||
             (substr($path, 0, length($elem)) eq $elem
              && (($path eq $elem) || (substr($path, length($elem), 1) eq "/")));
     }
@@ -28,25 +29,27 @@ sub isInPathsToLink {
 # For each activated package, determine what symlinks to create.
 
 my %symlinks;
-$symlinks{""} = ""; # create root directory
+$symlinks{""} = ["", 0]; # create root directory
+
+my %priorities;
 
 sub findFiles;
 
 sub findFilesInDir {
-    my ($relName, $target, $ignoreCollisions) = @_;
+    my ($relName, $target, $ignoreCollisions, $priority) = @_;
 
     opendir DIR, "$target" or die "cannot open `$target': $!";
     my @names = readdir DIR or die;
     closedir DIR;
-    
+
     foreach my $name (@names) {
         next if $name eq "." || $name eq "..";
-        findFiles("$relName/$name", "$target/$name", $name, $ignoreCollisions);
+        findFiles("$relName/$name", "$target/$name", $name, $ignoreCollisions, $priority);
     }
 }
-    
+
 sub findFiles {
-    my ($relName, $target, $baseName, $ignoreCollisions) = @_;
+    my ($relName, $target, $baseName, $ignoreCollisions, $priority) = @_;
 
     # Urgh, hacky...
     return if
@@ -57,41 +60,48 @@ sub findFiles {
         $baseName eq "perllocal.pod" ||
         $baseName eq "log";
 
-    my $oldTarget = $symlinks{$relName};
+    my ($oldTarget, $oldPriority) = @{$symlinks{$relName} // [undef, undef]};
 
-    if (!defined $oldTarget) {
-        $symlinks{$relName} = $target;
+    # If target doesn't exist, create it. If it already exists as a
+    # symlink to a file (not a directory) in a lower-priority package,
+    # overwrite it.
+    if (!defined $oldTarget || ($priority < $oldPriority && ($oldTarget ne "" && ! -d $oldTarget))) {
+        $symlinks{$relName} = [$target, $priority];
+        return;
+    }
+
+    # If target already exists as a symlink to a file (not a
+    # directory) in a higher-priority package, skip.
+    if (defined $oldTarget && $priority > $oldPriority && $oldTarget ne "" && ! -d $oldTarget) {
         return;
     }
 
     unless (-d $target && ($oldTarget eq "" || -d $oldTarget)) {
         if ($ignoreCollisions) {
-            warn "collision between `$target' and `$oldTarget'" if $ignoreCollisions == 1;
+            warn "collision between `$target' and `$oldTarget'\n" if $ignoreCollisions == 1;
             return;
         } else {
-            die "collision between `$target' and `$oldTarget'";
+            die "collision between `$target' and `$oldTarget'\n";
         }
     }
 
-    findFilesInDir($relName, $oldTarget, $ignoreCollisions) unless $oldTarget eq "";
-    findFilesInDir($relName, $target, $ignoreCollisions);
-    
-    $symlinks{$relName} = ""; # denotes directory
+    findFilesInDir($relName, $oldTarget, $ignoreCollisions, $oldPriority) unless $oldTarget eq "";
+    findFilesInDir($relName, $target, $ignoreCollisions, $priority);
+
+    $symlinks{$relName} = ["", $priority]; # denotes directory
 }
 
 
 my %done;
 my %postponed;
 
-sub addPkg;
-sub addPkg($;$) {
-    my $pkgDir = shift;
-    my $ignoreCollisions = shift;
+sub addPkg {
+    my ($pkgDir, $ignoreCollisions, $priority)  = @_;
 
     return if (defined $done{$pkgDir});
     $done{$pkgDir} = 1;
 
-    findFiles("", "$pkgDir", "", $ignoreCollisions);
+    findFiles("", $pkgDir, "", $ignoreCollisions, $priority);
 
     my $propagatedFN = "$pkgDir/nix-support/propagated-user-env-packages";
     if (-e $propagatedFN) {
@@ -106,23 +116,25 @@ sub addPkg($;$) {
 }
 
 
-# Symlink to the packages that have been installed explicitly by the user.
-my @args = split ' ', $ENV{"paths"};
-
-foreach my $pkgDir (@args) {
-    addPkg($pkgDir, $ENV{"ignoreCollisions"} eq "1") if -e $pkgDir;
+# Symlink to the packages that have been installed explicitly by the
+# user.
+for my $pkg (@{decode_json $ENV{"pkgs"}}) {
+    for my $path (@{$pkg->{paths}}) {
+        addPkg($path, $ENV{"ignoreCollisions"} eq "1", $pkg->{priority}) if -e $path;
+    }
 }
 
 
 # Symlink to the packages that have been "propagated" by packages
-# installed by the user (i.e., package X declares that it want Y
+# installed by the user (i.e., package X declares that it wants 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, 2);
+        addPkg($pkgDir, 2, $priorityCounter++);
     }
 }
 
@@ -130,7 +142,7 @@ while (scalar(keys %postponed) > 0) {
 # Create the symlinks.
 my $nrLinks = 0;
 foreach my $relName (sort keys %symlinks) {
-    my $target = $symlinks{$relName};
+    my ($target, $priority) = @{$symlinks{$relName}};
     my $abs = "$out/$relName";
     next unless isInPathsToLink $relName;
     if ($target eq "") {
diff --git a/pkgs/build-support/buildenv/default.nix b/pkgs/build-support/buildenv/default.nix
index 293291dc1dad..2ae8123faca4 100644
--- a/pkgs/build-support/buildenv/default.nix
+++ b/pkgs/build-support/buildenv/default.nix
@@ -9,10 +9,10 @@
 , # The manifest file (if any).  A symlink $out/manifest will be
   # created to it.
   manifest ? ""
-  
+
 , # The paths to symlink.
   paths
-  
+
 , # Whether to ignore collisions or abort.
   ignoreCollisions ? false
 
@@ -28,7 +28,11 @@
 }:
 
 runCommand name
-  { inherit manifest paths ignoreCollisions passthru pathsToLink postBuild;
+  { inherit manifest ignoreCollisions passthru pathsToLink postBuild;
+    pkgs = builtins.toJSON (map (drv: {
+      paths = [ drv ]; # FIXME: handle multiple outputs
+      priority = drv.meta.priority or 5;
+    }) paths);
     preferLocalBuild = true;
   }
   ''
diff --git a/pkgs/os-specific/linux/firmware/firmware-linux-nonfree/default.nix b/pkgs/os-specific/linux/firmware/firmware-linux-nonfree/default.nix
index 259c5acdf873..a995b193a845 100644
--- a/pkgs/os-specific/linux/firmware/firmware-linux-nonfree/default.nix
+++ b/pkgs/os-specific/linux/firmware/firmware-linux-nonfree/default.nix
@@ -30,6 +30,7 @@ stdenv.mkDerivation rec {
     license = licenses.unfreeRedistributableFirmware;
     platforms = platforms.linux;
     maintainers = with maintainers; [ wkennington ];
+    priority = 6; # give precedence to kernel firmware
   };
 
   passthru = { inherit version; };
diff --git a/pkgs/os-specific/linux/nvidia-x11/default.nix b/pkgs/os-specific/linux/nvidia-x11/default.nix
index ab564c10e2e5..cbd9a19777e5 100644
--- a/pkgs/os-specific/linux/nvidia-x11/default.nix
+++ b/pkgs/os-specific/linux/nvidia-x11/default.nix
@@ -63,5 +63,6 @@ stdenv.mkDerivation {
     license = licenses.unfreeRedistributable;
     platforms = platforms.linux;
     maintainers = [ maintainers.vcunat ];
+    priority = 4; # resolves collision with xorg-server's "lib/xorg/modules/extensions/libglx.so"
   };
 }
diff --git a/pkgs/os-specific/linux/util-linux/default.nix b/pkgs/os-specific/linux/util-linux/default.nix
index 7f2aeca255c8..7768875ca57f 100644
--- a/pkgs/os-specific/linux/util-linux/default.nix
+++ b/pkgs/os-specific/linux/util-linux/default.nix
@@ -53,5 +53,6 @@ stdenv.mkDerivation rec {
     homepage = http://www.kernel.org/pub/linux/utils/util-linux/;
     description = "A set of system utilities for Linux";
     platforms = stdenv.lib.platforms.linux;
+    priority = 6; # lower priority than coreutils ("kill") and shadow ("login" etc.) packages
   };
 }
diff --git a/pkgs/tools/archivers/cpio/default.nix b/pkgs/tools/archivers/cpio/default.nix
index 2cd65391216d..f2207b588499 100644
--- a/pkgs/tools/archivers/cpio/default.nix
+++ b/pkgs/tools/archivers/cpio/default.nix
@@ -35,5 +35,6 @@ stdenv.mkDerivation {
     homepage = http://www.gnu.org/software/cpio/;
     description = "A program to create or extract from cpio archives";
     platforms = stdenv.lib.platforms.all;
+    priority = 6; # resolves collision with gnutar's "libexec/rmt"
   };
 }