From 153d4e65a1c4ed37877c4db982727d89df15ea82 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 28 Nov 2006 16:46:12 +0000 Subject: * Fork of build-env in the Nix distribution. This one supports ignoring collisions and selectively including directories. svn path=/nixpkgs/trunk/; revision=7160 --- pkgs/build-support/buildenv/builder.pl | 167 ++++++++++++++++++++++++++++++++ pkgs/build-support/buildenv/default.nix | 29 ++++++ pkgs/top-level/all-packages.nix | 4 + 3 files changed, 200 insertions(+) create mode 100755 pkgs/build-support/buildenv/builder.pl create mode 100644 pkgs/build-support/buildenv/default.nix (limited to 'pkgs') diff --git a/pkgs/build-support/buildenv/builder.pl b/pkgs/build-support/buildenv/builder.pl new file mode 100755 index 000000000000..5515f55d6e46 --- /dev/null +++ b/pkgs/build-support/buildenv/builder.pl @@ -0,0 +1,167 @@ +#! @perl@ -w + +use strict; +use Cwd; +use IO::Handle; +use File::Path; +use File::Basename; + +STDOUT->autoflush(1); + +my $out = $ENV{"out"}; +mkdir "$out", 0755 || die "error creating $out"; + + +my $symlinks = 0; + + +my @pathsToLink = split ' ', $ENV{"pathsToLink"}; + +sub isInPathsToLink { + my $path = shift; + $path = "/" if $path eq ""; + foreach my $elem (@pathsToLink) { + return 1 if substr($path, 0, length($elem)) eq $elem; + } + return 0; +} + + +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, create symlinks. + +sub createLinks { + my $relName = shift; + my $srcDir = shift; + my $dstDir = shift; + my $ignoreCollisions = shift; + + 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$/ || + $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) { + if (!$ignoreCollisions) { + my $target = readlink $dstFile; + die "collission between `$srcFile' and `$target'"; + } + } + + else { + next unless isInPathsToLink($relName2); + symLinkMkdir $srcFile, $dstFile; + } + } +} + + +my %done; +my %postponed; + +sub addPkg; +sub addPkg { + my $pkgDir = shift; + my $ignoreCollisions = shift; + + return if (defined $done{$pkgDir}); + $done{$pkgDir} = 1; + +# print "symlinking $pkgDir\n"; + createLinks("", "$pkgDir", "$out", $ignoreCollisions); + + my $propagatedFN = "$pkgDir/nix-support/propagated-user-env-packages"; + if (-e $propagatedFN) { + open PROP, "<$propagatedFN" or die; + my $propagated = ; + close PROP; + my @propagated = split ' ', $propagated; + foreach my $p (@propagated) { + $postponed{$p} = 1 unless defined $done{$p}; + } + } +} + + +# Symlink to the packages that have been installed explicitly by the user. +my @args = split ' ', $ENV{"paths"}; + +foreach my $pkgDir (sort @args) { + addPkg($pkgDir, $ENV{"ignoreCollisions"} eq "1"); +} + + +# 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. +while (scalar(keys %postponed) > 0) { + my @pkgDirs = keys %postponed; + %postponed = (); + foreach my $pkgDir (sort @pkgDirs) { + addPkg($pkgDir, 1); + } +} + + +print STDERR "created $symlinks symlinks in user environment\n"; + + +my $manifest = $ENV{"manifest"}; +if ($manifest ne "") { + symlink($manifest, "$out/manifest") or die "cannot create manifest"; +} diff --git a/pkgs/build-support/buildenv/default.nix b/pkgs/build-support/buildenv/default.nix new file mode 100644 index 000000000000..9f150d8bda20 --- /dev/null +++ b/pkgs/build-support/buildenv/default.nix @@ -0,0 +1,29 @@ +# buildEnv creates a tree of symlinks to the specified paths. This is +# a fork of the buildEnv in the Nix distribution. Most changes should +# eventually be merged back into the Nix distribution. + +{stdenv, perl}: + +{ name + +, # 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 + +, # 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. + pathsToLink ? ["/"] +}: + +stdenv.mkDerivation { + inherit name manifest paths ignoreCollisions pathsToLink; + realBuilder = perl + "/bin/perl"; + args = ["-w" ./builder.pl]; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 8bf29d427ee5..da0261eb3eb5 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -164,6 +164,10 @@ rec { ### BUILD SUPPORT + buildEnv = import ../build-support/buildenv { + inherit stdenv perl; + }; + fetchcvs = import ../build-support/fetchcvs { inherit stdenv cvs nix; }; -- cgit 1.4.1