1
- # ! /run/current-system/sw/ bin/perl -w
1
+ # ! /usr/ bin/env perl
2
2
3
3
use strict;
4
+ use warnings;
4
5
use Data::Dumper;
5
6
use Fcntl qw( :flock) ;
6
7
use File::Basename;
9
10
use JSON::PP;
10
11
use LWP::UserAgent;
11
12
use List::MoreUtils qw( uniq) ;
13
+ use Net::Amazon::S3;
12
14
13
15
my $channelName = $ARGV [0];
14
16
my $releaseUrl = $ARGV [1];
15
- my $isMainRelease = ($ARGV [2] // 0) eq 1;
16
17
17
- die " Usage: $0 CHANNEL-NAME RELEASE-URL [IS-MAIN-RELEASE] \n " unless defined $channelName && defined $releaseUrl ;
18
+ die " Usage: $0 CHANNEL-NAME RELEASE-URL\n " unless defined $channelName && defined $releaseUrl ;
18
19
19
20
$channelName =~ / ^([a-z]+)-(.*)$ / or die ;
20
21
my $channelDirRel = $channelName eq " nixpkgs-unstable" ? " nixpkgs" : " $1 /$2 " ;
21
- my $releasesDir = " /data/releases/$channelDirRel " ;
22
+
23
+
24
+ # Configuration.
22
25
my $channelsDir = " /data/releases/channels" ;
23
26
my $filesCache = " /data/releases/nixos-files.sqlite" ;
27
+ my $bucketName = " nix-releases" ;
24
28
25
29
$ENV {' GIT_DIR' } = " /home/hydra-mirror/nixpkgs-channels" ;
26
30
31
+
32
+ # S3 setup.
33
+ my $aws_access_key_id = $ENV {' AWS_ACCESS_KEY_ID' } or die ;
34
+ my $aws_secret_access_key = $ENV {' AWS_SECRET_ACCESS_KEY' } or die ;
35
+
36
+ my $s3 = Net::Amazon::S3-> new(
37
+ { aws_access_key_id => $aws_access_key_id ,
38
+ aws_secret_access_key => $aws_secret_access_key ,
39
+ retry => 1,
40
+ host => " s3-eu-west-1.amazonaws.com" ,
41
+ });
42
+
43
+ my $bucket = $s3 -> bucket($bucketName ) or die ;
44
+
45
+
27
46
sub fetch {
28
47
my ($url , $type ) = @_ ;
29
48
@@ -42,13 +61,12 @@ sub fetch {
42
61
my $releaseName = $releaseInfo -> {nixname } or die ;
43
62
my $evalId = $releaseInfo -> {jobsetevals }-> [0] or die ;
44
63
my $evalUrl = " https://hydra.nixos.org/eval/$evalId " ;
45
- my $releaseDir = " $releasesDir /$releaseName " ;
46
-
47
64
my $evalInfo = decode_json(fetch($evalUrl , ' application/json' ));
65
+ my $releasePrefix = " $channelDirRel /$releaseName " ;
48
66
49
67
my $rev = $evalInfo -> {jobsetevalinputs }-> {nixpkgs }-> {revision } or die ;
50
68
51
- print STDERR " release is ‘$releaseName ’ (build $releaseId ), eval is $evalId , dir is ‘ $releaseDir ’ , Git commit is $rev \n " ;
69
+ print STDERR " release is ‘$releaseName ’ (build $releaseId ), eval is $evalId , prefix is $releasePrefix , Git commit is $rev \n " ;
52
70
53
71
# Guard against the channel going back in time.
54
72
my $curReleaseDir = readlink " $channelsDir /$channelName " ;
@@ -59,10 +77,10 @@ sub fetch {
59
77
die " channel would go back in time from $curRelease to $releaseName , bailing out\n " if $d == 1;
60
78
}
61
79
62
- if (-d $releaseDir ) {
80
+ if ($bucket -> head_key( " $releasePrefix /github-link " ) ) {
63
81
print STDERR " release already exists\n " ;
64
82
} else {
65
- my $tmpDir = dirname( $releaseDir ) . " / $ releaseName-tmp " ;
83
+ my $tmpDir = " /data/releases/tmp/release- $channelName / $ releaseName" ;
66
84
File::Path::make_path($tmpDir );
67
85
68
86
write_file(" $tmpDir /src-url" , $evalUrl );
@@ -74,18 +92,6 @@ sub fetch {
74
92
write_file(" $tmpDir /store-paths" , join (" \n " , uniq(@{$storePaths })) . " \n " );
75
93
}
76
94
77
- # Copy the manual.
78
- my $manualJob = $channelName =~ / nixos/ ? " nixos.manual.x86_64-linux" : " manual" ;
79
- my $manualDir = $channelName =~ / nixos/ ? " nixos" : " nixpkgs" ;
80
- if (! -e " $tmpDir /manual" ) {
81
- my $manualInfo = decode_json(fetch(" $evalUrl /job/$manualJob " , ' application/json' ));
82
- my $manualPath = $manualInfo -> {buildoutputs }-> {out }-> {path } or die ;
83
- system (" nix-store" , " -r" , $manualPath ) == 0 or die " unable to fetch $manualPath \n " ;
84
- system (" cp" , " -rd" , " $manualPath /share/doc/$manualDir " , " $tmpDir /manual" ) == 0 or die " unable to copy manual from $manualPath " ;
85
- system (" chmod" , " -R" , " u+w" , " $tmpDir /manual" );
86
- symlink (" manual.html" , " $tmpDir /manual/index.html" ) unless -e " $tmpDir /manual/index.html" ;
87
- }
88
-
89
95
sub downloadFile {
90
96
my ($jobName , $dstName ) = @_ ;
91
97
@@ -95,22 +101,24 @@ sub fetch {
95
101
$dstName //= basename($srcFile );
96
102
my $dstFile = " $tmpDir /" . $dstName ;
97
103
104
+ my $sha256_expected = $buildInfo -> {buildproducts }-> {1 }-> {sha256hash } or die ;
105
+
98
106
if (! -e $dstFile ) {
99
107
print STDERR " downloading $srcFile to $dstFile ...\n " ;
108
+ write_file(" $dstFile .sha256" , $sha256_expected );
100
109
system (" NIX_REMOTE=https://cache.nixos.org/ nix cat-store '$srcFile ' > '$dstFile .tmp'" ) == 0
101
110
or die " unable to fetch $srcFile \n " ;
102
111
rename (" $dstFile .tmp" , $dstFile ) or die ;
103
112
}
104
113
105
- my $sha256_expected = $buildInfo -> {buildproducts }-> {1 }-> {sha256hash } or die ;
106
- my $sha256_actual = ` nix hash-file --type sha256 '$dstFile '` ;
107
- chomp $sha256_actual ;
108
- if ($sha256_expected ne $sha256_actual ) {
109
- print STDERR " file $dstFile is corrupt\n " ;
110
- exit 1;
114
+ if (-e " $dstFile .sha256" ) {
115
+ my $sha256_actual = ` nix hash-file --type sha256 '$dstFile '` ;
116
+ chomp $sha256_actual ;
117
+ if ($sha256_expected ne $sha256_actual ) {
118
+ print STDERR " file $dstFile is corrupt $sha256_expected $sha256_actual \n " ;
119
+ exit 1;
120
+ }
111
121
}
112
-
113
- write_file(" $dstFile .sha256" , $sha256_expected );
114
122
}
115
123
116
124
if ($channelName =~ / nixos/ ) {
@@ -129,19 +137,14 @@ sub fetch {
129
137
downloadFile(" tarball" , " nixexprs.tar.xz" );
130
138
}
131
139
132
- # Make "github-link" a redirect to the GitHub history of this
133
- # release.
134
- write_file(" $tmpDir /.htaccess" ,
135
- " Redirect /releases/$channelDirRel /$releaseName /github-link https://github.com/NixOS/nixpkgs-channels/commits/$rev \n " );
136
- write_file(" $tmpDir /github-link" , " " );
137
-
138
140
# Generate the programs.sqlite database and put it in nixexprs.tar.xz.
139
- if ($channelName =~ / nixos/ ) {
141
+ if ($channelName =~ / nixos/ && -e " $tmpDir /store-paths " ) {
140
142
File::Path::make_path(" $tmpDir /unpack" );
141
143
system (" tar" , " xfJ" , " $tmpDir /nixexprs.tar.xz" , " -C" , " $tmpDir /unpack" ) == 0 or die ;
142
144
my $exprDir = glob (" $tmpDir /unpack/*" );
143
145
system (" generate-programs-index $filesCache $exprDir /programs.sqlite http://nix-cache.s3.amazonaws.com/ $tmpDir /store-paths $exprDir /nixpkgs" ) == 0 or die ;
144
146
system (" rm -f $tmpDir /nixexprs.tar.xz $exprDir /programs.sqlite-journal" ) == 0 or die ;
147
+ unlink (" $tmpDir /nixexprs.tar.xz.sha256" );
145
148
system (" tar" , " cfJ" , " $tmpDir /nixexprs.tar.xz" , " -C" , " $tmpDir /unpack" , basename($exprDir )) == 0 or die ;
146
149
system (" rm -rf $tmpDir /unpack" ) == 0 or die ;
147
150
}
@@ -150,7 +153,29 @@ sub fetch {
150
153
system (" xz" , " $tmpDir /store-paths" ) == 0 or die ;
151
154
}
152
155
153
- rename ($tmpDir , $releaseDir ) or die ;
156
+ # Upload the release to S3.
157
+ for my $fn (glob (" $tmpDir /*" )) {
158
+ my $key = " $releasePrefix /" . basename $fn ;
159
+ unless (defined $bucket -> head_key($key )) {
160
+ print STDERR " mirroring $fn to s3://$bucketName /$key ...\n " ;
161
+ $bucket -> add_key_filename(
162
+ $key , $fn ,
163
+ { content_type => $fn =~ / .sha256|src-url|binary-cache-url|git-revision/ ? " text/plain" : " application/octet-stream" })
164
+ or die $bucket -> err . $bucket -> errstr;
165
+ }
166
+ }
167
+
168
+ # Make "github-link" a redirect to the GitHub history of this
169
+ # release.
170
+ my $link = " https://github.com/NixOS/nixpkgs-channels/commits/$rev " ;
171
+ $bucket -> add_key(
172
+ " $releasePrefix /github-link" , $link ,
173
+ { ' x-amz-website-redirect-location' => $link ,
174
+ content_type => " text/plain"
175
+ })
176
+ or die $bucket -> err . $bucket -> errstr;
177
+
178
+ File::Path::remove_tree($tmpDir );
154
179
}
155
180
156
181
# Prevent concurrent writes to the channels and the Git clone.
@@ -159,13 +184,14 @@ sub fetch {
159
184
160
185
# Update the channel.
161
186
my $htaccess = " $channelsDir /.htaccess-$channelName " ;
187
+ my $target = " https://d3g5gsiof5omrk.cloudfront.net/$releasePrefix " ;
162
188
write_file($htaccess ,
163
- " Redirect /channels/$channelName /releases/ $channelDirRel / $releaseName \n " .
164
- " Redirect /releases/nixos/channels/$channelName /releases/ $channelDirRel / $releaseName \n " );
189
+ " Redirect /channels/$channelName $target \n " .
190
+ " Redirect /releases/nixos/channels/$channelName $target \n " );
165
191
166
192
my $channelLink = " $channelsDir /$channelName " ;
167
193
unlink (" $channelLink .tmp" );
168
- symlink ( $releaseDir , " $channelLink .tmp" ) or die ;
194
+ write_file( " $channelLink .tmp" , " $target " ) ;
169
195
rename (" $channelLink .tmp" , $channelLink ) or die ;
170
196
171
197
system (" cat $channelsDir /.htaccess-nix* > $channelsDir /.htaccess.tmp" ) == 0 or die ;
@@ -174,32 +200,3 @@ sub fetch {
174
200
# Update the nixpkgs-channels repo.
175
201
system (" git remote update origin >&2" ) == 0 or die ;
176
202
system (" git push channels $rev :refs/heads/$channelName >&2" ) == 0 or die ;
177
-
178
- # If this is the "main" stable release, generate a .htaccess with some
179
- # symbolic redirects to the latest ISOs.
180
-
181
- if ($isMainRelease ) {
182
-
183
- my $baseURL = " /releases/$channelDirRel /$releaseName " ;
184
- my $res = " Redirect /releases/nixos/latest $baseURL \n " ;
185
-
186
- sub add {
187
- my ($name , $wildcard ) = @_ ;
188
- my @files = glob " $releaseDir /$wildcard " ;
189
- die if scalar @files != 1;
190
- my $fn = basename($files [0]);
191
- $res .= " Redirect /releases/nixos/$name $baseURL /$fn \n " ;
192
- $res .= " Redirect /releases/nixos/$name -sha256 $baseURL /$fn .sha256\n " ;
193
- }
194
-
195
- add(" latest-iso-minimal-i686-linux" , " nixos-minimal-*-i686-linux.iso" );
196
- add(" latest-iso-minimal-x86_64-linux" , " nixos-minimal-*-x86_64-linux.iso" );
197
- # add("latest-iso-graphical-i686-linux", "nixos-graphical-*-i686-linux.iso");
198
- add(" latest-iso-graphical-x86_64-linux" , " nixos-graphical-*-x86_64-linux.iso" );
199
- # add("latest-ova-i686-linux", "nixos-*-i686-linux.ova");
200
- add(" latest-ova-x86_64-linux" , " nixos-*-x86_64-linux.ova" );
201
-
202
- my $htaccess2 = " /data/releases/nixos/.htaccess" ;
203
- write_file(" $htaccess2 .tmp" , $res );
204
- rename (" $htaccess2 .tmp" , $htaccess2 ) or die ;
205
- }
0 commit comments