| #!/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.5,5.4,5.3,5.2', |
| 'p' => '-p0', |
| ); |
| |
| # sets the order shown |
| our @codetrees = ('main', |
| '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', |
| '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]; |
| }, @_]] |
| }]; |
| } |