blob: 02acd8ac772e187f98f078e49dbdbdf682729187 [file] [log] [blame]
lahiker427a45dc12008-10-01 00:29:30 +00001#! /usr/bin/perl -w
2
3# pkgwrite 0.0.8: Build native packages from source code
4# and pkgwriteinfo files.
5#
6# This file contains POD documentation: try `perldoc pkgwrite' for help.
7#
8# Copyright Dave Benson <daveb@ffem.org>, 2000-2001.
9
10# Requirements:
11# perl 5.004 or higher,
12# and native packaging tools for the output packages, that is:
13# For redhat `rpm'. And for debian `dpkg' and `dpkg-buildpackage'.
14
15# pkgwrite
16#
17# This program is free software; you can redistribute it and/or
18# modify it under the terms of the GNU General Public
19# License as published by the Free Software Foundation; either
20# version 2 of the License, or (at your option) any later version.
21#
22# This program is distributed in the hope that it will be useful,
23# but WITHOUT ANY WARRANTY; without even the implied warranty of
24# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25# General Public License for more details.
26#
27# You should have received a copy of the GNU General Public
28# License along with this program; if not, write to the Free Software
29# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30#
31# ---
32#
33# This software may also be licensed under the terms of
34# the GNU Lesser General Public License, version 2 or higher.
35# (This is so that the pkgwrite script may be legally included
36# with LGPL'd software.)
37#
38# ---
39#
40# Furthermore, the packages and intermediary files generated
41# with pkgwrite are specifically excluded from the terms of
42# this license. Hence, pkgwrite adds no additional restrictions to
43# the package's licensing, but they must comply with the
44# licensing on the other source code, libraries and tools used
45# to generate the package.
46
47# Finally, this contains the rpmrc that is distributed with
48# rpm 4.0: CVS entry: rpmrc.in 2.28.2.2 2000/09/13.
49# That file had no copyright info. The RPM source code,
50# like pkgwrite, is licenced under both the LGPL and the GPL.
51
52require 5.004;
53use Carp;
54use Config; # for signal names
55use Symbol qw(gensym);
56
57# Table of Contents of the Source Code.
58# Section 0: Initialization & Configuration.
59# Section 1: Helper functions.
60# Section 2: parse_pkgwriteinfo_file: Return package information.
61# Section 3: Verify that a package is correctly formed.
62# Section 4: ChangeLog parsing code.
63# Section 5: Redhat tape.
64# Section 6: Debian tape.
65# Section 7: High-level API: Make a package from a tarball.
66# Section 8: Usage message.
67# Section 9: Main program.
68# Section 10: POD Documention.
69
70
71#=====================================================================
72# Section 0: Initialization & Configuration.
73#=====================================================================
74# --- function prototypes ---
75sub dump_list ($); # print a builtin table to stdout
76sub initialize_packaging_tables (); # redhat/debian package mgnt specifics
77sub initialize_signal_tables (); # signal number to id mappings
78sub add_automatic_conflicts ($); # add conflicts if file sets intersect
79
80# --- global initialization ---
81$initial_dir = `pwd`;
82chomp ($initial_dir);
83initialize_packaging_tables ();
84initialize_signal_tables ();
85$PKGWRITE_VERSION = '0.0.8';
86
87# --- configuration ---
88# set to 0 for debugging: don't delete working directories.
89$do_cleanup = 1;
90$do_cleanup = $ENV{DO_CLEANUP} if defined($ENV{DO_CLEANUP});
91
92# force the changelog to refer to this exact version.
93$strict_changelog_checking = 1;
94
95# whether to perform an extra packaging sanity test phase.
96$do_sanity_check = 1;
97
98# for the changelog, which distribution should be listed?
99# XXX: hm, what if a single package changes dist? look at
100# packages in stable for an example, i guess... (actually
101# this isn't a problem if you *always* use pkgwrite,
102# but that's annoying.)
103$debian_dist = 'unstable';
104
105# options to pass to ./configure (these differ due on different
106# distros due to different standard directories -- most likely,
107# the redhat usage will converge to the debian/fhsstnd.)
108@common_config_flags = ( '--sysconfdir=/etc',
109 '--prefix=/usr',
110 '--quiet' );
111$redhat_config_flags = join(' ',
112 @common_config_flags
113 );
114$debian_config_flags = join(' ',
115 @common_config_flags,
116 '--mandir=/usr/share/man',
117 '--infodir=/usr/share/info',
118 '--datadir=/usr/share');
119
120# Directories where shared libraries are kept: if we install a library
121# in any of these directories we need to run `ldconfig'.
122@ldconfig_dirs = ( '/usr/lib', '/lib', '/usr/X11/lib',
123 '/usr/X11R6/lib', '/usr/lib/X11' );
124
125# --- configuration ---
126# gzip/gunzip programs + arguments that can act as filters.
127$gzip = 'gzip -9 -c -';
128$gunzip = 'gzip -d -c -';
129
130# flags which cause `tar' to extract a file to stdout from an archive.
131# usage: tar $untar_to_stdout ARCHIVE FILE
132# or zcat ARCHIVE | tar $untar_to_stdout - FILE
133# (perhaps this isn't portable?)
134$untar_to_stdout = "xOf";
135
136# Location of the optional system-wide rpmrc file.
137$system_rpmrc_file = "/var/lib/rpm/rpmrc";
138
139# Standard build architectures. Yes, hardcoding this sucks...
140$default_redhat_archs = "i386 alpha sparc sparc64";
141
142# --- configure-time substitutions (!) ---
143# The RHS of these assignments is a autoconf-substitution;
144# in pkgwrite.in there are autoconf AC_SUBST()d variables,
145# and in pkgwrite these is a 0 or 1 to indicate
146# whether `configure' detected a suitable version of these
147# packaging systems.
148$has_rpm_support = 1;
149$has_dpkg_support = 1;
150
151# --- build hash tables of fixed strings ---
152sub initialize_packaging_tables ()
153{
154 # --- Debian packaging values ---
155 # valid values for the Priority: field.
156 for (qw(required important standard optional extra))
157 {
158 $DPKG_PRIORITY_LEVELS{$_} = $_;
159 }
160
161 # valid values for the Section: field.
162 for (qw(admin base comm contrib devel doc editors electronics
163 games graphics hamradio interpreters libs mail
164 math misc net news non-free oldlibs otherosfs
165 shells sound tex text utils web x11))
166 {
167 $DPKG_SECTIONS{$_} = $_;
168 }
169
170 # --- Redhat packaging values ---
171 for ('Amusements/Games', 'Amusements/Graphics', 'Applications/Archiving',
172 'Applications/Communications', 'Applications/Databases',
173 'Applications/Editors', 'Applications/Emulators',
174 'Applications/Engineering', 'Applications/File',
175 'Applications/Internet', 'Applications/Multimedia',
176 'Applications/Productivity', 'Applications/Publishing',
177 'Applications/System', 'Applications/Text',
178 'Development/Debuggers', 'Development/Languages',
179 'Development/Libraries', 'Development/System',
180 'Development/Tools', 'Documentation',
181 'System Environment/Base', 'System Environment/Daemons',
182 'System Environment/Kernel', 'System Environment/Libraries',
183 'System Environment/Shells', 'User Interface/Desktops',
184 'User Interface/X', 'User Interface/X Hardware Support')
185 {
186 $RPM_GROUPS{lc($_)} = $_;
187 }
188}
189
190# initialize_signal_tables: Build a lookup-table mapping from
191# signal number to the signal's name (the part which follows
192# SIG in the C macro: for example: HUP, KILL, TERM, SEGV, ABRT, etc)
193# based on perl's configuration.
194sub initialize_signal_tables ()
195{
196 defined $Config{sig_name} || die "No sigs?";
197 my $i = 0;
198 foreach $name (split(' ', $Config{sig_name}))
199 {
200 #$signo{$name} = $i;
201 $signame[$i] = $name;
202 $i++;
203 }
204}
205
206
207#=====================================================================
208# Section 1: Helper functions.
209#=====================================================================
210# --- run: run a program or die ---
211sub run($)
212{
213 my $command = $_[0];
214 print STDERR "<PKGWRITE> running: $command\n";
215 my $rv = system ($command);
216 if ($rv != 0)
217 {
218 if ($rv < 256)
219 {
220 die "command `$command' killed by signal " . $signame[$rv];
221 }
222 else
223 {
224 die "command `$command' exited with status " . ($rv >> 8);
225 }
226 }
227}
228
229# safe_mkdir: make a directory if it doesn't exist,
230# or die with an error message.
231sub safe_mkdir($)
232{
233 croak "safe_mkdir(undef) called" unless defined $_[0];
234 mkdir ($_[0], 0755) or croak "mkdir($_[0]) failed";
235}
236
237# check_field(OBJECT, HASH-ENTRY, FIELD)
238#
239# Verify that OBJECT->{HASH-ENTRY} is value, or die with a diagnostic.
240sub check_field($$$)
241{
242 if (!defined($_[0]->{$_[1]}))
243 {
244 my $type = $_[0]->{type};
245 my $name = $_[0]->{name};
246 $name = "(unknown name)" unless defined $name;
247 $type = "packaging" unless defined $type;
248 die "field `$_[2]' required in $type for $name";
249 }
250}
251
252# undef_or_empty: Test if an array reference is undefined or of zero length.
253sub undef_or_empty ($)
254{
255 return 1 unless defined $_[0];
256 my $array = $_[0];
257 return 1 unless scalar (@$array);
258 return 0;
259}
260
261# write_entries: Write out optional field entries from a hash-table $object.
262# $field_list and $hash_entries are parallel lists.
263sub write_entries ($$$$)
264{
265 my ($fh, $object, $field_list, $hash_entries) = @_;
266 my $count = scalar(@$field_list);
267 my $i;
268 for ($i = 0; $i < $count; $i++)
269 {
270 my $hentry = $hash_entries->[$i];
271 my $fname = $field_list->[$i];
272 if (defined($object->{$hentry}))
273 {
274 print $fh $fname, ": ", $object->{$hentry}, "\n";
275 }
276 }
277}
278
279# make a full path from a possibly relative path specified
280# on the command line.
281sub make_absolute($)
282{
283 if ($_[0] !~ m,^/,)
284 {
285 return "$initial_dir/" . $_[0];
286 }
287 else
288 {
289 return $_[0];
290 }
291}
292
293# write_list_to_file(\@LIST, $FNAME)
294# Write each element of LIST on a separate line to a file named $FNAME.
295sub write_list_to_file ($$)
296{
297 my ($list, $fname) = @_;
298 open Z, ">$fname" or die "write_list_to_file: couldn't create $fname";
299 for (@$list)
300 {
301 print Z "$_\n";
302 }
303 close Z;
304}
305
306# make_file: Create a file with the contents of a given string.
307sub make_file ($$)
308{
309 my ($fname, $contents) = @_;
310 open Z, ">$fname" or die "make_file: couldn't create $fname";
311 print Z $contents;
312 close Z;
313}
314
315# maybe_print_make_dirs(\%MADE_DIRECTORIES, $FILE_HANDLE, $DIRECTORY):
316#
317# Print a script to make the directories and subdirectories
318# of $dir, recording made directories in MADE_DIRECTORIES
319# to avoid duplication.
320sub maybe_print_make_dirs ($$$)
321{
322 my ($made_dirs, $fh, $dir) = @_;
323 my $cur = '';
324 $cur = ($dir =~ s,^/+,,) ? '' : '.';
325 for (split /\//, $dir)
326 {
327 $cur .= "/$_";
328 if (!defined($made_dirs->{$cur}))
329 {
330 print $fh "\ttest -d $cur || mkdir $cur\n";
331 $made_dirs->{$cur} = 1;
332 }
333 }
334}
335
336# string_to_boolean: take the normal yes/no/false/true/0/1 mess
337# and output 0, 1, or undef.
338sub string_to_boolean ($)
339{
340 my $s = $_[0];
341 return 0 if ($s eq '0'
342 || $s eq 'f' || $s eq 'F'
343 || $s eq 'n' || $s eq 'N'
344 || $s eq 'no' || $s eq 'NO'
345 || $s eq 'false' || $s eq 'FALSE');
346 return 1 if ($s eq '1'
347 || $s eq 't' || $s eq 'T'
348 || $s eq 'y' || $s eq 'Y'
349 || $s eq 'yes' || $s eq 'YES'
350 || $s eq 'true' || $s eq 'TRUE');
351 return undef;
352}
353
354# Read lines from FILE-HEADER until a non-empty line is encountered.
355# Return undef if no nonempty line is encountered.
356sub skip_empty_lines ($)
357{
358 my $fh = $_[0];
359 while (<$fh>)
360 {
361 chomp;
362 return $_ if /\S/;
363 }
364 return undef;
365}
366
367# From the basename of a manpage (eg zshall.1.gz or exit.3tcl)
368# find the man-section (resp. 1 or 3).
369sub get_manpage_section ($)
370{
371 my $b = $_[0];
372 $b =~ s/\.gz$//;
373 $b =~ s/\.bz2$//;
374 $b =~ s/\.Z$//;
375 $b =~ s/^.*\.//;
376 if ($b =~ /^(\d+)/)
377 {
378 return $b;
379 }
380 die "Couldn't figure out what man-section $_[0] was in";
381}
382
383
384
385# --- Creating and destroying the temporary working area ---
386sub get_tmp_dir() {
387 return $ENV{'TMPDIR'} || $ENV{'TEMPDIR'} || "/tmp";
388}
389sub get_work_dir ()
390{
391 # Make a working directory.
392 if (!defined($global_work_dir))
393 {
394 $global_work_dir = get_tmp_dir() . "/mkpkg-$$-$ENV{USER}";
395 mkdir ($global_work_dir, 0755)
396 or die "couldn't make tmp directory $global_work_dir";
397 }
398 $SIG{__DIE__} = sub { remove_work_dir (); };
399 return $global_work_dir;
400}
401
402sub remove_work_dir ()
403{
404 if (defined($global_work_dir))
405 {
406 $SIG{__DIE__} = sub {};
407 run ("rm -rf $global_work_dir") if $do_cleanup;
408 undef($global_work_dir);
409 }
410}
411
412
413
414#=====================================================================
415# Section 2: parse_pkgwriteinfo_file: Return package information.
416#=====================================================================
417# DATA STRUCTURES
418#
419# The return value is a Package, a hash-table with the following fields:
420# name => NAME-OF-PACKAGE
421# output_name => NAME-OF-PACKAGE [sometimes mangled for co-installation]
422# section => DEBIAN-SECTION
423# group => REDHAT-GROUP
424# priority => DEBIAN-PRIORITY
425# author => AUTHOR
426# builds => \@BUILDS
427# targets => \@TARGETS
428# url => URL
429# summary => SUMMARY
430# license => LICENSE
431# version => UPSTREAM-VERSION
432# release => RELEASE
433# packager => PACKAGER_FULLNAME
434# packager_email = PACKAGER_EMAIL
435# changelog => CHANGELOG-FILE
436# fullname => PACKAGE-VERSION-RELEASE
437# upstream_fullname => PACKAGE-VERSION
438# needs_noarch => [01]
439# needs_arch_specific => [01]
440# upstream_is_packager => [01] Whether the packager and author are the same.
441# (The default is 1, meaning TRUE)
442# changelog_file => changelog.gz or changelog.Debian.gz
443#
444# Each Target's information is a hash-table with the following fields:
445# name => TARGET-NAME [without PACKAGE-, or {MAIN}]
446# summary => SUMMARY
447# description => DESCRIPTION
448# section => DEBIAN-SECTION [default to package's section]
449# group => REDHAT-GROUP [default to package's group]
450# files => \@PATTERNS
451# conffiles => \@PATTERNS
452# manpages => \@MANPAGES [just the basename -- no path]
453# arch_indep => [01] [whether this target contains compiled code]
454# build_name => BUILD-NAME
455# build => BUILD
456# installed_docs => \@DOCS [docs the package installs]
457# source_docs => \@DOCS [docs from the package tarball]
458#
459# Each Build's information is a hash-table with the following fields:
460# name => BUILD-NAME [or {MAIN} for the default]
461# configure_flags => FLAGS [addl flags to pass to the configure script]
462# configure_envars => ENVARS [NAME=VALUE pairs...]
463# make_flags => FLAGS [addl flags to pass to make & make install]
464# build_flags => FLAGS [addl flags to pass to make]
465# install_flags => FLAGS [addl flags to pass to make install]
466# extra_build_targets => \@T [addl `make' targets to build]
467# extra_install_targets => \@T [addl `make' targets to install]
468
469sub parse_pkgwriteinfo_file($)
470{
471 open PINFO, "$_[0]" or die "couldn't open $_[0]";
472 my $package;
473 my @lines = ();
474
475 # ---
476 # Break the line up into sections starting with Target, Package, Build,
477 # and call the appropriate parser on those blocks,
478 # which are functions named handle_{target,package,build}.
479 #
480 # Each of those functions takes a list of lines as arguments
481 # and returns a hash-table reference of the appropriate {'type'}.
482
483 # Parse the first block, which is always Package:.
484 while (<PINFO>)
485 {
486 # Ignore whitespace.
487 next if /^\s*$/;
488
489 # Ignore comments.
490 next if /^\s*#/;
491
492 chomp;
493 $line = $_;
494 if ($line =~ /^Target:/ || $line =~ /^Build:/)
495 {
496 # Clear out the current lines as the main package entry.
497 $package = handle_package (@lines);
498 die unless defined $package;
499
500 # This line begins the new block.
501 @lines = ( $line );
502 last;
503 }
504 else
505 {
506 push @lines, $_;
507 }
508 }
509 while (<PINFO>)
510 {
511 # Ignore whitespace.
512 next if /^\s*$/;
513
514 # Ignore comments.
515 next if /^\s*#/;
516
517 chomp;
518 $line = $_;
519
520 # Are we are a block boundary?
521 if (($line =~ /^Target:/) || ($line =~ /^Build:/))
522 {
523 # What type of block did we just complete?
524 if ($lines[0] =~ /^Target:/)
525 {
526 # Parse the Target.
527 my $target = handle_target (@lines);
528 die unless defined $target;
529 $target->{package} = $package;
530 my $targets = $package->{targets};
531 push @$targets, $target;
532 }
533 else
534 {
535 # Parse the Build.
536 my $build = handle_build (@lines);
537 die unless defined $build;
538 $build->{package} = $package;
539 my $builds = $package->{builds};
540 push @$builds, $build;
541
542 # Compute the name of the src rpm, which will also
543 # be the prefix for all the other packages.
544 my $name = $package->{output_name};
545 $name .= ("-" . $build->{name}) if ($build->{name} ne '{MAIN}');
546 $build->{package_name} = $name;
547 $build->{package} = $package;
548 }
549 @lines = ( $line );
550 next;
551 }
552 else
553 {
554 push @lines, $line;
555 }
556 }
557 if (scalar (@lines) > 0)
558 {
559 die "The last block in a pkgwriteinfo file must always be a target"
560 unless ($lines[0] =~ /^Target:/i);
561
562 $target = handle_target (@lines);
563 die unless defined $target;
564 my $targets = $package->{targets};
565 push @$targets, $target;
566 }
567 {
568 my $targets = $package->{targets};
569 for my $target (@$targets)
570 {
571 for my $inherited (qw(group))
572 {
573 if (!defined($target->{$inherited}))
574 {
575 $target->{$inherited} = $package->{$inherited}
576 }
577 }
578 }
579 }
580 my %BUILDS_BY_NAME = ();
581 {
582 my $targets = $package->{targets};
583 my $builds = $package->{builds};
584 die "malformed package: no targets" if scalar (@$targets) == 0;
585 die "malformed package: no builds" if scalar (@$builds) == 0;
586 for (@$builds)
587 {
588 $BUILDS_BY_NAME{$_->{name}} = $_;
589 }
590 my $needs_noarch = 0;
591 my $needs_arch_specific = 0;
592 for my $target (@$targets)
593 {
594 my $build = $target->{build_name};
595 my $name = $target->{name};
596 $build = '{MAIN}' unless defined $build;
597 if (!defined $BUILDS_BY_NAME{$build})
598 {
599 die "no build for target $name named $build";
600 }
601 if ($target->{arch_indep})
602 {
603 $needs_noarch = 1;
604 }
605 else
606 {
607 $needs_arch_specific = 1;
608 }
609 $target->{build} = $BUILDS_BY_NAME{$build};
610 $target->{package_name} = $package->{output_name};
611 $target->{package} = $package;
612 if ($name ne '{MAIN}')
613 {
614 $target->{package_name} .= "-$name";
615 }
616 }
617 $package->{needs_noarch} = $needs_noarch;
618 $package->{needs_arch_specific} = $needs_arch_specific;
619 }
620
621 # Add conflicts based purely on `Files:' lists.
622 add_automatic_conflicts ($package);
623 return $package;
624}
625
626# --- handle_package: create a $package from a pkgwrite intro ---
627sub handle_package
628{
629 my $package = {};
630 $package->{type} = 'package';
631 $package->{targets} = [];
632 $package->{builds} = [];
633 $package->{upstream_is_packager} = 1;
634 my $in_description = 0;
635 for (@_)
636 {
637 if ($in_description)
638 {
639 if (/^\S/)
640 {
641 $in_description = 0;
642 }
643 else
644 {
645 s/^\s//;
646 $package->{description} .= "\n$_";
647 next;
648 }
649 }
650
651 if (/^Package:\s*(.*)/)
652 {
653 $package->{name} = $1;
654 }
655 elsif (/^Output-Package:\s*(.*)/)
656 {
657 $package->{output_name} = $1;
658 }
659 elsif (/^Section:\s*(.*)/)
660 {
661 $package->{section} = $1;
662 }
663 elsif (/^Group:\s*(.*)/)
664 {
665 $package->{group} = $1;
666 }
667 elsif (/^Priority:\s*(.*)/)
668 {
669 $package->{priority} = $1;
670 }
671 elsif (/^Home-Page:\s*(.*)/)
672 {
673 $package->{home_page} = $1;
674 }
675 elsif (/^Source-Url:\s*(.*)/)
676 {
677 $package->{url} = $1;
678 }
679 elsif (/^Version:\s*(.*)/)
680 {
681 $package->{version} = $1;
682 }
683 elsif (/^Release:\s*(.*)/)
684 {
685 $package->{release} = $1;
686 }
687 elsif (/^Change[lL]og:\s*(.*)/)
688 {
689 $package->{changelog} = $1;
690 }
691 elsif (/^Author:\s*(.*)/)
692 {
693 my $author = $1;
694 $package->{authors} = [] unless defined $package->{authors};
695 my $authors = $package->{authors};
696 push @$authors, $author;
697 }
698 elsif (/^Description:\s*(.*)/)
699 {
700 $package->{description} = $1;
701 $in_description = 1;
702 }
703 elsif (/^Synopsis:\s*(.*)/)
704 {
705 $package->{summary} = $1;
706 }
707 elsif (/^License:\s*(.*)/)
708 {
709 $package->{license} = $1;
710 }
711 elsif (/^Packager:\s*(.*)/)
712 {
713 $package->{packager} = $1;
714 }
715 elsif (/^Packager-Email:\s*(.*)/)
716 {
717 $package->{packager_email} = $1;
718 }
719 elsif (/^Upstream-is-Packager:\s*(.*)/i)
720 {
721 $package->{upstream_is_packager} = $1;
722 }
723 else
724 {
725 chomp;
726 die "unparsable line in pkgwriteinfo file: $_";
727 }
728 }
729
730 $package->{changelog_file}
731 = $package->{upstream_is_packager} ? "changelog.gz" : "changelog.Debian.gz";
732
733 # check that all the needed fields have been found.
734 check_field ($package, 'name', 'Package');
735 check_field ($package, 'section', 'Section');
736 check_field ($package, 'version', 'Version');
737 check_field ($package, 'release', 'Release');
738 check_field ($package, 'priority', 'Priority');
739 check_field ($package, 'authors', 'Author');
740 check_field ($package, 'description', 'Description');
741 check_field ($package, 'summary', 'Synopsis');
742 check_field ($package, 'license', 'License');
743 check_field ($package, 'packager', 'Packager');
744 check_field ($package, 'packager_email', 'Packager-Email');
745
746 $package->{output_name} = $package->{name} unless defined $package->{output_name};
747 $package->{upstream_fullname} = $package->{name} . '-' . $package->{version};
748 $package->{fullname} = $package->{output_name}
749 . '-' . $package->{version}
750 . '-' . $package->{release};
751 $package->{lcname} = lc($package->{name});
752
753 return $package;
754}
755
756# --- handle_target: create a $target from a pkgwriteinfo entry ---
757sub handle_target
758{
759 my $target = {};
760 my $in_description = 0;
761 $target->{type} = 'target';
762 $target->{manpages} = [];
763 $target->{source_docs} = [];
764 $target->{installed_docs} = [];
765 $target->{arch_indep} = 0;
766 $target->{debian_data} = {};
767
768 for (@_)
769 {
770 if ($in_description)
771 {
772 if (/^\S/)
773 {
774 $in_description = 0;
775 }
776 else
777 {
778 s/^\s//;
779 $target->{description} .= "\n$_";
780 next;
781 }
782 }
783
784 if (/^Target:\s*(.*)/)
785 {
786 $target->{name} = $1;
787 }
788 elsif (/^Depends:\s*(.*)/)
789 {
790 my $dep = $1;
791 if (defined($target->{depends}))
792 {
793 $target->{depends} = $target->{depends} . ", " . $dep;
794 }
795 else
796 {
797 $target->{depends} = $dep;
798 }
799 }
800 elsif (/^Redhat-Requires:\s*(.*)/)
801 {
802 $target->{redhat_requires} = $1;
803 }
804 elsif (/^Conflicts:\s*(.*)/)
805 {
806 my $conflict = $1;
807 if (defined($target->{conflicts}))
808 {
809 $target->{conflicts} = $target->{conflicts} . ", " . $conflict;
810 }
811 else
812 {
813 $target->{conflicts} = $conflict;
814 }
815 }
816 elsif (/^Redhat-Conflicts:\s*(.*)/)
817 {
818 $target->{redhat_conflicts} = $1;
819 }
820 elsif (/^Synopsis:\s*(.*)/)
821 {
822 $target->{summary} = $1;
823 }
824 elsif (/^Files:\s*(.*)/)
825 {
826 my $pattern = $1;
827 $target->{files} = [] unless defined $target->{files};
828 my $files = $target->{files};
829 push @$files, $pattern;
830 }
831 elsif (/^Description:\s*(.*)/)
832 {
833 $target->{description} = $1;
834 $in_description = 1;
835 }
836 elsif (/^Man-Page:\s*(.*)/)
837 {
838 my $manpage = $1;
839 my $manpages = $target->{manpages};
840 push @$manpages, $manpage;
841 }
842 elsif (/^Doc:\s*(.*)/)
843 {
844 my $doc = $1;
845 my $docs = $target->{installed_docs};
846 push @$docs, $doc;
847 }
848 elsif (/^Source-Doc:\s*(.*)/)
849 {
850 my $doc = $1;
851 my $docs = $target->{source_docs};
852 push @$docs, $doc;
853 }
854 elsif (/^Platform-Independent:\s*(.*)/)
855 {
856 $target->{arch_indep} = string_to_boolean ($1);
857 }
858 elsif (/^Needs-[lD]dconfig:\s*(.*)/)
859 {
860 $target->{needs_ldconfig} = string_to_boolean ($1);
861 }
862 elsif (/^Which-Build:\s*(.*)/)
863 {
864 $target->{build_name} = $1;
865 }
866 else
867 {
868 chomp;
869 die "unparsable line in pkgwriteinfo file: $_";
870 }
871 }
872
873 # check that all the needed fields have been found.
874 check_field ($target, 'name', 'Target');
875
876 if (undef_or_empty ($target->{installed_docs})
877 && undef_or_empty ($target->{source_docs})
878 && undef_or_empty ($target->{files}))
879 {
880 die "either Files, Doc, Source-Doc are required but missing in target "
881 . $target->{name};
882 }
883
884 if ($target->{name} ne '{MAIN}')
885 {
886 check_field ($target, 'description', 'Description');
887 check_field ($target, 'summary', 'Synopsis');
888 }
889
890 # --- Figure out other information about this target. ---
891
892 # Figure out if ldconfig must be run after this package
893 # is installed.
894 if (!defined ($target->{needs_ldconfig}))
895 {
896 my $needs_ldconfig = 0;
897 my $files = $target->{files};
898 $files = [] unless defined $files;
899 PER_FILE: for my $file (@$files)
900 {
901 my $tmp = $file;
902 $tmp =~ s,/[^/]+$,,;
903 for my $dir (@ldconfig_dirs)
904 {
905 if ($tmp eq $dir)
906 {
907 $needs_ldconfig = 1;
908 last PER_FILE;
909 }
910 }
911 }
912 $target->{needs_ldconfig} = $needs_ldconfig;
913 }
914
915 return $target;
916}
917
918# --- handle_build: create a $build from a pkgwriteinfo entry ---
919sub handle_build
920{
921 my $build = {};
922 $build->{type} = 'build';
923 $build->{extra_build_targets} = [];
924 $build->{extra_install_targets} = [];
925 for (@_)
926 {
927 if (/^Build:\s*(.*)/)
928 {
929 $build->{name} = $1;
930 }
931 elsif (/^Configure-Flags:\s*(.*)/)
932 {
933 $build->{configure_flags} = $1;
934 }
935 elsif (/^Configure-Envars:\s*(.*)/)
936 {
937 $build->{configure_envars} = $1;
938 }
939 elsif (/^Make-Flags:\s*(.*)/)
940 {
941 $build->{make_flags} = $1;
942 }
943 elsif (/^Install-Flags:\s*(.*)/)
944 {
945 $build->{install_flags} = $1;
946 }
947 elsif (/^Build-Flags:\s*(.*)/)
948 {
949 $build->{build_flags} = $1;
950 }
951 elsif (/^Extra-Build-Targets:\s*(.*)/)
952 {
953 my $list = $build->{extra_build_targets};
954 push @$list, $1;
955 }
956 elsif (/^Extra-Install-Targets:\s*(.*)/)
957 {
958 my $list = $build->{extra_install_targets};
959 push @$list, $1;
960 }
961 else
962 {
963 die "unrecognized line under Build ($_)";
964 }
965 }
966 return $build;
967}
968
969# --- add_automatic_conflicts ---
970# Add packages to eachothers conflict lists whenever they
971# have Files: entries that are the same and don't have wildcards.
972sub add_automatic_conflicts ($)
973{
974 my ($package) = @_;
975 my $targets = $package->{targets};
976
977 # a table: defined ($conflict_table->{A}->{B}) => A and B conflict.
978 my $conflict_table = {};
979
980 # a table mapping a filename that doesn't contain
981 # wildcards, to a list of packages containing that file.
982 my $by_installed_file = {};
983
984 # Traverse all the targets, flush one $conflict_table.
985 #
986 # Basically, if any two packages are in the same list,
987 # they must have a conflict.
988 for my $target (@$targets)
989 {
990 my $files = $target->{files};
991 for my $file (@$files)
992 {
993 next if $file =~ /[\*\?\[\]]/;
994 my $list = $by_installed_file->{$file};
995 $list = $by_installed_file->{$file} = [] unless defined ($list);
996 push @$list, $target;
997 }
998 }
999
1000 my %name_to_target = ();
1001
1002 # Build a table of all the conflicted package pairs,
1003 # by scanning the above lists.
1004 for my $conflicted_targets (values %$by_installed_file)
1005 {
1006 my $count = scalar (@$conflicted_targets);
1007 next if ($count < 2);
1008 for (my $i = 0; $i < $count; $i++)
1009 {
1010 my $t1 = $conflicted_targets->[$i];
1011 my $p1 = $t1->{package_name};
1012 $name_to_target{$p1} = $t1;
1013 for (my $j = 0; $j < $count; $j++)
1014 {
1015 next if $i == $j;
1016 my $t2 = $conflicted_targets->[$j];
1017 my $p2 = $t2->{package_name};
1018 my $t = $conflict_table->{$p1};
1019 $t = $conflict_table->{$p1} = {} unless defined $t;
1020 $t->{$p2} = 1;
1021 }
1022 }
1023 }
1024
1025 # Add those conflicts, unless they have been explicitly mentioned already.
1026 my $file_a;
1027 my $hash_b;
1028 while (($name_a, $hash_b) = each %$conflict_table)
1029 {
1030 my $target_a = $name_to_target{$name_a};
1031 my $cstring = $target_a->{conflicts};
1032
1033 # Compute the initial list of conflicted packages.
1034 my @conflicts;
1035 if (!defined ($cstring) || $cstring eq '')
1036 {
1037 @conflicts = ();
1038 }
1039 else
1040 {
1041 @conflicts = map { s/^\s+//; s/\s+$//; $_ } (split /,/, $cstring);
1042 }
1043
1044 for my $name_b (keys %$hash_b)
1045 {
1046 my $preconflicted = 0;
1047 my $target_b = $name_to_target{$name_a};
1048 for (@conflicts)
1049 {
1050 if (/^$target_b / || ($_ eq $target_b))
1051 {
1052 $preconflicted = 1;
1053 last;
1054 }
1055 }
1056
1057 # Add a conflict if needed.
1058 unless ($preconflicted)
1059 {
1060 if (!defined ($cstring) || $cstring eq '')
1061 {
1062 $target_a->{conflicts} = $name_b;
1063 }
1064 else
1065 {
1066 $target_a->{conflicts} .= ", $name_b";
1067 }
1068 }
1069 }
1070 }
1071}
1072
1073
1074#=====================================================================
1075# Section 3: Verify that a package is correctly formed.
1076#=====================================================================
1077
1078# Run a user-specified function (a predicate) on a package and all its targets.
1079# (only possible b/c they are both hash-tables).
1080#
1081# Return the first package for which the predicate returns true,
1082# or `undef' if none is found.
1083sub search_package_and_targets ($$)
1084{
1085 my ($package, $func) = @_;
1086
1087 return $package if &$func ($package);
1088
1089 my $targets = $package->{targets};
1090 for my $target (@$targets)
1091 {
1092 return $target if &$func ($target);
1093 }
1094 return undef;
1095}
1096
1097# check that a package is valid.
1098sub sanity_check_package ($)
1099{
1100 my $package = $_[0];
1101 my $targets = $package->{targets};
1102 my $builds = $package->{builds};
1103
1104 # Verify that $package->{group} and $package->{section} are valid.
1105 my $invalid = search_package_and_targets
1106 ($package,
1107 sub {
1108 my $p = $_[0];
1109 return 0 unless defined $p->{group};
1110 return 0 if defined $RPM_GROUPS{lc($p->{group})};
1111 print STDERR "WARNING: "
1112 . "The Group: `" . $p->{group}
1113 . "'is unknown.\n";
1114 return 1;
1115 });
1116 if (defined($invalid))
1117 {
1118 die "try pkgwrite --query-list=rpm-groups";
1119 }
1120 $invalid = search_package_and_targets
1121 ($package,
1122 sub {
1123 my $p = $_[0];
1124 return 0 unless defined $p->{section};
1125 my $s = lc ($p->{section});
1126 return 0 if defined $DPKG_SECTIONS{$s};
1127 print STDERR "WARNING: "
1128 . "The Section: `" . $p->{section}
1129 . "'is unknown.\n";
1130 return 1;
1131 });
1132 if (defined($invalid))
1133 {
1134 die "invalid Section: try pkgwrite --query-list=deb-sections for a list";
1135 }
1136
1137 # Verify that documentation doesn't contain wildcards.
1138 $invalid = search_package_and_targets
1139 ($package,
1140 sub {
1141 my $p = $_[0];
1142 my @docs;
1143 my $sd = $p->{source_docs};
1144 my $id = $p->{installed_docs};
1145 @docs = ( ((defined $id) ? @$id : ()),
1146 ((defined $sd) ? @$sd : ()) );
1147 for (@docs)
1148 {
1149 if (/\*/ || /\?/)
1150 {
1151 print STDERR "WARNING: "
1152 . "documentation specifications "
1153 . "may not contain wildcards."
1154 . "($_)\n";
1155 return 1;
1156 }
1157 }
1158 return 0;
1159 });
1160 if (defined($invalid))
1161 {
1162 die $invalid->{type} . " " . $invalid->{name}
1163 . " had an invalid documentation entry";
1164 }
1165
1166 # Verify that the manpages are in valid sections.
1167 $invalid = search_package_and_targets
1168 ($package,
1169 sub {
1170 my $p = $_[0];
1171 my $m = $p->{manpages};
1172 my @manpages = (defined ($m) ? @$m : ());
1173 for (@manpages)
1174 {
1175 if (!defined (get_manpage_section ($_)))
1176 {
1177 print STDERR "WARNING: "
1178 . "manpage $_ was not in any "
1179 . "known man section.\n";
1180 return 1;
1181 }
1182 if (/\//)
1183 {
1184 print STDERR "ERROR: "
1185 . "manpage $_ contained a /; it "
1186 . "should be a bare filename.\n";
1187 return 1;
1188 }
1189 }
1190 return 0;
1191 });
1192 if (defined ($invalid))
1193 {
1194 die "bad manpage section in $invalid->{type} $invalid->{name}"
1195 }
1196
1197 # Verify that none of the packages have the same names.
1198 my %used_names = ();
1199 for my $t (@$targets)
1200 {
1201 my $pname = $t->{package_name};
1202 die "two packages are named $pname" if defined $used_names{$pname};
1203 $used_names{$pname} = 1;
1204 }
1205
1206 # Verify that no two installed documents in a single package
1207 # have the same name.
1208 for my $t (@$targets)
1209 {
1210 my $pname = $t->{package_name};
1211 my @installed_docs = ();
1212 my $d1 = $t->{installed_docs};
1213 my $d2 = $t->{source_docs};
1214 for my $d (@$d1, @$d2)
1215 {
1216 next unless $d =~ m,([^/]+)/?$,;
1217 my $base = $1;
1218 if (defined ($used_names{$base}))
1219 {
1220 die "two documents in $pname are named $base";
1221 }
1222 $used_names{$base} = 1;
1223 }
1224 }
1225}
1226
1227
1228#=====================================================================
1229# Section 4: ChangeLog parsing code.
1230#=====================================================================
1231# create a new changelog parser.
1232# doesn't parse any entries.
1233#
1234# you may pass in anything that may be open()d for reading: a filename
1235# or `program |'.
1236sub changelog_parser_new ($)
1237{
1238 my $fh = gensym ();
1239 open $fh, "$_[0]" or return undef;
1240 my $cp = {};
1241 $cp->{fh} = $fh;
1242 $cp->{filename} = $_[0];
1243 $cp->{lineno} = 0;
1244 return $cp;
1245}
1246
1247# skip empty lines, but also keep around the line number for error reporting.
1248sub _cp_skip_empty_lines ($)
1249{
1250 my $rv = skip_empty_lines ($_[0]->{fh});
1251 $_[0]->{lineno} = $.;
1252 return $rv;
1253}
1254
1255# parse one entry: store it in the public fields of $changelog_parser:
1256# {package} => PACKAGE_NAME
1257# {version} => VERSION-RELEASE
1258# {change_text} => raw text of the changes
1259# {full_name} => NAME-OF-AUTHOR
1260# {email} => EMAIL-OF-AUTHOR
1261# {date} => ENTRY-DATE (in rfc 822, eg date -R)
1262# return whether this fields are valid.
1263sub changelog_parser_advance ($)
1264{
1265 my $cp = $_[0];
1266 my $package_line = _cp_skip_empty_lines ($cp);
1267 return 0 unless defined $package_line;
1268 if ($package_line !~ /^([a-zA-Z0-9\-_]+)\s\(([^\(\)]+)\)/)
1269 {
1270 die "error parsing changelog package line ($package_line) ("
1271 . $cp->{filename} . ", line " . $cp->{lineno} . ")";
1272 }
1273 $cp->{package} = $1;
1274 $cp->{version} = $2;
1275
1276 my $byline;
1277
1278 # grab the text.
1279 my $text = _cp_skip_empty_lines ($cp);
1280 my $was_empty = 0;
1281
1282 # got a header line, but nothing else: that's an error.
1283 if (!defined ($text))
1284 {
1285 die "no changelog entry was encountered: premature eof at "
1286 . $cp->{filename} . ", line " . $cp->{lineno};
1287 }
1288 $text .= "\n";
1289
1290 # Data to be parsed from the packager's byline
1291 # (which we will do in order to detect the end-of-record anyway).
1292 my $full_name;
1293 my $email;
1294 my $date;
1295 my $got_byline = 0;
1296 my $fh = $cp->{fh};
1297 while (defined ($text))
1298 {
1299 my $line = scalar (<$fh>);
1300 last unless defined $line;
1301
1302 if ($line =~ /^\s+-- ([^<>]+) <([^<>]+)>\s+(.*)/)
1303 {
1304 $full_name = $1;
1305 $email = $2;
1306 $date = $3;
1307 $got_byline = 1;
1308 last;
1309 }
1310 $text .= $line;
1311 }
1312 $text =~ s/\n\n+$/\n/s;
1313
1314 # parse the byline.
1315 if (!$got_byline)
1316 {
1317 die "missing byline at " . $cp->{filename} . ", line " . $cp->{lineno};
1318 }
1319 $cp->{change_text} = $text;
1320 $cp->{full_name} = $full_name;
1321 $cp->{email} = $email;
1322 $cp->{date} = $date;
1323
1324 return 1;
1325}
1326
1327# Write a debian-style changelog entry.
1328# (on a debian system, look in /usr/share/doc/packaging-manual/manual.text.gz)
1329sub changelog_write_debian_style ($$)
1330{
1331 my ($cp, $ofh) = @_;
1332 my $lcpackage = lc($cp->{package});
1333 print $ofh $lcpackage,
1334 " (", $cp->{version}, ") $debian_dist; urgency=low\n\n",
1335 $cp->{change_text},
1336 "\n -- ", $cp->{full_name},
1337 " <", $cp->{email}, "> ", $cp->{date}, "\n\n";
1338}
1339
1340# Write a redhat-style changelog entry.
1341# (see http://www.rpm.org/RPM-HOWTO/build.html#CHANGELOG)
1342sub changelog_write_redhat_style ($$)
1343{
1344 my ($cp, $ofh) = @_;
1345
1346 # Convert the date from
1347 # `date -R' format (complies with rfc 822)
1348 # to
1349 # `date +"%a %b %d %Y"' format
1350 # HMM: it'd be nice to support an rfc 822 date parser here,
1351 # but i'm hesitant unless such a beast comes with perl.
1352 if ($cp->{date} !~ /^([A-Z][a-z][a-z]),\s+(\d+) ([A-Z][a-z][a-z]) (\d+)/)
1353 {
1354 die "could not parse date " . $cp->{date};
1355 }
1356 my ($day_of_week, $day_of_month, $month_shortname, $year) = ($1, $2, $3, $4);
1357 $day_of_month = "0$day_of_month" unless $day_of_month >= 10;
1358 my $short_date = "$day_of_week $month_shortname $day_of_month $year";
1359
1360 print $ofh "* $short_date ", $cp->{full_name}, " <", $cp->{email}, ">\n\n";
1361
1362 # XXX: not part of any packaging standard.
1363 print $ofh " Version ", $cp->{version}, "\n";
1364
1365 for (split /\n/, $cp->{change_text})
1366 {
1367 # hmm, convert * to - for readability (?!?)
1368 s/^ \*/ -/;
1369 print $ofh $_, "\n";
1370 }
1371 print $ofh "\n\n";
1372}
1373
1374# destroy the changelog parser.
1375sub changelog_parser_destroy ($)
1376{
1377 my $cp = $_[0];
1378 if (! close ($cp->{fh}))
1379 {
1380 die "error running $cp->{filename}: $?";
1381 }
1382}
1383
1384
1385#=====================================================================
1386# Section 5: Redhat tape.
1387#=====================================================================
1388# if $make_script == 1,
1389# return a list of commands (newline-terminated)
1390# to concatenate into a script which will copy said
1391# docs into /usr/doc/PACKAGE-VERSION-RELEASE.
1392#
1393# if $make_script == 0, just return a list of files,
1394# `${prefix}/doc/PACKAGE-VERSION-RELEASE/FILENAME'.
1395sub redhat_make_install_doc_section ($$)
1396{
1397 my ($package, $build) = @_;
1398 my @cmds = ();
1399 my $targets = $package->{targets};
1400 my $docs = $target->{installed_docs};
1401 my $buildfullname = $build->{package_name} . '-' . $package->{version};
1402 my $docdir = "%{_topdir}/%{prefix}/doc/" . join ('-',
1403 $package->{name},
1404 $package->{version},
1405 $package->{release});
1406
1407 # the union of all source docs for this build.
1408 my %source_docs = ();
1409
1410 # the union of all installed docs for this build.
1411 my %installed_docs = ();
1412
1413 for my $target (@$targets)
1414 {
1415 # skip unrelated targets.
1416 next unless $target->{build} == $build;
1417
1418 my $doc_list;
1419
1420 $doc_list = $target->{source_docs};
1421 for (@$doc_list) { $source_docs{$_} = 1 }
1422
1423 $doc_list = $target->{installed_docs};
1424 for (@$doc_list) { $installed_docs{$_} = 1 }
1425 }
1426
1427 # if there is no documentation to install, skip out rather than make
1428 # an empty doc directory.
1429 if (scalar(keys(%source_docs)) == 0 && scalar(keys(%installed_docs)) == 0)
1430 {
1431 return;
1432 }
1433
1434 # mkdir -p isn't generally portable, but it works under redhat. hmm...
1435 push @cmds, "test -d $docdir || mkdir -p $docdir\n";
1436
1437 for my $doc (sort keys %source_docs)
1438 {
1439 # Produce commands to copy $src_doc from the unpacked tarball
1440 # to the $docdir.
1441 my $base;
1442 $doc =~ m,([^/]+/?)$,;
1443 $base = $1;
1444 if ($doc =~ m,/$,)
1445 {
1446 # directory
1447 push @cmds, "rm -rf $docdir/$base\n",
1448 "cp -dpr %{_builddir}/$buildfullname/$doc $docdir/$base\n";
1449 }
1450 else
1451 {
1452 # file.
1453 push @cmds, "cp -dpf %{_builddir}/$buildfullname/$doc $docdir/\n";
1454 }
1455 }
1456
1457 for my $doc (sort keys %installed_docs)
1458 {
1459 # Produce commands to copy $installed_doc from the installed
1460 # area to the $docdir.
1461 my $base;
1462 $doc =~ m,([^/]+/?)$,;
1463 $base = $1;
1464
1465 # Try to avoid copying a file over itself.
1466 my $srcpath = "%{_topdir}/$doc";
1467 my $dstpath = "$docdir/$base";
1468 $srcpath =~ s,/+$,,; $srcpath =~ s,//+,/,;
1469 $dstpath =~ s,/+$,,; $dstpath =~ s,//+,/,;
1470 next if $srcpath eq $dstpath;
1471
1472 # Write the script if needed.
1473 if ($doc =~ m,/$,)
1474 {
1475 # directory
1476 push @cmds, "rm -rf $docdir/$base\n",
1477 "cp -r %{_topdir}/$doc $docdir/$base\n";
1478 }
1479 else
1480 {
1481 # file.
1482 push @cmds, "cp -dpf %{_topdir}/$doc $docdir/\n";
1483 }
1484 }
1485 return @cmds;
1486}
1487
1488# output a list of file including their path.
1489sub redhat_make_doc_section_list ($$$)
1490{
1491 my ($fh, $package, $target) = @_;
1492 my $docs;
1493 my $docdir = "%{prefix}/doc/" . join ('-',
1494 $package->{name},
1495 $package->{version},
1496 $package->{release});
1497 $docs = $target->{installed_docs};
1498 for (@$docs)
1499 {
1500 next unless m/([^\/]+\/?)$/;
1501 push @docs, "$docdir/$1";
1502 }
1503 $docs = $target->{source_docs};
1504 for (@$docs)
1505 {
1506 next unless m/([^\/]+\/?)$/;
1507 push @docs, "$docdir/$1";
1508 }
1509 return @docs;
1510}
1511
1512# Print either an opening or closing architecture conditional
1513# for a certain target.
1514sub print_arch_conditional ($$$)
1515{
1516 my ($fh, $target, $is_open) = @_;
1517 my $arch_indep = $target->{arch_indep};
1518 if ($is_open)
1519 {
1520 print $fh ($arch_indep ? "%ifarch noarch\n" : "%ifnarch noarch\n");
1521 }
1522 else
1523 {
1524 print $fh "%endif # ", ($arch_indep ? "noarch" : "!noarch"), "\n";
1525 }
1526}
1527
1528sub make_redhat_specfile($$$)
1529{
1530 my ($package, $build, $spec_file_out) = @_;
1531
1532 open SPECFILE, ">$spec_file_out" or die "could not create $spec_file_out: $!";
1533
1534 my $rh_requires = compute_redhat_requires ($package);
1535 my $download_url = $package->{url};
1536 print SPECFILE "\%define prefix /usr\n";
1537
1538 # For now, disable this "fascist" option.
1539 # For some reason, our .tar.gz winds up in the list of
1540 # files, which kills us.
1541 print SPECFILE "\%define _unpackaged_files_terminate_build 0\n";
1542
1543 write_entries ('SPECFILE', $build,
1544 [qw(Name)],
1545 [qw(package_name)]);
1546 write_entries ('SPECFILE', $package,
1547 [qw(Version Release Copyright Vendor URL
1548 Group Summary Provides License)],
1549 [qw(version release copyright vendor home_page
1550 group summary output_name license)]);
1551
1552
1553 # Table of all the manpages we will need to gzip.
1554 my %build_manpages = ();
1555
1556 # The primary target, that is, the target whose name is the
1557 # build's name (the same as the .src.rpm will assume).
1558 my $primary_target;
1559
1560 # Compute the primary target and build_manpages.
1561 my $targets = $package->{targets};
1562 for my $target (@$targets)
1563 {
1564 next unless $target->{build} == $build;
1565
1566 if ($target->{name} eq $build->{name})
1567 {
1568 $primary_target = $target;
1569 }
1570 my $manpages = $target->{manpages};
1571 for my $manpage (@$manpages)
1572 {
1573 $build_manpages{$manpage} = 1;
1574 }
1575 }
1576
1577 my $tarball = $package->{name} . '-' . $package->{version} . ".tar.gz";
1578 print SPECFILE "Source: $tarball\n";
1579 #print SPECFILE "Packager: $packager_id\n";
1580 print SPECFILE "Prefix: /usr\n";
1581 print SPECFILE "BuildRoot: %{_topdir}\n";
1582 # Print flags that actually pertain to the primary target.
1583
1584 my $needs_arch_conditionals = 0;
1585 if ($package->{needs_noarch})
1586 {
1587 if ($package->{needs_arch_specific})
1588 {
1589 print SPECFILE "BuildArch: noarch $default_redhat_archs\n";
1590 $needs_arch_conditionals = 1;
1591 }
1592 else
1593 {
1594 print SPECFILE "BuildArch: noarch\n";
1595 }
1596 }
1597 if (defined ($primary_target))
1598 {
1599 # Print dependencies and conflicts.
1600 my $rh_requires = compute_redhat_requires ($primary_target);
1601 print SPECFILE "Requires: $rh_requires\n" if ($rh_requires ne '');
1602
1603 my $rh_conflicts = compute_redhat_conflicts ($primary_target);
1604 print SPECFILE "Conflicts: $rh_conflicts\n" if ($rh_conflicts ne '');
1605 }
1606
1607 print SPECFILE "%description\n",
1608 make_debian_description ($package->{description}),
1609 "\n";
1610
1611 my $config_flags;
1612 $config_flags = $redhat_config_flags
1613 . " " .
1614 (defined ($build->{configure_flags})
1615 ? $build->{configure_flags}
1616 : '');
1617 my $env_settings = (defined ($build->{configure_envars})
1618 ? "$build->{configure_envars} "
1619 : "");
1620 my $make_flags = defined ($build->{make_flags})
1621 ? $build->{make_flags} : '';
1622 my $build_flags = defined ($build->{build_flags})
1623 ? $build->{build_flags} : '';
1624 my $install_flags = defined ($build->{install_flags})
1625 ? $build->{install_flags} : '';
1626 $build_flags .= " $make_flags";
1627 $install_flags .= " $make_flags";
1628 my $full_main_package = "$package->{name}-$package->{version}";
1629 my $full_target_package = "$build->{package_name}-$package->{version}";
1630 print SPECFILE
1631 "%prep\n",
1632 "rm -rf \$RPM_BUILD_DIR/$full_main_package\n",
1633 "rm -rf \$RPM_BUILD_DIR/$full_target_package\n",
1634 "zcat \$RPM_SOURCE_DIR/$full_main_package.tar.gz | tar -xvf -\n",
1635 ($full_main_package eq $full_target_package
1636 ? ''
1637 : "mv $full_main_package $full_target_package\n"),
1638 "%build\n",
1639 "test -d \$RPM_BUILD_DIR || mkdir -p \$RPM_BUILD_DIR\n",
1640 "cd \$RPM_BUILD_DIR/$full_target_package\n",
1641 "$env_settings ./configure $config_flags\n",
1642 "make PREFIX=/usr $build_flags\n\n";
1643
1644 my $make_targets = $build->{extra_build_targets};
1645 for (@$make_targets)
1646 {
1647 print SPECFILE "make $_ PREFIX=/usr $build_flags\n";
1648 }
1649 print SPECFILE
1650 "%install\n",
1651 "cd \$RPM_BUILD_DIR/$full_target_package\n",
1652 "make install PREFIX=/usr DESTDIR=%{_topdir} $install_flags\n";
1653 $make_targets = $build->{extra_install_targets};
1654 for (@$make_targets)
1655 {
1656 print SPECFILE "make $_ PREFIX=/usr DESTDIR=%{_topdir} $install_flags\n";
1657 }
1658
1659 print SPECFILE redhat_make_install_doc_section ($package, $build);
1660
1661 for my $manpage (keys %build_manpages)
1662 {
1663 my $man_section = get_manpage_section ($manpage);
1664 print SPECFILE "gzip -9 -f %{_topdir}/usr/man/man$man_section/$manpage\n";
1665 }
1666 print SPECFILE "\n";
1667
1668 print SPECFILE
1669 "%clean\n",
1670 "rm -rf %{_builddir}\n",
1671 "mkdir %{_builddir}\n", # without the mkdir, this doesn't run twice...
1672 "\n\n";
1673
1674 if (defined ($primary_target))
1675 {
1676 if ($needs_arch_conditionals)
1677 {
1678 print_arch_conditional ('SPECFILE', $primary_target, 1)
1679 }
1680 if ($primary_target->{needs_ldconfig})
1681 {
1682 # This is from the gtk+.spec file.
1683 # Usually they are all pretty godly, but i'll be damned
1684 # if this works :) Furthermore all documentation alludes
1685 # to the next method; -p is wholy undocumented as far as i can tell.
1686 #print SPECFILE "%post -p /sbin/ldconfig\n\n",
1687 # "%postun -p /sbin/ldconfig\n\n";
1688
1689 print SPECFILE "%post\n",
1690 "/sbin/ldconfig\n\n",
1691 "%postun\n",
1692 "/sbin/ldconfig\n\n",
1693 }
1694 write_redhat_files_section ('SPECFILE', $primary_target);
1695 if ($needs_arch_conditionals)
1696 {
1697 print_arch_conditional ('SPECFILE', $primary_target, 0)
1698 }
1699 }
1700
1701 for my $target (@$targets)
1702 {
1703 my $rh_requires = compute_redhat_requires ($target);
1704 my $target_name = $target->{package_name};
1705
1706 # Only process $target if it pertains to the current $build.
1707 next if $target->{build} != $build;
1708
1709 # For the main package, the remaining data are
1710 # handled in the main preamble.
1711 next if ($target->{name} eq $build->{name});
1712
1713 if ($needs_arch_conditionals)
1714 {
1715 print_arch_conditional ('SPECFILE', $target, 1);
1716 }
1717
1718 # Various standard fields for the non-major package.
1719 # XXX: should probably try to avoid needless `-n' flags.
1720 print SPECFILE "%package -n $target_name\n";
1721 write_entries ('SPECFILE', $target,
1722 [qw(Group)],
1723 [qw(group)]);
1724 print SPECFILE "Requires: $rh_requires\n" if ($rh_requires ne '');
1725
1726 my $rh_conflicts = compute_redhat_conflicts ($target);
1727 print SPECFILE "Conflicts: $rh_conflicts\n" if ($rh_conflicts ne '');
1728
1729 # Summary is required for Redhat packages,
1730 # so we checked the availability of the Synopsis:
1731 # field on input, so an undef'd $summary should never occur.
1732 my $summary = $target->{summary};
1733 die unless defined $summary;
1734 print SPECFILE "Summary: $summary\n";
1735
1736 if ($target->{needs_ldconfig})
1737 {
1738 print SPECFILE "%post -n $target_name -p /sbin/ldconfig\n\n",
1739 "%postun -n $target_name -p /sbin/ldconfig\n\n";
1740 }
1741
1742 # Likewise, Description is mandatory.
1743 my $desc = $target->{description};
1744 if (!defined($desc)) { $desc = $package->{description}; }
1745 die unless defined $desc;
1746 print SPECFILE "%description -n $target_name\n$desc\n";
1747
1748 # Print the %files section (Based on Files: in the pkgwriteinfo file.)
1749 write_redhat_files_section ('SPECFILE', $target);
1750 if ($needs_arch_conditionals)
1751 {
1752 print_arch_conditional ('SPECFILE', $target, 0);
1753 }
1754 print SPECFILE "\n\n";
1755 }
1756
1757 # If there is a changelog, include it in the specfile.
1758 # This is annoying b/c there is not necessarily any unpacked
1759 # source code around...
1760 my $changelog = $package->{changelog};
1761 if (defined ($changelog))
1762 {
1763 my $cl_file;
1764 if ($package->{package_source_dir})
1765 {
1766 $cl_file = $package->{package_source_dir} . "/$changelog";
1767 }
1768 else
1769 {
1770 # perform the necessary `tar' command.
1771 $cl_file = "$gunzip < " . $package->{package_tarball}
1772 . " | tar $untar_to_stdout - "
1773 . $package->{upstream_fullname} . "/$changelog |";
1774 }
1775 my $cp = changelog_parser_new ($cl_file);
1776 print SPECFILE "\n%changelog\n";
1777 my $first_time = 1;
1778 while (changelog_parser_advance ($cp))
1779 {
1780 if ($first_time)
1781 {
1782 my $ver = $package->{version} . '-' . $package->{release};
1783 if ($strict_changelog_checking && $cp->{version} ne $ver)
1784 {
1785 die "package version in changelog (" . $cp->{version} . ")"
1786 . " and in pkgwriteinfo file ($ver) do not match!";
1787 }
1788 $first_time = 0;
1789 }
1790 changelog_write_redhat_style ($cp, 'SPECFILE');
1791 }
1792 changelog_parser_destroy ($cp);
1793 }
1794 close SPECFILE;
1795}
1796
1797sub write_redhat_files_section($$)
1798{
1799 my ($fh, $target) = @_;
1800 print $fh '%files -n ', $target->{package_name}, "\n";
1801 my $files_list = $target->{files};
1802 if (defined($files_list))
1803 {
1804 print $fh '%defattr(-, root, root)', "\n";
1805 for my $wildcard (@$files_list)
1806 {
1807 my $tmp = $wildcard;
1808 $tmp =~ s,^/usr/,%{prefix}/,;
1809 print $fh "$tmp\n";
1810 }
1811 }
1812 my $manpages = $target->{manpages};
1813 for my $manpage (@$manpages)
1814 {
1815 my $section = get_manpage_section ($manpage);
1816 print $fh "%{prefix}/man/man$section/$manpage.gz\n"
1817 }
1818 for my $doc (redhat_make_doc_section_list ($fh, $target->{package}, $target))
1819 {
1820 print $fh "%doc $doc\n";
1821 }
1822}
1823
1824# --- print canned rpmrc ---
1825# This is based on the spec file distributed with rpm 4.0.
1826# See comments in the legal section of pkgwrite.
1827sub print_canned_rpmrc ($)
1828{
1829 my $fh = $_[0];
1830 for (qw(i386 i486 i586 i686 athlon))
1831 { print $fh "optflags: $_ -O2 -march=$_\n" }
1832 for (qw(ia64 mipseb mipsel ia64))
1833 { print $fh "optflags: $_ -O2\n" }
1834 print $fh "optflags: alpha -O2 -mieee\n";
1835 for (qw(ev5 ev56 pca56 ev6 ev67))
1836 { print $fh "optflags: alpha$_ -O2 -mieee -mcpu=$_\n" }
1837 print $fh "optflags: sparc -O2 -m32 -mtune=ultrasparc\n";
1838 print $fh "optflags: sparcv9 -O2 -m32 -mcpu=ultrasparc\n";
1839 print $fh "optflags: sparc64 -O2 -m64 -mcpu=ultrasparc\n";
1840 print $fh "optflags: ppc -O2 -fsigned-char\n";
1841 for (qw(parisc hppa1.0 hppa1.1 hppa1.2 hppa2.0))
1842 { print $fh "optflags: $_ -O2 -mpa-risc-1-0\n" }
1843 for (qw(armv4b armv4l))
1844 { print $fh "optflags: $_ -O2 -fsigned-char -fomit-frame-pointer\n" }
1845 for (qw(m68k atarist atariste ataritt falcon atariclone milan hades))
1846 { print $fh "optflags: $_ -O2 -fomit-frame-pointer\n" }
1847 for (qw(athlon i686 i586 i486 i386))
1848 { print $fh "arch_canon: $_: $_ 1\n" }
1849 for (qw(alpha alphaev5 alphaev56 alphapca56 alphaev6 alphaev67))
1850 { print $fh "arch_canon: $_: $_ 2\n" }
1851 for (qw(alpha alphaev5 alphaev56 alphapca56 alphaev6 alphaev67))
1852 { print $fh "arch_canon: $_: sparc 3\n" }
1853 for (qw(sparcv9))
1854 { print $fh "arch_canon: $_: $_ 3\n" }
1855 print $fh <<'EOF';
1856arch_canon: mipseb: mipseb 4
1857arch_canon: ppc: ppc 5
1858arch_canon: m68k: m68k 6
1859arch_canon: IP: sgi 7
1860arch_canon: rs6000: rs6000 8
1861arch_canon: ia64: ia64 9
1862arch_canon: sparc64:sparc64 10
1863arch_canon: sun4u: sparc64 10
1864arch_canon: mipsel: mipsel 11
1865arch_canon: armv4b: armv4b 12
1866arch_canon: armv4l: armv4l 12
1867EOF
1868 for (qw(atarist atariste ataritt falcon atariclone milan hades))
1869 { print $fh "arch_canon: $_: m68kmint 13\n" }
1870 for (qw(s398 i370))
1871 { print $fh "arch_canon: $_: $_ 14\n" }
1872
1873 print $fh <<'EOF';
1874# Canonical OS names and numbers
1875
1876os_canon: Linux: Linux 1
1877os_canon: IRIX: Irix 2
1878# This is wrong
1879os_canon: SunOS5: solaris 3
1880os_canon: SunOS4: SunOS 4
1881
1882os_canon: AmigaOS: AmigaOS 5
1883os_canon: AIX: AIX 5
1884os_canon: HP-UX: hpux10 6
1885os_canon: OSF1: osf1 7
1886os_canon: osf4.0: osf1 7
1887os_canon: osf3.2: osf1 7
1888os_canon: FreeBSD: FreeBSD 8
1889os_canon: SCO_SV: SCO_SV3.2v5.0.2 9
1890os_canon: IRIX64: Irix64 10
1891os_canon: NEXTSTEP: NextStep 11
1892os_canon: BSD/OS: BSD_OS 12
1893os_canon: machten: machten 13
1894os_canon: CYGWIN32_NT: cygwin32 14
1895os_canon: CYGWIN32_95: cygwin32 15
1896os_canon: UNIX_SV: MP_RAS: 16
1897os_canon: MiNT: FreeMiNT 17
1898os_canon: OS/390: OS/390 18
1899os_canon: VM/ESA: VM/ESA 19
1900os_canon: Linux/390: OS/390 20
1901os_canon: Linux/ESA: VM/ESA 20
1902EOF
1903
1904 for (qw(s398 i370))
1905 { print $fh "arch_canon: $_: $_ 14\n" }
1906 for (qw(osfmach3_i686 osfmach3_i586 osfmach3_i486 osfmach3_i386
1907 athlon i686 i586 i486 i386))
1908 { print $fh "buildarchtranslate: $_: i386\n" }
1909 for (qw(ia64))
1910 { print $fh "buildarchtranslate: $_: ia64\n" }
1911 for (qw(osfmach3_ppc powerpc powerppc))
1912 { print $fh "buildarchtranslate: $_: ppc\n" }
1913 for (qw(alphaev5 alphaev56 alphapca56 alphaev6 alphaev67))
1914 { print $fh "buildarchtranslate: $_: alpha\n" }
1915 for (qw(sun4c sun4d sun4m sparcv9))
1916 { print $fh "buildarchtranslate: $_: sparc\n" }
1917 for (qw(sun4u))
1918 { print $fh "buildarchtranslate: $_: sparc64\n" }
1919 for (qw(atarist atariste ataritt falcon atariclone milan hades))
1920 { print $fh "buildarchtranslate: $_: m68kmint\n" }
1921 for ('alphaev67: alphaev6', 'alphaev6: alphapca56', 'alphapca56: alphaev56',
1922 'alphaev56: alphaev5', 'alphaev5: alpha', 'alpha: axp noarch',
1923 'ia64: noarch', 'athlon: i686', 'i686: i586', 'i586: i486',
1924 'i486: i386', 'i386: noarch', 'osfmach3_i686: i686 osfmach3_i586',
1925 'osfmach3_i586: i586 osfmach3_i486',
1926 'osfmach3_i486: i486 osfmach3_i386', 'osfmach3_i386: i486',
1927 'osfmach3_ppc: ppc', 'powerpc: ppc', 'powerppc: ppc',
1928 'sun4c: sparc', 'sun4d: sparc', 'sun4m: sparc', 'sun4u: sparc64',
1929 'sparc64: sparcv9', 'sparcv9: sparc', 'sparc: noarch',
1930 'ppc: rs6000', 'rs6000: noarch', 'mipseb: noarch', 'mipsel: noarch',
1931 'hppa2.0: hppa1.2', 'hppa1.2: hppa1.1', 'hppa1.1: hppa1.0',
1932 'hppa1.0: parisc', 'parisc: noarch',
1933 'armv4b: noarch', 'armv4l: noarch',
1934 'atarist: m68kmint noarch', 'atariste: m68kmint noarch',
1935 'ataritt: m68kmint noarch', 'falcon: m68kmint noarch',
1936 'atariclone: m68kmint noarch', 'milan: m68kmint noarch',
1937 'hades: m68kmint noarch', 's390: i370', 'i370: noarch',
1938 'ia64: noarch')
1939 { print $fh "arch_compat: $_\n" }
1940 print $fh <<'EOF';
1941os_compat: IRIX64: IRIX
1942os_compat: solaris2.7: solaris2.3 solaris2.4 solaris2.5 solaris2.6
1943os_compat: solaris2.6: solaris2.3 solaris2.4 solaris2.5
1944os_compat: solaris2.5: solaris2.3 solaris2.4
1945os_compat: solaris2.4: solaris2.3
1946
1947os_compat: hpux11.00: hpux10.30
1948os_compat: hpux10.30: hpux10.20
1949os_compat: hpux10.20: hpux10.10
1950os_compat: hpux10.10: hpux10.01
1951os_compat: hpux10.01: hpux10.00
1952os_compat: hpux10.00: hpux9.07
1953os_compat: hpux9.07: hpux9.05
1954os_compat: hpux9.05: hpux9.04
1955
1956os_compat: osf4.0: osf3.2 osf1
1957
1958os_compat: ncr-sysv4.3: ncr-sysv4.2
1959
1960os_compat: FreeMiNT: mint MiNT TOS
1961os_compat: MiNT: FreeMiNT mint TOS
1962os_compat: mint: FreeMiNT MiNT TOS
1963os_compat: TOS: FreeMiNT MiNT mint
1964
1965buildarch_compat: ia64: noarch
1966
1967buildarch_compat: athlon: i686
1968buildarch_compat: i686: i586
1969buildarch_compat: i586: i486
1970buildarch_compat: i486: i386
1971buildarch_compat: i386: noarch
1972
1973buildarch_compat: sun4c: noarch
1974buildarch_compat: sun4d: noarch
1975buildarch_compat: sun4m: noarch
1976buildarch_compat: sun4u: noarch
1977buildarch_compat: sparc64: noarch
1978buildarch_compat: sparcv9: sparc
1979buildarch_compat: sparc: noarch
1980
1981buildarch_compat: alphaev67: alphaev6
1982buildarch_compat: alphaev6: alphapca56
1983buildarch_compat: alphapca56: alphaev56
1984buildarch_compat: alphaev56: alphaev5
1985buildarch_compat: alphaev5: alpha
1986buildarch_compat: alpha: noarch
1987
1988buildarch_compat: m68k: noarch
1989buildarch_compat: ppc: noarch
1990buildarch_compat: mipsel: noarch
1991buildarch_compat: mipseb: noarch
1992buildarch_compat: armv4b: noarch
1993buildarch_compat: armv4l: noarch
1994buildarch_compat: parisc: noarch
1995
1996buildarch_compat: atarist: m68kmint noarch
1997buildarch_compat: atariste: m68kmint noarch
1998buildarch_compat: ataritt: m68kmint noarch
1999buildarch_compat: falcon: m68kmint noarch
2000buildarch_compat: atariclone: m68kmint noarch
2001buildarch_compat: milan: m68kmint noarch
2002buildarch_compat: hades: m68kmint noarch
2003
2004buildarch_compat: ia64: noarch
2005buildarch_compat: s390: noarch
2006EOF
2007}
2008
2009# --- make redhat dir ---
2010#
2011# Make a bunch of files needed to produce an rpm
2012# and writes them in $dir, which it creates.
2013#
2014# Return a list of commands that should be run to build
2015# the RPM given this directory.
2016#
2017# Also needs a distribution tarball (made by `make dist')
2018# and an architecture.
2019sub make_redhat_dir ($$$$)
2020{
2021 my ($package, $dir, $tarball, $arch) = @_;
2022
2023 run ("rm -rf $dir");
2024 safe_mkdir ("$dir");
2025 safe_mkdir ("$dir/rpm-tmp");
2026 safe_mkdir ("$dir/rpm-tmp/usr");
2027 safe_mkdir ("$dir/rpm-tmp/usr/src");
2028 safe_mkdir ("$dir/rpm-tmp/usr/src/redhat");
2029 safe_mkdir ("$dir/tmp");
2030 for (qw(SOURCES SPECS BUILD RPMS SRPMS))
2031 {
2032 safe_mkdir ("$dir/rpm-tmp/usr/src/redhat/$_");
2033 }
2034 run ("cp $tarball $dir/rpm-tmp/usr/src/redhat/SOURCES");
2035 chdir ($dir) or die;
2036 $dir = `pwd`;
2037 chomp($dir);
2038 #$REDHAT_DIR = $dir;
2039 $BUILD_TOP = "$dir/tmp";
2040 $STAGING_TOP = "$dir/rpm-tmp";
2041
2042 my $tmp_rpm_macros_fname = "$dir/rpmmacros.tmp";
2043 my $tmp_rpm_rc_fname = "$dir/rpmrc.tmp";
2044
2045 open T, ">$tmp_rpm_macros_fname"
2046 or die "couldn't create $tmp_rpm_macros_fname";
2047 print T <<"EOF";
2048%_builddir ${BUILD_TOP}
2049%_buildshell /bin/sh
2050%_dbpath %{_var}/lib/rpm
2051%_defaultdocdir %{_usr}/doc
2052%_instchangelog 5
2053%_rpmdir ${STAGING_TOP}/usr/src/redhat/RPMS
2054%_rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm
2055%_signature none
2056%_sourcedir ${STAGING_TOP}/usr/src/redhat/SOURCES
2057%_specdir ${STAGING_TOP}/usr/src/redhat/SPECS
2058%_srpmdir ${STAGING_TOP}/usr/src/redhat/SRPMS
2059%_srcrpmdir ${STAGING_TOP}/usr/src/redhat/SRPMS
2060%_tmppath /tmp
2061%_topdir ${STAGING_TOP}
2062EOF
2063 close T;
2064
2065
2066 open (RPMRC, ">$tmp_rpm_rc_fname") or die "couldn't create $tmp_rpm_rc_fname";
2067 print RPMRC "macrofiles: ",
2068 join (':', '/usr/lib/rpm/macros',
2069 '/usr/lib/rpm/%{_target}/macros',
2070 '/etc/rpm/macros',
2071 '/etc/rpm/%{_target}/macros',
2072 $tmp_rpm_macros_fname);
2073 print RPMRC "\n\n\n";
2074
2075 # If available, include the system-installed version
2076 # (w/o its `macrofiles:' lines), instead of the "canned" one;
2077 # (which actually just comes from rpm 4.0, see above);
2078 # the system version should be /var/lib/rpm/rpmrc.
2079 if (-r $system_rpmrc_file)
2080 {
2081 open SYSRPMRC, $system_rpmrc_file or die "internal error: " .
2082 "couldn't open $system_rpmrc_file";
2083 while (<SYSRPMRC>)
2084 {
2085 next if /^\s*macrofiles:/i;
2086 print RPMRC $_;
2087 }
2088 close SYSRPMRC;
2089 }
2090 else
2091 {
2092 print_canned_rpmrc ('RPMRC');
2093 }
2094
2095 close RPMRC;
2096
2097 my $builds = $package->{builds};
2098 my @commands = ();
2099 my $targets = $package->{targets};
2100 for my $build (@$builds)
2101 {
2102 my $tmp_specfile_name;
2103 if ($build->{name} eq '{MAIN}')
2104 {
2105 $tmp_specfile_name = "$dir/" . $package->{name} . ".spec";
2106 }
2107 else
2108 {
2109 $tmp_specfile_name = "$dir/" . $package->{name} .
2110 '-' . $build->{name} . ".spec";
2111 }
2112
2113 make_redhat_specfile($package, $build, $tmp_specfile_name);
2114 push @commands, "test -d $BUILD_TOP || mkdir $BUILD_TOP";
2115
2116 my $cmd = join (' ',
2117 "rpmbuild",
2118 "--target=$arch",
2119 "--rcfile $tmp_rpm_rc_fname",
2120 "-ba",
2121 "$tmp_specfile_name");
2122 push @commands, $cmd;
2123 }
2124 return @commands;
2125}
2126
2127
2128# --- Automatic Depedency Conversions (Guessing involved) ---
2129sub deb_to_rh_package_spec_list ($)
2130{
2131 my $depends = $_[0];
2132 my @pieces = ();
2133 for (split /,/, $depends)
2134 {
2135 s/^\s+//;
2136 s/\s+$//;
2137 s/[()]//g;
2138 push @pieces, $_;
2139 }
2140 return join(', ', @pieces);
2141}
2142
2143#
2144# convert debian-style dependencies to redhat-style.
2145# (redhat calls the line `Requires')
2146# debian/pkgwrite format:
2147#Depends: libglade0, libglib1.2 (>= 1.2.0), libgtk1.2 (>= 1.2.5), libxml1, libz1, xlib6g, mpg123
2148#Requires: libglade >= 0.11, gtk+ >= 1.2, libxml >= 1.7, mpg123
2149# As you can see, this cannot necessarily be automated,
2150# so we support Redhat-Requires: for override purposes.
2151sub compute_redhat_requires($)
2152{
2153 my $object = $_[0];
2154 if (defined($object->{redhat_requires}))
2155 {
2156 return $object->{redhat_requires};
2157 }
2158 elsif (defined($object->{depends}))
2159 {
2160 return deb_to_rh_package_spec_list ($object->{depends});
2161 }
2162 else
2163 {
2164 return '';
2165 }
2166}
2167sub compute_redhat_conflicts($)
2168{
2169 my $object = $_[0];
2170 if (defined($object->{redhat_conflicts}))
2171 {
2172 return $object->{redhat_conflicts};
2173 }
2174 elsif (defined($object->{conflicts}))
2175 {
2176 return deb_to_rh_package_spec_list ($object->{conflicts});
2177 }
2178 else
2179 {
2180 return '';
2181 }
2182}
2183
2184
2185#=====================================================================
2186# Section 6: Debian tape.
2187#=====================================================================
2188sub copy_docs ($$$$)
2189{
2190 my ($fh, $basedir, $list, $targetdocdir) = @_;
2191 my @rv = ();
2192
2193 for my $doc (@$list)
2194 {
2195 my $docbase;
2196 next unless $doc =~ m,([^/]+)/?$,;
2197 $docbase = $1;
2198 if ($doc =~ /\/$/)
2199 {
2200 print $fh "\t( cd $basedir/$doc/.. && \\\n",
2201 "\t tar cf - $docbase | \\\n",
2202 "\t $gzip || exit 1 \\\n",
2203 "\t) > $targetdocdir/$docbase.tar.gz\n";
2204 push @rv, $docbase;
2205 }
2206 elsif ($doc =~ /\.gz$/)
2207 {
2208 print $fh "\tcp -dp $basedir/$doc $targetdocdir\n";
2209 push @rv, $docbase;
2210 }
2211 else
2212 {
2213 print $fh "\t$gzip < $basedir/$doc > $targetdocdir/$docbase.gz\n";
2214 push @rv, "$docbase.gz";
2215 }
2216 }
2217}
2218
2219# debian_docs_from_list: return a list of full paths to documentation.
2220sub debian_docs_from_list ($)
2221{
2222 my $list = $_[0];
2223
2224 # Treat directories, gzipped and non-gzipped files differently.
2225 return map { my $base;
2226 if (/\//)
2227 {
2228 $base = $_;
2229 }
2230 elsif (/\.gz$/)
2231 {
2232 s/^.*\///;
2233 $base = $_;
2234 }
2235 else
2236 {
2237 s/^.*\///;
2238 $base = "$_.gz";
2239 }
2240 "/usr/share/doc/" . $target->{package_name} . "/$base";
2241 } @$list;
2242}
2243
2244# --- Create a debian `rules' file. ---
2245sub write_rules_file ($$)
2246{
2247 my ($fname, $package) = @_;
2248 open RULES, ">$fname" or die "couldn't create rules file ($fname)";
2249 print RULES <<'EOF';
2250#!/usr/bin/make -f
2251EOF
2252 print RULES "CONFIG_OPTS = $debian_config_flags\n";
2253
2254 print RULES <<'EOF';
2255# --- make the configure script itself (only needed from CVS) ---
2256configure:
2257 if test -x configure ; then \
2258 true ; \
2259 else \
2260 if test -x bootstrap ; then \
2261 ./bootstrap ; \
2262 elif test -x autogen.sh ; then \
2263 ./autogen.sh ; \
2264 fi \
2265 fi
2266 test -x configure
2267EOF
2268
2269 # Different "builds" -- these are completely rebuilt versions
2270 # of the source code, usually with just different configure flags, etc.
2271 my $builds = $package->{builds};
2272 my $install_targets = '';
2273 my $binary_package_targets = '';
2274 for my $build (@$builds)
2275 {
2276 my $suffix; my $path;
2277 if ($build->{name} eq '{MAIN}')
2278 {
2279 $suffix = '';
2280 $path = 'MAIN';
2281 }
2282 else
2283 {
2284 $path = $build->{name};
2285 $suffix = "-$path";
2286 }
2287 my $cfg_envars = $build->{configure_envars};
2288 my $cfg_flags = $build->{configure_flags};
2289
2290 print RULES '#', ('='x69), "\n",
2291 '# Methods for building', $build->{name}, "\n",
2292 '#', ('='x69), "\n";
2293
2294 # figure out how to run configure.
2295 print RULES <<"EOF";
2296configured$suffix: configured$suffix.pkgwrite-stamp
2297configured$suffix.pkgwrite-stamp: configure
2298EOF
2299 $has_configure = 1;
2300 if ($has_configure)
2301 {
2302 print RULES "\ttest -d debian/BUILDS || mkdir debian/BUILDS\n";
2303 print RULES "\trm -rf debian/BUILDS/$path\n";
2304 print RULES "\tmkdir debian/BUILDS/$path\n";
2305 print RULES "\tcd debian/BUILDS/$path && \\\n";
2306 print RULES "\t$cfg_envars \\\n" if defined $cfg_envars;
2307 $cfg_flags = '' unless defined ($cfg_flags);
2308 $cfg_flags .= " $debian_config_flags";
2309 print RULES "\t../../../configure $cfg_flags\n";
2310 print RULES "\ttouch configured$suffix.pkgwrite-stamp\n";
2311 }
2312 print RULES "\n";
2313
2314 # figure out how to build.
2315 my $build_flags = join (' ',
2316 $build->{make_flags} || '',
2317 $build->{build_flags} || '');
2318 print RULES <<"EOF";
2319build$suffix: build$suffix.pkgwrite-stamp
2320build$suffix.pkgwrite-stamp: configured$suffix.pkgwrite-stamp
2321 cd debian/BUILDS/$path && \$(MAKE) PREFIX=/usr $build_flags
2322EOF
2323 my $make_targets = $build->{extra_build_targets};
2324 for (@$make_targets)
2325 {
2326 print RULES "\tcd debian/BUILDS/$path && \\\n",
2327 "\t\t\$(MAKE) PREFIX=/usr $_ $build_flags\n";
2328 }
2329
2330 # figure out how to install.
2331 my $make_flags = $build->{make_flags};
2332 my $install_flags = $build->{install_flags};
2333 $install_flags = '' unless defined $install_flags;
2334 $install_flags .= " $make_flags" if defined $make_flags;
2335
2336 print RULES <<"EOF";
2337install$suffix: install$suffix.pkgwrite-stamp
2338install$suffix.pkgwrite-stamp: build$suffix.pkgwrite-stamp
2339 test -d debian/INSTALLS || mkdir debian/INSTALLS
2340 test -d debian/INSTALLS/$path || mkdir debian/INSTALLS/$path
2341 cd debian/BUILDS/$path && \\
2342 \$(MAKE) PREFIX=/usr DESTDIR=`pwd`/../../INSTALLS/$path \\
2343 $install_flags install
2344EOF
2345 $make_targets = $build->{extra_install_targets};
2346 for (@$make_targets)
2347 {
2348 print RULES "\tcd debian/BUILDS/$path && \\\n",
2349 "\t\t\$(MAKE) PREFIX=/usr \\\n",
2350 "\t\tDESTDIR=`pwd`/../../INSTALLS/$path \\\n",
2351 "\t\t$install_flags $_\n";
2352 }
2353 print RULES <<"EOF";
2354 touch install$suffix.pkgwrite-stamp
2355 rm -f target-dist.pkgwrite-stamp
2356EOF
2357 $install_stamp_targets .= " install$suffix.pkgwrite-stamp";
2358 $install_targets .= " install$suffix";
2359 }
2360
2361
2362 print RULES '#', ('='x69), "\n",
2363 "# Copying files into per-target directories.\n",
2364 '#', ('='x69), "\n",
2365 "target-dist: target-dist.pkgwrite-stamp\n",
2366 "target-dist.pkgwrite-stamp: $install_stamp_targets\n";
2367 my $targets = $package->{targets};
2368 my %MADE_DIRS = ();
2369 for my $target (@$targets)
2370 {
2371 my $suffix = '';
2372
2373 my $pname = $target->{package_name};
2374 # Move file from the build area to a target directory.
2375 my $files = $target->{files};
2376
2377 # figure out the target's build's directory name.
2378 my $buildname = $target->{build}->{name};
2379 if ($buildname eq '{MAIN}')
2380 {
2381 $buildname = 'MAIN';
2382 }
2383
2384 # find the string to suffix makefile targets with.
2385 if ($target->{name} ne '{MAIN}')
2386 {
2387 $suffix = "-" . $target->{name};
2388 }
2389 for my $pattern (@$files)
2390 {
2391 my $dir = $pattern;
2392 my $cp_command = 'cp -dp';
2393 $cp_command = 'cp -dpr' if $dir =~ s,/$,,;
2394
2395 # Are there any wild-cards in the directory part
2396 # of the pattern: they will require a different
2397 # strategy.
2398 if ($pattern =~ /.*[\?\*].*\/.*/)
2399 {
2400 print RULES "\tset -e ; (cd debian/INSTALLS/$buildname ; tar cf - ./$pattern) | ( cd debian/TARGETS/$pname ; tar xf -)\n";
2401 next;
2402 }
2403
2404 $dir =~ s,/[^/]+$,,;
2405 maybe_print_make_dirs (\%MADE_DIRS,
2406 'RULES',
2407 "debian/TARGETS/$pname/$dir");
2408 print RULES "\t$cp_command debian/INSTALLS/$buildname/$pattern debian/TARGETS/$pname/$dir\n";
2409 }
2410 my $manpages = $target->{manpages};
2411 for my $manpage (@$manpages)
2412 {
2413 my $section = get_manpage_section ($manpage);
2414 maybe_print_make_dirs (\%MADE_DIRS, 'RULES',
2415 "debian/TARGETS/$pname/usr/share/man/man$section");
2416 my $syspath = "usr/share/man/man$section/$manpage";
2417 print RULES "\tgzip -9 -c < debian/INSTALLS/$buildname/$syspath > debian/TARGETS/$pname/$syspath.gz\n";
2418 }
2419 my $inst_doc_dir = "debian/INSTALLS/$buildname/usr/share/doc";
2420 my $target_doc_dir = "debian/TARGETS/$pname/usr/share/doc";
2421 $target_doc_dir .= "/" . $target->{package_name};
2422 maybe_print_make_dirs (\%MADE_DIRS, 'RULES', $target_doc_dir);
2423 copy_docs ('RULES', "debian/INSTALLS/$buildname",
2424 $target->{installed_docs}, $target_doc_dir);
2425 copy_docs ('RULES', ".", $target->{source_docs}, $target_doc_dir);
2426
2427 # Copy the Changelog, if any, and add it to the list
2428 # of files for this target.
2429 print RULES "\tgzip -9 -c < debian/changelog > ",
2430 "$target_doc_dir/", $package->{changelog_file}, "\n";
2431
2432 $binary_package_targets .= " binary-package-target$suffix";
2433 }
2434 print RULES "\ttouch target-dist.pkgwrite-stamp\n";
2435 print RULES "\trm -f $binary_package_targets\n";
2436
2437 print RULES "\n\n";
2438 print RULES '#', ('='x69), "\n",
2439 "# Methods for creating binary packages.\n",
2440 '#', ('='x69), "\n";
2441
2442 # I don't think there's ever any reason to build
2443 # the arch-indep files separately, but someday we
2444 # might conceivable support a Platform-Independent flag
2445 # for builds; then they could be placed here.
2446 print RULES "# Build architecture-independent files here.\n",
2447 "binary-indep:\n",
2448 "\ttrue\n\n";
2449
2450 print RULES "# Build architecture-dependent files here.\n";
2451 for my $target (@$targets)
2452 {
2453 my $pname = $target->{package_name};
2454 my $build = $target->{build};
2455 $pname = 'MAIN' if $pname eq '{MAIN}';
2456 my $lcpname = lc($pname);
2457
2458 my $suffix = '';
2459 $suffix = ("-" . $target->{name}) if ($target->{name} ne '{MAIN}');
2460
2461 # build this binary package.
2462 print RULES <<"EOF";
2463binary-package-target$suffix: binary-package-target$suffix.pkgwrite-stamp
2464binary-package-target$suffix.pkgwrite-stamp: target-dist.pkgwrite-stamp
2465 # Compose DEBIAN directory (in debian/TARGETS/$pname)
2466 test -d debian/TARGETS/$pname/DEBIAN || mkdir debian/TARGETS/$pname/DEBIAN
2467 chmod o-w debian/TARGETS/$pname/DEBIAN
2468 dpkg-gencontrol -p$lcpname -Pdebian/TARGETS/$pname
2469EOF
2470 my $ddata = $target->{debian_data};
2471
2472 # copy various worker scripts into the DEBIAN directory.
2473 for my $variant (qw(preinst postinst prerm postrm))
2474 {
2475 if (defined ($ddata->{"needs_" . $variant}))
2476 {
2477 my $script = $target->{package_name} . ".$variant";
2478 print RULES "\tcp debian/$script debian/TARGETS/$pname/DEBIAN\n";
2479 print RULES "\tchmod +x debian/TARGETS/$pname/DEBIAN/$script\n";
2480 }
2481 }
2482
2483 print RULES <<"EOF";
2484 # Build the package.
2485 dpkg-deb --build debian/TARGETS/$pname ..
2486 touch binary-package-target$suffix.pkgwrite-stamp
2487EOF
2488 }
2489
2490 print RULES "# Debian standard targets.\n";
2491 print RULES "binary-package: $binary_package_targets\n";
2492 print RULES "binary-arch: $binary_package_targets\n";
2493 print RULES "binary: binary-indep binary-arch\n\n";
2494 print RULES "# these files may not be created by targets of their name.\n";
2495 print RULES ".PHONY: build clean binary-indep binary-arch binary\n";
2496 print RULES ".PHONY:$binary_package_targets\n";
2497 print RULES ".PHONY:$install_targets\n";
2498
2499 close (RULES);
2500 chmod (0755, $fname) or die "could not make `$fname' executable: $!";
2501}
2502
2503sub make_debian_description($)
2504{
2505 my @new_desc = ();
2506 my $old_desc = $_[0];
2507 for (split /\n/, $old_desc)
2508 {
2509 if (/^\S/)
2510 { push @new_desc, " $_" }
2511 elsif (/\S/)
2512 { push @new_desc, $_ }
2513 else
2514 { push @new_desc, " ." }
2515 }
2516 return join ("\n", @new_desc);
2517}
2518
2519sub make_debian_directory($$)
2520{
2521 my ($package, $source_dir) = @_;
2522 my $output_dir = "$source_dir/debian";
2523
2524 mkdir("$output_dir", 0755)
2525 or die "couldn't make the directory `$output_dir': $!";
2526
2527 # --- Create control file ---
2528 open CONTROL, ">$output_dir/control" or die "couldn't create control file";
2529 write_entries ('CONTROL', $package,
2530 [qw(Source Section Priority)],
2531 [qw(lcname section priority)]);
2532 if (defined($package->{authors}))
2533 {
2534 my $author0 = $package->{authors}->[0];
2535 print CONTROL "Maintainer: $author0\n";
2536 }
2537 print CONTROL "Standards-Version: 3.0.1\n\n";
2538
2539 my $targets = $package->{targets};
2540 for my $target (@$targets)
2541 {
2542 my $target_name = $target->{package_name};
2543 my $deb_description;
2544 if (defined($target->{description}))
2545 {
2546 $deb_description = make_debian_description ($target->{description});
2547 }
2548 else
2549 {
2550 $deb_description = make_debian_description ($package->{description});
2551 }
2552 my $target_arch = 'any';
2553 $target_arch = 'all' if $target->{arch_indep};
2554 print CONTROL "Package: " . lc($target_name) . "\n",
2555 "Architecture: ",
2556 ($target->{arch_indep} ? "all" : "any"),
2557 "\n";
2558 my $depends = $target->{depends};
2559 print CONTROL "Depends: $depends\n" if defined $depends;
2560 my $conflicts = $target->{conflicts};
2561 print CONTROL "Conflicts: $conflicts\n" if defined $conflicts;
2562 print CONTROL "Description: $deb_description\n\n";
2563 }
2564 close CONTROL;
2565
2566 for my $target (@$targets)
2567 {
2568 my $target_name = $target->{package_name};
2569 my $subname_dot;
2570 if ($target->{name} eq '{MAIN}')
2571 {
2572 $subname_dot = "";
2573 }
2574 else
2575 {
2576 $subname_dot = "$target_name.";
2577 }
2578
2579 # Create the list of all installed files (including docs).
2580 my $list = $target->{files};
2581 my $docdir = "/usr/share/doc/" . $target->{package_name};
2582 $list = [] unless defined $list;
2583 my @files = (
2584 @$list,
2585 debian_docs_from_list ($target->{source_docs}),
2586 debian_docs_from_list ($target->{installed_docs}),
2587 "$docdir/" . $package->{changelog_file}
2588 );
2589
2590 # --- Create the .files files ---
2591 write_list_to_file (\@files, "$output_dir/$target_name.files");
2592
2593 if (defined $target->{conffiles})
2594 {
2595 # --- Create the .conffile files ---
2596 write_list_to_file ($target->{conffiles},
2597 "$output_dir/$target_name.conffiles");
2598 }
2599
2600 # --- If ldconfig is needed, create .prerm and .postinst files. ---
2601 # XXX: i gotta learn if prerm is really correct.
2602 if ($target->{needs_ldconfig})
2603 {
2604 my $do_ldconfig_script = <<'EOF';
2605#! /bin/sh
2606
2607if test -x /sbin/ldconfig ; then
2608 /sbin/ldconfig
2609else
2610 ldconfig
2611fi
2612EOF
2613 make_file ("$output_dir/$target_name.postinst",
2614 $do_ldconfig_script);
2615 make_file ("$output_dir/$target_name.prerm",
2616 $do_ldconfig_script);
2617 $target->{debian_data}->{needs_prerm} = 1;
2618 $target->{debian_data}->{needs_postinst} = 1;
2619 }
2620 }
2621
2622 my $prefab_entry;
2623 {
2624 my $package_name = $package->{name};
2625 my $version = $package->{version};
2626 my $release = $package->{release};
2627 my $packager = $package->{packager};
2628 my $packager_email = $package->{packager_email};
2629 my $date = `date -R` ; chomp ($date);
2630 die unless defined $package_name;
2631 die unless defined $version;
2632 die unless defined $release;
2633 die unless defined $packager;
2634 die unless defined $packager_email;
2635 $prefab_entry =
2636 "$package_name ($version-$release) $debian_dist; urgency=low\n\n" .
2637 " * packaged by pkgwrite\n" .
2638 "\n" .
2639 " -- $packager <$packager_email> $date\n";
2640 }
2641 $changelog = $package->{changelog};
2642 if (defined($changelog))
2643 {
2644 $changelog = "$source_dir/$changelog";
2645 my $cp = changelog_parser_new ($changelog);
2646 die "couldn't read $changelog" unless defined $cp;
2647 my $got_first = 0;
2648 open OCL, ">$output_dir/changelog" or die "couldn't create changelog";
2649 while (changelog_parser_advance ($cp))
2650 {
2651 # Verify that the changelog matches package/version.
2652 unless ($got_first)
2653 {
2654 if ($cp->{package} ne $package->{name})
2655 {
2656 die "package name from changelog (" . $cp->{package} . ") "
2657 . "and according to the pkgwriteinfo "
2658 . "(" . $package->{name} . ")"
2659 . " do not match!";
2660 }
2661 my $ver = $package->{version} . '-' . $package->{release};
2662 if ($cp->{version} ne $ver)
2663 {
2664 if ($strict_changelog_checking)
2665 {
2666 die "package version in changelog (".$cp->{version}.")"
2667 . " and in pkgwriteinfo file ($ver) do not match!";
2668 }
2669 else
2670 {
2671 print OCL $prefab_entry;
2672 }
2673 }
2674 $got_first = 1;
2675 }
2676
2677 changelog_write_debian_style ($cp, 'OCL');
2678 }
2679 close OCL;
2680 changelog_parser_destroy ($cp);
2681 }
2682 else
2683 {
2684 make_file ("$output_dir/changelog", $prefab_entry);
2685 }
2686
2687 # --- Create rules file ---
2688 write_rules_file ("$output_dir/rules", $package);
2689}
2690
2691
2692#=====================================================================
2693# Section 7: Make a package from a tarball.
2694#=====================================================================
2695sub make_package($$$$$)
2696{
2697 my ($package, $tarball, $vendor, $arch, $output_dir) = @_;
2698
2699 my $workdir = get_work_dir ();
2700 chdir ($workdir) or die "couldn't cd $workdir";
2701
2702 # Assert: Various paths cannot be relative.
2703 die unless $tarball =~ m,^/,;
2704 die unless $output_dir =~ m,^/,;
2705
2706 # Make the packages.
2707 if ($vendor eq 'redhat')
2708 {
2709 my $rhdir = "$workdir/redhat";
2710 my @rpm_commands = make_redhat_dir ($package, $rhdir, $tarball, $arch);
2711 chdir "$rhdir" or die "couldn't cd to $rhdir";
2712 for my $rpm_command (@rpm_commands)
2713 {
2714 run ("$rpm_command");
2715 }
2716 my $rpmdir = "$workdir/redhat/rpm-tmp/usr/src/redhat";
2717 run ("cp $rpmdir/SRPMS/*.rpm $rpmdir/RPMS/*.rpm $output_dir");
2718 }
2719 elsif ($vendor eq 'debian')
2720 {
2721 my $ddir = "$workdir/debian";
2722 mkdir ($ddir, 0775) or die "couldn't make the directory $ddir";
2723
2724 # Untar.
2725 chdir ($ddir) or die "couldn't cd to $ddir";
2726 run ("zcat $tarball | tar xf -");
2727
2728 # Make the packaging directory.
2729 my $dir;
2730 $dir = "$ddir/" . $package->{name} . '-' . $package->{version};
2731
2732 make_debian_directory ($package, "$dir");
2733 chdir ($dir) or die "couldn't cd to $dir";
2734 run ("cd $dir && dpkg-buildpackage -rfakeroot -uc -us");
2735 run ("mv $ddir/*.deb $output_dir");
2736 my $dprefix = $package->{name}
2737 . "_" . $package->{version}
2738 . "-" . $package->{release};
2739
2740 # Move the debian source package.
2741 run ("mv $ddir/$dprefix.tar.gz $output_dir");
2742 run ("mv $ddir/$dprefix*.changes $output_dir");
2743 run ("mv $ddir/$dprefix*.dsc $output_dir");
2744 }
2745 else
2746 {
2747 die "i can only make `redhat' and `debian' packages";
2748 }
2749}
2750
2751
2752#=====================================================================
2753# Section 8: Usage message.
2754#=====================================================================
2755sub usage
2756{
2757 print STDERR <<"EOF";
2758usage: pkgwrite (--tarball=TARBALL | --srcdir=SRCDIR)
2759 [--pkgwriteinfo-file=pkgwriteinfo]
2760 [--no-cleanup]
2761 [--no-strict-changelog]
2762 [--debian-dist=DIST]
2763 --format=(redhat|debian|all)
2764 --output=OUTPUT
2765 --arch=ARCH
2766
2767Make either redhat or debian packages for source code and
2768a pkgwriteinfo file.
2769
2770(Run pkgwrite --extra-help for unusual command-line flags.)
2771
2772EOF
2773 print STDERR "The system supports .rpm building.\n" if $has_rpm_support;
2774 print STDERR "The system supports .deb building.\n" if $has_dpkg_support;
2775 exit (1);
2776}
2777
2778sub extra_usage
2779{
2780 print STDERR <<"EOF";
2781usage: pkgwrite [flags]
2782
2783Querying hardcoded lists of values in pkgwrite:
2784
2785 pkgwrite --query-list={deb-sections,rpm-groups,deb-priorities}
2786EOF
2787 exit (1);
2788}
2789
2790sub version
2791{
2792 print "This is pkgwrite, version $PKGWRITE_VERSION.\n";
2793 exit 0;
2794}
2795
2796
2797
2798
2799#=====================================================================
2800# Section 9: Main program.
2801#=====================================================================
2802my $pkg_tarball;
2803my $pkg_sourcedir;
2804my $pkgwriteinfo_file;
2805my $pkg_format;
2806my $pkg_arch;
2807my $output_dir;
2808
2809# --- Process arguments ---
2810while (defined($arg=shift(@ARGV)))
2811 {
2812 # Arguments that cause us to print something and exit.
2813 if ($arg eq '--help') { usage () }
2814 if ($arg eq '--extra-help') { extra_usage () }
2815 if ($arg eq '--version') { version () }
2816 if ($arg =~ s/--query-list=//) { dump_list ($arg); }
2817
2818 # Other flags.
2819 if ($arg eq '--no-strict-changelog') { $strict_changelog_checking = 0; }
2820 elsif ($arg eq '--skip-sanity-check') { $do_sanity_check = 0; }
2821 elsif ($arg eq '--no-cleanup') { $do_cleanup = 0; }
2822 elsif ($arg =~ s/--tarball=//) { $pkg_tarball = $arg; }
2823 elsif ($arg =~ s/--source-dir=//) { $pkg_sourcedir = $arg; }
2824 elsif ($arg =~ s/--output=//) { $output_dir = $arg; }
2825 elsif ($arg =~ s/--pkgwriteinfo-file=//){ $pkgwriteinfo_file = $arg; }
2826 elsif ($arg =~ s/--debian-dist=//) { $debian_dist = $arg; }
2827 elsif ($arg =~ s/--arch=//) { $pkg_arch = $arg; }
2828 elsif ($arg =~ s/--format=//) { $pkg_format = $arg; }
2829 elsif (($arg eq '--tarball')
2830 || ($arg eq '--source-dir')
2831 || ($arg eq '--output')
2832 || ($arg eq '--pkgwriteinfo-file')
2833 || ($arg eq '--format')
2834 || ($arg eq '--arch')
2835 || ($arg eq '--debian-dist')
2836 || ($arg eq '--query-list'))
2837 {
2838 my $newarg = shift(@ARGV);
2839 die "$arg requires a parameter" unless defined $newarg;
2840 if ($arg eq '--tarball') { $pkg_tarball = $newarg; }
2841 elsif ($arg eq '--source-dir') { $pkg_sourcedir = $newarg; }
2842 elsif ($arg eq '--pkgwriteinfo-file'){ $pkgwriteinfo_file = $newarg; }
2843 elsif ($arg eq '--output') { $output_dir = $newarg; }
2844 elsif ($arg eq '--arch') { $pkg_arch = $newarg; }
2845 elsif ($arg eq '--debian-dist') { $debian_dist = $newarg; }
2846 elsif ($arg eq '--format') { $pkg_format = $newarg; }
2847 elsif ($arg eq '--query-list') { dump_list ($newarg); }
2848 else { die "internal error" }
2849 }
2850 else
2851 {
2852 warn "unrecognized argument: $arg";
2853 usage ();
2854 }
2855 }
2856
2857unless (defined($pkg_tarball) || defined($pkg_sourcedir))
2858 {
2859 die "either --tarball or --source-dir must be specified"
2860 }
2861unless (defined ($pkg_format))
2862 {
2863 die "--format must be specified";
2864 }
2865unless (defined ($output_dir))
2866 {
2867 die "--output must be specified";
2868 }
2869unless (defined ($pkg_arch))
2870 {
2871 die "--arch must be specified";
2872 }
2873if ($pkg_format ne 'all'
2874 && $pkg_format ne 'debian'
2875 && $pkg_format ne 'redhat')
2876 {
2877 my $valid = join (', ', qw(all debian redhat));
2878 die "format `$pkg_format' was invalid: only $valid are known";
2879 }
2880if (($pkg_format eq 'all' || $pkg_format eq 'redhat')
2881 && !$has_rpm_support)
2882 {
2883 die "cannot make RPMs on this system";
2884 }
2885if (($pkg_format eq 'all' || $pkg_format eq 'debian')
2886 && !$has_dpkg_support)
2887 {
2888 die "cannot make Debian packages on this system";
2889 }
2890
2891
2892# Make all paths absolute.
2893#
2894# We are about to `chdir' all over the place.
2895# While technically `make_absolute' is cheesy
2896# (b/c eg it doesn't work if `pwd` has been deleted),
2897# it least it works in practice,
2898# and makes the programming much easier.
2899if (defined($pkg_tarball))
2900 { $pkg_tarball = make_absolute ($pkg_tarball) }
2901if (defined($pkg_sourcedir))
2902 { $pkg_sourcedir = make_absolute ($pkg_sourcedir) }
2903if (defined($pkgwriteinfo_file))
2904 { $pkgwriteinfo_file = make_absolute ($pkgwriteinfo_file) }
2905if (defined($output_dir))
2906 { $output_dir = make_absolute ($output_dir);
2907 run ("mkdir -p $output_dir"); }
2908if (defined($debian_changelog))
2909 { $debian_changelog = make_absolute ($debian_changelog) }
2910
2911
2912# Create pkgwriteinfo_file if necessary.
2913if (!defined($pkgwriteinfo_file))
2914 {
2915 # Build a temporary working area to monkey with the source code.
2916 my $workdir = get_work_dir ();
2917 my $edir = "$workdir/pkgwriteinfo-tmp-extract";
2918 mkdir ($edir, 0755) or die;
2919 my $tmp_source_dir;
2920
2921 # Extract the source code, to (hopefully) find a pkgwriteinfo{,.in} file.
2922 if (defined($pkg_tarball))
2923 {
2924 run ("cd $edir ; $gunzip < $pkg_tarball | tar xf -");
2925
2926 # find the tmp source directory inside $edir.
2927 opendir X, "$edir" or die "error scanning $edir";
2928 for (readdir X)
2929 {
2930 next if $_ eq '.';
2931 next if $_ eq '..';
2932 next unless -d "$edir/$_";
2933 $tmp_source_dir = "$edir/$_";
2934 last;
2935 }
2936 closedir X;
2937 }
2938 else
2939 {
2940 $tmp_source_dir = $pkg_sourcedir;
2941 }
2942 die "could not find directory in tarball" unless defined $tmp_source_dir;
2943
2944 # If there isn't a pkgwriteinfo file, try running configure.
2945 if (!-e "$tmp_source_dir/pkgwriteinfo")
2946 {
2947 if (-e "$tmp_source_dir/pkgwriteinfo.in")
2948 {
2949 if (! -x "$tmp_source_dir/configure")
2950 {
2951 # Uh, maybe `bootstrap' or `autogen.sh' will help?
2952 if (-x "$tmp_source_dir/bootstrap")
2953 {
2954 run ("cd $tmp_source_dir; ./bootstrap");
2955 run ("cd $tmp_source_dir; ./configure --quiet");
2956 }
2957 elsif (-x "$tmp_source_dir/autogen.sh")
2958 {
2959 run ("cd $tmp_source_dir; ./autogen.sh --quiet");
2960 }
2961 }
2962 else
2963 {
2964 # Excellent: configure it.
2965 run ("cd $tmp_source_dir; ./configure --quiet");
2966 }
2967 unless (-e "$tmp_source_dir/pkgwriteinfo.in")
2968 {
2969 warn "pkgwriteinfo is probably needed in AC_OUTPUT";
2970 }
2971 }
2972 else
2973 {
2974 die "could not find pkgwriteinfo{.in} in the tarball";
2975 }
2976 }
2977
2978 # If there isn't a pkgwriteinfo file, it's an error.
2979 if (!-e "$tmp_source_dir/pkgwriteinfo")
2980 {
2981 die "couldn't make pkgwriteinfo file";
2982 }
2983
2984 # Copy the pkgwriteinfo file about and remove $edir.
2985 $pkgwriteinfo_file = "$workdir/pkgwriteinfo";
2986 run ("cp $tmp_source_dir/pkgwriteinfo $pkgwriteinfo_file");
2987 run ("rm -rf $edir");
2988 }
2989
2990# --- Build the package(s) ---
2991my $package = parse_pkgwriteinfo_file ($pkgwriteinfo_file);
2992die "couldn't parse package from $pkgwriteinfo_file" unless defined $package;
2993
2994# Sanity check the package.
2995sanity_check_package ($package) if ($do_sanity_check);
2996
2997$package->{package_tarball} = $pkg_tarball;
2998$package->{package_source_dir} = $pkg_sourcedir;
2999
3000# Produce a list of formats.
3001my @format_list;
3002if ($pkg_format eq 'all')
3003 {
3004 @format_list = qw(debian redhat)
3005 }
3006else
3007 {
3008 @format_list = ( $pkg_format );
3009 }
3010
3011# Make all the desired formats.
3012for my $format (@format_list)
3013 {
3014 make_package ($package, $pkg_tarball, $format, $pkg_arch, $output_dir);
3015 }
3016
3017# Clean up.
3018remove_work_dir ();
3019
3020exit (0);
3021
3022# --- Miscellaneous "main" helper functions ---
3023
3024# dump_table: Print the values of a hash-table reference to standard-output.
3025sub dump_table ($)
3026{
3027 my $table = $_[0];
3028 for (sort keys %$table)
3029 {
3030 print $table->{$_}, "\n";
3031 }
3032 exit (0);
3033}
3034
3035# dump_list: dump one of the standard builtin hashtables to standard output.
3036sub dump_list ($)
3037{
3038 my $list = $_[0];
3039 if ($list eq 'deb-sections') { dump_table (\%DPKG_SECTIONS); }
3040 elsif ($list eq 'deb-priorities') { dump_table (\%DPKG_PRIORITY_LEVELS); }
3041 elsif ($list eq 'rpm-groups') { dump_table (\%RPM_GROUPS); }
3042 else { die "unknown list to dump (to --query-list): $list" }
3043}
3044
3045
3046#=====================================================================
3047# Section 10: POD Documention.
3048#=====================================================================
3049=pod
3050
3051=head1 NAME
3052
3053pkgwrite - Make RedHat and Debian packages from the same source.
3054
3055=head1 SYNOPSIS
3056
3057 pkgwrite (--tarball=TARBALL | --srcdir=SRCDIR) \
3058 [--pkgwriteinfo-file=pkgwriteinfo] \
3059 --arch=ARCH \
3060 --format={redhat,debian}
3061 [options]
3062
3063
3064 pkgwrite --query-list=LISTNAME
3065
3066=head1 DESCRIPTION
3067
3068pkgwrite takes a standard automake package, either from a source directory
3069or from a distributed tarball, and a C<pkgwrite> input file
3070and makes either RedHat or Debian packages.
3071
3072The actual package source code must be specified either by
3073directory (using --srcdir) or from a tarball created with `make dist'
3074(using --tarball).
3075
3076Additional packaging information is taken from pkgwriteinfo.
3077If --pkgwriteinfo-file is omitted, pkgwriteinfo from the source
3078directory or tarball is taken instead. (after configure is run,
3079so you might generally use a pkgwriteinfo.in).
3080
3081There are a few command-line parameters which affect the package-making:
3082
3083=over 4
3084
3085=item --no-strict-changelog
3086
3087Don't force the user's changelog and pkgwriteinfo file to
3088have the same version. (If the packaging system
3089requires that the changelog's latest entry be equal to
3090the package's version, then pkgwrite will generate a
3091changelog entry. This happens under Debian.)
3092
3093=item --no-cleanup
3094
3095Don't remove the temporary directory (which will
3096be C</tmp/mkpkg-###-$USER>). Useful for debugging.
3097
3098=item --debian-dist=DIST
3099
3100Generate packaging for the given debian distribution:
3101this mostly affects the changelog so
3102setting DIST to C<stable> or C<unstable> is recommended.
3103
3104=item --skip-sanity-check
3105
3106Disable the usual checks that the package is valid.
3107The package may still partially work, even if a sanity-check
3108would normally fail.
3109
3110=back
3111
3112=head1 TERMINOLOGY
3113
3114=over 4
3115
3116=item package
3117
3118A family of packages for various distributions
3119which all come from one tarball and one pkgwriteinfo file.
3120
3121=item build
3122
3123A compilation of the source code into binaries.
3124Some packages require multiple builds, for example, to make debugging
3125and nondebugging versions of a libraries.
3126Normally you just use the C<{MAIN}> build.
3127
3128=item target
3129
3130A single set of installed files in a package.
3131Simple packages only have a single target C<{MAIN}>
3132because the package is an all-or-nothing proposition.
3133
3134Some packages contain many parts, not all applicable to all users.
3135These packages should be broken in to different targets.
3136
3137For example, a client/server based application might be
3138conveniently packaged C<foo-server>, C<foo-client-curses>, C<foo-client-gtk>.
3139That way, users without X can use the curses version without
3140installing gtk+, often the clients and servers are run exclusively on
3141different machines, so installing both is a waste of disk space.
3142
3143=back
3144
3145The resulting system-dependent binary's name is just
3146the main C<Package:> name if the C<Target:> is C<{MAIN}>;
3147otherwise it will be the C<Package> and C<Target> separated by
3148a hyphen (C<->).
3149
3150=head1 MAINTAINING CHANGELOGS
3151
3152We recommend that you maintain a changelog in debian format,
3153here is an example:
3154
3155 gdam (0.934-1) unstable; urgency=low
3156
3157 * many bug fixes
3158 * split into many packages
3159
3160 -- David Benson <daveb@ffem.org> Wed, 17 Jan 2000 13:09:36 -0800
3161
3162(No spaces for each version banner; 2 spaces on each bullet;
31631 space before the packager byline.)
3164
3165If you don't maintain a changelog, we will generate a changelog
3166with just this version of the package in it.
3167
3168You should specify the changelog using the C<Changelog:> directive.
3169
3170=head1 EXAMPLES
3171
3172Here are a few examples of common types of packages.
3173The pkgwrite distribution includes these packages
3174inside the C<examples/tiny> directory.
3175
3176=head2 EXAMPLE: SINGLE-TARGET PACKAGE
3177
3178The most common type of package has one set of files
3179it installs or uninstalls: there are no packaged bits or pieces.
3180(A Target in pkgwrite terminology is the installed set of files.)
3181
3182Here is the pkgwrite file from the single-target example
3183included with the pkgwrite distribution:
3184
3185 Package: aa
3186 Section: text
3187 Group: Applications/Text
3188 Priority: low
3189 Home-Page: NONE
3190 Source-Url: NONE
3191 Author: David Benson <daveb@ffem.org>
3192 Version: 0.0.8
3193 Release: 1
3194 Synopsis: test package aa
3195 Packager: daveb
3196 Packager-Email: daveb@ffem.org
3197 License: NONE
3198 Description: test package (aa).
3199
3200 Build: {MAIN}
3201
3202 Target: {MAIN}
3203 Files: /usr/bin/dummy-*
3204 Synopsis: test a (single-target package)
3205
3206This package's name is C<aa>; this file will produce a binary RPM
3207named C<aa-0.0-1.$ARCH.rpm>.
3208
3209=over 4
3210
3211=item *
3212
3213we wanted to name this C<a>, but debian packages must be at least two
3214letters.
3215
3216=item *
3217
3218$ARCH is the target architecture, for example
3219C<i386>, C<alpha>, or C<powerpc>.
3220
3221=item *
3222
3223The Target C<{MAIN}> is special, it
3224means "don't use any suffix" -- the package's
3225name is to be C<aa>. For any other Target line,
3226if STRING was specified, the resulting
3227RPM or deb would have the name C<aa-STRING>.
3228
3229=item *
3230
3231Each wildcard from Files lines describe a file or files to move
3232into that target.
3233
3234=item *
3235
3236Unlisted files will not wind up in any binary package.
3237
3238=back
3239
3240=head2 EXAMPLE: MULTI-TARGET PACKAGE
3241
3242A multi-target, single-build package is a package that need
3243only be compiled once, but which must be separated into
3244several system packages, because the targets appeal to
3245different users or have different dependencies.
3246
3247Here is the pkgwriteinfo file from the example multi-target single-build
3248package:
3249
3250
3251 Package: bb
3252 Section: text
3253 Group: Applications/Text
3254 Priority: low
3255 Home-Page: NONE
3256 Source-Url: NONE
3257 Author: David Benson <daveb@ffem.org>
3258 Version: 0.0
3259 Release: 1
3260 Synopsis: test package bb
3261 Packager: daveb
3262 Packager-Email: daveb@ffem.org
3263 License: NONE
3264 Description: test package (bb).
3265
3266 Build: {MAIN}
3267
3268 Target: a
3269 Files: /usr/bin/bb-a
3270 Synopsis: part a of package bb
3271 Description: whatever (bb-a)
3272
3273 Target: b
3274 Files: /usr/bin/bb-b
3275 Synopsis: part b of package bb
3276 Description: whatever (bb-b)
3277
3278In this package, only a single default Build: is required.
3279Some packages may require the C<Configure-Flags> or
3280C<Configure-Envars> fields in order to compile correctly.
3281
3282By default, all the targets use the C<{MAIN}> Build.
3283
3284Then each package contains a default file list,
3285a description and a synopsis.
3286
3287=head2 EXAMPLE: MULTI-BUILD PACKAGE
3288
3289The most complex type of package must be built multiple times,
3290with different configure or make flags. Each target must then
3291refer to the build from which it was produced,
3292using the C<Which-Build> field (the default is C<{MAIN}>).
3293
3294Here is the example of such a package from the C<pkgwrite>
3295distribution:
3296
3297 Package: cc
3298 Section: text
3299 Group: Applications/Text
3300 Priority: low
3301 Home-Page: NONE
3302 Source-Url: NONE
3303 Author: David Benson <daveb@ffem.org>
3304 Version: 0.0
3305 Release: 1
3306 Synopsis: test package cc
3307 Packager: daveb
3308 Packager-Email: daveb@ffem.org
3309 License: NONE
3310 Description: test package (cc).
3311
3312 Build: nond
3313 Configure-Flags: --program-suffix=-nondebug
3314
3315 Build: d
3316 Configure-Flags: --program-suffix=-debug
3317
3318 Target: nondebug
3319 Which-Build: nond
3320 Files: /usr/bin/test-nondebug
3321 Synopsis: nondebug package cc
3322 Description: whatever (cc-nondebug)
3323
3324 Target: debug
3325 Which-Build: d
3326 Files: /usr/bin/test-debug
3327 Synopsis: debug package cc
3328 Description: whatever (cc-debug)
3329
3330Each Build section corresponds to a complete configure, build, install phase.
3331In this package, the C<nond> build just wants configure to be run
3332 configure --program-suffix=-nondebug ...
3333whereas for the C<d> build,
3334 configure --program-suffix=-debug ...
3335(Note that the ... will be somewhat different from distribution to
3336distribution)
3337
3338Also, it is often convenient to use the same names for the builds and
3339the targets. We would rename C<nond> as C<nondebug> and C<d> as C<debug>
3340if this were a real package -- we did this to discuss it more
3341conveniently.
3342
3343It is perfectly possible to have more than one Target pointing to the same
3344Build, just as multi-target single-build packages do.
3345But the opposite is not allowed: a Target must specify exactly one
3346Build.
3347
3348=head1 HARDCODED VALUES
3349
3350Many lists and values are hardcoded into pkgwrite.
3351You may query these lists through the --query-list flag.
3352Here are the lists you may obtain in this manner:
3353
3354=over 4
3355
3356=item deb-sections
3357
3358Known allowed Section: fields for debian packages.
3359
3360=item rpm-groups
3361
3362Known allowed Group: fields for redhat packages.
3363
3364=item deb-priority
3365
3366Known allowed Priority: fields for debian packages.
3367
3368=back
3369
3370For example to get a list of allowed values for the Section:
3371field, use C<pkgwrite --query-list=deb-sections>.
3372
3373=head1 PKGWRITE'S pkgwriteinfo FORMAT
3374
3375This (long) section describes the file
3376that describes the targets to build from a tarball.
3377This description file is called a C<pkgwriteinfo> file.
3378
3379The C<pkgwriteinfo> file consists of one package description part,
3380then a number of Build sections,
3381then a number of Target sections.
3382
3383=head2 PER-PACKAGE INFO
3384
3385The package file should begin with a section that describes
3386the overall source code of the package:
3387
3388 Package: gdam
3389 Section: sound
3390 Group: Multimedia/Sound
3391 Priority: optional
3392 Home-Page: http://ffem.org/gdam
3393 Source-Url: http://ffem.org/gdam/downloads/gdam-0.0.930.tar.gz
3394 Version: 0.0.930
3395 Release: 1
3396 Author: David Benson <daveb@ffem.org>
3397
3398Here is a description of each allowed field:
3399
3400=over 4
3401
3402=item Package
3403
3404Name of the source package.
3405
3406=item Output-Package
3407
3408Sometimes, all packages from a tarball use a somewhat
3409different name than the tarball itself.
3410This is used as a bit of a hack to support co-installation
3411of multiple versions of a package. This is like
3412gtk, which has gtk1.2 and gtk2.0 packages, which can be installed concurrently.
3413
3414=item Version
3415
3416The version number given to this version of the package
3417by its maintainer.
3418
3419=item Release
3420
3421Increment this each time a new package is released without
3422a corresponding upstream version-number change.
3423
3424=item Section
3425
3426The debian section this package belongs in.
3427
3428=item Group
3429
3430The redhat group this package belongs in.
3431
3432=item Priority
3433
3434Priority of this package (debian-style).
3435
3436=item Home-Page
3437
3438A URL giving the home page for this package or project.
3439
3440=item Source-Url
3441
3442A URL describing how to download this package.
3443
3444=item Author
3445
3446An author of this package, with email optional.
3447
3448=item Synopsis
3449
3450Under one line summary of this target.
3451
3452=item Description
3453
3454Multiple-line description of this target.
3455
3456=item Packager
3457
3458Full name of the person who made this packaging.
3459
3460=item Packager-Email
3461
3462Email address at which to reach the packager.
3463
3464=item Changelog
3465
3466Specify the location of a Debian format changelog to include with
3467the package (it will be converted to another standard format, if needed)
3468
3469=item Upstream-is-Packager
3470
3471Whether the packager (the person running C<pkgwrite>)
3472is the same as the upstream maintainer of a package.
3473
3474Right now, this only affects the filename used for the changelog,
3475it will either be C<changelog.gz> if they are the same person,
3476or C<changelog.Debian.gz> if they are not.
3477
3478=back
3479
3480=head2 PER-TARGET INFO
3481
3482For each output binary package there must be a "target" section:
3483
3484 Target: xmms-plugins
3485 Depends: gdam-clients-gtk, gdam-server, xmms
3486 Synopsis: GDAM XMMS plugin support
3487 Description: use XMMS visualization plugins with GDAM.
3488 Files: /usr/bin/gdamxmmsvishelper
3489
3490=over 4
3491
3492=item Target
3493
3494Name of this target. The name of the package that results will
3495be prepended with SOURCE-; in this example the package's name
3496is C<gdam-xmms-plugins>.
3497
3498=item Platform-Independent
3499
3500Set this to C<yes> if this package will be installable on
3501any architecture (it contains no system-specific or compiled code).
3502
3503Set this to C<no> for packages containing compiled,
3504architecture-specific binaries.
3505
3506=item Depends
3507
3508Debian-formatted dependency lists for this package.
3509
3510=item Redhat-Requires
3511
3512Specify the redhat packages that this one depends on.
3513(We will try to compute this from the C<Depends:> lines by default;
3514this is just in case we cannot guess correctly.)
3515
3516=item Conflicts
3517
3518Debian-formatted list of packages that conflict with this one.
3519
3520=item Redhat-Conflicts
3521
3522Redhat-formatted list of packages that conflict with this one.
3523Computed from C<Conflicts:> by default.
3524
3525=item Synopsis
3526
3527Under one line summary of this target.
3528
3529=item Man-Page
3530
3531The basename of a man page, for example C<pkgwrite.1>.
3532It will automatically be installed into the correct
3533section directory based on its extension.
3534
3535=item Doc
3536
3537Miscellaneous documentation.
3538Each path is assumed to be inside the installed area.
3539
3540It will be always be copied into the distribution's
3541documentation area, and it will be gzip'd if that is needed.
3542Also, whole directories will be recursively copied,
3543if the entry ends with a /, for example,
3544
3545 Doc: /usr/share/doc/gdam/example-configs/
3546
3547=item Source-Doc
3548
3549Miscellaneous documentation that is not normally
3550installed by this package's makefile:
3551
3552These must be files directly from the distributed tarball.
3553They will be always be copied into the distribution's
3554documentation area and will be gzip'd if that is needed.
3555Whole directories will be recursively copied,
3556if the entry ends with a /.
3557
3558=item Description
3559
3560Multiple-line description of this target.
3561
3562=item Which-Build
3563
3564Name of the build whose files should be used.
3565(Defaults to C<{MAIN}>).
3566
3567=item Files
3568
3569A wildcard matching ordinary files to be distributed with
3570this target.
3571
3572=back
3573
3574=head2 PER-BUILD INFO
3575
3576=over 4
3577
3578=item Build
3579
3580The name of this build. The default build should be named
3581C<{MAIN}>.
3582
3583=item Configure-Flags
3584
3585Options to be passed to the C<configure> script.
3586
3587=item Configure-Envars
3588
3589Space-separated environment variables to add when configuring.
3590
3591=item Make-Flags
3592
3593Extra parameters to the C<make> program during both
3594the build and the install phase.
3595
3596=item Build-Flags
3597
3598Extra parameters to the C<make> program during just
3599the build phase.
3600
3601=item Install-Flags
3602
3603Extra parameters to the C<make> program during just
3604the install phase.
3605
3606=item Extra-Build-Targets
3607
3608Another C<make> target that is necessary to build the package,
3609that is not run by the default target. This must not
3610require root priviledges. (You may specify
3611any number of C<Extra-Build-Targets:> lines.)
3612
3613=item Extra-Install-Targets
3614
3615Another C<make> target that is necessary to install the package,
3616that is not run by the default target. On Debian systems, these commands
3617may require root or fakeroot. (You may specify
3618any number of C<Extra-Install-Targets:> lines.)
3619
3620=back
3621
3622=head1 DEBUGGING
3623
3624If you have problems, here are some hints:
3625
3626=over 4
3627
3628=item *
3629
3630If you are familiar with one of the packaging systems (Redhat or Debian)
3631that is not working, try building that with either
3632the C<--no-cleanup> flag or equivalently have the C<DO_CLEANUP>
3633environment variable set to C<0>. (You can find the
3634directory where work was done by running: C<ls -ltr /tmp/mkpkg-*>)
3635
3636=item *
3637
3638Otherwise, redirect the output to a log file and read the whole thing.
3639Some packaging systems output a log of messages
3640even after a fatal error.
3641
3642=item *
3643
3644Then, try and cut out pieces of the C<pkgwriteinfo>
3645file until you locate the problem.
3646Report a bug if the problem is clear.
3647
3648=back
3649
3650=head1 COMMON PROBLEMS
3651
3652Here are some trivial mistakes made often:
3653
3654=over 4
3655
3656=item *
3657
3658C<pkgwriteinfo> is generated by C<configure> from C<pkgwriteinfo.in>.
3659It is easy to forget to rerun C<configure> and very slow.
3660
3661I don't know of any easy solution to forgetting
3662at the moment, but you may just run C<config.status>
3663instead, in order save time.
3664
3665=back
3666
3667=head1 RELEASING PACKAGES
3668
3669Of course, you can and should work however you want,
3670but for your information, I will write the testing process
3671I use for releasing packages.
3672
3673I always make C<automake> packages that use
3674C<pkgwriteinfo> inside the tarball.
3675
3676It is important to note that my packages always
3677support C<make rpm> and C<make deb> using C<pkgwrite>,
3678and that these targets only C<make dist> if the tarball
3679isn't present!
3680
3681=over 4
3682
3683=item 1
3684
3685Check out the package from CVS. Then either use whichever
3686bootstrap script is provided: my recent packages use C<bootstrap>
3687(as recommended by the C<automake> authors), but many packages
3688use C<./autogen.sh>, which traditionally also runs C<./configure>.
3689
3690If you used C<bootstrap>, you will need to run C<./configure>.
3691
3692Then make the tarball using C<make distcheck>.
3693
3694=item 2
3695
3696On a RedHat machine and a Debian machine,
3697untar the tarball and copy that same tarball
3698into the PACKAGE-VERSION directory that was created.
3699(This way, the exact same tarball will be reused).
3700
3701=item 3
3702
3703On each system, run C<./configure>, then
3704C<make rpm> and C<make deb>, respectively.
3705
3706=item 4
3707
3708Copy all the returned packages, the C<dist> tarball,
3709into a directory which you will upload.
3710
3711=item 5
3712
3713Test install those packages on machines.
3714
3715I also inspect them with the following commands:
3716
3717 System| RedHat Debian
3718 Action |
3719 --------------+------------------------------------------------
3720 List of files | rpm -qpl *.rpm dpkg-deb -c *.deb
3721 General data | rpm -qpi *.rpm dpkg-deb -e *.deb
3722
3723=back
3724
3725=head1 EXAMPLE AUTOMAKE FILES
3726
3727TODO
3728
3729=head1 AUTHOR
3730
3731Written by Dave Benson <daveb@ffem.org>.
3732
3733=cut