#!/usr/bin/perl # # traverses debian/changelog until a version is found which is tagged # for all untagged versions, attempt to download the upstream source # from snapshot.debian.org and import it with # git-import-orig --no-merge --pristine-tar # if there is no upstream branch, attempts to create one from origin/upstream # or creates one from scratch # when all tarballs are done, merge upstream to master # # To be run in the root directory of the package use strict; use warnings; use feature 'say'; use autodie; use File::Basename qw(basename); use File::Temp qw(tempdir); use Getopt::Long; use Git; use IPC::Run qw(run); use Parse::DebianChangelog; use WWW::Mechanize; our $opt_check_only; our $opt_skip_missing_snapshots; GetOptions( 'check-only!' => \$opt_check_only, 'skip-missing-snapshots!' => \$opt_skip_missing_snapshots, ) or exit 1; my $me = basename($0); my $has_non_native_releases = 0; my $cl = Parse::DebianChangelog->init( { infile => 'debian/changelog' } ) or die "Parse error\n"; my $git = Git->repository(); my %tags = map ( ( $_ => 1 ), $git->command('tag') ); my @releases; my %versions; my $releases = $cl->rfc822( { all => 1 } ); my $pkg; for my $r ( @$releases ) { $pkg = $r->{Source}; my $ver = $r->{Version}; $ver =~ s/^\d+://; if ( not $ver =~ s/-[^-]+$// ) { say "Skipping native version $ver"; next; } $has_non_native_releases = 1; my $tag = "upstream/$ver"; last if $tags{$tag}; ( my $tmp_tag = $tag ) =~ s/~/_/; last if $tags{$tmp_tag}; ( $tmp_tag = $tag ) =~ s/~/-/; last if $tags{$tmp_tag}; ( $tmp_tag = $tag ) =~ s/~/./; last if $tags{$tmp_tag}; push @releases, $r unless $versions{$ver}; $versions{$ver} = 1; } unless ( @releases ) { say "$pkg: All releases have upstream tags"; my @branches = $git->command('branch'); if ( grep { /^[* ] upstream$/ } @branches ) { my @upstream_in_branches = $git->command('branch', '--contains', 'upstream'); unless ( grep { /^[* ] master$/ } @upstream_in_branches ) { warn "$pkg: branch upstream not merged into master\n"; my @last_tag = $git->command( 'tag', '--contains', 'upstream' ); if ( @last_tag ) { warn "$pkg: the last upstream tag seems to be @last_tag\n"; $git->command( 'merge', @last_tag ); } else { warn "Unable to find the latest upstream tag. Merging 'upstream'\n"; $git->command( merge => 'upstream' ); } $git->command('push'); } exit 0; } else { die "Package $pkg has no local upstream branch.\n" if $has_non_native_releases; } exit 0; } warn "$me: Missing upstream tags: ", join( ' ', map( $_->{Version}, @releases ) ), "\n"; exit 1 if $opt_check_only; my $tmp = tempdir( CLEANUP => 1 ); my $web = WWW::Mechanize->new( autocheck => 0 ); while ( my $r = pop @releases ) { my $source = $r->{Source}; my $version = $r->{Version}; $version =~ s/-[^-]+$//; $version =~ s/^\d+://; $web->get("http://snapshot.debian.org/package/$source/"); my @ver_links = $web->find_all_links( text_regex => qr/^\Q$version\E/ ); unless ( @ver_links ) { if ($opt_skip_missing_snapshots) { warn "Version $version not found on http://snapshot.debian.org/package/$source/ Skipping.\n"; next; } } my $filename; foreach my $ver_link (@ver_links) { $web->get( $ver_link->url_abs ) or die "Can't GET " . $ver_link->url; my $orig = $web->follow_link( text_regex => qr/\.orig\.tar\./ ) or warn "Unable to find a link to the original source tarball on " . $web->uri . "\n", next; $filename = "$tmp/$source\_$version.orig.tar.gz"; open( my $fh, '>', $filename ); print $fh $orig->content; close $fh; say $web->uri . " downloaded."; last; } unless($filename) { my $wanted = "../$source\_$version.orig.tar.gz"; if ( -f $wanted ) { warn "Using $wanted as upstream source.\n"; $filename = $wanted; } } die "Unable to find orig.tar for version $version and nothing appropriate found in ../.\n" unless $filename; unless (`git branch | grep 'upstream'`) { say "Missing branch 'upstream'"; if (`git branch -a | grep origin/upstream`) { say "Creating it from origin/upstream"; run( [qw( git branch upstream origin/upstream )] ); } else { say "Creating it from scratch"; $git->command( checkout => '--orphan', 'upstream' ); $git->command( rm => '-qrf', '.' ); $git->command( commit => '--allow-empty', "-mCreated empty upstream branch" ); $git->command( checkout => 'master' ); } } run([ 'git-import-orig', '--no-merge', '--pristine-tar', "--upstream-version=$version", $filename ] ) or die "git-import-orig failed"; say "$me: $source\_$version.orig.tar.gz imported."; } say "$me: merging upstream branch into master"; $git->command( merge => 'upstream' ); say "$me: \\o/ Done!"; say "$me: Don't forget to 'git push --all' and 'git push --tags' :)";