blob: 0fd50ee4aa360633f3d8c6bfba8661cece289b47 [file] [log] [blame]
#!/usr/bin/perl
use Getopt::GUI::Long;
use QWizard;
use QWizard::API;
use Data::Dumper;
use Cwd;
use Getopt::Std;
Getopt::GUI::Long::Configure(qw(display_help no_ignore_case));
use strict;
our %opts =
(
'd' => $ENV{'HOME'} . "/src/snmp/patme/",
'b' => 'main,5.6,5.5,5.4,5.3',
'p' => '-p0',
);
# sets the order shown
our @codetrees = ('main',
'5.6',
'5.5',
'5.4',
'5.3',
'5.2',
'5.1',
'5.0',
'UCD');
our %codetrees = ('5.0' => 'V5-0-patches',
'5.1' => 'V5-1-patches',
'5.2' => 'V5-2-patches',
'5.3' => 'V5-3-patches',
'5.4' => 'V5-4-patches',
'5.5' => 'V5-5-patches',
'5.6' => 'V5-6-patches',
'main' => 'net-snmp',
'UCD' => 'V4-2-patches');
our (@captures, $capfilt, $result, %captures, $capturenum);
GetOptions(\%opts,
['f|file=s', 'Patch file'],
['d|base-directory=s', 'Base directory of checkouts'],
['p|patch-args=s', 'Default patch arguments (-p1)'],
['GUI:separator', 'Patch application specifics;'],
['b|braches=s', 'Branches to apply to (eg 5.1,5.2,...)'],
['m|commit-msg=s', 'Default commit message to use'],
['D|subdir=s', 'Apply patches to a subdirectory'],
['u|no-update', 'Do not run svn status/update in the directory first. Only use this if it\'s known clean.'],
);
my %bs;
if ($opts{'b'}) {
map { $bs{$_} = 1; } split(/,\s*/,$opts{'b'});
}
$opts{'d'} .= "/" if ($opts{'d'} !~ /\/$/);
my $qw = new QWizard();
my $pris = load_primaries();
$qw->{'primaries'} = $pris;
$qw->qwparam('svncommit',$opts{'m'}) if ($opts{'m'});
$qw->magic('top');
sub make_tops {
my @tops;
foreach my $k (@codetrees) {
push @tops,
qw_checkbox($k, "Apply to $k", 1, 0,
default => $qw->qwparam($k) || $bs{$k},
override => 1);
}
return @tops;
}
sub load_primaries {
my @tops = make_tops();
return
{
top =>
qw_primary('top','Select packages to apply the patch to:', '',
[@tops,
qw_text('basedir', 'Base code directory:',
default => $opts{'d'}),
qw_hidden('no_confirm',1),
qw_text('patchfile','Patch file:', default => $opts{f},
check_value => sub {
return "patch file doesn't exist" if (! -f qwparam('patchfile'))
}),
qw_checkbox('noupdate','Don\'t run svn update/revert first:',
1, 0, default => $opts{'u'} || 0)],
[],[],sub_modules => ['commit', 'commitmsg', 'maketest',
'edit', 'applying', 'check',
'patch_info']),
patch_info =>
qw_primary('check','Checking code directory status:', '',
[qw_paragraph('patch pieces:',
sub { capture("egrep '^(---|\\+\\+\\+)' " .
qwparam('patchfile'))},
width => 80,
height => 30),
qw_text('patchargs','Patch arguments',
default => $opts{'p'}),
qw_text('subdir', 'Apply in package subdir:',
default => $opts{'D'}),
qw_paragraph('Note:','Hitting next below will first clean your local repositories which could take a bit (watch the console for deails on what it\'s doing at any moment)', doif => sub {!qwparam('noupdate')}),
]),
check =>
qw_primary('check','Checking code directory status:', '',
[qw_paragraph('removed .rej files:',
sub { my $it = captureeachdir('find . -name \*.rej');
captureeachdir('find . -name \*.rej | xargs rm -f');
return $it;
},
preformatted => 1,
width => 80,
height => 60,
),
qw_paragraph('svn update:',
sub {
my ($res, $one);
foreach my $k (@codetrees) {
next if (!qwparam($k));
$res .= "$k:\n";
$one = capturedir($codetrees{$k},
"svn update");
$res .= $one;
$one = capturedir($codetrees{$k},
"svn revert -R .");
$res .= $one;
}
return $res;
},
preformatted => 1,
width => 80,
height => 60,
doif => sub{!qwparam('noupdate')}
) ],
),
applying =>
qw_primary("applying", 'Applying patches to the code bases', '',
[{type => 'table',
text => 'Results:',
values => sub {
my @tab;
foreach my $k (@codetrees) {
next if (!qwparam($k));
push @tab, [$k,
qw_paragraph("r$k","",
preformatted => 1,
width => 80,
height => 20,
values =>
sub { my $cmd = "patch " . qwparam('patchargs') . " < " . qwparam('patchfile');
my $results = "Running on $k: $cmd" . "\n" . capturedir($codetrees{$k},$cmd);
return $results})];
}
return [\@tab];
}}],[],[]),
edit =>
qw_primary('edit','Fix the following files:','',
[qw_paragraph('Fix these (maybe):',
sub {
$capfilt = '(.*.rej)';
my $res =
captureeachdir('find . -name \*.rej');
print Dumper(\%captures);
$capfilt = undef;
return $res;
},
preformatted => 1,
width => 80,
height => 60,
),
qw_label('failed files:',
sub { $capturenum = 0;
map { $capturenum += $#{$captures{$_}} + 1;
} (keys(%captures));
return $capturenum;
}),
qw_checkbox('edithem','Open an editor on the failed files?',
1, 0, doif => sub { return $capturenum > 0 }),
qw_text('editor','Editor:',default => $ENV{'EDITOR'} || 'vi',
doif => sub { return $capturenum > 0 })],
[sub {
if (qwparam('edithem')) {
foreach my $k (keys(%captures)) {
foreach my $f (@{$captures{$k}}) {
my $file = qwparam('basedir') .
$codetrees{$k} .
qwparam('subdir') . '/' . $f->[0];
print STDERR "editing: $file\n";
system(qwparam('editor') . " " . $file);
}
}
}
}]
),
maketest =>
qw_primary("maketest", "Run make?",'',
[qw_checkbox('makeit','Run make?', 1, 0),
qw_checkbox('maketest', 'Run make test?', 1, 0)
],
[sub {
if (qwparam('makeit') || qwparam('maketest')) {
$_[0]->add_todos(-early, 'domake');
}
}]
),
domake =>
qw_primary("domake", "Make results",'',
[qw_paragraph('Make results:',
sub { return captureeachdir('make'); },
preformatted => 1,
width => 80,
height => 20,
doif => sub { qwparam('makeit') }
),
qw_paragraph('Make test results:',
sub { return captureeachdir('make test'); },
preformatted => 1,
width => 80,
height => 20,
doif => sub { qwparam('maketest') }
)]
),
commitmsg =>
qw_primary("commitmsg", 'Commit info:', '',
[qw_text('svncommit','Commit message',
default => qwparam('svncommit') || $opts{'m'}),
{type => 'dynamic',
values => sub { my @tops = make_tops(1); return \@tops}}]),
commit =>
qw_primary("commit", 'running commit:', '',
[qw_paragraph('committing files:',
sub { my $msg = qwparam('svncommit');
$msg =~ s/\'/\'\"\'\"\'/g; # escape 's
return capturedir($opts{'d'},
'svn commit -m \'' . $msg . '\' ' . get_codedirs_str()); },
preformatted => 1,
width => 80,
height => 20,
)]),
editing =>
qw_primary("applying", 'Edit the following files:', '',
[{type => 'table',
text => 'Results:',
values => sub { return [\@captures]},
}],[],[])
}
}
sub capture {
my $cmd = join(" ",@_);
my $results = "Running: $cmd\n";
my @a;
print $results;
open(I,"$cmd 2>&1|");
while (<I>) {
$results .= $_;
print $_;
if ($capfilt) {
print "capfilt: $capfilt\n";
@a = /$capfilt/;
print " capfilt: @a\n";
push @captures, [@a];
}
}
close(I);
$result = $? >> 8;
$results .= "RESULT: " . (($result) ? "FAIL" : "SUCCESS") . "($result)\n";
return $results;
}
sub capturedir {
my $dir = shift;
$dir .= "/" if ($dir !~ /\/$/);
my $basedir = qwparam('basedir');
$basedir .= "/" if ($basedir !~ /\/$/);
my $olddir = getcwd();
my $newdir = "$basedir$dir" . qwparam('subdir');
my $res = "changing to: $newdir\n";
print $res;
chdir($newdir);
$res .= capture(@_);
chdir($olddir);
return $res;
}
sub get_codedirs_str() {
my $res = "";
foreach my $k (@codetrees) {
next if (!qwparam($k));
$res .= " $opts{'d'}$codetrees{$k}";
}
$res =~ s/^ //;
return $res;
}
sub captureeachdir {
my $out;
%captures = ();
foreach my $k (@codetrees) {
next if (!qwparam($k));
$out .= "$k:\n";
$out .= capturedir($codetrees{$k}, @_) . "\n";
if ($#captures > -1) {
@{$captures{$k}} = @captures;
@captures = ();
}
}
return $out;
}
sub dodir {
my $text = shift;
return
[{type => 'table',
text => $text,
values => [[sub {
my @tab;
foreach my $k (@codetrees) {
next if (!qwparam($k));
push @tab, [$k,
qw_paragraph("r$k","",
preformatted => 1,
width => 80,
height => 20,
values =>
[[sub { $_->[0]($k)},
@_]])];
}
return [\@tab];
}, @_]]
}];
}