Skip to content

Commit

Permalink
* First figure out what symlinks need to be created, then create
Browse files Browse the repository at this point in the history
  them.  This prevents unnecessary unlink operations to resolve
  collisions between directories.

svn path=/nixpkgs/trunk/; revision=22526
  • Loading branch information
edolstra committed Jul 8, 2010
1 parent eb2cb9a commit a6fcf45
Showing 1 changed file with 67 additions and 91 deletions.
158 changes: 67 additions & 91 deletions pkgs/build-support/buildenv/builder.pl
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
STDOUT->autoflush(1);

my $out = $ENV{"out"};
mkdir "$out", 0755 || die "error creating $out";


my $symlinks = 0;


my @pathsToLink = split ' ', $ENV{"pathsToLink"};
Expand All @@ -27,95 +23,58 @@ sub isInPathsToLink {
}


sub symLinkMkdir {
my $src = shift;
my $dst = shift;
my $dir = dirname $dst;
mkpath $dir;
symlink($src, $dst) ||
die "error creating link `$dst': $!";
$symlinks++;
}
# For each activated package, determine what symlinks to create.

my %symlinks;
$symlinks{""} = ""; # create root directory

# For each activated package, create symlinks.
sub findFiles;

sub createLinks {
my $relName = shift;
my $srcDir = shift;
my $dstDir = shift;
my $ignoreCollisions = shift;
sub findFilesInDir {
my ($relName, $target, $ignoreCollisions) = @_;

my @srcFiles = glob("$srcDir/*");

foreach my $srcFile (@srcFiles) {
my $baseName = $srcFile;
$baseName =~ s/^.*\///g; # strip directory
my $dstFile = "$dstDir/$baseName";
my $relName2 = "$relName/$baseName";

# Urgh, hacky...
if ($srcFile =~ /\/propagated-build-inputs$/ ||
$srcFile =~ /\/nix-support$/ ||
$srcFile =~ /\/perllocal.pod$/ ||
$srcFile =~ /\/info\/dir$/ ||
( $relName2 =~ /^\/share\/mime\// && !( $relName2 =~ /^\/share\/mime\/packages/ ) ) ||
$srcFile =~ /\/log$/)
{
# Do nothing.
}

elsif (-d $srcFile) {

if (!isInPathsToLink($relName2)) {
# This path is not in the list of paths to link, but
# some of its children may be.
createLinks($relName2, $srcFile, $dstFile, $ignoreCollisions);
next;
}

lstat $dstFile;

if (-d _) {
createLinks($relName2, $srcFile, $dstFile, $ignoreCollisions);
}

elsif (-l _) {
my $target = readlink $dstFile or die;
if (!-d $target) {
die "collission between directory `$srcFile' and non-directory `$target'";
}
unlink $dstFile or die "error unlinking `$dstFile': $!";
mkpath $dstFile;
createLinks($relName2, $target, $dstFile, $ignoreCollisions);
createLinks($relName2, $srcFile, $dstFile, $ignoreCollisions);
}

else {
symLinkMkdir $srcFile, $dstFile;
}
}

elsif (-l $dstFile) {
my $oldTarget = readlink $dstFile;
my $oldTargetReal = abs_path $oldTarget;
my $newTarget = $srcFile;
my $newTargetReal = abs_path $newTarget;
unless ($newTargetReal eq $oldTargetReal) {
if ($ignoreCollisions) {
warn "collision between `$newTarget' and `$oldTarget'\n";
}
else {
die "collision between `$newTarget' and `$oldTarget'";
}
}
}
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);
}
}

sub findFiles {
my ($relName, $target, $baseName, $ignoreCollisions) = @_;

# Urgh, hacky...
return if
$relName eq "/propagated-build-inputs" ||
$relName eq "/nix-support" ||
$relName =~ /info\/dir/ ||
( $relName =~ /^\/share\/mime\// && !( $relName =~ /^\/share\/mime\/packages/ ) ) ||
$baseName eq "perllocal.pod" ||
$baseName eq "log";

my $oldTarget = $symlinks{$relName};

if (!defined $oldTarget) {
$symlinks{$relName} = $target;
return;
}

else {
next unless isInPathsToLink($relName2);
symLinkMkdir $srcFile, $dstFile;
unless (-d $target && ($oldTarget eq "" || -d $oldTarget)) {
if ($ignoreCollisions) {
warn "collision between `$target' and `$oldTarget'";
return;
} else {
die "collision between `$target' and `$oldTarget'";
}
}

findFilesInDir($relName, $oldTarget, $ignoreCollisions) unless $oldTarget eq "";
findFilesInDir($relName, $target, $ignoreCollisions);

$symlinks{$relName} = ""; # denotes directory
}


Expand All @@ -130,8 +89,7 @@ ($;$)
return if (defined $done{$pkgDir});
$done{$pkgDir} = 1;

# print "symlinking $pkgDir\n";
createLinks("", "$pkgDir", "$out", $ignoreCollisions);
findFiles("", "$pkgDir", "", $ignoreCollisions);

my $propagatedFN = "$pkgDir/nix-support/propagated-user-env-packages";
if (-e $propagatedFN) {
Expand All @@ -140,7 +98,6 @@ ($;$)
close PROP;
my @propagated = split ' ', $propagated;
foreach my $p (@propagated) {
print "$pkgDir propagates $p\n";
$postponed{$p} = 1 unless defined $done{$p};
}
}
Expand All @@ -167,17 +124,36 @@ ($;$)
}
}


# Create the symlinks.
my $nrLinks = 0;
foreach my $relName (sort keys %symlinks) {
my $target = $symlinks{$relName};
my $abs = "$out/$relName";
next unless isInPathsToLink $relName;
if ($target eq "") {
#print "creating directory $relName\n";
mkpath $abs or die "cannot create directory `$abs': $!";
} else {
#print "creating symlink $relName to $target\n";
symlink $target, $abs ||
die "error creating link `$abs': $!";
$nrLinks++;
}
}


if (-x "$out/bin/update-mime-database" && -d "$out/share/mime/packages") {
system("$out/bin/update-mime-database -V $out/share/mime") == 0
or die "Can't update mime-database";
}


print STDERR "created $symlinks symlinks in user environment\n";
print STDERR "created $nrLinks symlinks in user environment\n";


my $manifest = $ENV{"manifest"};
if ($manifest ne "") {
if ($manifest) {
symlink($manifest, "$out/manifest") or die "cannot create manifest";
}

Expand Down

1 comment on commit a6fcf45

@nixos-discourse
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/cant-call-a-program-log/49868/12

Please sign in to comment.