Jiri Slaby 5225f4
#!/usr/bin/perl -w
Jiri Slaby 5225f4
use strict;
Jiri Slaby 1dc9b0
use Error qw(:try);
Jiri Slaby 5225f4
use File::Copy qq(move);
Jiri Slaby 1dc9b0
use Git;
Jiri Slaby 1dc9b0
use Storable qq(retrieve);
Jiri Slaby 1dc9b0
use Term::ANSIColor qw(colored);
Jiri Slaby 5225f4
Jiri Slaby 5225f4
my $tmpdir = $ENV{TMPDIR} || "/tmp";
Jiri Slaby 5225f4
Jiri Slaby 1dc9b0
my $repo = Git->repository;
Jiri Slaby 5225f4
Jiri Slaby 1dc9b0
if (scalar @ARGV < 1) {
Jiri Slaby 1dc9b0
        print "Usage: $0 patches_dir [nonzero_to_force_removal]\n";
Jiri Slaby 5225f4
        exit 1;
Jiri Slaby 5225f4
}
Jiri Slaby 5225f4
Jiri Slaby 5225f4
open(SERIES, "+
Jiri Slaby 5225f4
my $series;
Jiri Slaby 5225f4
my $series_changed = 0;
Jiri Slaby 5225f4
{
Jiri Slaby 5225f4
	local $/;
Jiri Slaby 5225f4
	$series = <SERIES>;
Jiri Slaby 5225f4
}
Jiri Slaby 5225f4
Jiri Slaby 1dc9b0
my $patchdir = $ARGV[0];
Jiri Slaby 1dc9b0
my $idsfile = "$patchdir/ids";
Jiri Slaby 1dc9b0
my $force_removal = $ARGV[1] || 0;
Jiri Slaby 1dc9b0
my $destdir = "patches.kernel.org";
Jiri Slaby 5225f4
mkdir $destdir if (! -d $destdir);
Jiri Slaby 5225f4
Jiri Slaby 1dc9b0
my $ids = retrieve($idsfile) or die "cannot read $idsfile";
Jiri Slaby 1dc9b0
my $regexp = join "|", map @$_, values %$ids;
Jiri Slaby 1dc9b0
my @candidates = ();
Jiri Slaby c1046c
Jiri Slaby c1046c
if ($regexp eq "") {
Jiri Slaby 1dc9b0
	print STDERR colored("empty regexp computed? Skipping patches removal...\n", 'yellow');
Jiri Slaby c1046c
} else {
Jiri Slaby 1dc9b0
	try {
Jiri Slaby 1dc9b0
		@candidates = $repo->command('grep', '-El', $regexp, '--',
Jiri Slaby 1dc9b0
			'patches.*') or die "cannot execute git grep";
Jiri Slaby 1dc9b0
	} catch Git::Error::Command with {
Jiri Slaby 1dc9b0
		# not found is OK
Jiri Slaby 1dc9b0
	};
Jiri Slaby 5225f4
}
Jiri Slaby 5225f4
Jiri Slaby 5225f4
sub output_refs($@) {
Jiri Slaby 5225f4
	my ($fh, @refs) = @_;
Jiri Slaby 6de83d
	my %uniq = map {
Jiri Slaby 6de83d
		s/fate/FATE/i;
Jiri Slaby 6de83d
		s/bnc/bnc/i;
Jiri Slaby 6de83d
		$_, 1
Jiri Slaby 6de83d
	} @refs;
Jiri Slaby 6cdcb5
	print $fh "References: ", join(' ', sort keys %uniq), "\n";
Jiri Slaby 5225f4
}
Jiri Slaby 5225f4
Jiri Slaby 1dc9b0
sub push_refs($@) {
Jiri Slaby 1dc9b0
	my ($dest, @refs) = @_;
Jiri Slaby 1dc9b0
Jiri Slaby 704ec8
	open(DEST, "<$dest") || die "cannot open $dest for reading";
Jiri Slaby 5225f4
	my @dest = <DEST>;
Jiri Slaby 5225f4
	close DEST;
Jiri Slaby 1dc9b0
Jiri Slaby 704ec8
	open(DEST, ">$dest") || die "cannot open $dest for writing";
Jiri Slaby 5225f4
	my $had_git_commit = 0;
Jiri Slaby 5225f4
	foreach my $line (@dest) {
Jiri Slaby 5225f4
		if (!$had_git_commit && $line =~ /^Git-commit: /) {
Jiri Slaby 1dc9b0
			output_refs(\*DEST, @refs);
Jiri Slaby 5225f4
			$had_git_commit = 1;
Jiri Slaby 5225f4
		} elsif ($line =~ /^References: (.*)$/) {
Jiri Slaby 5225f4
			chomp $1;
Jiri Slaby 1dc9b0
			push @refs, (split /[\s,]+/, $1);
Jiri Slaby 5225f4
			next;
Jiri Slaby 5225f4
		}
Jiri Slaby 5225f4
		print DEST $line;
Jiri Slaby 5225f4
	}
Jiri Slaby 5225f4
	close DEST;
Jiri Slaby 1dc9b0
}
Jiri Slaby 5225f4
Jiri Slaby 1dc9b0
my %files;
Jiri Slaby 1dc9b0
my $tags = qr/(?:Git-[Cc]ommit: |Patch-[Mm]ainline: |From )([0-9a-f]{40})/;
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
sub handle_removal($$) {
Jiri Slaby 1dc9b0
	my ($line, $dest) = @_;
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	$line =~ /^([^:]+):($tags)?/;
Jiri Slaby 1dc9b0
	my $file = $1;
Jiri Slaby 1dc9b0
	my $match = $2;
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	$files{$file} = 1;
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	# weird git-commit tag or file may be deleted already
Jiri Slaby 1dc9b0
	return unless (defined $match && -f $file);
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	print colored("\tRemoving $file\n", "yellow");
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	open(PATCH, "<$file") or die "cannot open $file";
Jiri Slaby 1dc9b0
	my %shas = ();
Jiri Slaby 1dc9b0
	my @refs = ();
Jiri Slaby 1dc9b0
	while (my $line = <PATCH>) {
Jiri Slaby 1dc9b0
		chomp $line;
Jiri Slaby 1dc9b0
		$shas{$1} = 1 if ($line =~ /^$tags/);
Jiri Slaby 1dc9b0
		if ($line =~ /^References: (.*)$/) {
Jiri Slaby 1dc9b0
			push @refs, (split /[\s,]+/, $1);
Jiri Slaby 1dc9b0
		}
Jiri Slaby 1dc9b0
	}
Jiri Slaby 1dc9b0
	close PATCH;
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	return unless ($force_removal || scalar(keys %shas) == 1);
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	try {
Jiri Slaby 1dc9b0
		$repo->command('rm', '--', $file);
Jiri Slaby 1dc9b0
	} catch Git::Error::Command with {
Jiri Slaby 1dc9b0
		# sometimes, they are dirty
Jiri Slaby 1dc9b0
	};
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	$series =~ s/
Jiri Slaby 1dc9b0
		(?:
Jiri Slaby 1dc9b0
			# empty or non-comment line
Jiri Slaby 1dc9b0
			(^(?:$|[ \t]*[^ \t#].*)\n)
Jiri Slaby 1dc9b0
			# comment to be deleted
Jiri Slaby 1dc9b0
			[ \t]*\#.*\n
Jiri Slaby 1dc9b0
		)?
Jiri Slaby 1dc9b0
		# file to be deleted
Jiri Slaby 1dc9b0
		[ \t]+\Q$file\E[ \t]*\n
Jiri Slaby 1dc9b0
		/$1 || ""/mex;
Jiri Slaby 1dc9b0
	$series_changed = 1;
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	if (scalar @refs) {
Jiri Slaby 1dc9b0
		if (-f $dest) {
Jiri Slaby 1dc9b0
			push_refs($dest, @refs);
Jiri Slaby 1dc9b0
		} else {
Jiri Slaby 1dc9b0
			print STDERR colored("\tmissed references:\n\t", 'red');
Jiri Slaby 1dc9b0
			output_refs(\*STDERR, @refs);
Jiri Slaby 1dc9b0
		}
Jiri Slaby 1dc9b0
	}
Jiri Slaby 1dc9b0
}
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
foreach my $patch (sort keys %$ids) {
Jiri Slaby 1dc9b0
	my $src = "$patchdir/$patch";
Jiri Slaby 1dc9b0
	my $dest = "$destdir/$patch";
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	print "Handling $patch\n";
Jiri Slaby 1dc9b0
	if (-f $src && ! -f $dest) {
Jiri Slaby 1dc9b0
		move($src, $dest) || die "cannot move $src to $dest";
Jiri Slaby 1dc9b0
		print "\tMoved to $destdir\n";
Jiri Slaby 1dc9b0
		$repo->command('add', $dest);
Jiri Slaby 1dc9b0
		print "\tAdded to GIT\n";
Jiri Slaby 1dc9b0
		unless ($series =~ s/(latest standard kernel patches(?:\n[^\n]+)+\n)\n/$1\t$dest\n\n/) {
Jiri Slaby 1dc9b0
			die "cannot find a place in series.conf to add a patch";
Jiri Slaby 1dc9b0
		}
Jiri Slaby 1dc9b0
		$series_changed = 1;
Jiri Slaby 1dc9b0
	}
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	my $re = join("|", @{$$ids{$patch}});
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	if (scalar @candidates > 0 && $re ne "") {
Jiri Slaby 1dc9b0
		my @found;
Jiri Slaby 1dc9b0
		try {
Jiri Slaby 1dc9b0
			@found = $repo->command('grep', '-E', $re, '--',
Jiri Slaby 1dc9b0
					@candidates) or
Jiri Slaby 1dc9b0
				die "cannot execute git grep";
Jiri Slaby 1dc9b0
		} catch Git::Error::Command with {
Jiri Slaby 1dc9b0
			# not found is OK
Jiri Slaby 1dc9b0
		};
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
		foreach (@found) {
Jiri Slaby 1dc9b0
			next if (/patches\.kernel\.org\//);
Jiri Slaby 1dc9b0
			handle_removal($_, $dest);
Jiri Slaby 1dc9b0
		}
Jiri Slaby 5225f4
	}
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
}
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
if ($series_changed) {
Jiri Slaby 1dc9b0
	seek(SERIES, 0, 0) || die "cannot seek series.conf";
Jiri Slaby 1dc9b0
	truncate(SERIES, 0) || die "cannot truncate series.conf";
Jiri Slaby 1dc9b0
	print SERIES $series;
Jiri Slaby 1dc9b0
}
Jiri Slaby 1dc9b0
close SERIES;
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
foreach my $file (keys %files) {
Jiri Slaby 1dc9b0
	next unless (-e $file);
Jiri Slaby 1dc9b0
Jiri Slaby 1dc9b0
	try {
Jiri Slaby 1dc9b0
		$repo->command_noisy('grep', '-E', $regexp, '--',
Jiri Slaby 1dc9b0
				$file);
Jiri Slaby 1dc9b0
	} catch Git::Error::Command with {
Jiri Slaby 1dc9b0
		# not found is OK
Jiri Slaby 1dc9b0
	};
Jiri Slaby 5225f4
}
Jiri Slaby 5225f4
Jiri Slaby 5225f4
0;