#!/usr/bin/perl -w
use strict;
use File::Basename qq(basename);
use Git;
use Storable qw(store);
use Term::ANSIColor qw(colored);
if (@ARGV < 2) {
print "Usage: $0 suse_machine stable_version\n";
exit 1;
}
my $machine = shift;
my $stable_ver = shift;
my $old_version;
my $new_version;
my $bnc;
my %bnc_map = (
'3.12' => '1012620',
'4.1' => '1023711',
'4.4' => '1012382',
'4.12' => '1060662',
'other' => '1012628',
);
if ($stable_ver =~ /^v?(([3-9]\.[0-9]+)\.([0-9]+))$/) {
$new_version = $1;
$old_version = $2;
$bnc = $bnc_map{$old_version};
if ($3 ne 1) {
$old_version .= '.' . ($3 - 1);
}
} else {
die "cannot understand stable version $stable_ver";
}
if (!defined $bnc) {
print colored("Kernel version not found in the map, assuming Tumbleweed\n", 'red');
$bnc = $bnc_map{'other'};
}
my $patchpar = '/dev/shm';
my $patchdir = "patches-$new_version";
my $patchpath = "$patchpar/$patchdir";
my $idsfile = "$patchpath/ids";
if (!mkdir $patchpath) {
die "$patchpath already exists";
}
my $range = "v$old_version..v$new_version";
my $repo = Git->repository();
my @revs = $repo->command('rev-list', '--reverse', $range);
my %ids;
my $counter = 1;
my @to_delete;
my $sha_re = qr/[0-9a-f]{40}/;
foreach my $rev (@revs) {
my ($filename, @commit_log) = $repo->command('show', '--no-patch',
'--format=%f%n%B', $rev);
my $cont = 0;
my @shas;
my @unmatched_shas;
foreach (@commit_log) {
if ($cont) {
if (/^\s+($sha_re)\s*[\])]$/) {
push @shas, $1;
$cont = 0;
next;
}
}
if (/^commit ($sha_re) upstream\.?$/ ||
/^[\[(]\s*[Uu]pstream commit ($sha_re)\s*[\])]$/ ||
/^[uU]pstream commit ($sha_re)\.$/ ||
/^This is a backport of ($sha_re)$/ ||
/^\(cherry picked from commit ($sha_re)\)$/) {
push @shas, $1;
} elsif (/^[\[(]\s*[Uu]pstream commits ($sha_re)\s+and\s*$/) {
push @shas, $1;
$cont = 1;
} elsif (/^(Fixes:|This reverts commit) $sha_re(?: \(".*)?\.?$/ ||
/^Link: .*lkml/) {
# ignore
} elsif (/\b$sha_re\b/) {
push @unmatched_shas, $_;
}
}
# better than nothing
if (!scalar @shas) {
push @shas, $rev;
}
my @patch = $repo->command('format-patch', '--stdout',
'--signoff', '--no-renames',
'-1', $rev,
'--add-header', "References: bnc#$bnc",
'--add-header', "Patch-mainline: $new_version",
(map { ('--add-header', "Git-commit: $_") } @shas));
# drop From
shift(@patch) =~ /^From/ or die "From line is not the first one?";
my $newname = sprintf("$new_version-%03d-%s", $counter, $filename);
# 57 is what git-format-patch uses
$newname =~ s/^(.{1,57}).*$/$1.patch/;
my $newpath = "$patchpath/$newname";
open(PATCH, ">$newpath") or die "cannot output to $newpath";
print PATCH join "\n", @patch;
print PATCH "\n";
close PATCH;
$ids{$newname} = [ @shas ];
$rev =~ /.{12}/;
print colored($&, "yellow"), " -> $newname\n";
foreach (@shas) {
/.{12}/;
print "\tUpstream SHA: ", colored("$&\n", "yellow");
}
foreach (@unmatched_shas) {
print colored("\tUNMATCHED SHA:", 'bold red'), " $_\n";
}
push @to_delete, $newpath;
$counter++;
}
store(\%ids, $idsfile) or die "cannot write $idsfile";
push @to_delete, $idsfile;
system("tar -cC $patchpar $patchdir|ssh -C $machine -o StrictHostKeyChecking=no 'tar -xC $patchpar'") == 0 ||
die "ssh didn't start";
print "Written patches and ids to $machine:$patchpath\n";
unlink(@to_delete) or print STDERR "cannot delete some temp files\n";
rmdir("$patchpath") or print STDERR "cannot remove $patchpath\n";
0;