#! @perl@ -w use strict; use Cwd; use IO::Handle; use Fcntl; STDOUT->autoflush(1); my $out = $ENV{"out"}; mkdir "$out", 0755 || die "error creating $out"; sub readlink_or_StateWrapper; my $symlinks = 0; my %path_state_identifier; my %path_runtimeArgs; my $nixBinDir = $ENV{"nixBinDir"}; my $nixStore = $ENV{"nixStore"}; # For each activated package, create symlinks. sub createLinks { my $srcDir = shift; #Lookup each $stateIdentifiers in $path_state_identifier #we strip $srcDir to its rootdir e.g. /nix/store/......./ my @srcDirParts = split /\// , substr($srcDir, length ($nixStore), length ($srcDir)); my $srcDirRoot = $nixStore . "/" . $srcDirParts[1]; # print "srcDirRoot $srcDirRoot \n"; my $pkgStateIdentifier = $path_state_identifier{$srcDirRoot}; my $pkgRuntimeStateArgs = $path_runtimeArgs{$srcDirRoot}; my $dstDir = shift; my $ignoreCollisions = shift; # print "createLinks $srcDir to $dstDir with iden $pkgStateIdentifier \n"; my @srcFiles = glob("$srcDir/*"); foreach my $srcFile (@srcFiles) { my $baseName = $srcFile; $baseName =~ s/^.*\///g; # strip directory my $dstFile = "$dstDir/$baseName"; # 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; #go recursive on directorys if (-d _) { createLinks($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': $!"; mkdir $dstFile, 0755 || die "error creating directory `$dstFile': $!"; createLinks($target, $dstFile, $ignoreCollisions); createLinks($srcFile, $dstFile, $ignoreCollisions); } else { # print "1STLINK $srcFile to $dstFile with iden $pkgStateIdentifier \n"; symlink($srcFile, $dstFile) || die "error creating link `$dstFile': $!"; $symlinks++; } } else { # print "ELSE LINK $srcFile to $dstFile with iden $pkgStateIdentifier \n"; # if we have ..... if($pkgStateIdentifier ne "__NOSTATE__" && $pkgStateIdentifier ne ""){ my @pathparts = split /\// , $srcFile; my $parentDir = $pathparts[scalar(@pathparts) - 2]; if( $parentDir eq "bin" || $parentDir eq "sbin"){ #hacky.... print "STATELINK $srcFile to $dstFile - $pkgStateIdentifier \n"; my $new_dstFile; my $new_stateIdentifier; if($pkgStateIdentifier eq "__EMTPY__"){ $new_dstFile = $dstFile; $new_stateIdentifier = ""; } else{ $new_dstFile = "$dstFile-$pkgStateIdentifier"; $new_stateIdentifier = $pkgStateIdentifier; } # We also check with -e if the wrapperscript-file exists, and if is it a symlink (with -l) if (-l $new_dstFile || -e $new_dstFile) { if (!$ignoreCollisions) { my $target = readlink_or_StateWrapper $new_dstFile; die "(state) collission between `$srcFile' and `$target' (over $new_dstFile)"; } } sysopen (DSTFILEHANDLE, $new_dstFile, O_RDWR|O_EXCL|O_CREAT, 0755); printf DSTFILEHANDLE "#! @shell@ \n"; if($pkgRuntimeStateArgs eq "__NOARGS__"){ printf DSTFILEHANDLE "$nixBinDir/nix-state --run --identifier=$new_stateIdentifier $srcFile \"\$@\" \n"; } else{ printf DSTFILEHANDLE "$nixBinDir/nix-state --run --identifier=$new_stateIdentifier $srcFile \"\$@\" $pkgRuntimeStateArgs \n"; } # TODO, maybe first R.T.A. then other args ? close (DSTFILEHANDLE); } } else{ if (-l $dstFile || -e $dstFile) { if (!$ignoreCollisions) { my $target = readlink_or_StateWrapper $dstFile; die "collission between `$srcFile' and `$target'"; } } symlink($srcFile, $dstFile) || die "error creating link `$dstFile': $!"; $symlinks++; } } } } 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}; } } } sub readlink_or_StateWrapper { my $src = shift; my $target; if (-l $src) { $target = readlink $src; } else{ open(DAT, $src) || die("Could not open file!"); my @raw_data=; close(DAT); $target = $raw_data[1]; } return $target } # Symlink to the packages that have been installed explicitly by the user. my @storePaths = split ' ', $ENV{"derivations"}; my @stateIdentifiers = split ' ', $ENV{"stateIdentifiers"}; my @runtimeStateArgs = split ' ', $ENV{"runtimeStateArgs_arg"}; my $si_counter = 0; foreach my $pkgDir (@storePaths) { #Commented the sort out #Link each $pkgDir to a $stateIdentifiers in $path_state_identifier $path_state_identifier{$pkgDir} = $stateIdentifiers[$si_counter]; $path_runtimeArgs{$pkgDir} = $runtimeStateArgs[$si_counter]; # print "SP: $pkgDir \n"; # print "SI: $path_state_identifier{$pkgDir} \n"; # print "RT: $path_runtimeArgs{$pkgDir} \n"; addPkg($pkgDir, 0); $si_counter++; } # 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"; symlink($ENV{"manifest"}, "$out/manifest") or die "cannot create manifest";