#!/usr/bin/perl use strict; use Getopt::Long; # User preferences my $inidiff = 3330; # Initial diff, if etc/last_retrieved not found my $test = 0; # Don't use/update last_retrieved my $no_update = 0; # Don't update from master repository my $local_update= 0; # update from ~/master my $gen_brk_out = 0; # Force generation of broken-out patches my $debug = 0; my $init_rev; my $only_rev; my $end_rev; my $help; my %patchset; GetOptions("init-rev=i" => \$init_rev, "rev=i" => \$only_rev, "end-rev=i" => \$end_rev, "local!" => \$local_update, "help+" => \$help, "debug" => \$debug, ); my $pullrepo = shift or die ("Need to specify a repository to pull"); my $is_patch = 0; $is_patch = 1 if ($pullrepo =~ m/.patch$/); if ($help) { printf ("Usage: $0 [--rev ] [--end-rev ] [--local] [--help]\n"); exit; } # Directory configurations my $main = '/home/v4l/'; my $tmp = '$main/tmp'; my $gentree = "$main/bin/gentree.pl --strip_dead_code"; my $url; if ($local_update) { $url = '~/master'; } else { $url = 'http://linuxtv.org/hg/v4l-dvb'; } my $last = "$main/etc/last_retrieved"; # empty $blacklist_file means: no blacklist #my $blacklist_file = "$main/etc/blacklist.txt"; my $blacklist_file; my $temprepo = "$tmp/hg_temp"; my $repository = "$tmp/hg/v4l-dvb"; my $cleantree = "$tmp/linux"; my $cleanold = "$tmp/oldtree"; my $in_queue = "patches"; my $checkpatch = "scripts/checkpatch.pl"; my $hg = 'hg'; my $series = "$in_queue/series"; my $tmpseries = "$in_queue/series.tmp"; my $ver; open IN,"$main/etc/kern_version" or die "No kernel version file!"; while () { if (m/^\s*\n/) { next; } $ver = $_; # Kernel version used on cleanups $ver =~ s/\n//; } close IN; printf "Generating patches for version $ver\n"; $ENV{PATH} = "/usr/local/bin:/usr/bin:/bin:$main"; # Reads a patch and reformats sub patchread($$) { my ($path,$num)=@_; my $patch=""; my $diff=""; my $header=""; my $diffstat=""; my $initer=""; my $signers=""; my $subject; my $description=0; print "$hg -R $path log -r $num -v -p\n" if ($debug); open HEAD,"$hg -R $path log -r $num -v -p |"; while () { if (m/^user:\s*(.*)\n/) { $header="Commiter: $1\n".$header; next; } if (m/^date:\s*(.*)\n/) { $header=$header."Date: $1\n"; next; } if (m/^tag:\s*(.*)\n/) { $header=$header."Tag: $1\n"; next; } if (m/^branch:\s*(.*)\n/) { $header=$header."Branch: $1\n"; next; } if (m/^description:/) { $description=1; next; } if (!$description) { next; } if (!$subject) { $header=$header."Subject: $_"; $subject=$_; next; } if (m/^(From:)\s*(.*)(<.*>)/) { $header="$1 $2 $3\n$header"; next; } if (m/^diff/) { $diff="$diff$_"; next; } if ($diff eq "") { if (m/^(Signed-off-by|Acked-by|Reviewed-by):/) { $signers="$signers$_"; $signers=~ s/mchehab\@infradead.org/mchehab\@redhat.com/; next; } $patch="$patch$_"; } else { # Hack: Fixes a trouble at chanseset #176 if (m|^\\ No newline at end of file|) { next; } $diff="$diff$_"; } } # Strip blank lines at the beginning and at the end $patch =~ s/^\n+//; $patch =~ s/\n+$/\n/; $patch="Changeset: $num\n$header\n$patch\n$signers---\n\n"; return ($patch, $diff, $subject); } sub check_pending($$) { my ($path, $blacklist)=@_; my ($init, $end); system "mkdir $in_queue"; if ($only_rev) { $init_rev=$only_rev; $end_rev=$only_rev; } if (!$init_rev) { # get info about the latest commit if (open HEAD,"<$last") { while () { $init = $_; } close HEAD; } else { $init=$inidiff-1; } } else { $init=$init_rev-1; } if (!$end_rev) { print "$hg -R $path tip\n" if ($debug); open HEAD,"$hg -R $path tip |"; while () { if (m/changeset:\s*(.\d+):/) { $end = $1; } } } else { die "Need to specify initial revision" if (!$init_rev); $end = $end_rev; } close HEAD; if ( $test ) { $init = $inidiff-1; } if ( "$init" ne "$end" ) { printf "Processing from patch %i to patch %i\n",$init+1, $end; for (my $i = $init + 1; $i <= $end; $i++) { next if (!defined($patchset{$i})); print "Processing changeset $i\r"; my ($patch, $diff, $fname)=patchread("$path", $i); $fname =~ tr/[A-Z]/[a-z]/; $fname =~ s/^v4l_dvb//g; $fname =~ s/[^a-z0-9]+/_/g; $fname =~ s/^_+//; $fname =~ s/^\d+_*//; $fname =~ s/_+$//; $fname =~ s/_+/_/g; $fname = sprintf "hg_%i_$fname.patch", $i; # Clean old stuff print "rm -rf $path/* $cleanold $cleantree\n" if ($debug); system "rm -rf $path/* $cleanold $cleantree"; # Make a clean update at current pos print "$hg -q -R $path update -C $i\n" if ($debug); system("$hg -q -R $path update -C $i"); # Generate the previous and current clean tree print "$gentree $ver $path/linux $cleantree >/dev/null\n" if ($debug); system "$gentree $ver $path/linux $cleantree >/dev/null"; print "patch -R -p1 -s -E -l -d $path -i /tmp/orig_$i.patch\n" if ($debug); open DIFF,"|patch -R -p1 -s -E -l -d $path" or die ("Error applying patch"); print DIFF $diff or die ("Error applying patch"); close DIFF or die ("Error applying patch"); if ($debug) { open TMP, ">/tmp/orig_$i.patch"; print TMP $diff; close TMP; } print "$gentree $ver $path/linux $cleanold >/dev/null\n" if ($debug); system "$gentree $ver $path/linux $cleanold >/dev/null"; # Generate diff between the two trees print "diff -upNr $cleanold $cleantree >/tmp/fixed_$i.patch\n" if ($debug); open DIFF,"diff -upNr $cleanold $cleantree |"; my $fixdiff=""; my $ok=1; while () { if (m/^diff/) { if ($blacklist && m/($blacklist)/) { $ok=0; m|^diff.*/([^/]*) |; print "** Removing file $1 because it is at blacklist ($blacklist matched)\n"; next; } else { $ok=1; } s|$tmp/||g; } if ($ok) { s|^([\-\+]..\ )$tmp/(.*)$|\1\2|; $fixdiff=$fixdiff.$_; } } close DIFF; if ($debug) { open TMP, ">/tmp/fixed_$i.patch"; print TMP $fixdiff; close TMP; } if ($fixdiff ne "") { printf "Generating $fname\n"; open OUT, ">$in_queue/$fname" or die "Failed to create patch $in_queue/$fname"; print OUT $patch, $fixdiff; close OUT; open OUT,">>$tmpseries" or die "Can't open $tmpseries file\n"; print OUT "$fname\n"; close OUT; system "$checkpatch -q --strict $in_queue/$fname"; } } } print " \r"; if ( $test ) { return; } if (!$end_rev) { open OUT,">$last" or die "Cannot open $last for update."; print OUT $end; close OUT; } } sub readfile ($) { my ($filename) = @_; my $file; open FILE, "<$filename" or die "can't open file $filename: $!"; { local $/; undef $/; $file = } close FILE; return $file; } # # Main # open OUT,">$tmpseries" or die "Can't create $tmpseries"; printf OUT "# Mercurial patches imported from $pullrepo\n"; close OUT; my $blacklist; if ($blacklist_file) { $blacklist = readfile("$blacklist_file"); $blacklist =~ s/(\n)/|/g; $blacklist =~ s/^(.*)\|$/\(\1\)/; } if (!$no_update) { print("Retrieving changes at master repository\n"); print "$hg -R $repository pull $url\n" if ($debug); system("$hg -R $repository pull $url"); } # First of all, create a temporary cloned tree system("rm -rf $temprepo"); my $r = system("$hg clone $repository $temprepo"); die("hg clone $repository $temprepo failed with error $?") if ($r); if (!$is_patch) { $r = system("$hg -R $temprepo pull $pullrepo"); die("$hg -R $temprepo pull $pullrepo failed with error $?") if ($r); } else { $r = system("$hg -R $temprepo import $pullrepo"); die("Failed to import $pullrepo patch") if ($r); } # Now, checks what are the new patches there print "hg incoming -R $repository $temprepo\n"; if (!$init_rev) { open IN, "$hg incoming -R $repository $temprepo|"; while () { if (m/changeset:\s*(.*):/) { my $cs = $1; if (!$init_rev) { $init_rev = $cs; } elsif ($init_rev > $cs) { $init_rev = $cs; } $patchset{$cs} = 1; } } close IN; print "New patches start at $init_rev\n"; } check_pending($temprepo, $blacklist); system("rm -rf $temprepo"); open IN, "<$series" or die "Can't open $series file\n"; open OUT,">>$tmpseries" or die "Can't open $tmpseries file\n"; print OUT "\n"; while () { print OUT $_; } close OUT; close IN; system("mv $series $series.old"); system("mv $tmpseries $series");