summary refs log tree commit diff
path: root/scripts/nix-copy-closure.in
blob: 23d5619519a4c09b3b1327409e2836d779b88b93 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#! @perl@ -w @perlFlags@

use Nix::SSH;
use Nix::Config;
use Nix::Store;
use Nix::CopyClosure;
use List::Util qw(sum);


if (scalar @ARGV < 1) {
    print STDERR <<EOF
Usage: nix-copy-closure [--from | --to] HOSTNAME [--sign] [--gzip] [--bzip2] [--xz] PATHS...
EOF
    ;
    exit 1;
}


# Get the target host.
my $sshHost;
my $sign = 0;
my $compressor = "";
my $decompressor = "";
my $progressViewer = "";
my $toMode = 1;
my $includeOutputs = 0;
my $dryRun = 0;
my $useSubstitutes = 0;


# !!! Copied from nix-pack-closure, should put this in a module.
my @storePaths = ();

while (@ARGV) {
    my $arg = shift @ARGV;

    if ($arg eq "--help") {
        exec "man nix-copy-closure" or die;
    }
    elsif ($arg eq "--sign") {
        $sign = 1;
    }
    elsif ($arg eq "--gzip") {
        $compressor = "gzip";
        $decompressor = "gunzip";
    }
    elsif ($arg eq "--bzip2") {
        $compressor = "bzip2";
        $decompressor = "bunzip2";
    }
    elsif ($arg eq "--xz") {
        $compressor = "xz";
        $decompressor = "xz -d";
    }
    elsif ($arg eq "--from") {
        $toMode = 0;
    }
    elsif ($arg eq "--to") {
        $toMode = 1;
    }
    elsif ($arg eq "--include-outputs") {
        $includeOutputs = 1;
    }
    elsif ($arg eq "--show-progress") {
        $progressViewer = "@pv@";
    }
    elsif ($arg eq "--dry-run") {
        $dryRun = 1;
    }
    elsif ($arg eq "--use-substitutes" || $arg eq "-s") {
        $useSubstitutes = 1;
    }
    elsif (!defined $sshHost) {
        $sshHost = $arg;
    }
    else {
        push @storePaths, $arg;
    }
}

die "$0: you did not specify a host name\n" unless defined $sshHost;


openSSHConnection $sshHost or die "$0: unable to start SSH\n";


if ($toMode) { # Copy TO the remote machine.
    Nix::CopyClosure::copyTo(
        $sshHost, [ @sshOpts ], [ @storePaths ], $compressor, $decompressor,
        $includeOutputs, $dryRun, $sign, $progressViewer, $useSubstitutes);
}

else { # Copy FROM the remote machine.

    # Query the closure of the given store paths on the remote
    # machine.  Paths are assumed to be store paths; there is no
    # resolution (following of symlinks).
    my $extraOpts = $includeOutputs ? "--include-outputs" : "";
    my $pid = open(READ,
        "set -f; ssh @sshOpts $sshHost nix-store --query --requisites $extraOpts @storePaths|") or die;

    while (<READ>) {
        chomp;
        die "bad: $_" unless /^\//;
        push @missing, $_ unless isValidPath($_);
    }

    close READ or die "nix-store on remote machine `$sshHost' failed: $?";

    my $missingSize = 0;
    if ($progressViewer ne "") {
        $missingSize = sum (split ' ', `set -f; ssh @sshOpts $sshHost nix-store -q --size @missing`) or die;
    }

    # Export the store paths on the remote machine and import them locally.
    if (scalar @missing > 0) {
        print STDERR "copying ", scalar @missing, " missing paths from ‘$sshHost’...\n";
        unless ($dryRun) {
            if ($useSubstitutes) {
                system "$Nix::Config::binDir/nix-store -r --ignore-unknown @missing";
            }
            $compressor = "| $compressor" if $compressor ne "";
            $decompressor = "$decompressor |" if $decompressor ne "";
            $progressViewer = "$progressViewer -s $missingSize |" if $progressViewer ne "";
            my $extraOpts = $sign ? "--sign" : "";
            system("set -f; ssh $sshHost @sshOpts 'nix-store --export $extraOpts @missing $compressor' | $decompressor $progressViewer $Nix::Config::binDir/nix-store --import > /dev/null") == 0
                or die "copying store paths from remote machine `$sshHost' failed: $?";
        }
    }

}