Annotation of embedaddon/rsync/packaging/release-rsync, revision 1.1.1.1

1.1       misho       1: #!/usr/bin/perl
                      2: # This script expects the directory ~/samba-rsync-ftp to exist and to be a
                      3: # copy of the /home/ftp/pub/rsync dir on samba.org.  When the script is done,
                      4: # the git repository in the current directory will be updated, and the local
                      5: # ~/samba-rsync-ftp dir will be ready to be rsynced to samba.org.
                      6: 
                      7: use strict;
                      8: use warnings;
                      9: use Cwd;
                     10: use Getopt::Long;
                     11: use Term::ReadKey;
                     12: use Date::Format;
                     13: 
                     14: my $dest = $ENV{HOME} . '/samba-rsync-ftp';
                     15: my $passfile = $ENV{HOME} . '/.rsyncpass';
                     16: my $path = $ENV{PATH};
                     17: my $make_gen_cmd = 'make -f prepare-source.mak conf && ./config.status && make gen';
                     18: 
                     19: &Getopt::Long::Configure('bundling');
                     20: &usage if !&GetOptions(
                     21:     'branch|b=s' => \( my $master_branch = 'master' ),
                     22:     'help|h' => \( my $help_opt ),
                     23: );
                     24: &usage if $help_opt;
                     25: 
                     26: my $now = time;
                     27: my $cl_today = time2str('* %a %b %d %Y', $now);
                     28: my $year = time2str('%Y', $now);
                     29: my $ztoday = time2str('%d %b %Y', $now);
                     30: (my $today = $ztoday) =~ s/^0//;
                     31: 
                     32: my $curdir = Cwd::cwd;
                     33: 
                     34: END {
                     35:     unlink($passfile);
                     36: }
                     37: 
                     38: my @extra_files;
                     39: open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
                     40: while (<IN>) {
                     41:     if (s/^GENFILES=//) {
                     42:        while (s/\\$//) {
                     43:            $_ .= <IN>;
                     44:        }
                     45:        @extra_files = split(' ', $_);
                     46:        last;
                     47:     }
                     48: }
                     49: close IN;
                     50: 
                     51: my $break = <<EOT;
                     52: ==========================================================================
                     53: EOT
                     54: 
                     55: print $break, <<EOT, $break, "\n";
                     56: == This will release a new version of rsync onto an unsuspecting world. ==
                     57: EOT
                     58: 
                     59: die "$dest does not exist\n" unless -d $dest;
                     60: die "There is no .git dir in the current directory.\n" unless -d '.git';
                     61: die "'a' must not exist in the current directory.\n" if -e 'a';
                     62: die "'b' must not exist in the current directory.\n" if -e 'b';
                     63: 
                     64: require 'packaging/git-status.pl';
                     65: check_git_state($master_branch, 1, 1);
                     66: 
                     67: my $confversion;
                     68: open(IN, '<', 'configure.ac') or die $!;
                     69: while (<IN>) {
                     70:     if (/^RSYNC_VERSION=(.*)/) {
                     71:        $confversion = $1;
                     72:        last;
                     73:     }
                     74: }
                     75: close IN;
                     76: die "Unable to find RSYNC_VERSION in configure.ac\n" unless defined $confversion;
                     77: 
                     78: open(IN, '<', 'OLDNEWS') or die $!;
                     79: $_ = <IN>;
                     80: my($lastversion) = /(\d+\.\d+\.\d+)/;
                     81: my($last_protocol_version, %pdate);
                     82: while (<IN>) {
                     83:     if (my($ver,$pdate,$pver) = /^\s+\S\S\s\S\S\S\s\d\d\d\d\s+(\d+\.\d+\.\d+)\s+(\d\d \w\w\w \d\d\d\d\s+)?(\d+)$/) {
                     84:        $pdate{$ver} = $pdate if defined $pdate;
                     85:        $last_protocol_version = $pver if $ver eq $lastversion;
                     86:     }
                     87: }
                     88: close IN;
                     89: die "Unable to determine protocol_version for $lastversion.\n" unless defined $last_protocol_version;
                     90: 
                     91: my $protocol_version;
                     92: open(IN, '<', 'rsync.h') or die $!;
                     93: while (<IN>) {
                     94:     if (/^#define\s+PROTOCOL_VERSION\s+(\d+)/) {
                     95:        $protocol_version = $1;
                     96:        last;
                     97:     }
                     98: }
                     99: close IN;
                    100: die "Unable to determine the current PROTOCOL_VERSION.\n" unless defined $protocol_version;
                    101: 
                    102: my $version = $confversion;
                    103: $version =~ s/dev/pre1/ || $version =~ s/pre(\d+)/ 'pre' . ($1 + 1) /e;
                    104: 
                    105: print "Please enter the version number of this release: [$version] ";
                    106: chomp($_ = <STDIN>);
                    107: if ($_ eq '.') {
                    108:     $version =~ s/pre\d+//;
                    109: } elsif ($_ ne '') {
                    110:     $version = $_;
                    111: }
                    112: die "Invalid version: `$version'\n" unless $version =~ /^[\d.]+(pre\d+)?$/;
                    113: 
                    114: if (`git tag -l v$version` ne '') {
                    115:     print "Tag v$version already exists.\n\nDelete tag or quit? [q/del] ";
                    116:     $_ = <STDIN>;
                    117:     exit 1 unless /^del/i;
                    118:     system "git tag -d v$version";
                    119: }
                    120: 
                    121: if ($version =~ s/[-.]*pre[-.]*/pre/ && $confversion !~ /dev$/) {
                    122:     $lastversion = $confversion;
                    123: }
                    124: 
                    125: print "Enter the previous version to produce a patch against: [$lastversion] ";
                    126: chomp($_ = <STDIN>);
                    127: $lastversion = $_ if $_ ne '';
                    128: $lastversion =~ s/[-.]*pre[-.]*/pre/;
                    129: 
                    130: my $pre = $version =~ /(pre\d+)/ ? $1 : '';
                    131: 
                    132: my $release = $pre ? '0.1' : '1';
                    133: print "Please enter the RPM release number of this release: [$release] ";
                    134: chomp($_ = <STDIN>);
                    135: $release = $_ if $_ ne '';
                    136: $release .= ".$pre" if $pre;
                    137: 
                    138: (my $finalversion = $version) =~ s/pre\d+//;
                    139: my($proto_changed,$proto_change_date);
                    140: if ($protocol_version eq $last_protocol_version) {
                    141:     $proto_changed = 'unchanged';
                    142:     $proto_change_date = "\t\t";
                    143: } else {
                    144:     $proto_changed = 'changed';
                    145:     if (!defined($proto_change_date = $pdate{$finalversion})) {
                    146:        while (1) {
                    147:            print "On what date did the protocol change to $protocol_version get checked in? (dd Mmm yyyy) ";
                    148:            chomp($_ = <STDIN>);
                    149:            last if /^\d\d \w\w\w \d\d\d\d$/;
                    150:        }
                    151:        $proto_change_date = "$_\t";
                    152:     }
                    153: }
                    154: 
                    155: my($srcdir,$srcdiffdir,$lastsrcdir,$skipping);
                    156: if ($lastversion =~ /pre/) {
                    157:     if (!$pre) {
                    158:        die "You should not diff a release version against a pre-release version.\n";
                    159:     }
                    160:     $srcdir = $srcdiffdir = $lastsrcdir = 'src-previews';
                    161:     $skipping = ' ** SKIPPING **';
                    162: } elsif ($pre) {
                    163:     $srcdir = $srcdiffdir = 'src-previews';
                    164:     $lastsrcdir = 'src';
                    165:     $skipping = ' ** SKIPPING **';
                    166: } else {
                    167:     $srcdir = $lastsrcdir = 'src';
                    168:     $srcdiffdir = 'src-diffs';
                    169:     $skipping = '';
                    170: }
                    171: 
                    172: print "\n", $break, <<EOT;
                    173: \$version is "$version"
                    174: \$lastversion is "$lastversion"
                    175: \$dest is "$dest"
                    176: \$curdir is "$curdir"
                    177: \$srcdir is "$srcdir"
                    178: \$srcdiffdir is "$srcdiffdir"
                    179: \$lastsrcdir is "$lastsrcdir"
                    180: \$release is "$release"
                    181: 
                    182: About to:
                    183:     - tweak SUBPROTOCOL_VERSION in rsync.h, if needed
                    184:     - tweak the version in configure.ac and the spec files
                    185:     - tweak NEWS and OLDNEWS to ensure header values are correct
                    186:     - tweak the date in the *.yo files and generate the manpages
                    187:     - generate configure.sh, config.h.in, and proto.h
                    188:     - page through the differences
                    189: 
                    190: EOT
                    191: print "<Press Enter to continue> ";
                    192: $_ = <STDIN>;
                    193: 
                    194: my %specvars = ( 'Version:' => $finalversion, 'Release:' => $release,
                    195:                 '%define fullversion' => "\%{version}$pre", 'Released' => "$version.",
                    196:                 '%define srcdir' => $srcdir );
                    197: my @tweak_files = ( glob('packaging/*.spec'), glob('packaging/*/*.spec'), glob('*.yo'),
                    198:                    qw( configure.ac rsync.h NEWS OLDNEWS options.c ) );
                    199: 
                    200: foreach my $fn (@tweak_files) {
                    201:     open(IN, '<', $fn) or die $!;
                    202:     undef $/; $_ = <IN>; $/ = "\n";
                    203:     close IN;
                    204:     if ($fn =~ /configure/) {
                    205:        s/^RSYNC_VERSION=.*/RSYNC_VERSION=$version/m
                    206:            or die "Unable to update RSYNC_VERSION in $fn\n";
                    207:     } elsif ($fn =~ /\.spec/) {
                    208:        while (my($str, $val) = each %specvars) {
                    209:            s/^\Q$str\E .*/$str $val/m
                    210:                or die "Unable to update $str in $fn\n";
                    211:        }
                    212:        s/^\* \w\w\w \w\w\w \d\d \d\d\d\d (.*)/$cl_today $1/m
                    213:            or die "Unable to update ChangeLog header in $fn\n";
                    214:     } elsif ($fn =~ /\.yo/) {
                    215:        s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m
                    216:            or die "Unable to update date in manpage() header in $fn\n";
                    217:        s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m
                    218:            or die "Unable to update current version info in $fn\n";
                    219:     } elsif ($fn eq 'rsync.h') {
                    220:        s{(#define\s+SUBPROTOCOL_VERSION)\s+(\d+)}
                    221:         { $1 . ' ' . get_subprotocol_version($2) }e
                    222:            or die "Unable to find SUBPROTOCOL_VERSION define in $fn\n";
                    223:     } elsif ($fn eq 'NEWS') {
                    224:        s{^(NEWS for rsync \Q$finalversion\E )(\(UNRELEASED\))\s*(\nProtocol: )(\d+) (\([^)]+\))\n}
                    225:         { $1 . ($pre ? $2 : "($today)") . "$3$protocol_version ($proto_changed)\n" }ei
                    226:            or die "The first 2 lines of $fn are not in the right format.  They must be:\n"
                    227:                 . "NEWS for rsync $finalversion (UNRELEASED)\n"
                    228:                 . "Protocol: $protocol_version ($proto_changed)\n";
                    229:     } elsif ($fn eq 'OLDNEWS') {
                    230:        s{^(\t\S\S\s\S\S\S\s\d\d\d\d)(\t\Q$finalversion\E\t).*}
                    231:         { ($pre ? $1 : "\t$ztoday") . $2 . $proto_change_date . $protocol_version }em
                    232:            or die "Unable to find \"?? ??? $year\t$finalversion\" line in $fn\n";
                    233:     } elsif ($fn eq 'options.c') {
                    234:        if (s/(Copyright \(C\) 2002-)(\d+)( Wayne Davison)/$1$year$3/
                    235:         && $2 ne $year) {
                    236:            die "Copyright comments need to be updated to $year in all files!\n";
                    237:        }
                    238:        # Adjust the year in the --version output.
                    239:        s/(rprintf\(f, "Copyright \(C\) 1996-)(\d+)/$1$year/
                    240:            or die "Unable to find Copyright string in --version output of $fn\n";
                    241:        next if $2 eq $year;
                    242:     } else {
                    243:        die "Unrecognized file in \@tweak_files: $fn\n";
                    244:     }
                    245:     open(OUT, '>', $fn) or die $!;
                    246:     print OUT $_;
                    247:     close OUT;
                    248: }
                    249: 
                    250: print $break;
                    251: system "git diff --color | less -p '^diff .*'";
                    252: 
                    253: my $srctar_name = "rsync-$version.tar.gz";
                    254: my $pattar_name = "rsync-patches-$version.tar.gz";
                    255: my $diff_name = "rsync-$lastversion-$version.diffs.gz";
                    256: my $srctar_file = "$dest/$srcdir/$srctar_name";
                    257: my $pattar_file = "$dest/$srcdir/$pattar_name";
                    258: my $diff_file = "$dest/$srcdiffdir/$diff_name";
                    259: my $news_file = "$dest/$srcdir/rsync-$version-NEWS";
                    260: my $lasttar_file = "$dest/$lastsrcdir/rsync-$lastversion.tar.gz";
                    261: 
                    262: print $break, <<EOT;
                    263: 
                    264: About to:
                    265:     - commit all version changes
                    266:     - merge the $master_branch branch into the patch/$master_branch/* branches
                    267:     - update the files in the "patches" dir and OPTIONALLY
                    268:       (if you type 'y') to launch a shell for each patch
                    269: 
                    270: EOT
                    271: print "<Press Enter OR 'y' to continue> ";
                    272: my $ans = <STDIN>;
                    273: 
                    274: system "git commit -a -m 'Preparing for release of $version'" and exit 1;
                    275: 
                    276: print "Updating files in \"patches\" dir ...\n";
                    277: system "packaging/patch-update --branch=$master_branch";
                    278: 
                    279: if ($ans =~ /^y/i) {
                    280:     print "\nVisiting all \"patch/$master_branch/*\" branches ...\n";
                    281:     system "packaging/patch-update --branch=$master_branch --shell";
                    282: }
                    283: 
                    284: if (-d 'patches/.git') {
                    285:     system "cd patches && git commit -a -m 'The patches for $version.'" and exit 1;
                    286: }
                    287: 
                    288: print $break, <<EOT;
                    289: 
                    290: About to:
                    291:     - create signed tag for this release: v$version
                    292:     - create release diffs, "$diff_name"
                    293:     - create release tar, "$srctar_name"
                    294:     - generate rsync-$version/patches/* files
                    295:     - create patches tar, "$pattar_name"
                    296:     - update top-level README, *NEWS, TODO, and ChangeLog
                    297:     - update top-level rsync*.html manpages
                    298:     - gpg-sign the release files
                    299:     - update hard-linked top-level release files$skipping
                    300: 
                    301: EOT
                    302: print "<Press Enter to continue> ";
                    303: $_ = <STDIN>;
                    304: 
                    305: # We want to use our passphrase-providing "gpg" script, so modify the PATH.
                    306: $ENV{PATH} = "$curdir/packaging/bin:$path";
                    307: 
                    308: my $passphrase;
                    309: while (1) {
                    310:     ReadMode('noecho');
                    311:     print "\nEnter your GPG pass-phrase: ";
                    312:     chomp($passphrase = <STDIN>);
                    313:     ReadMode(0);
                    314:     print "\n";
                    315: 
                    316:     # Briefly create a temp file with the passphrase for git's tagging use.
                    317:     my $oldmask = umask 077;
                    318:     unlink($passfile);
                    319:     open(OUT, '>', $passfile) or die $!;
                    320:     print OUT $passphrase, "\n";
                    321:     close OUT;
                    322:     umask $oldmask;
                    323:     $ENV{'GPG_PASSFILE'} = $passfile;
                    324: 
                    325:     $_ = `git tag -s -m 'Version $version.' v$version 2>&1`;
                    326:     print $_;
                    327:     next if /bad passphrase/;
                    328:     exit 1 if /failed/;
                    329: 
                    330:     if (-d 'patches/.git') {
                    331:        $_ = `cd patches && git tag -s -m 'Version $version.' v$version 2>&1`;
                    332:        print $_;
                    333:        exit 1 if /bad passphrase|failed/;
                    334:     }
                    335: 
                    336:     unlink($passfile);
                    337:     last;
                    338: }
                    339: 
                    340: $ENV{PATH} = $path;
                    341: 
                    342: # Extract the generated files from the old tar.
                    343: @_ = @extra_files;
                    344: map { s#^#rsync-$lastversion/# } @_;
                    345: system "tar xzf $lasttar_file @_";
                    346: rename("rsync-$lastversion", 'a');
                    347: 
                    348: print "Creating $diff_file ...\n";
                    349: system "$make_gen_cmd && rsync -a @extra_files b/" and exit 1;
                    350: my $sed_script = 's:^((---|\+\+\+) [ab]/[^\t]+)\t.*:\1:';
                    351: system "(git diff v$lastversion v$version; diff -upN a b | sed -r '$sed_script') | gzip -9 >$diff_file";
                    352: system "rm -rf a";
                    353: rename('b', "rsync-$version");
                    354: 
                    355: print "Creating $srctar_file ...\n";
                    356: system "git archive --format=tar --prefix=rsync-$version/ v$version | tar xf -";
                    357: system "support/git-set-file-times --prefix=rsync-$version/";
                    358: system "fakeroot tar czf $srctar_file rsync-$version; rm -rf rsync-$version";
                    359: 
                    360: print "Updating files in \"rsync-$version/patches\" dir ...\n";
                    361: mkdir("rsync-$version", 0755);
                    362: mkdir("rsync-$version/patches", 0755);
                    363: system "packaging/patch-update --skip-check --branch=$master_branch --gen=rsync-$version/patches";
                    364: 
                    365: print "Creating $pattar_file ...\n";
                    366: system "fakeroot tar chzf $pattar_file rsync-$version/patches; rm -rf rsync-$version";
                    367: 
                    368: print "Updating the other files in $dest ...\n";
                    369: system "rsync -a README NEWS OLDNEWS TODO $dest";
                    370: unlink($news_file);
                    371: link("$dest/NEWS", $news_file);
                    372: system "git log --name-status | gzip -9 >$dest/ChangeLog.gz";
                    373: 
                    374: system "yodl2html -o $dest/rsync.html rsync.yo";
                    375: system "yodl2html -o $dest/rsyncd.conf.html rsyncd.conf.yo";
                    376: 
                    377: foreach my $fn ($srctar_file, $pattar_file, $diff_file) {
                    378:     unlink("$fn.asc");
                    379:     open(GPG, '|-', "gpg --batch --passphrase-fd=0 -ba $fn") or die $!;
                    380:     print GPG $passphrase, "\n";
                    381:     close GPG;
                    382: }
                    383: 
                    384: if (!$pre) {
                    385:     system "rm $dest/rsync-*.gz $dest/rsync-*.asc $dest/rsync-*-NEWS $dest/src-previews/rsync-*diffs.gz*";
                    386: 
                    387:     foreach my $fn ($srctar_file, "$srctar_file.asc",
                    388:                    $pattar_file, "$pattar_file.asc",
                    389:                    $diff_file, "$diff_file.asc", $news_file) {
                    390:        (my $top_fn = $fn) =~ s#/src(-\w+)?/#/#;
                    391:        link($fn, $top_fn);
                    392:     }
                    393: }
                    394: 
                    395: print $break, <<'EOT';
                    396: 
                    397: Local changes are done.  When you're satisfied, push the git repository
                    398: and rsync the release files.  Remember to announce the release on *BOTH*
                    399: rsync-announce@lists.samba.org and rsync@lists.samba.org (and the web)!
                    400: EOT
                    401: 
                    402: exit;
                    403: 
                    404: sub get_subprotocol_version
                    405: {
                    406:     my($subver) = @_;
                    407:     if ($pre && $proto_changed eq 'changed') {
                    408:        return $subver == 0 ? 1 : $subver;
                    409:     }
                    410:     0;
                    411: }
                    412: 
                    413: sub usage
                    414: {
                    415:     die <<EOT;
                    416: Usage: release-rsync [OPTIONS]
                    417: 
                    418: -b, --branch=BRANCH   The branch to release (default: master)
                    419: -h, --help            Display this help message
                    420: EOT
                    421: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>