summaryrefslogtreecommitdiffstats
path: root/OSX/updates.pl
diff options
context:
space:
mode:
Diffstat (limited to 'OSX/updates.pl')
-rwxr-xr-xOSX/updates.pl219
1 files changed, 219 insertions, 0 deletions
diff --git a/OSX/updates.pl b/OSX/updates.pl
new file mode 100755
index 0000000..5938a4a
--- /dev/null
+++ b/OSX/updates.pl
@@ -0,0 +1,219 @@
+#!/usr/bin/perl -w
+# Copyright © 2013 Jamie Zawinski <jwz@jwz.org>
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation. No representations are made about the suitability of this
+# software for any purpose. It is provided "as is" without express or
+# implied warranty.
+#
+# Generates updates.xml from README, archive/, and www/.
+#
+# Created: 27-Nov-2013.
+
+require 5;
+use diagnostics;
+use strict;
+
+use open ":encoding(utf8)";
+use POSIX;
+
+my $progname = $0; $progname =~ s@.*/@@g;
+my ($version) = ('$Revision: 1.2 $' =~ m/\s(\d[.\d]+)\s/s);
+
+my $verbose = 0;
+my $debug_p = 0;
+
+my $base_url = "https://www.jwz.org/";
+my $priv_key_file = "$ENV{HOME}/.ssh/sparkle_dsa_priv.pem";
+my $sign_update = "./sign_update.rb";
+
+
+sub generate_xml($$$$) {
+ my ($app_name, $changelog, $archive_dir, $www_dir) = @_;
+
+ my $outfile = "updates.xml";
+
+ my $obody = '';
+ my %sigs;
+ my %dates;
+ if (open (my $in, '<', $outfile)) {
+ print STDERR "$progname: reading $outfile\n" if $verbose;
+ local $/ = undef; # read entire file
+ $obody = <$in>;
+ close $in;
+ foreach my $item (split (/<item/i, $obody)) {
+ my ($v) = ($item =~ m/version="(.*?)"/si);
+ my ($sig) = ($item =~ m/dsaSignature="(.*?)"/si);
+ my ($date) = ($item =~ m/<pubDate>(.*?)</si);
+ next unless $v;
+ $sigs{$v} = $sig if $sig;
+ $dates{$v} = $date if $date;
+ print STDERR "$progname: $v: " . ($date || '?') . "\n"
+ if ($verbose > 1);
+ }
+ }
+
+ open (my $in, '<', $changelog) || error ("$changelog: $!");
+ print STDERR "$progname: reading $changelog\n" if $verbose;
+ local $/ = undef; # read entire file
+ my $body = <$in>;
+ close $in;
+
+ my $rss = "";
+
+ $body =~ s/^(\d+\.\d+[ \t])/\001$1/gm;
+ my @log = split (/\001/, $body);
+ shift @log;
+ my $count = 0;
+ foreach my $log (@log) {
+ my ($v1, $entry) = ($log =~ m/^(\d+\.\d+)\s+(.*)$/s);
+
+ $entry =~ s/^\s*\d\d?[- ][A-Z][a-z][a-z][- ]\d{4}:?\s+//s; # lose date
+
+ $entry =~ s/^\s+|\s+$//gs;
+ $entry =~ s/^\s+|\s+$//gm;
+ $entry =~ s/^[-*] /<BR>&bull; /gm;
+ $entry =~ s/^<BR>//si;
+ $entry =~ s/\s+/ /gs;
+
+ my $v2 = $v1; $v2 =~ s/\.//gs;
+ my $zip = undef;
+ DONE:
+ foreach my $ext ('zip', 'dmg', 'tar.gz', 'tar.Z') {
+ foreach my $v ($v1, $v2) {
+ foreach my $name ($app_name, "x" . lc($app_name)) {
+ my $f = "$name-$v.$ext";
+ if (-f "$archive_dir/$f") {
+ $zip = $f;
+ last DONE;
+ }
+ }
+ }
+ }
+
+ my $publishedp = ($zip && -f "$www_dir/$zip");
+ $publishedp = 1 if ($count == 0);
+
+ my $url = ("${base_url}$app_name/" . ($publishedp ? $zip : ""));
+
+ $url =~ s@DaliClock/@xdaliclock/@gs if $url; # Kludge
+
+ my @st = stat("$archive_dir/$zip") if $zip;
+ my $size = $st[7];
+ my $date = $st[9];
+ $date = ($zip ?
+ strftime ("%a, %d %b %Y %T %z", localtime($date))
+ : "");
+
+ my $odate = $dates{$v1};
+ my $sig = $sigs{$v1};
+ # Re-generate the sig if the file date changed.
+ $sig = undef if ($odate && $odate ne $date);
+
+ print STDERR "$progname: $v1: $date " . ($sig ? "Y" : "N") . "\n"
+ if ($verbose > 1);
+
+ if (!$sig && $zip) {
+ local %ENV = %ENV;
+ $ENV{PATH} = "/usr/bin:$ENV{PATH}";
+ $sig = `$sign_update "$archive_dir/$zip" "$priv_key_file"`;
+ $sig =~ s/\s+//gs;
+ }
+
+ my $enc = ($publishedp
+ ? ("<enclosure url=\"$url\"\n" .
+ " sparkle:version=\"$v1\"\n" .
+ " sparkle:dsaSignature=\"$sig\"\n" .
+ " length=\"$size\"\n" .
+ " type=\"application/octet-stream\" />\n")
+ : "<sparkle:version>$v1</sparkle:version>\n");
+
+ $enc =~ s/^/ /gm if $enc;
+ my $item = ("<item>\n" .
+ " <title>Version $v1</title>\n" .
+ " <link>$url</link>\n" .
+ " <description><![CDATA[$entry]]></description>\n" .
+ " <pubDate>$date</pubDate>\n" .
+ $enc .
+ "</item>\n");
+ $item =~ s/^/ /gm;
+
+ # I guess Sparkle doesn't like info-only items.
+ $item = '' unless $publishedp;
+
+ $rss .= $item;
+ $count++;
+ }
+
+ $rss = ("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" .
+ "<rss version=\"2.0\"\n" .
+ " xmlns:sparkle=\"http://www.andymatuschak.org/" .
+ "xml-namespaces/sparkle\"\n" .
+ " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n" .
+ " <channel>\n" .
+ " <title>$app_name updater</title>\n" .
+ " <link>${base_url}$app_name/updates.xml</link>\n" .
+ " <description>Updates to $app_name.</description>\n" .
+ " <language>en</language>\n" .
+ $rss .
+ " </channel>\n" .
+ "</rss>\n");
+
+ if ($rss eq $obody) {
+ print STDERR "$progname: $outfile: unchanged\n";
+ } else {
+ my $tmp = "$outfile.tmp";
+ open (my $out, '>', $tmp) || error ("$tmp: $!");
+ print $out $rss;
+ close $out;
+ if ($debug_p) {
+ system ("diff", "-wNU2", "$outfile", "$tmp");
+ unlink $tmp;
+ } else {
+ if (!rename ("$tmp", "$outfile")) {
+ unlink "$tmp";
+ error ("mv $tmp $outfile: $!");
+ } else {
+ print STDERR "$progname: wrote $outfile\n";
+ }
+ }
+ }
+}
+
+
+sub error($) {
+ my ($err) = @_;
+ print STDERR "$progname: $err\n";
+ exit 1;
+}
+
+sub usage() {
+ print STDERR "usage: $progname [--verbose] app-name changelog archive www\n";
+ exit 1;
+}
+
+sub main() {
+ my ($app_name, $changelog, $archive_dir, $www_dir);
+ while ($#ARGV >= 0) {
+ $_ = shift @ARGV;
+ if (m/^--?verbose$/) { $verbose++; }
+ elsif (m/^-v+$/) { $verbose += length($_)-1; }
+ elsif (m/^--?debug$/) { $debug_p++; }
+ elsif (m/^-./) { usage; }
+ elsif (!$app_name) { $app_name = $_; }
+ elsif (!$changelog) { $changelog = $_; }
+ elsif (!$archive_dir) { $archive_dir = $_; }
+ elsif (!$www_dir) { $www_dir = $_; }
+ else { usage; }
+ }
+
+ usage unless $www_dir;
+ generate_xml ($app_name, $changelog, $archive_dir, $www_dir);
+
+}
+
+main();
+exit 0;