#! @perl@ -w

use strict;
use Cwd;
use IO::Handle;

STDOUT->autoflush(1);

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


my $symlinks = 0;


# For each activated package, create symlinks.

sub createLinks {
    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";

        # 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;
            
            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 {
                symlink($srcFile, $dstFile) ||
                    die "error creating link `$dstFile': $!";
                $symlinks++;
            }
        }

        elsif (-l $dstFile) {
            if (!$ignoreCollisions) {
                my $target = readlink $dstFile;
                die "collission between `$srcFile' and `$target'";
            }
        }

        else {
            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 = <PROP>;
        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{"derivations"};

foreach my $pkgDir (sort @args) {
    addPkg($pkgDir, 0);
}


# 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";