lahiker42 | 7a45dc1 | 2008-10-01 00:29:30 +0000 | [diff] [blame] | 1 | #! /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 | |
| 52 | require 5.004; |
| 53 | use Carp; |
| 54 | use Config; # for signal names |
| 55 | use 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 --- |
| 75 | sub dump_list ($); # print a builtin table to stdout |
| 76 | sub initialize_packaging_tables (); # redhat/debian package mgnt specifics |
| 77 | sub initialize_signal_tables (); # signal number to id mappings |
| 78 | sub add_automatic_conflicts ($); # add conflicts if file sets intersect |
| 79 | |
| 80 | # --- global initialization --- |
| 81 | $initial_dir = `pwd`; |
| 82 | chomp ($initial_dir); |
| 83 | initialize_packaging_tables (); |
| 84 | initialize_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 --- |
| 152 | sub 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. |
| 194 | sub 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 --- |
| 211 | sub 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. |
| 231 | sub 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. |
| 240 | sub 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. |
| 253 | sub 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. |
| 263 | sub 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. |
| 281 | sub 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. |
| 295 | sub 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. |
| 307 | sub 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. |
| 320 | sub 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. |
| 338 | sub 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. |
| 356 | sub 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). |
| 369 | sub 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 --- |
| 386 | sub get_tmp_dir() { |
| 387 | return $ENV{'TMPDIR'} || $ENV{'TEMPDIR'} || "/tmp"; |
| 388 | } |
| 389 | sub 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 | |
| 402 | sub 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 | |
| 469 | sub 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 --- |
| 627 | sub 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 --- |
| 757 | sub 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 --- |
| 919 | sub 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. |
| 972 | sub 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. |
| 1083 | sub 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. |
| 1098 | sub 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 |'. |
| 1236 | sub 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. |
| 1248 | sub _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. |
| 1263 | sub 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) |
| 1329 | sub 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) |
| 1342 | sub 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. |
| 1375 | sub 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'. |
| 1395 | sub 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. |
| 1489 | sub 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. |
| 1514 | sub 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 | |
| 1528 | sub 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 | |
| 1797 | sub 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. |
| 1827 | sub 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'; |
| 1856 | arch_canon: mipseb: mipseb 4 |
| 1857 | arch_canon: ppc: ppc 5 |
| 1858 | arch_canon: m68k: m68k 6 |
| 1859 | arch_canon: IP: sgi 7 |
| 1860 | arch_canon: rs6000: rs6000 8 |
| 1861 | arch_canon: ia64: ia64 9 |
| 1862 | arch_canon: sparc64:sparc64 10 |
| 1863 | arch_canon: sun4u: sparc64 10 |
| 1864 | arch_canon: mipsel: mipsel 11 |
| 1865 | arch_canon: armv4b: armv4b 12 |
| 1866 | arch_canon: armv4l: armv4l 12 |
| 1867 | EOF |
| 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 | |
| 1876 | os_canon: Linux: Linux 1 |
| 1877 | os_canon: IRIX: Irix 2 |
| 1878 | # This is wrong |
| 1879 | os_canon: SunOS5: solaris 3 |
| 1880 | os_canon: SunOS4: SunOS 4 |
| 1881 | |
| 1882 | os_canon: AmigaOS: AmigaOS 5 |
| 1883 | os_canon: AIX: AIX 5 |
| 1884 | os_canon: HP-UX: hpux10 6 |
| 1885 | os_canon: OSF1: osf1 7 |
| 1886 | os_canon: osf4.0: osf1 7 |
| 1887 | os_canon: osf3.2: osf1 7 |
| 1888 | os_canon: FreeBSD: FreeBSD 8 |
| 1889 | os_canon: SCO_SV: SCO_SV3.2v5.0.2 9 |
| 1890 | os_canon: IRIX64: Irix64 10 |
| 1891 | os_canon: NEXTSTEP: NextStep 11 |
| 1892 | os_canon: BSD/OS: BSD_OS 12 |
| 1893 | os_canon: machten: machten 13 |
| 1894 | os_canon: CYGWIN32_NT: cygwin32 14 |
| 1895 | os_canon: CYGWIN32_95: cygwin32 15 |
| 1896 | os_canon: UNIX_SV: MP_RAS: 16 |
| 1897 | os_canon: MiNT: FreeMiNT 17 |
| 1898 | os_canon: OS/390: OS/390 18 |
| 1899 | os_canon: VM/ESA: VM/ESA 19 |
| 1900 | os_canon: Linux/390: OS/390 20 |
| 1901 | os_canon: Linux/ESA: VM/ESA 20 |
| 1902 | EOF |
| 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'; |
| 1941 | os_compat: IRIX64: IRIX |
| 1942 | os_compat: solaris2.7: solaris2.3 solaris2.4 solaris2.5 solaris2.6 |
| 1943 | os_compat: solaris2.6: solaris2.3 solaris2.4 solaris2.5 |
| 1944 | os_compat: solaris2.5: solaris2.3 solaris2.4 |
| 1945 | os_compat: solaris2.4: solaris2.3 |
| 1946 | |
| 1947 | os_compat: hpux11.00: hpux10.30 |
| 1948 | os_compat: hpux10.30: hpux10.20 |
| 1949 | os_compat: hpux10.20: hpux10.10 |
| 1950 | os_compat: hpux10.10: hpux10.01 |
| 1951 | os_compat: hpux10.01: hpux10.00 |
| 1952 | os_compat: hpux10.00: hpux9.07 |
| 1953 | os_compat: hpux9.07: hpux9.05 |
| 1954 | os_compat: hpux9.05: hpux9.04 |
| 1955 | |
| 1956 | os_compat: osf4.0: osf3.2 osf1 |
| 1957 | |
| 1958 | os_compat: ncr-sysv4.3: ncr-sysv4.2 |
| 1959 | |
| 1960 | os_compat: FreeMiNT: mint MiNT TOS |
| 1961 | os_compat: MiNT: FreeMiNT mint TOS |
| 1962 | os_compat: mint: FreeMiNT MiNT TOS |
| 1963 | os_compat: TOS: FreeMiNT MiNT mint |
| 1964 | |
| 1965 | buildarch_compat: ia64: noarch |
| 1966 | |
| 1967 | buildarch_compat: athlon: i686 |
| 1968 | buildarch_compat: i686: i586 |
| 1969 | buildarch_compat: i586: i486 |
| 1970 | buildarch_compat: i486: i386 |
| 1971 | buildarch_compat: i386: noarch |
| 1972 | |
| 1973 | buildarch_compat: sun4c: noarch |
| 1974 | buildarch_compat: sun4d: noarch |
| 1975 | buildarch_compat: sun4m: noarch |
| 1976 | buildarch_compat: sun4u: noarch |
| 1977 | buildarch_compat: sparc64: noarch |
| 1978 | buildarch_compat: sparcv9: sparc |
| 1979 | buildarch_compat: sparc: noarch |
| 1980 | |
| 1981 | buildarch_compat: alphaev67: alphaev6 |
| 1982 | buildarch_compat: alphaev6: alphapca56 |
| 1983 | buildarch_compat: alphapca56: alphaev56 |
| 1984 | buildarch_compat: alphaev56: alphaev5 |
| 1985 | buildarch_compat: alphaev5: alpha |
| 1986 | buildarch_compat: alpha: noarch |
| 1987 | |
| 1988 | buildarch_compat: m68k: noarch |
| 1989 | buildarch_compat: ppc: noarch |
| 1990 | buildarch_compat: mipsel: noarch |
| 1991 | buildarch_compat: mipseb: noarch |
| 1992 | buildarch_compat: armv4b: noarch |
| 1993 | buildarch_compat: armv4l: noarch |
| 1994 | buildarch_compat: parisc: noarch |
| 1995 | |
| 1996 | buildarch_compat: atarist: m68kmint noarch |
| 1997 | buildarch_compat: atariste: m68kmint noarch |
| 1998 | buildarch_compat: ataritt: m68kmint noarch |
| 1999 | buildarch_compat: falcon: m68kmint noarch |
| 2000 | buildarch_compat: atariclone: m68kmint noarch |
| 2001 | buildarch_compat: milan: m68kmint noarch |
| 2002 | buildarch_compat: hades: m68kmint noarch |
| 2003 | |
| 2004 | buildarch_compat: ia64: noarch |
| 2005 | buildarch_compat: s390: noarch |
| 2006 | EOF |
| 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. |
| 2019 | sub 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} |
| 2062 | EOF |
| 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) --- |
| 2129 | sub 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. |
| 2151 | sub 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 | } |
| 2167 | sub 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 | #===================================================================== |
| 2188 | sub 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. |
| 2220 | sub 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. --- |
| 2245 | sub 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 |
| 2251 | EOF |
| 2252 | print RULES "CONFIG_OPTS = $debian_config_flags\n"; |
| 2253 | |
| 2254 | print RULES <<'EOF'; |
| 2255 | # --- make the configure script itself (only needed from CVS) --- |
| 2256 | configure: |
| 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 |
| 2267 | EOF |
| 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"; |
| 2296 | configured$suffix: configured$suffix.pkgwrite-stamp |
| 2297 | configured$suffix.pkgwrite-stamp: configure |
| 2298 | EOF |
| 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"; |
| 2319 | build$suffix: build$suffix.pkgwrite-stamp |
| 2320 | build$suffix.pkgwrite-stamp: configured$suffix.pkgwrite-stamp |
| 2321 | cd debian/BUILDS/$path && \$(MAKE) PREFIX=/usr $build_flags |
| 2322 | EOF |
| 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"; |
| 2337 | install$suffix: install$suffix.pkgwrite-stamp |
| 2338 | install$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 |
| 2344 | EOF |
| 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 |
| 2356 | EOF |
| 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"; |
| 2463 | binary-package-target$suffix: binary-package-target$suffix.pkgwrite-stamp |
| 2464 | binary-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 |
| 2469 | EOF |
| 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 |
| 2487 | EOF |
| 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 | |
| 2503 | sub 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 | |
| 2519 | sub 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 | |
| 2607 | if test -x /sbin/ldconfig ; then |
| 2608 | /sbin/ldconfig |
| 2609 | else |
| 2610 | ldconfig |
| 2611 | fi |
| 2612 | EOF |
| 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 | #===================================================================== |
| 2695 | sub 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 | #===================================================================== |
| 2755 | sub usage |
| 2756 | { |
| 2757 | print STDERR <<"EOF"; |
| 2758 | usage: 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 | |
| 2767 | Make either redhat or debian packages for source code and |
| 2768 | a pkgwriteinfo file. |
| 2769 | |
| 2770 | (Run pkgwrite --extra-help for unusual command-line flags.) |
| 2771 | |
| 2772 | EOF |
| 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 | |
| 2778 | sub extra_usage |
| 2779 | { |
| 2780 | print STDERR <<"EOF"; |
| 2781 | usage: pkgwrite [flags] |
| 2782 | |
| 2783 | Querying hardcoded lists of values in pkgwrite: |
| 2784 | |
| 2785 | pkgwrite --query-list={deb-sections,rpm-groups,deb-priorities} |
| 2786 | EOF |
| 2787 | exit (1); |
| 2788 | } |
| 2789 | |
| 2790 | sub 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 | #===================================================================== |
| 2802 | my $pkg_tarball; |
| 2803 | my $pkg_sourcedir; |
| 2804 | my $pkgwriteinfo_file; |
| 2805 | my $pkg_format; |
| 2806 | my $pkg_arch; |
| 2807 | my $output_dir; |
| 2808 | |
| 2809 | # --- Process arguments --- |
| 2810 | while (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 | |
| 2857 | unless (defined($pkg_tarball) || defined($pkg_sourcedir)) |
| 2858 | { |
| 2859 | die "either --tarball or --source-dir must be specified" |
| 2860 | } |
| 2861 | unless (defined ($pkg_format)) |
| 2862 | { |
| 2863 | die "--format must be specified"; |
| 2864 | } |
| 2865 | unless (defined ($output_dir)) |
| 2866 | { |
| 2867 | die "--output must be specified"; |
| 2868 | } |
| 2869 | unless (defined ($pkg_arch)) |
| 2870 | { |
| 2871 | die "--arch must be specified"; |
| 2872 | } |
| 2873 | if ($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 | } |
| 2880 | if (($pkg_format eq 'all' || $pkg_format eq 'redhat') |
| 2881 | && !$has_rpm_support) |
| 2882 | { |
| 2883 | die "cannot make RPMs on this system"; |
| 2884 | } |
| 2885 | if (($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. |
| 2899 | if (defined($pkg_tarball)) |
| 2900 | { $pkg_tarball = make_absolute ($pkg_tarball) } |
| 2901 | if (defined($pkg_sourcedir)) |
| 2902 | { $pkg_sourcedir = make_absolute ($pkg_sourcedir) } |
| 2903 | if (defined($pkgwriteinfo_file)) |
| 2904 | { $pkgwriteinfo_file = make_absolute ($pkgwriteinfo_file) } |
| 2905 | if (defined($output_dir)) |
| 2906 | { $output_dir = make_absolute ($output_dir); |
| 2907 | run ("mkdir -p $output_dir"); } |
| 2908 | if (defined($debian_changelog)) |
| 2909 | { $debian_changelog = make_absolute ($debian_changelog) } |
| 2910 | |
| 2911 | |
| 2912 | # Create pkgwriteinfo_file if necessary. |
| 2913 | if (!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) --- |
| 2991 | my $package = parse_pkgwriteinfo_file ($pkgwriteinfo_file); |
| 2992 | die "couldn't parse package from $pkgwriteinfo_file" unless defined $package; |
| 2993 | |
| 2994 | # Sanity check the package. |
| 2995 | sanity_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. |
| 3001 | my @format_list; |
| 3002 | if ($pkg_format eq 'all') |
| 3003 | { |
| 3004 | @format_list = qw(debian redhat) |
| 3005 | } |
| 3006 | else |
| 3007 | { |
| 3008 | @format_list = ( $pkg_format ); |
| 3009 | } |
| 3010 | |
| 3011 | # Make all the desired formats. |
| 3012 | for my $format (@format_list) |
| 3013 | { |
| 3014 | make_package ($package, $pkg_tarball, $format, $pkg_arch, $output_dir); |
| 3015 | } |
| 3016 | |
| 3017 | # Clean up. |
| 3018 | remove_work_dir (); |
| 3019 | |
| 3020 | exit (0); |
| 3021 | |
| 3022 | # --- Miscellaneous "main" helper functions --- |
| 3023 | |
| 3024 | # dump_table: Print the values of a hash-table reference to standard-output. |
| 3025 | sub 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. |
| 3036 | sub 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 | |
| 3053 | pkgwrite - 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 | |
| 3068 | pkgwrite takes a standard automake package, either from a source directory |
| 3069 | or from a distributed tarball, and a C<pkgwrite> input file |
| 3070 | and makes either RedHat or Debian packages. |
| 3071 | |
| 3072 | The actual package source code must be specified either by |
| 3073 | directory (using --srcdir) or from a tarball created with `make dist' |
| 3074 | (using --tarball). |
| 3075 | |
| 3076 | Additional packaging information is taken from pkgwriteinfo. |
| 3077 | If --pkgwriteinfo-file is omitted, pkgwriteinfo from the source |
| 3078 | directory or tarball is taken instead. (after configure is run, |
| 3079 | so you might generally use a pkgwriteinfo.in). |
| 3080 | |
| 3081 | There are a few command-line parameters which affect the package-making: |
| 3082 | |
| 3083 | =over 4 |
| 3084 | |
| 3085 | =item --no-strict-changelog |
| 3086 | |
| 3087 | Don't force the user's changelog and pkgwriteinfo file to |
| 3088 | have the same version. (If the packaging system |
| 3089 | requires that the changelog's latest entry be equal to |
| 3090 | the package's version, then pkgwrite will generate a |
| 3091 | changelog entry. This happens under Debian.) |
| 3092 | |
| 3093 | =item --no-cleanup |
| 3094 | |
| 3095 | Don't remove the temporary directory (which will |
| 3096 | be C</tmp/mkpkg-###-$USER>). Useful for debugging. |
| 3097 | |
| 3098 | =item --debian-dist=DIST |
| 3099 | |
| 3100 | Generate packaging for the given debian distribution: |
| 3101 | this mostly affects the changelog so |
| 3102 | setting DIST to C<stable> or C<unstable> is recommended. |
| 3103 | |
| 3104 | =item --skip-sanity-check |
| 3105 | |
| 3106 | Disable the usual checks that the package is valid. |
| 3107 | The package may still partially work, even if a sanity-check |
| 3108 | would normally fail. |
| 3109 | |
| 3110 | =back |
| 3111 | |
| 3112 | =head1 TERMINOLOGY |
| 3113 | |
| 3114 | =over 4 |
| 3115 | |
| 3116 | =item package |
| 3117 | |
| 3118 | A family of packages for various distributions |
| 3119 | which all come from one tarball and one pkgwriteinfo file. |
| 3120 | |
| 3121 | =item build |
| 3122 | |
| 3123 | A compilation of the source code into binaries. |
| 3124 | Some packages require multiple builds, for example, to make debugging |
| 3125 | and nondebugging versions of a libraries. |
| 3126 | Normally you just use the C<{MAIN}> build. |
| 3127 | |
| 3128 | =item target |
| 3129 | |
| 3130 | A single set of installed files in a package. |
| 3131 | Simple packages only have a single target C<{MAIN}> |
| 3132 | because the package is an all-or-nothing proposition. |
| 3133 | |
| 3134 | Some packages contain many parts, not all applicable to all users. |
| 3135 | These packages should be broken in to different targets. |
| 3136 | |
| 3137 | For example, a client/server based application might be |
| 3138 | conveniently packaged C<foo-server>, C<foo-client-curses>, C<foo-client-gtk>. |
| 3139 | That way, users without X can use the curses version without |
| 3140 | installing gtk+, often the clients and servers are run exclusively on |
| 3141 | different machines, so installing both is a waste of disk space. |
| 3142 | |
| 3143 | =back |
| 3144 | |
| 3145 | The resulting system-dependent binary's name is just |
| 3146 | the main C<Package:> name if the C<Target:> is C<{MAIN}>; |
| 3147 | otherwise it will be the C<Package> and C<Target> separated by |
| 3148 | a hyphen (C<->). |
| 3149 | |
| 3150 | =head1 MAINTAINING CHANGELOGS |
| 3151 | |
| 3152 | We recommend that you maintain a changelog in debian format, |
| 3153 | here 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; |
| 3163 | 1 space before the packager byline.) |
| 3164 | |
| 3165 | If you don't maintain a changelog, we will generate a changelog |
| 3166 | with just this version of the package in it. |
| 3167 | |
| 3168 | You should specify the changelog using the C<Changelog:> directive. |
| 3169 | |
| 3170 | =head1 EXAMPLES |
| 3171 | |
| 3172 | Here are a few examples of common types of packages. |
| 3173 | The pkgwrite distribution includes these packages |
| 3174 | inside the C<examples/tiny> directory. |
| 3175 | |
| 3176 | =head2 EXAMPLE: SINGLE-TARGET PACKAGE |
| 3177 | |
| 3178 | The most common type of package has one set of files |
| 3179 | it installs or uninstalls: there are no packaged bits or pieces. |
| 3180 | (A Target in pkgwrite terminology is the installed set of files.) |
| 3181 | |
| 3182 | Here is the pkgwrite file from the single-target example |
| 3183 | included 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 | |
| 3206 | This package's name is C<aa>; this file will produce a binary RPM |
| 3207 | named C<aa-0.0-1.$ARCH.rpm>. |
| 3208 | |
| 3209 | =over 4 |
| 3210 | |
| 3211 | =item * |
| 3212 | |
| 3213 | we wanted to name this C<a>, but debian packages must be at least two |
| 3214 | letters. |
| 3215 | |
| 3216 | =item * |
| 3217 | |
| 3218 | $ARCH is the target architecture, for example |
| 3219 | C<i386>, C<alpha>, or C<powerpc>. |
| 3220 | |
| 3221 | =item * |
| 3222 | |
| 3223 | The Target C<{MAIN}> is special, it |
| 3224 | means "don't use any suffix" -- the package's |
| 3225 | name is to be C<aa>. For any other Target line, |
| 3226 | if STRING was specified, the resulting |
| 3227 | RPM or deb would have the name C<aa-STRING>. |
| 3228 | |
| 3229 | =item * |
| 3230 | |
| 3231 | Each wildcard from Files lines describe a file or files to move |
| 3232 | into that target. |
| 3233 | |
| 3234 | =item * |
| 3235 | |
| 3236 | Unlisted files will not wind up in any binary package. |
| 3237 | |
| 3238 | =back |
| 3239 | |
| 3240 | =head2 EXAMPLE: MULTI-TARGET PACKAGE |
| 3241 | |
| 3242 | A multi-target, single-build package is a package that need |
| 3243 | only be compiled once, but which must be separated into |
| 3244 | several system packages, because the targets appeal to |
| 3245 | different users or have different dependencies. |
| 3246 | |
| 3247 | Here is the pkgwriteinfo file from the example multi-target single-build |
| 3248 | package: |
| 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 | |
| 3278 | In this package, only a single default Build: is required. |
| 3279 | Some packages may require the C<Configure-Flags> or |
| 3280 | C<Configure-Envars> fields in order to compile correctly. |
| 3281 | |
| 3282 | By default, all the targets use the C<{MAIN}> Build. |
| 3283 | |
| 3284 | Then each package contains a default file list, |
| 3285 | a description and a synopsis. |
| 3286 | |
| 3287 | =head2 EXAMPLE: MULTI-BUILD PACKAGE |
| 3288 | |
| 3289 | The most complex type of package must be built multiple times, |
| 3290 | with different configure or make flags. Each target must then |
| 3291 | refer to the build from which it was produced, |
| 3292 | using the C<Which-Build> field (the default is C<{MAIN}>). |
| 3293 | |
| 3294 | Here is the example of such a package from the C<pkgwrite> |
| 3295 | distribution: |
| 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 | |
| 3330 | Each Build section corresponds to a complete configure, build, install phase. |
| 3331 | In this package, the C<nond> build just wants configure to be run |
| 3332 | configure --program-suffix=-nondebug ... |
| 3333 | whereas for the C<d> build, |
| 3334 | configure --program-suffix=-debug ... |
| 3335 | (Note that the ... will be somewhat different from distribution to |
| 3336 | distribution) |
| 3337 | |
| 3338 | Also, it is often convenient to use the same names for the builds and |
| 3339 | the targets. We would rename C<nond> as C<nondebug> and C<d> as C<debug> |
| 3340 | if this were a real package -- we did this to discuss it more |
| 3341 | conveniently. |
| 3342 | |
| 3343 | It is perfectly possible to have more than one Target pointing to the same |
| 3344 | Build, just as multi-target single-build packages do. |
| 3345 | But the opposite is not allowed: a Target must specify exactly one |
| 3346 | Build. |
| 3347 | |
| 3348 | =head1 HARDCODED VALUES |
| 3349 | |
| 3350 | Many lists and values are hardcoded into pkgwrite. |
| 3351 | You may query these lists through the --query-list flag. |
| 3352 | Here are the lists you may obtain in this manner: |
| 3353 | |
| 3354 | =over 4 |
| 3355 | |
| 3356 | =item deb-sections |
| 3357 | |
| 3358 | Known allowed Section: fields for debian packages. |
| 3359 | |
| 3360 | =item rpm-groups |
| 3361 | |
| 3362 | Known allowed Group: fields for redhat packages. |
| 3363 | |
| 3364 | =item deb-priority |
| 3365 | |
| 3366 | Known allowed Priority: fields for debian packages. |
| 3367 | |
| 3368 | =back |
| 3369 | |
| 3370 | For example to get a list of allowed values for the Section: |
| 3371 | field, use C<pkgwrite --query-list=deb-sections>. |
| 3372 | |
| 3373 | =head1 PKGWRITE'S pkgwriteinfo FORMAT |
| 3374 | |
| 3375 | This (long) section describes the file |
| 3376 | that describes the targets to build from a tarball. |
| 3377 | This description file is called a C<pkgwriteinfo> file. |
| 3378 | |
| 3379 | The C<pkgwriteinfo> file consists of one package description part, |
| 3380 | then a number of Build sections, |
| 3381 | then a number of Target sections. |
| 3382 | |
| 3383 | =head2 PER-PACKAGE INFO |
| 3384 | |
| 3385 | The package file should begin with a section that describes |
| 3386 | the 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 | |
| 3398 | Here is a description of each allowed field: |
| 3399 | |
| 3400 | =over 4 |
| 3401 | |
| 3402 | =item Package |
| 3403 | |
| 3404 | Name of the source package. |
| 3405 | |
| 3406 | =item Output-Package |
| 3407 | |
| 3408 | Sometimes, all packages from a tarball use a somewhat |
| 3409 | different name than the tarball itself. |
| 3410 | This is used as a bit of a hack to support co-installation |
| 3411 | of multiple versions of a package. This is like |
| 3412 | gtk, which has gtk1.2 and gtk2.0 packages, which can be installed concurrently. |
| 3413 | |
| 3414 | =item Version |
| 3415 | |
| 3416 | The version number given to this version of the package |
| 3417 | by its maintainer. |
| 3418 | |
| 3419 | =item Release |
| 3420 | |
| 3421 | Increment this each time a new package is released without |
| 3422 | a corresponding upstream version-number change. |
| 3423 | |
| 3424 | =item Section |
| 3425 | |
| 3426 | The debian section this package belongs in. |
| 3427 | |
| 3428 | =item Group |
| 3429 | |
| 3430 | The redhat group this package belongs in. |
| 3431 | |
| 3432 | =item Priority |
| 3433 | |
| 3434 | Priority of this package (debian-style). |
| 3435 | |
| 3436 | =item Home-Page |
| 3437 | |
| 3438 | A URL giving the home page for this package or project. |
| 3439 | |
| 3440 | =item Source-Url |
| 3441 | |
| 3442 | A URL describing how to download this package. |
| 3443 | |
| 3444 | =item Author |
| 3445 | |
| 3446 | An author of this package, with email optional. |
| 3447 | |
| 3448 | =item Synopsis |
| 3449 | |
| 3450 | Under one line summary of this target. |
| 3451 | |
| 3452 | =item Description |
| 3453 | |
| 3454 | Multiple-line description of this target. |
| 3455 | |
| 3456 | =item Packager |
| 3457 | |
| 3458 | Full name of the person who made this packaging. |
| 3459 | |
| 3460 | =item Packager-Email |
| 3461 | |
| 3462 | Email address at which to reach the packager. |
| 3463 | |
| 3464 | =item Changelog |
| 3465 | |
| 3466 | Specify the location of a Debian format changelog to include with |
| 3467 | the package (it will be converted to another standard format, if needed) |
| 3468 | |
| 3469 | =item Upstream-is-Packager |
| 3470 | |
| 3471 | Whether the packager (the person running C<pkgwrite>) |
| 3472 | is the same as the upstream maintainer of a package. |
| 3473 | |
| 3474 | Right now, this only affects the filename used for the changelog, |
| 3475 | it will either be C<changelog.gz> if they are the same person, |
| 3476 | or C<changelog.Debian.gz> if they are not. |
| 3477 | |
| 3478 | =back |
| 3479 | |
| 3480 | =head2 PER-TARGET INFO |
| 3481 | |
| 3482 | For 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 | |
| 3494 | Name of this target. The name of the package that results will |
| 3495 | be prepended with SOURCE-; in this example the package's name |
| 3496 | is C<gdam-xmms-plugins>. |
| 3497 | |
| 3498 | =item Platform-Independent |
| 3499 | |
| 3500 | Set this to C<yes> if this package will be installable on |
| 3501 | any architecture (it contains no system-specific or compiled code). |
| 3502 | |
| 3503 | Set this to C<no> for packages containing compiled, |
| 3504 | architecture-specific binaries. |
| 3505 | |
| 3506 | =item Depends |
| 3507 | |
| 3508 | Debian-formatted dependency lists for this package. |
| 3509 | |
| 3510 | =item Redhat-Requires |
| 3511 | |
| 3512 | Specify the redhat packages that this one depends on. |
| 3513 | (We will try to compute this from the C<Depends:> lines by default; |
| 3514 | this is just in case we cannot guess correctly.) |
| 3515 | |
| 3516 | =item Conflicts |
| 3517 | |
| 3518 | Debian-formatted list of packages that conflict with this one. |
| 3519 | |
| 3520 | =item Redhat-Conflicts |
| 3521 | |
| 3522 | Redhat-formatted list of packages that conflict with this one. |
| 3523 | Computed from C<Conflicts:> by default. |
| 3524 | |
| 3525 | =item Synopsis |
| 3526 | |
| 3527 | Under one line summary of this target. |
| 3528 | |
| 3529 | =item Man-Page |
| 3530 | |
| 3531 | The basename of a man page, for example C<pkgwrite.1>. |
| 3532 | It will automatically be installed into the correct |
| 3533 | section directory based on its extension. |
| 3534 | |
| 3535 | =item Doc |
| 3536 | |
| 3537 | Miscellaneous documentation. |
| 3538 | Each path is assumed to be inside the installed area. |
| 3539 | |
| 3540 | It will be always be copied into the distribution's |
| 3541 | documentation area, and it will be gzip'd if that is needed. |
| 3542 | Also, whole directories will be recursively copied, |
| 3543 | if the entry ends with a /, for example, |
| 3544 | |
| 3545 | Doc: /usr/share/doc/gdam/example-configs/ |
| 3546 | |
| 3547 | =item Source-Doc |
| 3548 | |
| 3549 | Miscellaneous documentation that is not normally |
| 3550 | installed by this package's makefile: |
| 3551 | |
| 3552 | These must be files directly from the distributed tarball. |
| 3553 | They will be always be copied into the distribution's |
| 3554 | documentation area and will be gzip'd if that is needed. |
| 3555 | Whole directories will be recursively copied, |
| 3556 | if the entry ends with a /. |
| 3557 | |
| 3558 | =item Description |
| 3559 | |
| 3560 | Multiple-line description of this target. |
| 3561 | |
| 3562 | =item Which-Build |
| 3563 | |
| 3564 | Name of the build whose files should be used. |
| 3565 | (Defaults to C<{MAIN}>). |
| 3566 | |
| 3567 | =item Files |
| 3568 | |
| 3569 | A wildcard matching ordinary files to be distributed with |
| 3570 | this target. |
| 3571 | |
| 3572 | =back |
| 3573 | |
| 3574 | =head2 PER-BUILD INFO |
| 3575 | |
| 3576 | =over 4 |
| 3577 | |
| 3578 | =item Build |
| 3579 | |
| 3580 | The name of this build. The default build should be named |
| 3581 | C<{MAIN}>. |
| 3582 | |
| 3583 | =item Configure-Flags |
| 3584 | |
| 3585 | Options to be passed to the C<configure> script. |
| 3586 | |
| 3587 | =item Configure-Envars |
| 3588 | |
| 3589 | Space-separated environment variables to add when configuring. |
| 3590 | |
| 3591 | =item Make-Flags |
| 3592 | |
| 3593 | Extra parameters to the C<make> program during both |
| 3594 | the build and the install phase. |
| 3595 | |
| 3596 | =item Build-Flags |
| 3597 | |
| 3598 | Extra parameters to the C<make> program during just |
| 3599 | the build phase. |
| 3600 | |
| 3601 | =item Install-Flags |
| 3602 | |
| 3603 | Extra parameters to the C<make> program during just |
| 3604 | the install phase. |
| 3605 | |
| 3606 | =item Extra-Build-Targets |
| 3607 | |
| 3608 | Another C<make> target that is necessary to build the package, |
| 3609 | that is not run by the default target. This must not |
| 3610 | require root priviledges. (You may specify |
| 3611 | any number of C<Extra-Build-Targets:> lines.) |
| 3612 | |
| 3613 | =item Extra-Install-Targets |
| 3614 | |
| 3615 | Another C<make> target that is necessary to install the package, |
| 3616 | that is not run by the default target. On Debian systems, these commands |
| 3617 | may require root or fakeroot. (You may specify |
| 3618 | any number of C<Extra-Install-Targets:> lines.) |
| 3619 | |
| 3620 | =back |
| 3621 | |
| 3622 | =head1 DEBUGGING |
| 3623 | |
| 3624 | If you have problems, here are some hints: |
| 3625 | |
| 3626 | =over 4 |
| 3627 | |
| 3628 | =item * |
| 3629 | |
| 3630 | If you are familiar with one of the packaging systems (Redhat or Debian) |
| 3631 | that is not working, try building that with either |
| 3632 | the C<--no-cleanup> flag or equivalently have the C<DO_CLEANUP> |
| 3633 | environment variable set to C<0>. (You can find the |
| 3634 | directory where work was done by running: C<ls -ltr /tmp/mkpkg-*>) |
| 3635 | |
| 3636 | =item * |
| 3637 | |
| 3638 | Otherwise, redirect the output to a log file and read the whole thing. |
| 3639 | Some packaging systems output a log of messages |
| 3640 | even after a fatal error. |
| 3641 | |
| 3642 | =item * |
| 3643 | |
| 3644 | Then, try and cut out pieces of the C<pkgwriteinfo> |
| 3645 | file until you locate the problem. |
| 3646 | Report a bug if the problem is clear. |
| 3647 | |
| 3648 | =back |
| 3649 | |
| 3650 | =head1 COMMON PROBLEMS |
| 3651 | |
| 3652 | Here are some trivial mistakes made often: |
| 3653 | |
| 3654 | =over 4 |
| 3655 | |
| 3656 | =item * |
| 3657 | |
| 3658 | C<pkgwriteinfo> is generated by C<configure> from C<pkgwriteinfo.in>. |
| 3659 | It is easy to forget to rerun C<configure> and very slow. |
| 3660 | |
| 3661 | I don't know of any easy solution to forgetting |
| 3662 | at the moment, but you may just run C<config.status> |
| 3663 | instead, in order save time. |
| 3664 | |
| 3665 | =back |
| 3666 | |
| 3667 | =head1 RELEASING PACKAGES |
| 3668 | |
| 3669 | Of course, you can and should work however you want, |
| 3670 | but for your information, I will write the testing process |
| 3671 | I use for releasing packages. |
| 3672 | |
| 3673 | I always make C<automake> packages that use |
| 3674 | C<pkgwriteinfo> inside the tarball. |
| 3675 | |
| 3676 | It is important to note that my packages always |
| 3677 | support C<make rpm> and C<make deb> using C<pkgwrite>, |
| 3678 | and that these targets only C<make dist> if the tarball |
| 3679 | isn't present! |
| 3680 | |
| 3681 | =over 4 |
| 3682 | |
| 3683 | =item 1 |
| 3684 | |
| 3685 | Check out the package from CVS. Then either use whichever |
| 3686 | bootstrap script is provided: my recent packages use C<bootstrap> |
| 3687 | (as recommended by the C<automake> authors), but many packages |
| 3688 | use C<./autogen.sh>, which traditionally also runs C<./configure>. |
| 3689 | |
| 3690 | If you used C<bootstrap>, you will need to run C<./configure>. |
| 3691 | |
| 3692 | Then make the tarball using C<make distcheck>. |
| 3693 | |
| 3694 | =item 2 |
| 3695 | |
| 3696 | On a RedHat machine and a Debian machine, |
| 3697 | untar the tarball and copy that same tarball |
| 3698 | into the PACKAGE-VERSION directory that was created. |
| 3699 | (This way, the exact same tarball will be reused). |
| 3700 | |
| 3701 | =item 3 |
| 3702 | |
| 3703 | On each system, run C<./configure>, then |
| 3704 | C<make rpm> and C<make deb>, respectively. |
| 3705 | |
| 3706 | =item 4 |
| 3707 | |
| 3708 | Copy all the returned packages, the C<dist> tarball, |
| 3709 | into a directory which you will upload. |
| 3710 | |
| 3711 | =item 5 |
| 3712 | |
| 3713 | Test install those packages on machines. |
| 3714 | |
| 3715 | I 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 | |
| 3727 | TODO |
| 3728 | |
| 3729 | =head1 AUTHOR |
| 3730 | |
| 3731 | Written by Dave Benson <daveb@ffem.org>. |
| 3732 | |
| 3733 | =cut |