buildEnv: Check the content of colliding paths.

Originally wanted to include ignoreCollisions in cups-progs, but I think
it's better if we use ignoreCollisions only if there are _real_
collisions between files with different contents.

Of course, we also check whether the file permissions match, so you get
a collision if contents are the same but the permissions are different.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
This commit is contained in:
aszlig 2014-11-23 20:42:14 +01:00
parent 85dd89f6eb
commit 4529ed1259
No known key found for this signature in database
GPG key ID: D0EBD0EC8C2DC961
2 changed files with 39 additions and 10 deletions

View file

@ -5,6 +5,7 @@ use Cwd 'abs_path';
use IO::Handle;
use File::Path;
use File::Basename;
use File::Compare;
use JSON::PP;
STDOUT->autoflush(1);
@ -38,7 +39,7 @@ for my $p (@pathsToLink) {
sub findFiles;
sub findFilesInDir {
my ($relName, $target, $ignoreCollisions, $priority) = @_;
my ($relName, $target, $ignoreCollisions, $checkCollisionContents, $priority) = @_;
opendir DIR, "$target" or die "cannot open `$target': $!";
my @names = readdir DIR or die;
@ -46,12 +47,28 @@ sub findFilesInDir {
foreach my $name (@names) {
next if $name eq "." || $name eq "..";
findFiles("$relName/$name", "$target/$name", $name, $ignoreCollisions, $priority);
findFiles("$relName/$name", "$target/$name", $name, $ignoreCollisions, $checkCollisionContents, $priority);
}
}
sub checkCollision {
my ($path1, $path2) = @_;
my $stat1 = (stat($path1))[2];
my $stat2 = (stat($path2))[2];
if ($stat1 != $stat2) {
warn "different permissions in `$path1' and `$path2': "
. sprintf("%04o", $stat1 & 07777) . " <-> "
. sprintf("%04o", $stat2 & 07777);
return 0;
}
return compare($path1, $path2) == 0;
}
sub findFiles {
my ($relName, $target, $baseName, $ignoreCollisions, $priority) = @_;
my ($relName, $target, $baseName, $ignoreCollisions, $checkCollisionContents, $priority) = @_;
# Urgh, hacky...
return if
@ -79,7 +96,9 @@ sub findFiles {
}
unless (-d $target && ($oldTarget eq "" || -d $oldTarget)) {
if ($ignoreCollisions) {
if ($checkCollisionContents && checkCollision($oldTarget, $target)) {
return;
} elsif ($ignoreCollisions) {
warn "collision between `$target' and `$oldTarget'\n" if $ignoreCollisions == 1;
return;
} else {
@ -87,8 +106,8 @@ sub findFiles {
}
}
findFilesInDir($relName, $oldTarget, $ignoreCollisions, $oldPriority) unless $oldTarget eq "";
findFilesInDir($relName, $target, $ignoreCollisions, $priority);
findFilesInDir($relName, $oldTarget, $ignoreCollisions, $checkCollisionContents, $oldPriority) unless $oldTarget eq "";
findFilesInDir($relName, $target, $ignoreCollisions, $checkCollisionContents, $priority);
$symlinks{$relName} = ["", $priority]; # denotes directory
}
@ -98,12 +117,12 @@ my %done;
my %postponed;
sub addPkg {
my ($pkgDir, $ignoreCollisions, $priority) = @_;
my ($pkgDir, $ignoreCollisions, $checkCollisionContents, $priority) = @_;
return if (defined $done{$pkgDir});
$done{$pkgDir} = 1;
findFiles("", $pkgDir, "", $ignoreCollisions, $priority);
findFiles("", $pkgDir, "", $ignoreCollisions, $checkCollisionContents, $priority);
my $propagatedFN = "$pkgDir/nix-support/propagated-user-env-packages";
if (-e $propagatedFN) {
@ -132,7 +151,11 @@ if (exists $ENV{"pkgsPath"}) {
# user.
for my $pkg (@{decode_json $pkgs}) {
for my $path (@{$pkg->{paths}}) {
addPkg($path, $ENV{"ignoreCollisions"} eq "1", $pkg->{priority}) if -e $path;
addPkg($path,
$ENV{"ignoreCollisions"} eq "1",
$ENV{"checkCollisionContents"} eq "1",
$pkg->{priority})
if -e $path;
}
}

View file

@ -16,6 +16,10 @@
, # Whether to ignore collisions or abort.
ignoreCollisions ? false
, # If there is a collision, check whether the contents and permissions match
# and only if not, throw a collision error.
checkCollisionContents ? true
, # The paths (relative to each element of `paths') that we want to
# symlink (e.g., ["/bin"]). Any file not inside any of the
# directories in the list is not symlinked.
@ -39,7 +43,9 @@
}:
runCommand name
rec { inherit manifest ignoreCollisions passthru meta pathsToLink extraPrefix postBuild buildInputs;
rec {
inherit manifest ignoreCollisions checkCollisionContents passthru
meta pathsToLink extraPrefix postBuild buildInputs;
pkgs = builtins.toJSON (map (drv: {
paths =
[ drv ]