Home Home > GIT Browse
summaryrefslogtreecommitdiff
blob: e188eab603997d49703198d9c9f16f7f4881cb00 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/usr/bin/perl -w
use strict;
use Error qw(:try);
use File::Copy qq(move);
use Git;
use Storable qq(retrieve);
use Term::ANSIColor qw(colored);

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

my $repo = Git->repository;

if (scalar @ARGV < 1) {
        print "Usage: $0 patches_dir [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 $patchdir = $ARGV[0];
my $idsfile = "$patchdir/ids";
my $force_removal = $ARGV[1] || 0;
my $destdir = "patches.kernel.org";
mkdir $destdir if (! -d $destdir);

my $ids = retrieve($idsfile) or die "cannot read $idsfile";
my $regexp = join "|", map @$_, values %$ids;
my @candidates = ();

if ($regexp eq "") {
	print STDERR colored("empty regexp computed? Skipping patches removal...\n", 'yellow');
} else {
	try {
		@candidates = $repo->command('grep', '-El', $regexp, '--',
			'patches.*') or die "cannot execute git grep";
	} catch Git::Error::Command with {
		# not found is OK
	};
}

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";
}

sub push_refs($@) {
	my ($dest, @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, @refs);
			$had_git_commit = 1;
		} elsif ($line =~ /^References: (.*)$/) {
			chomp $1;
			push @refs, (split /[\s,]+/, $1);
			next;
		}
		print DEST $line;
	}
	close DEST;
}

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

sub handle_removal($$) {
	my ($line, $dest) = @_;

	$line =~ /^([^:]+):($tags)?/;
	my $file = $1;
	my $match = $2;

	$files{$file} = 1;

	# weird git-commit tag or file may be deleted already
	return unless (defined $match && -f $file);

	print colored("\tRemoving $file\n", "yellow");

	open(PATCH, "<$file") or 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;

	return unless ($force_removal || scalar(keys %shas) == 1);

	try {
		$repo->command('rm', '--', $file);
	} catch Git::Error::Command with {
		# sometimes, they are dirty
	};

	$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;

	if (scalar @refs) {
		if (-f $dest) {
			push_refs($dest, @refs);
		} else {
			print STDERR colored("\tmissed references:\n\t", 'red');
			output_refs(\*STDERR, @refs);
		}
	}
}

foreach my $patch (sort keys %$ids) {
	my $src = "$patchdir/$patch";
	my $dest = "$destdir/$patch";

	print "Handling $patch\n";
	if (-f $src && ! -f $dest) {
		move($src, $dest) || die "cannot move $src to $dest";
		print "\tMoved to $destdir\n";
		$repo->command('add', $dest);
		print "\tAdded 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 a patch";
		}
		$series_changed = 1;
	}

	my $re = join("|", @{$$ids{$patch}});

	if (scalar @candidates > 0 && $re ne "") {
		my @found;
		try {
			@found = $repo->command('grep', '-E', $re, '--',
					@candidates) or
				die "cannot execute git grep";
		} catch Git::Error::Command with {
			# not found is OK
		};

		foreach (@found) {
			next if (/patches\.kernel\.org\//);
			handle_removal($_, $dest);
		}
	}

}

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;

foreach my $file (keys %files) {
	next unless (-e $file);

	try {
		$repo->command_noisy('grep', '-E', $regexp, '--',
				$file);
	} catch Git::Error::Command with {
		# not found is OK
	};
}

0;