Advertisement
Guest User

Untitled

a guest
Jul 24th, 2017
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.85 KB | None | 0 0
  1. #! /nix/store/jxs0zbsbvajw2kbf6j1pqvpsf3cijqbm-perl-5.24.1/bin/perl -w -I/nix/store/0m3cha88h649i7zf3q7qm2ky87y10wkw-nix-1.11.13/lib/perl5/site_perl/5.24.1/darwin-2level -I/nix/store/yj53jd5kl0ipq3ba3kj2m8spl0d7wl7w-perl-DBI-1.636/lib/perl5/site_perl -I/nix/store/c09ysri8dvrckn8pzh11vhyv3ikyr3b9-perl-DBD-SQLite-1.50/lib/perl5/site_perl -I/nix/store/yikv6vgrfc9602wpgq19njk1dphrylil-perl-WWW-Curl-4.17/lib/perl5/site_perl
  2.  
  3. use utf8;
  4. use strict;
  5. use File::Basename;
  6. use File::Path qw(mkpath);
  7. use File::stat;
  8. use File::Copy;
  9. use MIME::Base64;
  10. use Nix::Config;
  11. use Nix::Store;
  12. use Nix::Manifest;
  13. use Nix::Utils;
  14.  
  15. binmode STDERR, ":encoding(utf8)";
  16.  
  17. my $tmpDir = mkTempDir("nix-push");
  18.  
  19. my $nixExpr = "$tmpDir/create-nars.nix";
  20.  
  21.  
  22. # Parse the command line.
  23. my $compressionType = "xz";
  24. my $force = 0;
  25. my $destDir;
  26. my $writeManifest = 0;
  27. my $manifestPath;
  28. my $archivesURL;
  29. my $link = 0;
  30. my $secretKeyFile;
  31. my @roots;
  32. my @buildArgs;
  33.  
  34. for (my $n = 0; $n < scalar @ARGV; $n++) {
  35. my $arg = $ARGV[$n];
  36.  
  37. if ($arg eq "--help") {
  38. exec "man nix-push" or die;
  39. } elsif ($arg eq "--bzip2") {
  40. $compressionType = "bzip2";
  41. } elsif ($arg eq "--none") {
  42. $compressionType = "none";
  43. } elsif ($arg eq "--force") {
  44. $force = 1;
  45. } elsif ($arg eq "--dest") {
  46. $n++;
  47. die "$0: ‘$arg’ requires an argument\n" unless $n < scalar @ARGV;
  48. $destDir = $ARGV[$n];
  49. mkpath($destDir, 0, 0755);
  50. } elsif ($arg eq "--manifest") {
  51. $writeManifest = 1;
  52. } elsif ($arg eq "--manifest-path") {
  53. $n++;
  54. die "$0: ‘$arg’ requires an argument\n" unless $n < scalar @ARGV;
  55. $manifestPath = $ARGV[$n];
  56. $writeManifest = 1;
  57. mkpath(dirname($manifestPath), 0, 0755);
  58. } elsif ($arg eq "--url-prefix") {
  59. $n++;
  60. die "$0: ‘$arg’ requires an argument\n" unless $n < scalar @ARGV;
  61. $archivesURL = $ARGV[$n];
  62. } elsif ($arg eq "--link") {
  63. $link = 1;
  64. } elsif ($arg eq "--key-file") {
  65. $n++;
  66. die "$0: ‘$arg’ requires an argument\n" unless $n < scalar @ARGV;
  67. $secretKeyFile = $ARGV[$n];
  68. } elsif ($arg eq "--max-jobs" || $arg eq "-j") {
  69. $n++;
  70. die "$0: ‘$arg’ requires an argument\n" unless $n < scalar @ARGV;
  71. push @buildArgs, ($arg, $ARGV[$n]);
  72. } elsif (substr($arg, 0, 1) eq "-") {
  73. die "$0: unknown flag ‘$arg’\n";
  74. } else {
  75. push @roots, $arg;
  76. }
  77. }
  78.  
  79. die "$0: please specify a destination directory\n" if !defined $destDir;
  80.  
  81. $archivesURL = "file://$destDir" unless defined $archivesURL;
  82.  
  83.  
  84. # From the given store paths, determine the set of requisite store
  85. # paths, i.e, the paths required to realise them.
  86. my %storePaths;
  87.  
  88. foreach my $path (@roots) {
  89. # Get all paths referenced by the normalisation of the given
  90. # Nix expression.
  91. my $pid = open(READ,
  92. "$Nix::Config::binDir/nix-store --query --references --force-realise " .
  93. "--include-outputs '$path'|") or die;
  94.  
  95. while (<READ>) {
  96. chomp;
  97. die "bad: $_" unless /^\//;
  98. $storePaths{$_} = "";
  99. }
  100.  
  101. close READ or die "nix-store failed: $?";
  102. }
  103.  
  104. my @storePaths = keys %storePaths;
  105.  
  106.  
  107. # Don't create archives for files that are already in the binary cache.
  108. my @storePaths2;
  109. my %narFiles;
  110. foreach my $storePath (@storePaths) {
  111. my $pathHash = substr(basename($storePath), 0, 32);
  112. my $narInfoFile = "$destDir/$pathHash.narinfo";
  113. if (!$force && -e $narInfoFile) {
  114. my $narInfo = parseNARInfo($storePath, readFile($narInfoFile), 0, $narInfoFile) or die "cannot read ‘$narInfoFile’\n";
  115. my $narFile = "$destDir/$narInfo->{url}";
  116. if (-e $narFile) {
  117. print STDERR "skipping existing $storePath\n";
  118. # Add the NAR info to $narFiles if we're writing a
  119. # manifest.
  120. $narFiles{$storePath} = [
  121. { url => ("$archivesURL/" . basename $narInfo->{url})
  122. , hash => $narInfo->{fileHash}
  123. , size => $narInfo->{fileSize}
  124. , compressionType => $narInfo->{compression}
  125. , narHash => $narInfo->{narHash}
  126. , narSize => $narInfo->{narSize}
  127. , references => join(" ", map { "$Nix::Config::storeDir/$_" } @{$narInfo->{refs}})
  128. , deriver => $narInfo->{deriver} ? "$Nix::Config::storeDir/$narInfo->{deriver}" : undef
  129. }
  130. ] if $writeManifest;
  131. next;
  132. }
  133. }
  134. push @storePaths2, $storePath;
  135. }
  136.  
  137.  
  138. # Create a list of Nix derivations that turn each path into a Nix
  139. # archive.
  140. open NIX, ">$nixExpr";
  141. print NIX "[";
  142.  
  143. foreach my $storePath (@storePaths2) {
  144. die unless ($storePath =~ /\/[0-9a-z]{32}[^\"\\\$]*$/);
  145.  
  146. # Construct a Nix expression that creates a Nix archive.
  147. my $nixexpr =
  148. "(import <nix/nar.nix> " .
  149. "{ storePath = builtins.storePath \"$storePath\"; hashAlgo = \"sha256\"; compressionType = \"$compressionType\"; }) ";
  150.  
  151. print NIX $nixexpr;
  152. }
  153.  
  154. print NIX "]";
  155. close NIX;
  156.  
  157.  
  158. # Build the Nix expression.
  159. print STDERR "building compressed archives...\n";
  160. my @narPaths;
  161. my $pid = open(READ, "-|", "$Nix::Config::binDir/nix-build", $nixExpr, "-o", "$tmpDir/result", @buildArgs)
  162. or die "cannot run nix-build";
  163. while (<READ>) {
  164. chomp;
  165. die unless /^\//;
  166. push @narPaths, $_;
  167. }
  168. close READ or die "nix-build failed: $?";
  169.  
  170.  
  171. # Write the cache info file.
  172. my $cacheInfoFile = "$destDir/nix-cache-info";
  173. if (! -e $cacheInfoFile) {
  174. open FILE, ">$cacheInfoFile" or die "cannot create $cacheInfoFile: $!";
  175. print FILE "StoreDir: $Nix::Config::storeDir\n";
  176. print FILE "WantMassQuery: 0\n"; # by default, don't hit this cache for "nix-env -qas"
  177. close FILE;
  178. }
  179.  
  180.  
  181. # Copy the archives and the corresponding NAR info files.
  182. print STDERR "copying archives...\n";
  183.  
  184. my $totalNarSize = 0;
  185. my $totalCompressedSize = 0;
  186.  
  187. for (my $n = 0; $n < scalar @storePaths2; $n++) {
  188. my $storePath = $storePaths2[$n];
  189. my $narDir = $narPaths[$n];
  190. my $baseName = basename $storePath;
  191.  
  192. # Get info about the store path.
  193. my ($deriver, $narHash, $time, $narSize, $refs) = queryPathInfo($storePath, 1);
  194.  
  195. # In some exceptional cases (such as VM tests that use the Nix
  196. # store of the host), the database doesn't contain the hash. So
  197. # compute it.
  198. if ($narHash =~ /^sha256:0*$/) {
  199. my $nar = "$tmpDir/nar";
  200. system("$Nix::Config::binDir/nix-store --dump $storePath > $nar") == 0
  201. or die "cannot dump $storePath\n";
  202. $narHash = `$Nix::Config::binDir/nix-hash --type sha256 --base32 --flat $nar`;
  203. die "cannot hash ‘$nar’" if $? != 0;
  204. chomp $narHash;
  205. $narHash = "sha256:$narHash";
  206. $narSize = stat("$nar")->size;
  207. unlink $nar or die;
  208. }
  209.  
  210. $totalNarSize += $narSize;
  211.  
  212. # Get info about the compressed NAR.
  213. open HASH, "$narDir/nar-compressed-hash" or die "cannot open nar-compressed-hash";
  214. my $compressedHash = <HASH>;
  215. chomp $compressedHash;
  216. $compressedHash =~ /^[0-9a-z]+$/ or die "invalid hash";
  217. close HASH;
  218.  
  219. my $narName = "$compressedHash.nar" . ($compressionType eq "xz" ? ".xz" : $compressionType eq "bzip2" ? ".bz2" : "");
  220.  
  221. my $narFile = "$narDir/$narName";
  222. (-f $narFile) or die "NAR file for $storePath not found";
  223.  
  224. my $compressedSize = stat($narFile)->size;
  225. $totalCompressedSize += $compressedSize;
  226.  
  227. printf STDERR "%s [%.2f MiB, %.1f%%]\n", $storePath,
  228. $compressedSize / (1024 * 1024), $compressedSize / $narSize * 100;
  229.  
  230. # Copy the compressed NAR.
  231. my $dst = "$destDir/$narName";
  232. if (! -f $dst) {
  233. my $tmp = "$destDir/.tmp.$$.$narName";
  234. if ($link) {
  235. link($narFile, $tmp) or die "cannot link $tmp to $narFile: $!\n";
  236. } else {
  237. copy($narFile, $tmp) or die "cannot copy $narFile to $tmp: $!\n";
  238. }
  239. rename($tmp, $dst) or die "cannot rename $tmp to $dst: $!\n";
  240. }
  241.  
  242. # Write the info file.
  243. my $info;
  244. $info .= "StorePath: $storePath\n";
  245. $info .= "URL: $narName\n";
  246. $info .= "Compression: $compressionType\n";
  247. $info .= "FileHash: sha256:$compressedHash\n";
  248. $info .= "FileSize: $compressedSize\n";
  249. $info .= "NarHash: $narHash\n";
  250. $info .= "NarSize: $narSize\n";
  251. $info .= "References: " . join(" ", map { basename $_ } @{$refs}) . "\n";
  252. if (defined $deriver) {
  253. $info .= "Deriver: " . basename $deriver . "\n";
  254. if (isValidPath($deriver)) {
  255. my $drv = derivationFromPath($deriver);
  256. $info .= "System: $drv->{platform}\n";
  257. }
  258. }
  259.  
  260. if (defined $secretKeyFile) {
  261. my $s = readFile $secretKeyFile;
  262. chomp $s;
  263. my ($keyName, $secretKey) = split ":", $s;
  264. die "invalid secret key file ‘$secretKeyFile’\n" unless defined $keyName && defined $secretKey;
  265. my $fingerprint = fingerprintPath($storePath, $narHash, $narSize, $refs);
  266. my $sig = encode_base64(signString(decode_base64($secretKey), $fingerprint), "");
  267. $info .= "Sig: $keyName:$sig\n";
  268. }
  269.  
  270. my $pathHash = substr(basename($storePath), 0, 32);
  271.  
  272. $dst = "$destDir/$pathHash.narinfo";
  273. if ($force || ! -f $dst) {
  274. my $tmp = "$destDir/.tmp.$$.$pathHash.narinfo";
  275. open INFO, ">$tmp" or die;
  276. print INFO "$info" or die;
  277. close INFO or die;
  278. rename($tmp, $dst) or die "cannot rename $tmp to $dst: $!\n";
  279. }
  280.  
  281. $narFiles{$storePath} = [
  282. { url => "$archivesURL/$narName"
  283. , hash => "sha256:$compressedHash"
  284. , size => $compressedSize
  285. , compressionType => $compressionType
  286. , narHash => "$narHash"
  287. , narSize => $narSize
  288. , references => join(" ", @{$refs})
  289. , deriver => $deriver
  290. }
  291. ] if $writeManifest;
  292. }
  293.  
  294. printf STDERR "total compressed size %.2f MiB, %.1f%%\n",
  295. $totalCompressedSize / (1024 * 1024), $totalCompressedSize / ($totalNarSize || 1) * 100;
  296.  
  297.  
  298. # Optionally write a manifest.
  299. writeManifest($manifestPath // "$destDir/MANIFEST", \%narFiles, \()) if $writeManifest;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement