3 # Script to automate some easy-to-mess-up parts of the PuTTY release
10 use File::Temp qw/tempdir/;
18 GetOptions("version=s" => \$version,
21 "precheck" => \$precheck,
22 "postcheck" => \$postcheck)
25 # --set-version: construct a local commit which updates the version
26 # number, and the command-line help transcripts in the docs.
28 defined $version or die "use --version";
29 0 == system "git", "diff-index", "--quiet", "--cached", "HEAD"
30 or die "index is dirty";
31 0 == system "git", "diff-files", "--quiet" or die "working tree is dirty";
32 -f "Makefile" and die "run 'make distclean' first";
33 my $builddir = tempdir(DIR => ".", CLEANUP => 1);
34 0 == system "./mkfiles.pl" or die;
35 0 == system "cd $builddir && ../configure" or die;
36 0 == system "cd $builddir && make pscp plink RELEASE=${version}" or die;
37 our $pscp_transcript = `cd $builddir && ./pscp --help`;
38 $pscp_transcript =~ s/^Unidentified build/Release ${version}/m or die;
39 $pscp_transcript =~ s/^/\\c /mg;
40 our $plink_transcript = `cd $builddir && ./plink --help`;
41 $plink_transcript =~ s/^Unidentified build/Release ${version}/m or die;
42 $plink_transcript =~ s/^/\\c /mg;
43 &transform("LATEST.VER", sub { s/^\d+\.\d+$/$version/ });
44 &transform("windows/putty.iss", sub {
45 s/^(AppVerName=PuTTY version |VersionInfoTextVersion=Release |AppVersion=|VersionInfoVersion=)\d+\.\d+/$1$version/ });
46 our $transforming = 0;
47 &transform("doc/pscp.but", sub {
48 if (/^\\c.*>pscp$/) { $transforming = 1; $_ .= $pscp_transcript; }
49 elsif (!/^\\c/) { $transforming = 0; }
50 elsif ($transforming) { $_=""; }
53 &transform("doc/plink.but", sub {
54 if (/^\\c.*>plink$/) { $transforming = 1; $_ .= $plink_transcript; }
55 elsif (!/^\\c/) { $transforming = 0; }
56 elsif ($transforming) { $_=""; }
58 &transform("Buildscr", sub {
59 s!^(set Epoch )\d+!$1 . sprintf "%d", time/86400 - 1000!e });
60 0 == system ("git", "commit", "-a", "-m",
61 "Update version number for ${version} release.") or die;
65 # --upload: upload the release to all the places it should live, and
66 # check all signatures and md5sums once it arrives there.
68 defined $version or die "use --version";
70 # Run this inside the build.out directory.
71 -d "maps-x86" or die "no maps-x86 directory in cwd";
72 -d "putty" or die "no putty directory in cwd";
74 0 == system("rsync", "-av", "maps-x86/",
75 "atreus:src/putty-local/maps-$version")
76 or die "could not upload link maps";
78 for my $location (["atreus", "www/putty/$version"],
79 ["the", "www/putty/$version"],
80 ["chiark", "ftp/putty-$version"]) {
81 my ($host, $path) = @$location;
82 0 == system("rsync", "-av", "putty/", "$host:$path")
83 or die "could not upload release to $host";
84 open my $pipe, "|-", "ssh", $host, "cd $path && sh";
85 print $pipe "set -e\n";
89 if (m!^putty/(.*).gpg!) {
91 print $pipe "echo verifying $file\n";
92 if ($file =~ /sums$/) {
93 print $pipe "gpg --verify $file.gpg\n";
95 print $pipe "gpg --verify $file.gpg $file\n";
97 } elsif (m!^putty/(.*sum)s!) {
98 print $pipe "echo checking ${1}s\n";
99 print $pipe "$1 -c ${1}s\n";
101 }, no_chdir => 1}, "putty");
102 print $pipe "echo all verified ok\n";
104 die "VERIFICATION FAILED on $host" if $? != 0;
107 print "Uploaded $version OK!\n";
111 # --precheck and --postcheck: attempt to download the release from its
112 # various web and FTP locations.
113 if ($precheck || $postcheck) {
114 defined $version or die "use --version";
116 # Run this inside the build.out directory, so we can check the
117 # downloaded files against the exact contents they should have.
118 -d "putty" or die "no putty directory in cwd";
120 my $httpprefix = "http://the.earth.li/~sgtatham/putty/";
121 my $ftpprefix = "ftp://ftp.chiark.greenend.org.uk/users/sgtatham/putty-";
123 # Go through all the files in build.out.
127 die unless (m!^putty/(.*)$!);
130 # Don't try to check .htaccess - web servers will
132 return if $path =~ m!^(.*/)?.htaccess$!;
134 print "Checking $path\n";
136 my $real_content = "";
137 open my $fh, "<", $_ or die "$_: open local file: $!";
138 $real_content .= $_ while <$fh>;
141 my $http_numbered = "${httpprefix}$version/$path";
142 my $http_latest = "${httpprefix}latest/$path";
143 my $ftp_numbered = "${ftpprefix}$version/$path";
144 my $ftp_latest = "${ftpprefix}latest/$path";
146 my ($http_uri, $ftp_uri);
149 # Before the 'latest' links/redirects update,
150 # we just download from explicitly version-
152 $http_uri = $http_numbered;
153 $ftp_uri = $ftp_numbered;
156 # After 'latest' is updated, we're testing that
157 # the redirects work, so we download from the
158 # URLs with 'latest' in them.
159 $http_uri = $http_latest;
160 $ftp_uri = $ftp_latest;
163 # Now test-download the files themselves.
164 my $ftpdata = `curl -s $ftp_uri`;
165 printf " got %d bytes via FTP", length $ftpdata;
166 die "FTP download for $ftp_uri did not match"
167 if $ftpdata ne $real_content;
170 my $ua = LWP::UserAgent->new;
171 my $httpresponse = $ua->get($http_uri);
172 my $httpdata = $httpresponse->{_content};
173 printf " got %d bytes via HTTP", length $httpdata;
174 die "HTTP download for $http_uri did not match"
175 if $httpdata ne $real_content;
178 # Check content types on any files likely to go
180 my $ct = $httpresponse->{_headers}->{"content-type"};
182 printf " got content-type %s", $ct;
184 printf " got no content-type";
186 my $right_ct = undef;
187 if ($path =~ m/\.(hlp|cnt|chm)$/) {
188 $right_ct = "application/octet-stream";
189 } elsif ($path =~ /\.gpg$/) {
190 $right_ct = "application/pgp-signature";
192 if (defined $right_ct) {
193 if ($ct ne $right_ct) {
194 die "content-type $ct should be $right_ct";
203 # Finally, if we're testing the 'latest' URL,
204 # also check that the HTTP redirect header was
205 # present and correct.
206 my $redirected = $httpresponse->{_request}->{_uri};
207 printf " redirect -> %s\n", $redirected;
208 die "redirect header wrong for $http_uri"
209 if $redirected ne $http_numbered;
212 }, no_chdir => 1}, "putty");
221 my ($filename, $proc) = @_;
223 open $file, "<", $filename or die "$file: open for read: $!\n";
230 open $file, ">", $filename or die "$file: open for write: $!\n";
232 close $file or die "$file: close after write: $!\n";;
236 die "usage: release.pl --set-version=X.YZ\n";