Blob Blame History Raw
#!/usr/bin/perl -w
use strict;
use File::Basename qq(basename);
use File::Copy qq(move);

my $tmpdir = $ENV{TMPDIR} || "/tmp";

die "Has to be run from the kernel-source GIT dir" if (! -d ".git");

if (scalar @ARGV < 2) {
        print "Usage: $0 patch ids_file [nonzero_to_force_removal]\n";
        exit 1;
}

open(SERIES, "+<series.conf") || die "cannot open series.conf";
my $series;
my $series_changed = 0;
{
	local $/;
	$series = <SERIES>;
}

my $patch = $ARGV[0];
my $idsfile = $ARGV[1];
my $force_removal = $ARGV[2] || 0;
my $destdir = "patches.kernel.org/";
my $dest = $destdir . basename $patch;
mkdir $destdir if (! -d $destdir);

if (-f $patch && ! -f $dest) {
	move($patch, $dest) || die "cannot move $patch to $dest";
	print "Moved $patch to $dest\n";
	system("git add $dest");
	print "Added $dest to GIT\n";
	unless ($series =~ s/(latest standard kernel patches(?:\n[^\n]+)+\n)\n/$1\t$dest\n\n/) {
		die "cannot find a place in series.conf to add the patch";
	}
	$series_changed = 1;
}

open(IDS, "<$idsfile") || die "cannot open $idsfile";
my $regexp = join "|", map { chomp; $_ } <IDS>;
close IDS;

my @references = ();
my %files;

if ($regexp eq "") {
	print STDERR "empty regexp computed? Skipping patches removal...\n";
} else {

	open(GIT, "git grep -E '$regexp' patches.*|") ||
		die "cannot execute git";

	my $tags = qr/(?:Git-[Cc]ommit: |Patch-[Mm]ainline: |From )([0-9a-f]{40})/;

	while (<GIT>) {
		chomp;
		next if (/patches\.kernel\.org\/patch-[0-9]/);
		/^([^:]+):($tags)?/;
		my $file = $1;
		# file may be deleted already
		if (defined $2 && -f $file) {
			open(PATCH, "<$file") || die "cannot open $file";
			my %shas = ();
			my @refs = ();
			while (my $line = <PATCH>) {
				chomp $line;
				$shas{$1} = 1 if ($line =~ /^$tags/);
				if ($line =~ /^References: (.*)$/) {
					push @refs, (split /[\s,]+/, $1);
				}
			}
			close PATCH;
			if ($force_removal || scalar(keys %shas) == 1) {
				push @references, @refs;
				system("git rm $file");
				$series =~ s/
					(?:
						# empty or non-comment line
						(^(?:$|[ \t]*[^ \t#].*)\n)
						# comment to be deleted
						[ \t]*\#.*\n
					)?
					# file to be deleted
					[ \t]+\Q$file\E[ \t]*\n
					/$1 || ""/mex;
				$series_changed = 1;
			}
		}
		$files{$file} = 1;
	}

	close GIT;
}

if ($series_changed) {
	seek(SERIES, 0, 0) || die "cannot seek series.conf";
	truncate(SERIES, 0) || die "cannot truncate series.conf";
	print SERIES $series;
}
close SERIES;

sub output_refs($@) {
	my ($fh, @refs) = @_;
	my %uniq = map {
		s/fate/FATE/i;
		s/bnc/bnc/i;
		$_, 1
	} @refs;
	print $fh "References: ", join(' ', sort keys %uniq), "\n";
}

if (scalar @references) { REFS: {
	unless (-f $dest) {
		print STDERR "missed references:\n";
		output_refs(\*STDERR, @references);
		last REFS;
	}
	open(DEST, "<$dest") || die "cannot open $dest for reading";
	my @dest = <DEST>;
	close DEST;
	open(DEST, ">$dest") || die "cannot open $dest for writing";
	my $had_git_commit = 0;
	foreach my $line (@dest) {
		if (!$had_git_commit && $line =~ /^Git-commit: /) {
			output_refs(\*DEST, @references);
			$had_git_commit = 1;
		} elsif ($line =~ /^References: (.*)$/) {
			chomp $1;
			push @references, (split /[\s,]+/, $1);
			next;
		}
		print DEST $line;
	}
	undef @dest;
	close DEST;
}}

foreach my $file (keys %files) {
	if (-e $file) {
		system("git grep -E '$regexp' $file");
	}
}

0;