xref: /aosp_15_r20/external/pciutils/maint/release.pm (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
1#!/usr/bin/perl
2# A simple system for making software releases
3# (c) 2003--2011 Martin Mares <[email protected]>
4
5package UCW::Release;
6use strict;
7use warnings;
8use Getopt::Long;
9
10our $verbose = 0;
11
12sub new($$) {
13	my ($class,$basename) = @_;
14	my $s = {
15		"PACKAGE" => $basename,
16		"rules" => [
17			# p=preprocess, s=subst, -=discard
18			'(^|/)(CVS|\.arch-ids|{arch}|\.git|tmp)/' => '-',
19			'\.sw[a-z]$' => '-',
20			'\.(lsm|spec)$' => 'ps',
21			'(^|/)README$' => 's'
22			],
23		"directories" => [
24			],
25		"conditions" => {
26			},
27		"DATE" => `date '+%Y-%m-%d' | tr -d '\n'`,
28		"LSMDATE" => `date '+%y%m%d' | tr -d '\n'`,
29		"distfiles" => [
30			],
31		"archivedir" => $ENV{HOME} . "/archives/sw/$basename",
32		"uploads" => [
33			],
34		# Options
35		"do_test" => 1,
36		"do_patch" => 1,
37		"diff_against" => "",
38		"do_upload" => 1,
39		"do_sign" => 1,
40	};
41	bless $s;
42	return $s;
43}
44
45sub GetVersionFromFile($) {
46	my ($s,$file,$rx) = @_;
47	open F, $file or die "Unable to open $file for version autodetection";
48	while (<F>) {
49		chomp;
50		if (/$rx/) {
51			$s->{"VERSION"} = $1;
52			print "Detected version $1 from $file\n" if $verbose;
53			last;
54		}
55	}
56	close F;
57	if (!defined $s->{"VERSION"}) { die "Failed to auto-detect version"; }
58	return $s->{"VERSION"};
59}
60
61sub GetVersionsFromChangelog($) {
62	my ($s,$file,$rx) = @_;
63	open F, $file or die "Unable to open $file for version autodetection";
64	while (<F>) {
65		chomp;
66		if (/$rx/) {
67			if (!defined $s->{"VERSION"}) {
68				$s->{"VERSION"} = $1;
69				print "Detected version $1 from $file\n" if $verbose;
70			} elsif ($s->{"VERSION"} eq $1) {
71				# do nothing
72			} else {
73				$s->{"OLDVERSION"} = $1;
74				print "Detected previous version $1 from $file\n" if $verbose;
75				last;
76			}
77		}
78	}
79	close F;
80	if (!defined $s->{"VERSION"}) { die "Failed to auto-detect version"; }
81	return $s->{"VERSION"};
82}
83
84sub InitDist($) {
85	my ($s,$dd) = @_;
86	$s->{"DISTDIR"} = $dd;
87	print "Initializing dist directory $dd\n" if $verbose;
88	`rm -rf $dd`; die if $?;
89	`mkdir -p $dd`; die if $?;
90}
91
92sub ExpandVar($$) {
93	my ($s,$v) = @_;
94	if (defined $s->{$v}) {
95		return $s->{$v};
96	} else {
97		die "Reference to unknown variable $v";
98	}
99}
100
101sub CopyFile($$$$) {
102	my ($s,$f,$dir,$action) = @_;
103
104	(my $d = $f) =~ s@(^|/)[^/]*$@@;
105	$d = "$dir/$d";
106	-d $d || `mkdir -p $d`; die if $?;
107
108	my $preprocess = ($action =~ /p/);
109	my $subst = ($action =~ /s/);
110	if ($preprocess || $subst) {
111		open I, "$f" or die "open($f): $?";
112		open O, ">$dir/$f" or die "open($dir/$f): $!";
113		my @ifs = ();	# stack of conditions, 1=satisfied
114		my $empty = 0;	# last line was empty
115		my $is_makefile = ($f =~ /(Makefile|.mk)$/);
116		while (<I>) {
117			if ($subst) {
118				s/@([0-9A-Za-z_]+)@/$s->ExpandVar($1)/ge;
119			}
120			if ($preprocess) {
121				if (/^#/ || $is_makefile) {
122					if (/^#?ifdef\s+(\w+)/) {
123						if (defined ${$s->{"conditions"}}{$1}) {
124							push @ifs, ${$s->{"conditions"}}{$1};
125							next;
126						}
127						push @ifs, 0;
128					} elsif (/^#ifndef\s+(\w+)/) {
129						if (defined ${$s->{"conditions"}}{$1}) {
130							push @ifs, -${$s->{"conditions"}}{$1};
131							next;
132						}
133						push @ifs, 0;
134					} elsif (/^#if\s+/) {
135						push @ifs, 0;
136					} elsif (/^#?endif/) {
137						my $x = pop @ifs;
138						defined $x or die "Improper nesting of conditionals";
139						$x && next;
140					} elsif (/^#?else/) {
141						my $x = pop @ifs;
142						defined $x or die "Improper nesting of conditionals";
143						push @ifs, -$x;
144						$x && next;
145					}
146				}
147				@ifs && $ifs[$#ifs] < 0 && next;
148				if (/^$/) {
149					$empty && next;
150					$empty = 1;
151				} else { $empty = 0; }
152			}
153			print O;
154		}
155		close O;
156		close I;
157		! -x $f or chmod(0755, "$dir/$f") or die "chmod($dir/$f): $!";
158	} else {
159		`cp -a "$f" "$dir/$f"`; die if $?;
160	}
161}
162
163sub GenPackage($) {
164	my ($s) = @_;
165	$s->{"PKG"} = $s->{"PACKAGE"} . "-" . $s->{"VERSION"};
166	my $dd = $s->{"DISTDIR"};
167	my $pkg = $s->{"PKG"};
168	my $dir = "$dd/$pkg";
169	print "Generating $dir\n";
170
171	FILES: foreach my $f (`find . -type f`) {
172		chomp $f;
173		$f =~ s/^\.\///;
174		my $action = "";
175		my @rules = @{$s->{"rules"}};
176		while (@rules) {
177			my $rule = shift @rules;
178			my $act = shift @rules;
179			if ($f =~ $rule) {
180				$action = $act;
181				last;
182			}
183		}
184		($action =~ /-/) && next FILES;
185		print "$f ($action)\n" if $verbose;
186		$s->CopyFile($f, $dir, $action);
187	}
188
189	foreach my $d (@{$s->{"directories"}}) {
190		`mkdir -p $dir/$d`; die if $?;
191	}
192
193	if (-f "$dir/Makefile") {
194		print "Cleaning up\n";
195		`cd $dir && make distclean >&2`; die if $?;
196	}
197
198	print "Creating $dd/$pkg.tar.gz\n";
199	my $tarvv = $verbose ? "vv" : "";
200	`cd $dd && tar cz${tarvv}f $pkg.tar.gz $pkg >&2`; die if $?;
201	push @{$s->{"distfiles"}}, "$dd/$pkg.tar.gz";
202
203	if ($s->{'do_sign'}) {
204		print "Signing package\n";
205		system "gpg", "--armor", "--detach-sig", "$dd/$pkg.tar.gz";
206		die if $?;
207		rename "$dd/$pkg.tar.gz.asc", "$dd/$pkg.tar.gz.sign" or die "No signature produced!?\n";
208		push @{$s->{"distfiles"}}, "$dd/$pkg.tar.gz.sign";
209	}
210
211	my $adir = $s->{"archivedir"};
212	my $afile = "$adir/$pkg.tar.gz";
213	print "Archiving to $afile\n";
214	-d $adir or `mkdir -p $adir`;
215	`cp $dd/$pkg.tar.gz $afile`; die if $?;
216
217	return $dir;
218}
219
220sub GenFile($$) {
221	my ($s,$f) = @_;
222	my $sf = $s->{"DISTDIR"} . "/" . $s->{"PKG"} . "/$f";
223	my $df = $s->{"DISTDIR"} . "/$f";
224	print "Generating $df\n";
225	`cp $sf $df`; die if $?;
226	push @{$s->{"distfiles"}}, $df;
227}
228
229sub ParseOptions($) {
230	my ($s) = @_;
231	GetOptions(
232		"verbose!" => \$verbose,
233		"test!" => \$s->{"do_test"},
234		"patch!" => \$s->{"do_patch"},
235		"diff-against=s" => \$s->{"diff_against"},
236		"upload!" => \$s->{"do_upload"},
237		"sign!" => \$s->{"do_sign"},
238	) || die "Syntax: release [--verbose] [--test] [--nopatch] [--diff-against=<version>] [--noupload] [--nosign]";
239}
240
241sub Test($) {
242	my ($s) = @_;
243	my $dd = $s->{"DISTDIR"};
244	my $pkg = $s->{"PKG"};
245	my $log = "$dd/$pkg.log";
246	print "Doing a test compilation\n";
247	`( cd $dd/$pkg && make ) >$log 2>&1`;
248	die "There were errors. Please inspect $log" if $?;
249	`grep -q [Ww]arning $log`;
250	$? or print "There were warnings! Please inspect $log.\n";
251	print "Cleaning up\n";
252	`cd $dd/$pkg && make distclean`; die if $?;
253}
254
255sub MakePatch($) {
256	my ($s) = @_;
257	my $dd = $s->{"DISTDIR"};
258	my $pkg1 = $s->{"PKG"};
259	my $oldver;
260	if ($s->{"diff_against"} ne "") {
261		$oldver = $s->{"diff_against"};
262	} elsif (defined $s->{"OLDVERSION"}) {
263		$oldver = $s->{"OLDVERSION"};
264	} else {
265		print "WARNING: No previous version known. No patch generated.\n";
266		return;
267	}
268	my $pkg0 = $s->{"PACKAGE"} . "-" . $oldver;
269
270	my $oldarch = $s->{"archivedir"} . "/" . $pkg0 . ".tar.gz";
271	-f $oldarch or die "MakePatch: $oldarch not found";
272	print "Unpacking $pkg0 from $oldarch\n";
273	`cd $dd && tar xzf $oldarch`; die if $?;
274
275	my $diff = $s->{"PACKAGE"} . "-" . $oldver . "-" . $s->{"VERSION"} . ".diff.gz";
276	print "Creating a patch from $pkg0 to $pkg1: $diff\n";
277	`cd $dd && diff -ruN $pkg0 $pkg1 | gzip >$diff`; die if $?;
278	push @{$s->{"distfiles"}}, "$dd/$diff";
279}
280
281sub Upload($) {
282	my ($s) = @_;
283	foreach my $u (@{$s->{"uploads"}}) {
284		my $url = $u->{"url"};
285		print "Upload to $url :\n";
286		my @files = ();
287		my $filter = $u->{"filter"} || ".*";
288		foreach my $f (@{$s->{"distfiles"}}) {
289			if ($f =~ $filter) {
290				print "\t$f\n";
291				push @files, $f;
292			}
293		}
294		print "<confirm> "; <STDIN>;
295		if ($url =~ m@^scp://([^/]+)(.*)@) {
296			$, = " ";
297			my $host = $1;
298			my $dir = $2;
299			$dir =~ s@^/~@~@;
300			$dir =~ s@^/\./@@;
301			my $cmd = "scp @files $host:$dir\n";
302			`$cmd`; die if $?;
303		} elsif ($url =~ m@ftp://([^/]+)(.*)@) {
304			my $host = $1;
305			my $dir = $2;
306			open FTP, "|ftp -v $host" or die;
307			print FTP "cd $dir\n";
308			foreach my $f (@files) {
309				(my $ff = $f) =~ s@.*\/([^/].*)@$1@;
310				print FTP "put $f $ff\n";
311			}
312			print FTP "bye\n";
313			close FTP;
314			die if $?;
315		} else {
316			die "Don't know how to handle this URL scheme";
317		}
318	}
319}
320
321sub Dispatch($) {
322	my ($s) = @_;
323	$s->Test if $s->{"do_test"};
324	$s->MakePatch if $s->{"do_patch"};
325	$s->Upload if $s->{"do_upload"};
326}
327
3281;
329