source: trunk/debbuild@ 204

Last change on this file since 204 was 204, checked in by kdeugau, 9 years ago

/trunk

Factor out the if() tree for extracting source files, and extend to
support bare .tar archives. Patch mostly by Andreas Scherer (aside from
a minor variable rename for local clarity by Kris Deugau):

Use the DRY principle by replacing redundant code sections with a single
function. This fixed at least one bug and prepares for future extensions.

  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author
File size: 78.4 KB
Line 
1#!/usr/bin/perl -w
2# debbuild script
3# Shamelessly steals interface from rpm's "rpmbuild" to create
4# Debian packages. Please note that such packages are highly
5# unlikely to conform to "Debian Policy".
6###
7# SVN revision info
8# $Date: 2015-08-16 23:37:38 +0000 (Sun, 16 Aug 2015) $
9# SVN revision $Rev: 204 $
10# Last update by $Author: kdeugau $
11###
12# Copyright (C) 2005-2015 Kris Deugau <kdeugau@deepnet.cx>
13#
14# This program is free software; you can redistribute it and/or modify
15# it under the terms of the GNU General Public License as published by
16# the Free Software Foundation; either version 2 of the License, or
17# (at your option) any later version.
18#
19# This program is distributed in the hope that it will be useful,
20# but WITHOUT ANY WARRANTY; without even the implied warranty of
21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22# GNU General Public License for more details.
23#
24# You should have received a copy of the GNU General Public License
25# along with this program; if not, write to the Free Software
26# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
28use strict;
29use warnings;
30use Fcntl; # for sysopen flags
31use Cwd 'abs_path'; # for finding where files really are
32use Config;
33use File::Basename;
34
35my $version = "0.11.3"; #VERSION#
36
37# regex debugger
38#use re "debug";
39
40# Behavioural compatibility FTW! Yes, rpmbuild does this too.
41die "No .spec file to work with! Exiting.\n" if scalar(@ARGV) == 0;
42
43# Program flow:
44# -> Parse/execute "system" config/macros (if any - should be rare)
45# -> Parse/execute "user" config/macros (if any - *my* requirement is %_topdir)
46# -> Parse command line for options, spec file/tarball/.src.deb (NB - also accept .src.rpm)
47
48sub expandmacros;
49sub unpackcmd;
50
51# User's prefs for dirs, environment, etc,etc,etc.
52# config file ~/.debmacros
53# Default ordered search paths for config/macros:
54# /usr/lib/rpm/rpmrc /usr/lib/rpm/redhat/rpmrc /etc/rpmrc ~/.rpmrc
55# /usr/lib/rpm/macros /usr/lib/rpm/redhat/macros /etc/rpm/macros ~/.rpmmacros
56# **NOTE: May be possible to (ab)use bits of debhelper
57
58# Build tree
59# default is /usr/src/debian/{BUILD,SOURCES,SPECS,DEBS,SDEBS}
60
61# Globals
62my $finalmessages = ''; # A place to stuff messages that I want printed at the *very* end of any processing.
63my $specfile;
64my $tarball;
65my $srcpkg;
66my $cmdbuildroot;
67my $tarballdir = '%{name}-%{version}'; # We do this in case of a spec file not using %setup...
68my %specglobals; # For %define's in specfile, among other things.
69
70$specglobals{'_vendor'} = 'debbuild';
71# this can be changed by the Vendor: header in the spec file
72$specglobals{'vendor'} = 'debbuild';
73
74# Initialized globals
75my $verbosity = 0;
76my $NoAutoReq = 0;
77my %cmdopts = (type => '',
78 stage => 'a',
79 short => 'n'
80 );
81my $topdir = "/usr/src/debian";
82#my $specglobals{buildroot} = "%{_tmppath}/%{name}-%{version}-%{release}.root".int(rand(99998)+1);
83$specglobals{buildroot} = '%{_topdir}/BUILDROOT/%{name}-%{version}-%{release}';
84
85# "Constants"
86my %targets = ('p' => 'Prep',
87 'c' => 'Compile',
88 'i' => 'Install',
89 'l' => 'Verify %files',
90 'a' => 'Build binary and source',
91 'b' => 'Build binary',
92 's' => 'Build source'
93 );
94# Ah, the joys of multiple architectures. :( Feh.
95# As copied from rpm
96my %optflags = ( 'i386' => '-O2 -g -march=i386 -mcpu=i686',
97 'amd64' => '-O2 -g'
98 );
99my $hostarch; # we set this later...
100my $scriptletbase =
101q(#!/bin/bash
102
103 RPM_SOURCE_DIR="%{_topdir}/SOURCES"
104 RPM_BUILD_DIR="%{_topdir}/BUILD"
105 RPM_OPT_FLAGS="%{optflags}"
106 RPM_ARCH="%{_arch}"
107 RPM_OS="linux"
108 export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS
109 RPM_DOC_DIR="/usr/share/doc"
110 export RPM_DOC_DIR
111 RPM_PACKAGE_NAME="%{name}"
112 RPM_PACKAGE_VERSION="%{version}"
113 RPM_PACKAGE_RELEASE="%{release}"
114 export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE
115 LANG=C
116 export LANG
117 unset CDPATH DISPLAY ||:
118 RPM_BUILD_ROOT="%{buildroot}"
119 export RPM_BUILD_ROOT
120
121 PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:/usr/lib64/pkgconfig:/usr/share/pkgconfig"
122 export PKG_CONFIG_PATH
123);
124
125if (-e '/usr/bin/dpkg-architecture') {
126 foreach (`dpkg-architecture`) {
127 s/=(.+)/="$1"/;
128 $scriptletbase .= " $_";
129 ($hostarch) = (/^DEB_HOST_ARCH="(.+)"$/) if /DEB_HOST_ARCH=/;
130 }
131} else {
132 warn "Missing dpkg-architecture, DEB_HOST_ARCH will not be set!\n";
133}
134
135$scriptletbase .=
136q(
137 set -x
138 umask 022
139 cd "%{_topdir}/BUILD"
140);
141
142# Hackery to try to bring some semblance of sanity to packages built for more
143# than one Debian version at the same time. Whee.
144# /etc/debian-version and/or version of base-files package
145my %distmap = (
146# legacy Unbuntu
147 "3.1.9ubuntu" => "dapper",
148 "6.06" => "dapper",
149 "4ubuntu" => "feisty",
150 "7.04" => "fiesty",
151 "4.0.1ubuntu" => "hardy",
152 "8.04" => "hardy",
153# Note we do NOT support identification of "subrelease" versions (ie semimajor updates
154# to a given release). If your dependencies are really that tight, and you can't rely
155# on the versions of the actual dependencies, you're already in over your head, and
156# should probably only ship a tarballed installer.
157# only supporting LTS releases
158# base-files version doesn't map to the Ubuntu version the way Debian versions do, thus the doubled entries
159# Ubuntu 12.04.5 LTS (Precise Pangolin)
160 "6.5ubuntu" => "precise",
161 "12.04" => "precise",
162# Ubuntu 14.04.2 LTS (Trusty Tahr)
163 "7.2ubuntu" => "trusty",
164 "14.04" => "trusty",
165# Debian releases
166 "3.0" => "woody",
167 "3.1" => "sarge",
168 "4" => "etch",
169 "5" => "lenny",
170 "6" => "squeeze",
171 "7" => "wheezy",
172 "8" => "jessie",
173 "9" => "stretch",
174 "99" => "sid",
175);
176
177# Map Ubuntu base-files versions to the nominal public versions
178
179my %ubnt_vermap = (
180 "6.5ubuntu6" => "12.04",
181 "7.2ubuntu5" => "14.04",
182);
183
184# Enh. There doesn't seem to be any better way to do this... :(
185{
186# could theoretically also do something with this... it's about as stable as "dpkg-query ..." below... :(
187# my $releasever = qx { cat /etc/debian_version };
188# chomp $releasever;
189 my $basefiles;
190 my $basever;
191 my $baseos;
192
193 # Funny thing how files like this have become useful...
194 # Check for /etc/os-release. If that doesn't exist, try /etc/lsb-release. If that doesn't exist,
195 # check for existence of dpkg-query, and either call it Debian Woody (if missing), or fall through
196 # to guessing based on the version of the base-files package.
197 if (-e '/etc/os-release') {
198 open OSREL, "</etc/os-release";
199 # Look for ID and VERSION_ID lines.
200 while (<OSREL>) {
201 $baseos = $1 if /^ID=(\w+)/;
202 $basever = $1 if /^VERSION_ID="?([\d.]+)/;
203 }
204 close OSREL;
205
206 } elsif (-e '/etc/lsb-release') {
207 open LSBREL, "</etc/lsb-release";
208 # Look for DISTRIB_ID and DISTRIB_RELEASE lines.
209 # We could also theoretically extract the dist codename, but since we have to hand-map
210 # it in so many other cases there's little point.
211 while (<LSBREL>) {
212 $baseos = $1 if /^DISTRIB_ID=(\w+)/;
213 $basever = $1 if /^DISTRIB_RELEASE=([\d.]+)/;
214 }
215 close LSBREL;
216
217 } elsif ( ! -e '/usr/bin/dpkg-query' ) {
218 # call it woody, since sarge and newer have dpkg-query, and we don't much care about obsolete^n releases
219 $basever = "3.0";
220 $baseos = 'debian';
221
222 } else {
223# *eyeroll* there *really* has to be a better way to go about this. You
224# can't sanely build packages for multiple distro targets if you can't
225# programmatically figure out which one you're building on.
226
227# note that we care only about major release numbers; tracking minor or point
228# releases would be... exponentially more painful.
229
230 my $majver;
231 # for the lazy copy-paster: dpkg-query --showformat '${version}\n' -W base-files
232 # avoid shellisms
233 if (open BASEGETTER, "-|", "dpkg-query", "--showformat", '${version}', "-W", "base-files") {
234 $basever = <BASEGETTER>;
235 close BASEGETTER;
236
237 if ($basever =~ /ubuntu/) {
238 # Ubuntu, at least until they upset their versioning scheme again
239 # note that we remap the basefiles version to the public release number, to match the
240 # behaviour for Debian, and to match the unofficial standard for RHEL/Centos etc and Fedora
241 ($basefiles,$basever) = ($basever =~ /^(([\d.]+)ubuntu)\d/);
242 $baseos = 'ubuntu';
243 } else {
244 # Debian, or more "pure" derivative
245 $baseos = 'debian';
246 ($basever,$majver) = ($basever =~ /^((\d+)(?:\.\d)?)/);
247 if ($majver > 3) {
248 $basever = $majver;
249 }
250 }
251 }
252
253 if (!$basever) {
254 # Your llama is on fire
255 $basever = '99';
256 print "Warning: couldn't autodetect OS version, assuming sid/unstable\n";
257 }
258 } # got dpkg-query?
259
260 # Set some legacy globals.
261 $specglobals{"debdist"} = $distmap{$basever};
262 $specglobals{"debver"} = $basever; # this may have trouble with Ubuntu versions?
263
264 # Set the standard generic OS-class globals;
265 $baseos = lc($baseos);
266 $specglobals{"ubuntu"} = $basever if $baseos eq 'ubuntu';
267 $specglobals{"debian"} = $basever if $baseos eq 'debian';
268
269 # Default %{dist} to something marginally sane. Note this should be overrideable by --define.
270 # This has been chosen to most closely follow the usage in RHEL/CentOS and Fedora, ie "el5" or "fc20".
271 $specglobals{"dist"} = $baseos.$basever;
272
273} # done trying to set debian dist/version
274
275# Package data
276# This is the form of $pkgdata{pkgname}{meta}
277# meta includes Summary, Name, Version, Release, Group, Copyright,
278# Source, URL, Packager, BuildRoot, Description, BuildRequires,
279# Requires, Provides
280# 10/31/2005 Maybe this should be flatter? -kgd
281my %pkgdata = (main => {source => ''});
282my @pkglist = ('main'); #sigh
283# Files listing. Embedding this in %pkgdata would be, um, messy.
284my %filelist;
285my %doclist;
286my $buildreq = '';
287
288# Scriptlets
289my $prepscript = '';
290my $buildscript = '';
291# %install doesn't need the full treatment from %clean; just an empty place to install to.
292# NB - rpm doesn't do this; is it really necessary?
293my $installscript = '';
294#'[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT'."\n";
295my $cleanscript = '';
296
297# Snag some environment data
298my $tmpdir;
299if (defined $ENV{TMP} && $ENV{TMP} =~ /^(\/var)?\/tmp$/) {
300 $tmpdir = $ENV{TMP};
301} else {
302 $tmpdir = "/var/tmp";
303}
304
305##main
306
307load_userconfig();
308parse_cmd();
309
310if ($cmdopts{install}) {
311 install_sdeb();
312 exit 0;
313}
314
315# output stage of --showpkgs
316if ($cmdopts{type} eq 'd') {
317 parse_spec();
318 foreach my $pkg (@pkglist) {
319 $pkgdata{$pkg}{name} =~ tr/_/-/;
320
321 my $pkgfullname = "$pkgdata{$pkg}{name}_".
322 (defined($pkgdata{main}{epoch}) ? "$pkgdata{main}{epoch}:" : '').
323 "$pkgdata{$pkg}{version}-$pkgdata{main}{release}_$pkgdata{$pkg}{arch}.deb";
324
325 print "$pkgfullname\n" if $filelist{$pkg};
326
327 }
328 # Source package
329 print "$pkgdata{main}{name}-".
330 (defined($pkgdata{main}{epoch}) ? "$pkgdata{main}{epoch}:" : '').
331 "$pkgdata{main}{version}-$pkgdata{main}{release}.sdeb\n";
332 exit 0;
333}
334
335# Stick --rebuild handling in here - basically install_sdeb()
336# followed by tweaking options to run with -ba
337if ($cmdopts{type} eq 's') {
338 if ($srcpkg =~ /\.src\.rpm$/) {
339 my @srclist = qx { rpm -qlp $srcpkg };
340 foreach (@srclist) {
341 chomp;
342 $specfile = "$topdir/SPECS/$_" if /\.spec$/;
343 }
344 qx { rpm -i $srcpkg };
345 } else {
346 install_sdeb();
347 my @srclist = qx { pax < $srcpkg };
348 foreach (@srclist) {
349 chomp;
350 $specfile = "$topdir/$_" if /SPECS/;
351 }
352 }
353 $cmdopts{type} = 'b';
354 $cmdopts{stage} = 'a';
355}
356
357if ($cmdopts{type} eq 'b') {
358 # Need to read the spec file to find the tarball. Note that
359 # this also generates most of the shell script required.
360 parse_spec();
361 die "Can't build $pkgdata{main}{name}: build requirements not met.\n"
362 if !checkbuildreq();
363}
364
365if ($cmdopts{type} eq 't') {
366 # Need to unpack the tarball to find the spec file. Sort of the inverse of -b above.
367 # Note that rpmbuild doesn't seem to support this operation from a .zip file, so neither will we.
368 # zcat $tarball |tar -t |grep .spec
369 # collect some info about the tarball
370 $specfile = "$topdir/BUILD/". qx { zcat $tarball |tar -t |grep -e '[\.]spec\$' };
371 chomp $specfile;
372 my ($fileonly, $dirname) = ($tarball =~ /(([a-zA-Z0-9._-]+)\.(?:tgz|tar\.(?:gz|bz2|xz|Z)))$/);
373
374 $tarball = abs_path($tarball);
375##fixme: use macro expansions for the executables
376 my $unpackcmd = "cd $topdir/BUILD; ".
377 ( $tarball =~ /\.(?:tgz|tar\.(?:gz|Z))$/ ? "/bin/gzip" : "" ).
378 ( $tarball =~ /\.tar\.bz2$/ ? "/bin/bzip2" : "" ).
379 ( $tarball =~ /\.tar\.xz$/ ? "/usr/bin/xz" : "" ).
380 " -dc $tarball |/bin/tar -xf -";
381
382 system "$unpackcmd";
383 system "cp $tarball $topdir/SOURCES/$fileonly";
384 system "cp $specfile $topdir/SPECS/";
385 parse_spec();
386 die "Can't build $pkgdata{main}{name}: build requirements not met.\n"
387 if !checkbuildreq();
388}
389
390# -> srcpkg if -.s
391if ($cmdopts{stage} eq 's') {
392 srcpackage();
393 print $finalmessages;
394 exit 0;
395}
396
397# Hokay. Need to:
398# -> prep if -.p OR (-.[cilabs] AND !--short-circuit)
399if ($cmdopts{stage} eq 'p' || ($cmdopts{stage} =~ /[cilabs]/ && $cmdopts{short} ne 'y')) {
400 prep();
401}
402# -> build if -.c OR (-.[ilabs] AND !--short-circuit)
403if ($cmdopts{stage} eq 'c' || ($cmdopts{stage} =~ /[ilabs]/ && $cmdopts{short} ne 'y')) {
404 build();
405}
406# -> install if -.[ilabs]
407#if ($cmdopts{stage} eq 'i' || ($cmdopts{stage} =~ /[labs]/ && $cmdopts{short} ne 'y')) {
408if ($cmdopts{stage} =~ /[ilabs]/) {
409 install();
410#foreach my $pkg (@pkglist) {
411# print "files in $pkg:\n ".$filelist{$pkg}."\n";
412#}
413
414}
415# -> binpkg and srcpkg if -.a
416if ($cmdopts{stage} eq 'a') {
417 binpackage();
418 srcpackage();
419 clean();
420}
421# -> binpkg if -.b
422if ($cmdopts{stage} eq 'b') {
423 binpackage();
424 clean();
425}
426
427# Spit out any closing remarks
428print $finalmessages;
429
430# Just in case.
431exit 0;
432
433
434## load_userconfig()
435# Loads user configuration (if any)
436# Currently only handles .debmacros
437# Needs to handle "other files"
438sub load_userconfig {
439 my $homedir = (getpwuid($<))[7];
440 if (-e "$homedir/.debmacros") {
441 open USERMACROS,"<$homedir/.debmacros";
442 while (<USERMACROS>) {
443 # And we also only handle a few macros at the moment.
444 if (/^\%_topdir/) {
445 my (undef,$tmp) = split /\s+/, $_;
446 $topdir = $tmp;
447 }
448 next if /^\%_/;
449 # Allow arbitrary definitions. Note that we're only doing simple defs here for now.
450 if (/^\%([a-z0-9]+)\s+(.+)$/) {
451 $specglobals{$1} = $2;
452 }
453 }
454 }
455} # end load_userconfig()
456
457
458## parse_cmd()
459# Parses command line into global hash %cmdopts, other globals
460# Options based on rpmbuild's options
461sub parse_cmd {
462 # Don't feel like coding my own option parser...
463 #use Getopt::Long;
464 # ... but I may have to: (OTOH, rpm uses popt, so maybe we can too.)
465 #use Getopt::Popt qw(:all);
466 # Or not. >:( Stupid Debian lack of findable Perl module names in packages.
467
468 # ... also note, single-character options are mostly not flags, so they can't be
469 # sanely combined the way most other programs' single-character flag options can.
470
471 # Stuff it.
472 my $prevopt = '';
473 foreach (@ARGV) {
474 chomp;
475
476 # Is it an option?
477 if (/^-/) {
478
479 # Is it a long option?
480 if (/^--/) {
481 if (/^--short-circuit/) {
482 $cmdopts{short} = 'y';
483 } elsif (/^--rebuild/) {
484 $cmdopts{type} = 's';
485 } elsif (/^--showpkgs/) {
486 $cmdopts{type} = 'd'; # d for 'diagnostic' or 'debug' or 'dump'
487 } elsif (/^--help/) {
488 print "debbuild v$version".q{
489Copyright 2005-2015 Kris Deugau <kdeugau@deepnet.cx>
490
491Build .deb packages from RPM-style .spec files
492debbuild supports most package-building options rpmbuild does.
493
494Build options with [ <specfile> | <tarball> | <source package> ]:
495 -bp build through %prep (unpack sources and apply patches) from <specfile>
496 -bc build through %build (%prep, then compile) from <specfile>
497 -bi build through %install (%prep, %build, then install) from <specfile>
498 -bl verify %files section from <specfile>
499 -ba build source and binary packages from <specfile>
500 -bb build binary package only from <specfile>
501 -bs build source package only from <specfile>
502 -tp build through %prep (unpack sources and apply patches) from <tarball>
503 -tc build through %build (%prep, then compile) from <tarball>
504 -ti build through %install (%prep, %build, then install) from <tarball>
505 -ta build source and binary packages from <tarball>
506 -tb build binary package only from <tarball>
507 -ts build source package only from <tarball>
508 --rebuild build binary package from <source package>
509 --buildroot=DIRECTORY override build root
510 --short-circuit skip straight to specified stage (only for c,i)
511
512Common options:
513 -D, --define='MACRO EXPR' define MACRO with value EXPR
514
515debbuild-specific options:
516 -i Unpack a .sdeb in the %_topdir tree
517 --showpkgs Show package names that would be built. Only works with .spec files.
518
519};
520 exit;
521
522 } elsif (/^--define/) {
523 # nothing to do? Can't see anything needed, we handle the actual definition later.
524##fixme
525# add --self-package here
526# deps build-essential pax fakeroot
527 } else {
528 print "Long option $_ not handled\n";
529 }
530 } else {
531 # Not a long option
532 if (/^-[bt]/) {
533 if ($cmdopts{stage} eq 's') {
534 # Mutually exclusive options.
535 die "Can't use $_ with --rebuild\n";
536 } else {
537 # Capture the type (from "bare" files or tarball) and the stage (prep, build, etc)
538 ($cmdopts{stage}) = (/^-[bt]([pcilabs])/);
539 ($cmdopts{type}) = (/^-([bt])[pcilabs]/);
540 }
541 } elsif (/^-v/) {
542 # bump verbosity. Not sure what I'll actually do here...
543 } elsif (/^-i/) {
544 $cmdopts{install} = 1;
545 $prevopt = '-i';
546 } elsif (/^-D/) {
547 # --define. nothing to do on this round; actual work is done next time.
548 } else {
549 die "Bad option $_\n";
550 }
551 }
552
553 } else { # Not an option argument
554
555 # --buildroot is the only option that takes an argument
556 # Therefore, any *other* bare arguments are the spec file,
557 # tarball, or source package we're operating on - depending
558 # on which one we meet.
559 if ($prevopt eq '--buildroot') {
560 $cmdbuildroot = $_;
561 } elsif ($prevopt eq '--define' || $prevopt eq '-D') {
562 my ($macro,$value) = (/([a-z0-9_.-]+)(?:\s+(.+))?/i);
563 if ($value ne '') {
564 $specglobals{$macro} = $value;
565 } else {
566 warn "WARNING: missing value for macro $macro in --define! Ignoring.\n";
567 }
568 } elsif ($prevopt eq '-i') {
569 $srcpkg = $_;
570 } else {
571 if ($cmdopts{type} eq 's') {
572 # Source package
573 if (!/(sdeb|\.src\.rpm)$/) {
574 die "Can't --rebuild with $_\n";
575 }
576 $srcpkg = $_;
577 } elsif ($cmdopts{type} eq 'b' || $cmdopts{type} eq 'd') {
578 # Spec file
579 $specfile = $_;
580 } else {
581 # Tarball build. Need to extract tarball to find spec file. Whee.
582 $tarball = $_;
583 }
584 }
585 }
586 $prevopt = $_;
587 } # foreach @ARGV
588
589 # Some cross-checks. rpmbuild limits --short-circuit to just
590 # the "compile" and "install" targets - with good reason IMO.
591 # Note that --short-circuit with -.p is not really an error, just redundant.
592 # NB - this is NOT fatal, just ignored!
593 if ($cmdopts{short} eq 'y' && $cmdopts{stage} =~ /[labs]/) {
594 warn "Can't use --short-circuit for $targets{$cmdopts{stage}} stage. Ignoring.\n";
595 $cmdopts{short} = 'n';
596 }
597
598 # Valid options, with example arguments (if any):
599# Build from .spec file; mutually exclusive:
600 # -bp
601 # -bc
602 # -bi
603 # -bl
604 # -ba
605 # -bb
606 # -bs
607# Build from tarball; mutually exclusive:
608 # -tp
609 # -tc
610 # -ti
611 # -ta
612 # -tb
613 # -ts
614# Build from .src.(deb|rpm)
615 # --rebuild
616 # --recompile
617
618# General options
619 # --buildroot=DIRECTORY
620 # --clean
621 # --nobuild
622 # --nodeps
623 # --nodirtokens
624 # --rmsource
625 # --rmspec
626 # --short-circuit
627 # --target=CPU-VENDOR-OS
628
629 #my $popt = new Getopt::Popt(argv => \@ARGV, options => \@optionsTable);
630
631} # end parse_cmd()
632
633
634## parse_spec()
635# Parse the .spec file.
636sub parse_spec {
637 die "No .spec file specified! Exiting.\n" if !$specfile;
638 open SPECFILE,"<$specfile" or die "specfile ($specfile) barfed: $!";
639
640 my $iflevel = 0;
641 my $buildarch = $hostarch;
642 $pkgdata{main}{arch} = $hostarch;
643
644 my $stage = 'preamble';
645 my $subname = 'main';
646 my $scriptlet;
647
648# Basic algorithm:
649# For each line
650# if it's a member of an %if construct, branch and see which segment of the
651# spec file we need to parse and which one gets discarded, then
652# short-circuit back to the top of the loop.
653# if it's a %section, bump the stage. Preparse addons to the %section line
654# (eg subpackage) and stuff them in suitable loop-global variables, then
655# short-circuit back to the top of the loop.
656# Otherwise, parse the line according to which section we're supposedly
657# parsing right now
658
659LINE: while (<SPECFILE>) {
660 next if /^#/ && $stage eq 'preamble'; # Ignore comments...
661 next if /^\s*$/ && $stage eq 'preamble'; # ... and blank lines.
662
663# no sense in continuing if we find something we don't grok
664 # Yes, this is really horribly fugly. But it's a cheap crosscheck against invalid
665 # %-tags which also make rpmbuild barf. In theory.
666# notes: some of these are not *entirely* case-sensitive (%ifxxx), but most are.
667 # Extracted from the Maximum RPM online doc via:
668 # grep -h %[a-z] *|perl -e 'while (<>) { /\%([a-z0-9]+)\b/; print "$1|\n"; }'|sort -u
669 if (/^%[a-z]/ &&
670 $_ !~ /^%(?:attr|build|changelog|check|clean|config|configure|defattr|define|description|
671 dir|doc|docdir|else|endif|files|ghost|if|ifarch|ifn|ifnarch|ifnos|ifnxxx|fos|ifxxx|
672 install|makeinstall|package|patch\d*|post|postun|pre|prep|preun|readme|setup[^\s]*|
673 triggerin|triggerpostun|triggerun|verify|verifyscript)\b/x
674 ) {
675 my ($badtag) = (/^%([a-z]+)/i);
676 die "Unknown tag \%$badtag at line $. of $specfile\n";
677 }
678
679# preprocess %define's
680 if (my ($key, $def) = (/^\%(?:define|global)\s+([^\s]+)\s+(.+)$/) ) {
681 $specglobals{$key} = expandmacros($def,'g');
682 }
683
684 if (/^\%if/) {
685 s/^\%if//;
686 chomp;
687 my $expr = expandmacros($_, 'g');
688 $iflevel++;
689
690 if ($expr !~ /^\s*\d+\s*$/) {
691 # gots a logic statement we want to turn into a 1 or a 0. most likely by eval'ing it.
692
693 $expr =~ s/\s+//g;
694
695# For Great w00tness! New and Improved multilayered logic handling.
696
697 my @bits = split /\b/, $expr;
698 $expr = '';
699 foreach my $bit (@bits) {
700 next if $bit eq '"';
701 $bit =~ s/"//g;
702 $expr .= qq("$bit") if $bit =~ /^\w+$/;
703 $expr .= $bit if $bit !~ /^\w+$/;
704 }
705
706 # Done in this order so we don't cascade incorrectly. Yes, those spaces ARE correct in the replacements!
707 $expr =~ s/==/ eq /g;
708 $expr =~ s/!=/ ne /g;
709 $expr =~ s/<=>/ cmp /g;
710 $expr =~ s/<=/ le /g;
711 $expr =~ s/>=/ ge /g;
712 $expr =~ s/</ lt /g;
713 $expr =~ s/>/ gt /g;
714
715 # Turn it into something that eval's to a number. Maybe not needed? O_o
716 #$expr = "( $expr ? 1 : 0 )";
717
718 $expr = eval $expr;
719 }
720
721 next LINE if $expr != 0; # This appears to be the only case we call false.
722 while (<SPECFILE>) {
723 if (/^\%endif/) {
724 $iflevel--;
725 next LINE;
726 } elsif (/^\%else/) {
727 next LINE;
728 }
729 }
730 }
731 if (/^\%else/) {
732 while (<SPECFILE>) {
733 if (/^\%endif/) {
734 $iflevel--;
735 next LINE;
736 }
737 }
738 }
739 if (/^\%endif/) {
740 $iflevel--;
741 next LINE;
742 } # %if/%else/%endif
743
744 if (/^\%{echo:(.+)}/) {
745 my $output = expandmacros($1, 'gp');
746 print "$output";
747 next LINE;
748 }
749
750# now we pick out the sections and set "state" to parse that section. Fugly but I can't see a better way. >:(
751
752 if (/^\%description(?:\s+(?:-n\s+)?(.+))?/) {
753 $stage = 'desc';
754 $subname = "main";
755 if ($1) { # Magic to add entries to the right package
756 my $tmp = expandmacros("$1", 'gp');
757 if (/-n/) { $subname = $tmp; } else { $subname = "$pkgdata{main}{name}-$tmp"; }
758 }
759 next LINE;
760 } # %description
761
762 if (/^\%package\s+(?:-n\s+)?(.+)/) {
763 $stage = 'package';
764 if ($1) { # Magic to add entries to the right package
765 my $tmp = expandmacros("$1", 'gp');
766 if (/-n/) { $subname = $tmp; } else { $subname = "$pkgdata{main}{name}-$tmp"; }
767 }
768 push @pkglist, $subname;
769 $pkgdata{$subname}{name} = $subname;
770 $pkgdata{$subname}{version} = $pkgdata{main}{version};
771 # Build "same arch as previous package found" by default. Where rpm just picks the
772 # *very* last one, we want to allow arch<native>+arch-all
773 # (eg, Apache is i386, but apache-manual is all)
774 $pkgdata{$subname}{arch} = $buildarch; # Since it's likely subpackages will NOT have a BuildArch line...
775 next LINE;
776 } # %package
777
778 if (/^\%prep/) {
779 $stage = 'prep';
780 # Replace some core macros
781 $pkgdata{main}{source} = expandmacros($pkgdata{main}{source},'gp');
782 next LINE;
783 } # %prep
784
785 if (/^\%build/) {
786 $stage = 'build';
787 $buildscript .= "cd '$tarballdir'\n" if $pkgdata{main}{hassetup};
788 next LINE;
789 } # %build
790
791 if (/^\%install/) {
792 $stage = 'install';
793 $installscript .= "cd '$tarballdir'\n" if $pkgdata{main}{hassetup};
794 next LINE;
795 } # %install
796
797 if (/^\%clean/) {
798 $stage = 'clean';
799 $cleanscript .= "cd '$tarballdir'\n" if $pkgdata{main}{hassetup};
800 next LINE;
801 } # %clean
802
803 if (/^\%(pre|post|preun|postun)\b(?:\s+(?:-n\s+)?(.+))?/i) {
804 $stage = 'prepost';
805 $scriptlet = lc $1;
806 $subname = 'main';
807 if ($2) { # Magic to add entries to the right package
808 my $tmp = expandmacros("$2", 'g');
809 if (/-n/) { $subname = $tmp; } else { $subname = "$pkgdata{main}{name}-$tmp"; }
810 }
811 next LINE;
812 } # %pre/%post/%preun/%postun
813
814 if (/^\%files(?:\s+(?:-n\s+)?(.+))?/) {
815 $stage = 'files';
816 $subname = 'main';
817 if ($1) { # Magic to add entries to the right list of files
818 my $tmp = expandmacros("$1", 'gp');
819 if (/-n/) { $subname = $tmp; } else { $subname = "$pkgdata{main}{name}-$tmp"; }
820 }
821 next LINE;
822 } # %files
823
824 if (/^\%changelog/) {
825 $stage = 'changelog';
826 $pkgdata{main}{changelog} = '';
827 next LINE;
828 }
829
830# now we handle individual lines from the various sections
831
832 if ($stage eq 'desc') {
833 next LINE if /^\s*#/;
834 $pkgdata{$subname}{desc} .= " $_";
835 } # description
836
837 if ($stage eq 'package') {
838 # gotta expand %defines here. Whee.
839# Note that we look for the Debian-specific Recommends, Suggests, and Replaces,
840# although they will have to be wrapped in '%if %{_vendor} == "debbuild"' for
841# an rpmbuild-compatible .spec file
842# NB: NOT going to support Pre-Depends, since it's a "Don't Use" (mis)feature, and
843# RPM's support for a similar tag (PreReq) has been recently dropped.
844 if (my ($dname,$dvalue) = (/^(Recommends|Suggests|Enhances|Replaces|Summary|Group|Version|Requires|Conflicts|Provides|BuildArch(?:itecture)?):\s+(.+)$/i)) {
845 $dname =~ tr/[A-Z]/[a-z]/;
846 if ($dname =~ /^BuildArch/i) {
847 $dvalue =~ s/^noarch/all/ig;
848 $buildarch = $dvalue; # Emulate rpm's behaviour to a degree
849 $dname = 'arch';
850 }
851 if ($dname =~ /recommends|suggests|enhances|replaces|requires|conflicts|provides/) {
852 $pkgdata{$subname}{$dname} .= ", ".expandmacros($dvalue, 'gp');
853 } else {
854 $pkgdata{$subname}{$dname} = expandmacros($dvalue, 'gp');
855 }
856 }
857 } # package
858
859 if ($stage eq 'prep') {
860 # Actual handling for %prep section. May have %setup macro; may
861 # include %patch tags, may be just a bare shell script.
862 if (/^\%setup/) {
863 $pkgdata{main}{hassetup} = 1; # flag the fact that we've got %setup
864 # Parse out the %setup macro.
865 chomp;
866 # rpmbuild doesn't complain about gibberish immediately following %setup, but we will
867 warn "Suspect \%setup tag '$_', continuing\n" if ! /^\%setup(?:\s|$)/;
868
869 # Prepare some flags
870 my $changedir = 0;
871 my $deldir = 1;
872 my $quietunpack = 0;
873 my $deftarball = 1;
874 my $snum = '';
875 my $sbefore;
876 my $safter;
877 my $altsource = 0;
878
879 my @sbits = split /\s+/;
880 shift @sbits;
881 while (my $sopt = shift @sbits) {
882 if ($sopt eq '-n') {
883 $tarballdir = shift @sbits;
884 } elsif ($sopt eq '-a') {
885 # shift, next opt must be numeric (which sourcenn:)
886 $sopt = shift @sbits;
887 die "Argument for \%setup -a must be numeric at $specfile line $.\n" if $sopt !~ /^\d+$/;
888 $safter = $sopt;
889 $snum = $sopt;
890 $altsource = 1;
891 } elsif ($sopt eq '-b') {
892 # shift, next opt must be numeric (which sourcenn:)
893 $sopt = shift @sbits;
894 die "Argument for \%setup -b must be numeric at $specfile line $.\n" if $sopt !~ /^\d+$/;
895 $sbefore = $sopt;
896 $snum = $sopt;
897 $altsource = 2;
898 } elsif ($sopt eq '-c') {
899 # flag, create and change directory before unpack
900 $changedir = 1;
901 } elsif ($sopt eq '-D') {
902 # flag, do not delete directory before unpack
903 $deldir = 0;
904 } elsif ($sopt eq '-T') {
905 # flag, do not unpack first source
906 $deftarball = 0;
907 } elsif ($sopt eq '-q') {
908 # SSSH! Unpack quietly
909 $quietunpack = 1;
910 }
911 } # $sopt = shift @sbits
912
913# Note that this is an incomplete match to rpmbuild's full %setup expression.
914# Still known to do:
915# - Match implementation of -a and -b if both are specified.
916# Looks to be "expand -a into $aftersource and expand -b into $beforesource inside the while()"
917# instead of treating them as flags like the other arguments.
918# Known differences
919# - -q appears to be somewhat positional
920# - rpmbuild requires -n on all %setup macros, but carries the first down to %install etc,
921# debbuild sets the global on the first call, and keeps using it for further %setup calls
922
923 $prepscript .= "cd '$topdir/BUILD'\n";
924 $tarballdir = expandmacros($tarballdir,'gp');
925 $prepscript .= "rm -rf '$tarballdir'\n" if $deldir;
926 $prepscript .= "/bin/mkdir -p $tarballdir\n" if $changedir;
927
928 if ($deftarball) {
929 $prepscript .= "cd '$tarballdir'\n" if $changedir;
930 $prepscript .= unpackcmd($pkgdata{main}{source},$quietunpack);
931 }
932
933 if ($altsource) {
934 if ($altsource == 1) { # -a
935 $prepscript .= "cd '$tarballdir'\n";
936 $prepscript .= unpackcmd($pkgdata{sources}{$snum},$quietunpack);
937 } # $altsource == 1
938
939 if ($altsource == 2) { # -b
940 $prepscript .= unpackcmd($pkgdata{sources}{$snum},$quietunpack);
941 $prepscript .= "cd '$tarballdir'\n";
942 } # $altsource == 2
943 }
944
945# rpm doesn't seem to do the chowns any more
946# qq([ `/usr/bin/id -u` = '0' ] && /bin/chown -Rhf root .\n).
947# qq([ `/usr/bin/id -u` = '0' ] && /bin/chgrp -Rhf root .\n).
948 $prepscript .=
949 qq(/bin/chmod -Rf a+rX,u+w,g-w,o-w .\n);
950
951 } elsif ( my ($patchnum,$patchopts) = (/^\%patch(\d*)(\s+.+)?$/) ) {
952 unless ( $patchnum ) {
953 $patchnum = ( $patchopts =~ s/-P\s+(\d+)// ? $1 : 0 );
954 }
955 $prepscript .= qq(echo "Patch #$patchnum ($pkgdata{main}{"patch$patchnum"}):"\n);
956 # If there are options passed, use'em.
957 # Otherwise, catch a bare %patch and ASS-U-ME it's '-p0'-able.
958 # Will break on options that don't provide -pnn, but what the hell.
959 # Need to decompress .bz2 and .gz patches on the fly. Not sure why one
960 # would ever have such things, but there they are... and rpmbuild supports 'em
961 # patch originally suggested by Lucian Cristian for .bz2
962 # reworked and expanded to support .Z/.gz/.xz as well
963 if ( $pkgdata{main}{"patch$patchnum"} =~ /\.(?:Z|gz|bz2|xz)$/ ) {
964 my $decompressor;
965 $decompressor = 'gzip' if $pkgdata{main}{"patch$patchnum"} =~ /\.(?:Z|gz)$/;
966 $decompressor = 'bzip2' if $pkgdata{main}{"patch$patchnum"} =~ /\.bz2$/;
967 $decompressor = 'xz' if $pkgdata{main}{"patch$patchnum"} =~ /\.xz$/;
968 $prepscript .= qq(/bin/$decompressor -d < $topdir/SOURCES/$pkgdata{main}{"patch$patchnum"} | patch );
969 $prepscript .= $patchopts if $patchopts;
970 $prepscript .= "-p0" if !$patchopts;
971 $prepscript .= qq( -s\nSTATUS=\$?\nif [ \$STATUS -ne 0 ]; then\n exit \$STATUS\nfi\n);
972 } else {
973 $prepscript .= "patch ";
974 $prepscript .= $patchopts if $patchopts;
975 $prepscript .= "-p0" if !$patchopts;
976 $prepscript .= " -s <$topdir/SOURCES/".$pkgdata{main}{"patch$patchnum"}."\n";
977 }
978 } else {
979 $prepscript .= expandmacros($_,'gp');
980 }
981 next LINE;
982 } # prep
983
984 if ($stage eq 'build') {
985 # %build. This is pretty much just a shell script. There
986 # aren't many local macros to deal with.
987 if (/^\%configure/) {
988 $buildscript .= expandmacros($_,'cgbp');
989 } elsif (/^\%\{__make\}/) {
990 $buildscript .= expandmacros($_,'mgbp');
991 } else {
992 $buildscript .= expandmacros($_,'gp');
993 }
994 next LINE;
995 } # build
996
997 if ($stage eq 'install') {
998 if (/^\%makeinstall/) {
999 $installscript .= expandmacros($_,'igbp');
1000 } else {
1001 $installscript .= expandmacros($_,'gp');
1002 }
1003 next LINE;
1004 } # install
1005
1006 if ($stage eq 'clean') {
1007 $cleanscript .= expandmacros($_,'gp');
1008 next LINE;
1009 } # clean
1010
1011 if ($stage eq 'prepost') {
1012 $pkgdata{$subname}{$scriptlet} .= expandmacros($_,'gp');
1013 next LINE;
1014 } # prepost
1015
1016 if ($stage eq 'files') {
1017 # need to deal with these someday
1018 next LINE if /^\%dir/;
1019 next LINE if /^\%defattr/;
1020 next LINE if /^\%verify/;
1021 # dunno what to do with this; not sure if there's space in Debian's package structure for it.
1022 next LINE if /^\%ghost/;
1023 # Debian dpkg doesn't speak "%docdir". Meh.
1024 next LINE if /^\%docdir/;
1025# my $singleton = 0; # don't recall what this was for
1026 next LINE if /^\s*#/;
1027 next LINE if /^\s*$/;
1028
1029# create and initialize flags
1030 my ($perms, $owner, $group, $conf, $filesline);
1031 $perms = $owner = $group = $conf = '-';
1032
1033 $filesline = $_;
1034
1035 # strip and flag %attr constructs
1036 if ($filesline =~ /\%attr\b/) {
1037 # Extract %attr...
1038 my ($args) = (/(\%attr\s*\(\s*[\d-]+\s*,\s*["a-zA-Z0-9-]+\s*,\s*["a-zA-Z0-9-]+\s*\))/);
1039 $args =~ s/\s+//g;
1040 $args =~ s/"//g; # don't think quotes are ever necessary, but they're *allowed*
1041 # ... and parse it ...
1042 ($perms,$owner,$group) = ($args =~ /\(([\d-]+),([a-zA-Z0-9-]+),([a-zA-Z0-9-]+)/);
1043 # ... and wipe it when we're done.
1044 $filesline =~ s/\%attr\s*\(\s*[\d-]+\s*,\s*["a-zA-Z0-9-]+\s*,\s*["a-zA-Z0-9-]+\s*\)//;
1045 }
1046
1047 # Conffiles. Note that Debian and RH have similar, but not
1048 # *quite* identical ideas of what constitutes a conffile. Nrgh.
1049 # Note that dpkg will always ask if you want to replace the file - noreplace
1050 # is more or less permanently enabled.
1051##fixme
1052# also need to handle missingok (file that doesn't exist, but should be removed on uninstall)
1053# hmm. not sure if such is **POSSIBLE** with Debian... maybe an addition to %post?
1054 if ($filesline =~ /\%config\b(?:\s*\(\s*noreplace\s*\)\s*)?/) {
1055 $pkgdata{$subname}{conffiles} = 1; # Flag it for later
1056 $conf = 'y';
1057 $filesline =~ s/\%config\b(?:\s*\(\s*noreplace\s*\)\s*)?//;
1058 }
1059
1060 # %doc needs extra processing, because it can be a space-separated list, and may
1061 # include both full and partial pathnames. The partial pathnames must be fiddled
1062 # into place in the %install script, because Debian doesn't really have the concept
1063 # of "documentation file" that rpm does. (Debian "documentation files" are files
1064 # in /usr/share/doc/<packagename>.)
1065##fixme: unhandled case: %doc %defattr. Eeep.
1066# don't really know what to do with %defattr, generally. :(
1067 if ($filesline =~ /\%doc\b/) {
1068 $filesline =~ s/\s*\%doc\s+//;
1069
1070# this could probably go elsewhere.
1071 my $pkgname = $pkgdata{$subname}{name};
1072 $pkgname =~ tr/_/-/;
1073
1074 # have to extract the partial pathnames that %doc installs automagically
1075 foreach (split /\s+/, $filesline) {
1076 if (! (/^\%/ or m|^/|) ) {
1077 $doclist{$subname} .= " $_";
1078 my ($element) = m|([^/\s]+/?)$|;
1079 $filesline =~ s|$_|\%{_docdir}/$pkgname/$element|;
1080 }
1081 }
1082 } # $filesline =~ /\%doc\b/
1083
1084 $filesline =~ s/^\s*//; # Just In Case. For, uh, neatness.
1085
1086# due to Debian's total lack of real permissions-processing in its actual package
1087# handling component (dpkg-deb), this can't really be done "properly". We'll have
1088# to add chown/chmod commands to the postinst instead. Feh.
1089 $pkgdata{$subname}{'post'} .= "chown $owner $filesline\n" if $owner ne '-';
1090 $pkgdata{$subname}{'post'} .= "chgrp $group $filesline\n" if $group ne '-';
1091 $pkgdata{$subname}{'post'} .= "chmod $perms $filesline\n" if $perms ne '-';
1092
1093##fixme
1094# need hackery to assure only one filespec per %config. NB: "*" is one filespec. <g>
1095 push @{$pkgdata{$subname}{conflist}}, $filesline if $conf ne '-';
1096
1097 # now that we've got the specials out of the way, we can add things to the appropriate list of files.
1098 # ... and finally everything else
1099 $filelist{$subname} .= " $filesline";
1100
1101 next LINE;
1102 } # files
1103
1104 if ($stage eq 'changelog') {
1105 # this is one of the few places we do NOT generally want to replace macros...
1106 $pkgdata{main}{changelog} .= $_;
1107 }
1108
1109 if ($stage eq 'preamble') {
1110 if (/^summary:\s*(.+)/i) {
1111 $pkgdata{main}{summary} = $1;
1112 } elsif (/^name:\s*(.+)/i) {
1113 $pkgdata{main}{name} = expandmacros($1,'g');
1114 } elsif (/^epoch:\s*(.+)/i) {
1115 $pkgdata{main}{epoch} = expandmacros($1,'g');
1116 } elsif (/^version:\s*(.+)/i) {
1117 $pkgdata{main}{version} = expandmacros($1,'g');
1118 } elsif (/^release:\s*(.+)/i) {
1119 $pkgdata{main}{release} = expandmacros($1,'g');
1120 } elsif (/^group:\s*(.+)/i) {
1121 $pkgdata{main}{group} = $1;
1122 } elsif (/^copyright:\s*(.+)/i) {
1123 $pkgdata{main}{copyright} = $1;
1124 } elsif (/^url:\s*(.+)/i) {
1125 $pkgdata{main}{url} = $1;
1126 } elsif (/^packager:\s*(.+)/i) {
1127 $pkgdata{main}{packager} = $1;
1128 } elsif (/^vendor:\s*(.+)/i) {
1129 $specglobals{vendor} = $1;
1130 } elsif (/^buildroot:\s*(.+)/i) {
1131 $specglobals{buildroot} = $1;
1132 } elsif (my ($srcnum, $src) = (/^source(\d*):\s*(.+)/i)) {
1133 $src =~ s/\s*$//;
1134 $srcnum = 0 unless $srcnum;
1135 $pkgdata{sources}{$srcnum} = basename($src);
1136 $pkgdata{main}{source} = $pkgdata{sources}{0} if 0 == $srcnum;
1137 } elsif (my ($patchnum, $patch) = (/^patch(\d*):\s*(.+)/i)) {
1138 $patch =~ s/\s*$//;
1139 $patchnum = 0 unless $patchnum;
1140 $pkgdata{main}{"patch$patchnum"} = basename($patch);
1141 } elsif (/^buildarch(?:itecture)?:\s*(.+)/i) {
1142 $pkgdata{main}{arch} = $1;
1143 $pkgdata{main}{arch} =~ s/^noarch$/all/;
1144 $buildarch = $pkgdata{main}{arch};
1145 } elsif (/^buildrequires:\s*(.+)/i) {
1146 $buildreq .= ", $1";
1147 } elsif (/^requires:\s*(.+)/i) {
1148 $pkgdata{main}{requires} .= ", ".expandmacros("$1", 'gp');
1149 } elsif (/^provides:\s*(.+)/i) {
1150 $pkgdata{main}{provides} .= ", $1";
1151 } elsif (/^conflicts:\s*(.+)/i) {
1152 $pkgdata{main}{conflicts} .= ", $1";
1153 } elsif (/^recommends:\s*(.+)/i) {
1154 $pkgdata{main}{recommends} .= ", $1";
1155 warn "Warning: Debian-specific 'Recommends:' outside \%if wrapper\n" if $iflevel == 0;
1156# As of sometime between RHEL 6 and RHEL 7 or so, support was added for Recommends: and Enhances:,
1157# along with shiny new tag Supplements:. We'll continue to warn about them for a while.
1158 } elsif (/^suggests:\s*(.+)/i) {
1159 $pkgdata{main}{suggests} .= ", $1";
1160 warn "Warning: 'Suggests:' outside \%if wrapper\n" if $iflevel == 0;
1161 } elsif (/^enhances:\s*(.+)/i) {
1162 $pkgdata{main}{enhances} .= ", $1";
1163 warn "Warning: 'Enhances:' outside \%if wrapper\n" if $iflevel == 0;
1164 } elsif (/^supplements:\s*(.+)/i) {
1165 $pkgdata{main}{enhances} .= ", $1";
1166 warn "Warning: 'Supplements:' is not natively supported by .deb packages. Downgrading relationship to Enhances:.\n";
1167 } elsif (/^replaces:\s*(.+)/i) {
1168 $pkgdata{main}{replaces} .= ", $1";
1169 warn "Warning: 'Replaces:' outside \%if wrapper\n" if $iflevel == 0;
1170 } elsif (/^obsoletes:\s*(.+)/i) {
1171 $pkgdata{main}{replaces} .= ", $1";
1172 } elsif (/^autoreq(?:prov)?:\s*(.+)/i) {
1173 # we don't handle auto-provides (yet)
1174 $NoAutoReq = 1 if $1 =~ /(?:no|0)/i;
1175 }
1176 next LINE;
1177 } # preamble
1178
1179 } # while <SPEC>
1180
1181 # Parse and replace some more macros. More will be replaced even later.
1182
1183 # Expand macros as necessary.
1184 $scriptletbase = expandmacros($scriptletbase,'gp');
1185
1186 $cleanscript = expandmacros($cleanscript,'gp');
1187
1188 $specglobals{buildroot} = $cmdbuildroot if $cmdbuildroot;
1189 $specglobals{buildroot} = expandmacros($specglobals{buildroot},'gp');
1190
1191 close SPECFILE;
1192} # end parse_spec()
1193
1194
1195## prep()
1196# Writes and executes the %prep script (mostly) built while reading the spec file.
1197sub prep {
1198 # Replace some things here just to make sure.
1199 $prepscript = expandmacros($prepscript,'gp');
1200
1201 # create script filename
1202 my $prepscriptfile = "$tmpdir/deb-tmp.prep.".int(rand(99998)+1);
1203 sysopen(PREPSCRIPT, $prepscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
1204 or die "Can't open/create prep script file $prepscriptfile: $!\n";
1205 print PREPSCRIPT $scriptletbase;
1206 print PREPSCRIPT $prepscript;
1207 close PREPSCRIPT;
1208
1209 # execute
1210 print "Calling \%prep script $prepscriptfile...\n";
1211 system("/bin/sh -e $prepscriptfile") == 0
1212 or die "Can't exec: $!\n";
1213
1214 # and clean up
1215 unlink $prepscriptfile;
1216} # end prep()
1217
1218
1219## build()
1220# Writes and executes the %build script (mostly) built while reading the spec file.
1221sub build {
1222 # Expand the macros
1223 $buildscript = expandmacros($buildscript,'cgbp');
1224
1225 # create script filename
1226 my $buildscriptfile = "$tmpdir/deb-tmp.build.".int(rand(99998)+1);
1227 sysopen(BUILDSCRIPT, $buildscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
1228 or die "Can't open/create build script file $buildscriptfile: $!\n";
1229 print BUILDSCRIPT $scriptletbase;
1230 print BUILDSCRIPT $buildscript;
1231 close BUILDSCRIPT;
1232
1233 # execute
1234 print "Calling \%build script $buildscriptfile...\n";
1235 system("/bin/sh -e $buildscriptfile") == 0
1236 or die "Can't exec: $!\n";
1237
1238 # and clean up
1239 unlink $buildscriptfile;
1240} # end build()
1241
1242
1243## install()
1244# Writes and executes the %install script (mostly) built while reading the spec file.
1245sub install {
1246
1247 # munge %doc entries into place
1248 # rpm handles this with a separate executed %doc script, we're not going to bother.
1249 foreach my $docpkg (keys %doclist) {
1250 my $pkgname = $pkgdata{$docpkg}{name};
1251 $pkgname =~ s/_/-/g;
1252
1253 $installscript .= "DOCDIR=\$RPM_BUILD_ROOT\%{_docdir}/$pkgname\nexport DOCDIR\n";
1254 $installscript .= "mkdir -p \$DOCDIR\n";
1255 $doclist{$docpkg} =~ s/^\s*//;
1256 foreach (split(' ',$doclist{$docpkg})) {
1257 $installscript .= "cp -pr $_ \$DOCDIR/\n";
1258 }
1259 }
1260
1261 # Expand the macros
1262 $installscript = expandmacros($installscript,'igbp');
1263
1264 # create script filename
1265 my $installscriptfile = "$tmpdir/deb-tmp.inst.".int(rand(99998)+1);
1266 sysopen(INSTSCRIPT, $installscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
1267 or die "Can't open/create install script file $installscriptfile: $!\n";
1268 print INSTSCRIPT $scriptletbase;
1269 print INSTSCRIPT $installscript;
1270 close INSTSCRIPT;
1271
1272 # execute
1273 print "Calling \%install script $installscriptfile...\n";
1274 system("/bin/sh -e $installscriptfile") == 0
1275 or die "Can't exec: $!\n";
1276
1277 # and clean up
1278 unlink $installscriptfile;
1279
1280 # final bit: compress manpages if present
1281 # done here cuz I don't grok shell well
1282 # should probably error-check all kinds of things. <g>
1283 if (opendir MANROOT, "$specglobals{buildroot}/usr/share/man") {
1284 my @mansects = readdir MANROOT;
1285 closedir MANROOT;
1286 foreach my $mandir (@mansects) {
1287 next if $mandir !~ /^man/;
1288 opendir MANPAGES, "$specglobals{buildroot}/usr/share/man/$mandir";
1289 my @pagelist = readdir MANPAGES;
1290 closedir MANPAGES; # Slightly safer to to this; no accidental recursion. O_o
1291 foreach my $manpage (@pagelist) {
1292 $manpage = "$specglobals{buildroot}/usr/share/man/$mandir/$manpage";
1293 if ( -f $manpage) {
1294 if ($manpage =~ /^(.+)\.(?:Z|gz|bz2)\n?$/) {
1295 my $newpage = $1;
1296 `gunzip $manpage` if $manpage =~ /\.(?:Z|gz)$/;
1297 `bunzip2 $manpage` if $manpage =~ /\.bz2$/;
1298 $manpage = $newpage;
1299 }
1300 `gzip -9 -n $manpage`;
1301 } elsif ( -l $manpage) {
1302 my $linkdest = readlink $manpage;
1303 $linkdest =~ s/\.(?:Z|gz|bz2)//;
1304 unlink $manpage;
1305 $manpage =~ s/\.(?:Z|gz|bz2)//;
1306 symlink "$linkdest.gz", "$manpage.gz" or print "DEBUG: wibble: symlinking manpage failed: $!\n";
1307 }
1308 }
1309 }
1310 } # if opendir MANROOT
1311} # end install()
1312
1313
1314## binpackage()
1315# Creates the binary .deb package from the installed tree in $specglobals{buildroot}.
1316# Writes and executes a shell script to do so.
1317# Creates miscellaneous files required by dpkg-deb to actually build the package file.
1318# Should handle simple subpackages
1319sub binpackage {
1320
1321 foreach my $pkg (@pkglist) {
1322
1323 $pkgdata{$pkg}{arch} = $hostarch if !$pkgdata{$pkg}{arch}; # Just In Case.
1324
1325 # Make sure we have somewhere to write the .deb file
1326 if (!-e "$topdir/DEBS/$pkgdata{$pkg}{arch}") {
1327 mkdir "$topdir/DEBS/$pkgdata{$pkg}{arch}";
1328 }
1329
1330 # Skip building a package that doesn't have any files or dependencies. True
1331 # metapackages don't have any files, but they depend on a bunch of things.
1332 # Packages with neither have, essentially, no content.
1333 next if
1334 (!$filelist{$pkg} or $filelist{$pkg} =~ /^\s*$/) &&
1335 (!$pkgdata{$pkg}{requires});
1336 $filelist{$pkg} = '' if !$filelist{$pkg};
1337
1338 # Gotta do this first, otherwise we don't have a place to move files from %files
1339 mkdir "$specglobals{buildroot}/$pkg";
1340
1341 # Eliminate any lingering % macros
1342 $filelist{$pkg} = expandmacros $filelist{$pkg}, 'gp';
1343
1344 my @pkgfilelist = split ' ', $filelist{$pkg};
1345 foreach my $pkgfile (@pkgfilelist) {
1346 $pkgfile = expandmacros($pkgfile, 'gp');
1347
1348 # Feh. Manpages don't **NEED** to be gzipped, but rpmbuild does, and so shall we.
1349 # ... and your little info page too!
1350 if ($pkgfile =~ m{/usr/share/(?:man/man|info)}) {
1351 # need to check to see if manpage is gzipped
1352 if (-e "$specglobals{buildroot}$pkgfile") {
1353 # if we've just been pointed to a manpage section with "many" pages,
1354 # we need to gzip them all.
1355 # fortunately, we do NOT need to explicitly track each file for the
1356 # purpose of stuffing them in the package... the original %files
1357 # entry will do just fine.
1358 if ( -d "$specglobals{buildroot}$pkgfile") {
1359 foreach my $globfile (glob("$specglobals{buildroot}$pkgfile/*")) {
1360 gzip $globfile if $globfile !~ m|\.gz$|;
1361 }
1362 } else {
1363 if ($pkgfile !~ m|\.gz$|) {
1364 qx { gzip $specglobals{buildroot}$pkgfile };
1365 $pkgfile .= ".gz";
1366 }
1367 }
1368 } else {
1369 if ($pkgfile !~ m|\.gz$|) {
1370 $pkgfile .= ".gz";
1371 } else {
1372 $pkgfile =~ s/\.gz$//;
1373 qx { gzip $specglobals{buildroot}$pkgfile };
1374 $pkgfile .= ".gz";
1375 }
1376 }
1377 }
1378
1379 my ($fpath,$fname) = ($pkgfile =~ m|(.+?/?)?([^/]+/?)$|); # We don't need $fname now, but we might.
1380 qx { mkdir -p $specglobals{buildroot}/$pkg$fpath }
1381 if $fpath && $fpath ne '';
1382 qx { mv $specglobals{buildroot}$pkgfile $specglobals{buildroot}/$pkg$fpath };
1383 }
1384
1385 # Get the "Depends" (Requires) a la RPM. Ish. We strip the leading
1386 # comma and space here (if needed) in case there were "Requires" specified
1387 # in the spec file - those would precede these.
1388 $pkgdata{$pkg}{requires} .= getreqs("$specglobals{buildroot}/$pkg") if ! $NoAutoReq;
1389
1390 # magic needed to properly version dependencies...
1391 # only provided deps will really be included
1392 $pkgdata{$pkg}{requires} =~ s/^, //; # Still have to do this here.
1393 $pkgdata{$pkg}{requires} =~ s/\s+//g;
1394 my @deps = split /,/, $pkgdata{$pkg}{requires};
1395 my $tmp = '';
1396 foreach my $dep (@deps) {
1397 # Hack up the perl(Class::SubClass) deps into something dpkg can understand.
1398 # May or may not be versioned.
1399 # We do this first so the version rewriter can do its magic next.
1400 if (my ($mod,$ver) = ($dep =~ /^perl\(([A-Za-z0-9\:\-]+)\)([><=]+.+)?/) ) {
1401 $mod =~ s/^perl\(//;
1402 $mod =~ s/\)$//;
1403 $mod =~ s/::/-/g;
1404 $mod =~ tr/A-Z/a-z/;
1405 $mod = "lib$mod-perl";
1406 $mod .= $ver if $ver;
1407 $dep = $mod;
1408 }
1409 if (my ($name,$rel,$value) = ($dep =~ /^([a-zA-Z0-9._-]+)([><=]+)([a-zA-Z0-9._-]+)$/)) {
1410 $tmp .= ", $name ($rel $value)";
1411 } else {
1412 $tmp .= ", $dep";
1413 }
1414 }
1415 ($pkgdata{$pkg}{requires} = $tmp) =~ s/^, //;
1416
1417 # Do this here since we're doing {depends}...
1418 if (defined($pkgdata{$pkg}{provides})) {
1419 $pkgdata{$pkg}{provides} =~ s/^, //;
1420 $pkgdata{$pkg}{provides} = expandmacros($pkgdata{$pkg}{provides},'gp');
1421 }
1422 if (defined($pkgdata{$pkg}{conflicts})) {
1423 $pkgdata{$pkg}{conflicts} =~ s/^, //;
1424 $pkgdata{$pkg}{conflicts} = expandmacros($pkgdata{$pkg}{conflicts},'gp');
1425 }
1426
1427# These are Debian-specific!
1428 if (defined($pkgdata{$pkg}{recommends})) {
1429 $pkgdata{$pkg}{recommends} =~ s/^, //;
1430 $pkgdata{$pkg}{recommends} = expandmacros($pkgdata{$pkg}{recommends},'gp');
1431 }
1432 if (defined($pkgdata{$pkg}{suggests})) {
1433 $pkgdata{$pkg}{suggests} =~ s/^, //;
1434 $pkgdata{$pkg}{suggests} = expandmacros($pkgdata{$pkg}{suggests},'gp');
1435 }
1436 if (defined($pkgdata{$pkg}{enhances})) {
1437 $pkgdata{$pkg}{enhances} =~ s/^, //;
1438 $pkgdata{$pkg}{enhances} = expandmacros($pkgdata{$pkg}{enhances},'gp');
1439 }
1440 if (defined($pkgdata{$pkg}{replaces})) {
1441 $pkgdata{$pkg}{replaces} =~ s/^, //;
1442 $pkgdata{$pkg}{replaces} = expandmacros($pkgdata{$pkg}{replaces},'gp');
1443 }
1444
1445 # Gotta do this next, otherwise the control file has nowhere to go. >:(
1446 mkdir "$specglobals{buildroot}/$pkg/DEBIAN";
1447
1448 # Hack the filename for the package into a Debian-tool-compatible format. GRRRRRR!!!!!
1449 # Have I mentioned I hate Debian Policy?
1450 $pkgdata{$pkg}{name} =~ tr/_/-/;
1451
1452 # create script filename
1453 my $debscriptfile = "$tmpdir/deb-tmp.pkg.".int(rand(99998)+1);
1454 sysopen(DEBSCRIPT, $debscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
1455 or die "Can't open/create package-creation script file $debscriptfile: $!\n";
1456 print DEBSCRIPT $scriptletbase;
1457 print DEBSCRIPT "fakeroot -- dpkg-deb -b $specglobals{buildroot}/$pkg $topdir/DEBS/$pkgdata{$pkg}{arch}/".
1458 "$pkgdata{$pkg}{name}_".
1459 (defined($pkgdata{main}{epoch}) ? "$pkgdata{main}{epoch}:" : '').
1460 "$pkgdata{$pkg}{version}-$pkgdata{main}{release}_$pkgdata{$pkg}{arch}.deb\n";
1461 # %$&$%@#@@#%@@@ Debian and their horrible ugly package names. >:(
1462 close DEBSCRIPT;
1463
1464 $pkgdata{$pkg}{summary} = expandmacros($pkgdata{$pkg}{summary}, 'gp');
1465 my $control = "Package: $pkgdata{$pkg}{name}\n".
1466 "Version: ".(defined($pkgdata{main}{epoch}) ? "$pkgdata{main}{epoch}:" : '').
1467 "$pkgdata{$pkg}{version}-$pkgdata{main}{release}\n".
1468 "Section: ".($pkgdata{$pkg}{group} ? $pkgdata{$pkg}{group} : $pkgdata{main}{group})."\n".
1469 "Priority: optional\n".
1470 "Architecture: $pkgdata{$pkg}{arch}\n".
1471 "Maintainer: $pkgdata{main}{packager}\n".
1472 ( $pkgdata{$pkg}{requires} ne '' ? "Depends: $pkgdata{$pkg}{requires}\n" : '' ).
1473 ( defined($pkgdata{$pkg}{provides}) ? "Provides: $pkgdata{$pkg}{provides}\n" : '' ).
1474 ( defined($pkgdata{$pkg}{conflicts}) ? "Conflicts: $pkgdata{$pkg}{conflicts}\n" : '' ).
1475 ( defined($pkgdata{$pkg}{recommends}) ? "Recommends: $pkgdata{$pkg}{recommends}\n" : '' ).
1476 ( defined($pkgdata{$pkg}{suggests}) ? "Suggests: $pkgdata{$pkg}{suggests}\n" : '' ).
1477 ( defined($pkgdata{$pkg}{enhances}) ? "Enhances: $pkgdata{$pkg}{enhances}\n" : '' ).
1478 ( defined($pkgdata{$pkg}{replaces}) ? "Replaces: $pkgdata{$pkg}{replaces}\n" : '' ).
1479 "Description: $pkgdata{$pkg}{summary}\n";
1480 $pkgdata{$pkg}{desc} = expandmacros($pkgdata{$pkg}{desc}, 'gp');
1481 # Munge things so that Debian tools don't choke on errant blank lines
1482 $pkgdata{$pkg}{desc} =~ s/\s+$//g; # Trim trailing blanks
1483 $pkgdata{$pkg}{desc} =~ s/^ $/ ./mg; # Replace lines consisting of " \n" with " .\n"
1484 $control .= "$pkgdata{$pkg}{desc}\n";
1485
1486 open CONTROL, ">$specglobals{buildroot}/$pkg/DEBIAN/control";
1487 print CONTROL $control;
1488 close CONTROL;
1489
1490 # Iff there are conffiles (as specified in the %files list(s), add'em
1491 # in so dpkg-deb can tag them.
1492 if ($pkgdata{$pkg}{conffiles}) {
1493 open CONFLIST, ">$specglobals{buildroot}/$pkg/DEBIAN/conffiles";
1494 foreach my $conffile (@{$pkgdata{$pkg}{conflist}}) {
1495 $conffile = expandmacros($conffile, 'g');
1496 my @tmp = glob "$specglobals{buildroot}/$pkg/$conffile";
1497 foreach (@tmp) {
1498 s|$specglobals{buildroot}/$pkg/||g; # nrgl. gotta be a better way to do this...
1499 s/\s+/\n/g; # Not gonna support spaces in filenames. Ewww.
1500 print CONFLIST "$_\n";
1501 }
1502 }
1503 close CONFLIST;
1504 }
1505
1506 # found the point of scripts on subpackages.
1507 if ($pkgdata{$pkg}{'pre'}) {
1508 $pkgdata{$pkg}{'pre'} = expandmacros($pkgdata{$pkg}{'pre'},'gp');
1509 open PREINST, ">$specglobals{buildroot}/$pkg/DEBIAN/preinst";
1510 print PREINST "#!/bin/sh\nset -e\n\n";
1511 print PREINST $pkgdata{$pkg}{'pre'};
1512 close PREINST;
1513 chmod 0755, "$specglobals{buildroot}/$pkg/DEBIAN/preinst";
1514 }
1515 if ($pkgdata{$pkg}{'post'}) {
1516 $pkgdata{$pkg}{'post'} = expandmacros($pkgdata{$pkg}{'post'},'gp');
1517 open POSTINST, ">$specglobals{buildroot}/$pkg/DEBIAN/postinst";
1518 print POSTINST "#!/bin/sh\nset -e\n\n";
1519 print POSTINST $pkgdata{$pkg}{'post'};
1520 close POSTINST;
1521 chmod 0755, "$specglobals{buildroot}/$pkg/DEBIAN/postinst";
1522 }
1523 if ($pkgdata{$pkg}{'preun'}) {
1524 $pkgdata{$pkg}{'pre'} = expandmacros($pkgdata{$pkg}{'preun'},'gp');
1525 open PREUNINST, ">$specglobals{buildroot}/$pkg/DEBIAN/prerm";
1526 print PREUNINST "#!/bin/sh\nset -e\n\n";
1527 print PREUNINST $pkgdata{$pkg}{'preun'};
1528 close PREUNINST;
1529 chmod 0755, "$specglobals{buildroot}/$pkg/DEBIAN/prerm";
1530 }
1531 if ($pkgdata{$pkg}{'postun'}) {
1532 $pkgdata{$pkg}{'postun'} = expandmacros($pkgdata{$pkg}{'postun'},'gp');
1533 open POSTUNINST, ">$specglobals{buildroot}/$pkg/DEBIAN/postrm";
1534 print POSTUNINST "#!/bin/sh\nset -e\n\n";
1535 print POSTUNINST $pkgdata{$pkg}{'postun'};
1536 close POSTUNINST;
1537 chmod 0755, "$specglobals{buildroot}/$pkg/DEBIAN/postrm";
1538 }
1539
1540 # execute
1541 print "Calling package creation script $debscriptfile for $pkgdata{$pkg}{name}...\n";
1542 system("/bin/sh -e $debscriptfile") == 0
1543 or die "Can't exec: $!\n";
1544
1545 $finalmessages .= "Wrote binary package ".
1546 "$pkgdata{$pkg}{name}_".
1547 (defined($pkgdata{main}{epoch}) ? "$pkgdata{main}{epoch}:" : '').
1548 "$pkgdata{$pkg}{version}-$pkgdata{main}{release}_$pkgdata{$pkg}{arch}.deb".
1549 " in $topdir/DEBS/$pkgdata{$pkg}{arch}\n";
1550 # and clean up
1551 unlink $debscriptfile;
1552
1553 } # subpackage loop
1554
1555} # end binpackage()
1556
1557
1558## srcpackage()
1559# Builds a .src.deb source package. Note that Debian's idea of
1560# a "source package" is seriously flawed IMO, because you can't
1561# easily copy it as-is.
1562# Not quite identical to RPM, but Good Enough (TM).
1563sub srcpackage {
1564 # In case we were called with -bs.
1565 $pkgdata{main}{name} =~ tr/_/-/;
1566 my $pkgsrcname = "$pkgdata{main}{name}-".
1567 (defined($pkgdata{main}{epoch}) ? "$pkgdata{main}{epoch}:" : '').
1568 "$pkgdata{main}{version}-$pkgdata{main}{release}.sdeb";
1569
1570 my $paxcmd;
1571
1572 # We'll definitely need this later, and *may* need it sooner.
1573 (my $barespec = $specfile) =~ s|.+/([^/]+)$|$1|;
1574
1575 # Copy the specfile to the build tree, but only if it's not there already.
1576##buglet: need to deal with silly case where silly user has put the spec
1577# file in a subdir of %{_topdir}/SPECS. Ewww. Silly user!
1578 if (abs_path($specfile) !~ /^$topdir\/SPECS/) {
1579 $paxcmd .= "cp $specfile %{_topdir}/SPECS/; \n"
1580 }
1581
1582 # use pax -w [file] [file] ... >outfile.sdeb
1583 $paxcmd = "cd $topdir; pax -w ";
1584
1585 # some packages may not have a "main" source.
1586 $paxcmd .= "SOURCES/$pkgdata{main}{source} " if $pkgdata{main}{source};
1587
1588 # create file list: Source[nn], Patch[nn]
1589 foreach my $specbit (keys %{$pkgdata{main}} ) {
1590 next if $specbit eq 'source';
1591 $paxcmd .= "SOURCES/$pkgdata{main}{$specbit} " if $specbit =~ /^patch/;
1592##buglet: need to deal with case where patches are listed as URLs?
1593# or other extended pathnames? Silly !@$%^&!%%!%!! user!
1594 }
1595
1596 foreach my $source (keys %{$pkgdata{sources}}) {
1597 # Skip Source0, since it's also $pkgdata{main}{source}. Could arguably
1598 # just remove that instead, but I think that might backfire.
1599 next if $source eq '0';
1600 $paxcmd .= "SOURCES/$pkgdata{sources}{$source} ";
1601 }
1602
1603 # add the spec file, source package destination, and cd back where we came from.
1604 $paxcmd .= "SPECS/$barespec > $topdir/SDEBS/$pkgsrcname; cd -";
1605
1606 # In case of %-macros...
1607 $paxcmd = expandmacros($paxcmd,'gp');
1608
1609 system "$paxcmd";
1610 $finalmessages .= "Wrote source package $pkgsrcname in $topdir/SDEBS.\n";
1611} # end srcpackage()
1612
1613
1614## clean()
1615# Writes and executes the %clean script (mostly) built while reading the spec file.
1616sub clean {
1617 # Replace some things here just to make sure.
1618 $cleanscript = expandmacros($cleanscript,'gp');
1619
1620 # create script filename
1621 my $cleanscriptfile = "$tmpdir/deb-tmp.clean.".int(rand(99998)+1);
1622 sysopen(CLEANSCRIPT, $cleanscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
1623 or die $!;
1624 print CLEANSCRIPT $scriptletbase;
1625 print CLEANSCRIPT $cleanscript;
1626 close CLEANSCRIPT;
1627
1628 # execute
1629 print "Calling \%clean script $cleanscriptfile...\n";
1630 system("/bin/sh -e $cleanscriptfile") == 0
1631 or die "Can't exec: $!\n";
1632
1633 # and clean up
1634 unlink $cleanscriptfile;
1635} # end clean()
1636
1637
1638## checkbuildreq()
1639# Checks the build requirements (if any)
1640# Spits out a rude warning and returns a true-false error if any
1641# requirements are not met.
1642sub checkbuildreq {
1643 return 1 if $buildreq eq ''; # No use doing extra work.
1644
1645 # expand macros
1646 $buildreq = expandmacros($buildreq,'gp');
1647
1648 if ( ! -e "/usr/bin/dpkg-query" ) {
1649 print "**WARNING** dpkg-query not found. Can't check build-deps.\n".
1650 " Required for sucessful build:\n".$buildreq."\n".
1651 " Continuing anyway.\n";
1652 return 1;
1653 }
1654
1655 my $reqflag = 1; # unset iff a buildreq is missing
1656
1657 $buildreq =~ s/^, //; # Strip the leading comma and space
1658 my @reqlist = split /,\s+/, $buildreq;
1659
1660 my @missinglist;
1661 foreach my $req (@reqlist) {
1662 # from rpmbuild error message
1663 # Dependency tokens must begin with alpha-numeric, '_' or '/'
1664##fixme: check for suitable whitespace around $rel
1665 my ($pkg,$rel,$ver);
1666
1667 # We have two classes of requirements - versioned and unversioned.
1668 if ($req =~ /[><=]/) {
1669 # Pick up the details of versioned buildreqs
1670 ($pkg,$rel,$ver) = ($req =~ /([a-z0-9._-]+)\s+([><=]+)\s+([a-z0-9._-]+)/);
1671 } else {
1672 # And the unversioned ones.
1673 $pkg = $req;
1674 $rel = '>=';
1675 $ver = 0;
1676 }
1677
1678## Apparently a package that has been installed, then uninstalled, has a "known" dpkg status of
1679## "unknown ok not-installed" vs a package that has never been installed which returns nothing. O_o
1680## Virtual packages, of course, *also* show as "not installed" like this (WTF?)
1681## This causes real packages to be misdetected as installed "possible virtual packages" instead of "missing
1682## packages". I don't think there's really a solution until/unless Debian's tools properly register virtual
1683## packages as installed.
1684 my @pkglist = qx { dpkg-query --showformat '\${status}\t\${version}\n' -W $pkg };
1685 if (!$pkglist[0]) {
1686 print " * Missing build-dependency $pkg!\n $pkglist[0]";
1687 $reqflag = 0;
1688 push @missinglist, $pkg;
1689 } else {
1690# real package, installed
1691#kdeugau:~$ dpkg-query --showformat '${status}\t${version}\n' -W libc-client2007e-dev 2>&1
1692#install ok installed 8:2007f~dfsg-1
1693# virtual package, provided by ???
1694#kdeugau:~$ dpkg-query --showformat '${status}\t${version}\n' -W libc-client-dev 2>&1
1695#unknown ok not-installed
1696# real package or virtual package not installed or provided
1697#kdeugau:~$ dpkg-query --showformat '${status}\t${version}\n' -W libdb4.8-dbg 2>&1
1698#dpkg-query: no packages found matching libdb4.8-dbg
1699
1700 my ($reqstat,undef,undef,$reqver) = split /\s+/, $pkglist[0];
1701 if ($reqstat =~ /^unknown/) {
1702 # this seems to be a virtual package.
1703 print " * Warning: $pkg is probably installed but seems to be a virtual package.\n";
1704 } elsif ($reqstat =~ /^install/) {
1705 my ($resp) = qx { dpkg --compare-versions $reqver '$rel' $ver && echo "ok" };
1706 if ($resp !~ /^ok/) {
1707 $reqflag = 0;
1708 print " * Buildreq $pkg is installed, but wrong version ($reqver): Need $ver\n"
1709 }
1710 } else {
1711 # whatever state it's in, it's not completely installed, therefore it's missing.
1712 print " * Missing build-dependency $pkg!\n $pkglist[0]";
1713 $reqflag = 0;
1714 push @missinglist, $pkg;
1715 } # end not installed/installed check
1716 }
1717 } # end req loop
1718
1719 print "To install all missing dependencies, run 'apt-get install ".join(' ', @missinglist)."'.\n" unless $reqflag;
1720
1721 return $reqflag;
1722} # end checkbuildreq()
1723
1724
1725## getreqs()
1726# Find out which libraries/packages are required for any
1727# executables and libs in a given file tree.
1728# (Debian doesn't have soname-level deps; just package-level)
1729# Returns an empty string if the tree contains no binaries.
1730# Doesn't work well on shell scripts. but those *should* be
1731# fine anyway. (Yeah, right...)
1732sub getreqs() {
1733 my $pkgtree = $_[0];
1734
1735 print "Checking library requirements...\n";
1736 my @binlist = qx { find $pkgtree -type f -perm 755 };
1737
1738 if (scalar(@binlist) == 0) {
1739 return '';
1740 }
1741
1742 my @reqlist;
1743 foreach (@binlist) {
1744 push @reqlist, qx { LANG=C ldd $_ };
1745 }
1746
1747 # Get the list of libs provided by this package. Still doesn't
1748 # handle the case where the lib gets stuffed into a subpackage. :/
1749 my @intprovlist = qx { find $pkgtree -type f -name "*.so*" };
1750 my $provlist = '';
1751 foreach (@intprovlist) {
1752 s/$pkgtree//;
1753 $provlist .= "$_";
1754 }
1755
1756 my %reqs;
1757 my $reqlibs = '';
1758 my %reqliblist;
1759
1760 foreach (@reqlist) {
1761 next if /^$pkgtree/;
1762 next if /not a dynamic executable/;
1763 next if m|/lib(?:64)?/ld-linux|; # Hack! Hack! PTHBTT! (libc suxx0rz)
1764 next if /linux-gate.so/; # Kernel hackery for teh W1n!!1!1eleventy-one!1 (Don't ask. Feh.)
1765 next if /linux-vdso.so/; # More kernel hackery. Whee!
1766
1767 # Whee! more hackery to detect provided-here libs. Some apparently return from ldd as "not found".
1768 my ($a,$b) = split / => /;
1769 $a =~ s/\s*//g;
1770 if ($b =~ /not found/) {
1771 next if qx { find $specglobals{buildroot} -name "*$a" };
1772 }
1773
1774 my ($req) = (m|=\>\s+([a-zA-Z0-9._/+-]+)|); # dig out the actual library (so)name.
1775 # And feh, we need the *path*, since I've discovered a new edge case where
1776 # the same libnnn.1.2.3 *file*name is found across *several* lib dirs. >:(
1777
1778 # Ignore libs provided by this package. Note that we don't match
1779 # on word-boundary at the *end* of the lib we're looking for, as the
1780 # looked-for lib may not have the full soname version. (ie, it may
1781 # "just" point to one of the symlinks that get created somewhere.)
1782 next if $provlist =~ /\b$req/;
1783
1784 $reqlibs .= " $req";
1785 $reqliblist{$req} = 1;
1786 }
1787
1788 if (%reqliblist) {
1789 foreach my $rlib (keys %reqliblist) {
1790 my $libpkg = qx { dpkg -S $rlib };
1791 ($libpkg,undef) = split /:/, $libpkg;
1792 $reqs{$libpkg} = 1;
1793 }
1794 }
1795
1796 my $deplist = '';
1797 foreach (keys %reqs) {
1798 $deplist .= ", $_";
1799 }
1800
1801# For now, we're done. We're not going to meddle with versions yet.
1802# Among other things, it's messier than handling "simple" yes/no "do
1803# we have this lib?" deps. >:(
1804
1805 return $deplist;
1806} # end getreqs()
1807
1808
1809## install_sdeb()
1810# Extracts .sdeb contents to %_topdir as appropriate
1811sub install_sdeb {
1812 $srcpkg = abs_path($srcpkg);
1813
1814 my $paxcmd = "cd $topdir; pax -r <$srcpkg; cd -";
1815
1816 # In case of %-macros...
1817 $paxcmd = expandmacros($paxcmd,'gp');
1818
1819 system "$paxcmd";
1820 print "Extracted source package $srcpkg to $topdir.\n";
1821} # end install_sdeb()
1822
1823
1824## expandmacros()
1825# Expands all %{blah} macros in the passed string
1826# Split up a bit with some sections so we don't spend time trying to
1827# expand macros that are only used in a few specific places.
1828sub expandmacros {
1829 my $macrostring = shift;
1830 my $section = shift;
1831
1832 # To allow the FHS-ish %configure and %makeinstall to work The Right Way.
1833 # (Without clobbering the global $specglobals{buildroot}.)
1834 my $prefix = '';
1835
1836 if ($section =~ /c/) {
1837 # %configure macro
1838# Don't know what it's for, don't have a useful default replacement
1839# --program-prefix=%{_program_prefix} \
1840 $macrostring =~ s'%configure'./configure --host=$DEB_HOST_GNU_TYPE \
1841 --build=$DEB_BUILD_GNU_TYPE \
1842 --prefix=%{_prefix} \
1843 --exec-prefix=%{_exec_prefix} \
1844 --bindir=%{_bindir} \
1845 --sbindir=%{_sbindir} \
1846 --sysconfdir=%{_sysconfdir} \
1847 --datadir=%{_datadir} \
1848 --includedir=%{_includedir} \
1849 --libdir=%{_libdir} \
1850 --libexecdir=%{_libexecdir} \
1851 --localstatedir=%{_localstatedir} \
1852 --sharedstatedir=%{_sharedstatedir} \
1853 --mandir=%{_mandir} \
1854 --infodir=%{_infodir} ';
1855 } # done %configure
1856
1857 if ($section =~ /m/) {
1858 $macrostring =~ s'%{__make}'make ';
1859 } # done make
1860
1861# %makeinstall expands with recursive macros in rpm. whee.
1862 if ($section =~ /i/) {
1863 # This is where we need to mangle $prefix.
1864 $macrostring =~ s'%makeinstall'make \
1865 prefix=%{?buildroot:%{buildroot}}%{_prefix} \
1866 exec_prefix=%{?buildroot:%{buildroot}}%{_exec_prefix} \
1867 bindir=%{?buildroot:%{buildroot}}%{_bindir} \
1868 sbindir=%{?buildroot:%{buildroot}}%{_sbindir} \
1869 sysconfdir=%{?buildroot:%{buildroot}}%{_sysconfdir} \
1870 datadir=%{?buildroot:%{buildroot}}%{_datadir} \
1871 includedir=%{?buildroot:%{buildroot}}%{_includedir} \
1872 libdir=%{?buildroot:%{buildroot}}%{_libdir} \
1873 libexecdir=%{?buildroot:%{buildroot}}%{_libexecdir} \
1874 localstatedir=%{?buildroot:%{buildroot}}%{_localstatedir} \
1875 sharedstatedir=%{?buildroot:%{buildroot}}%{_sharedstatedir} \
1876 mandir=%{?buildroot:%{buildroot}}%{_mandir} \
1877 infodir=%{?buildroot:%{buildroot}}%{_infodir} \
1878 install ';
1879 $prefix = $specglobals{buildroot};
1880 } # done %install and/or %makeinstall
1881
1882 # Build data
1883 # Note that these are processed in reverse order to get the substitution order right
1884 if ($section =~ /b/) {
1885# $macrostring =~ s'%{fhs}'host=$DEB_HOST_GNU_TYPE \
1886# build=$DEB_BUILD_GNU_TYPE \
1887 $macrostring =~ s'%{fhs}'prefix=%{_prefix} \
1888 exec-prefix=%{_exec_prefix} \
1889 bindir=%{_bindir} \
1890 sbindir=%{_sbindir} \
1891 sysconfdir=%{_sysconfdir} \
1892 datadir=%{_datadir} \
1893 includedir=%{_includedir} \
1894 libdir=%{_libdir} \
1895 libexecdir=%{_libexecdir} \
1896 localstatedir=%{_localstatedir} \
1897 sharedstatedir=%{_sharedstatedir} \
1898 mandir=%{_mandir} \
1899 infodir=%{_infodir} \
1900';
1901
1902 # Note that the above regex terminates with the extra space
1903 # "Just In Case" of user additions, which will then get neatly
1904 # tagged on the end where they take precedence (supposedly)
1905 # over the "default" ones.
1906
1907 # Now we cascade the macros introduced above. >_<
1908 # Wot ot to go theah:
1909 $macrostring =~ s|%{_mandir}|%{_datadir}/man|g; #/usr/share/man
1910 $macrostring =~ s|%{_infodir}|%{_datadir}/info|g; #/usr/share/info
1911 $macrostring =~ s|%{_oldincludedir}|/usr/include|g; #/usr/include
1912 $macrostring =~ s|%{_includedir}|%{_prefix}/include|g; #/usr/include
1913 $macrostring =~ s|%{_libdir}|%{_exec_prefix}/%{_lib}|g; #/usr/lib
1914 $macrostring =~ s|%{_lib}|lib|g; #?
1915 $macrostring =~ s|%{_localstatedir}|/var|g; #/var
1916 $macrostring =~ s|%{_sharedstatedir}|%{_prefix}/com|g; #/usr/com WTF?
1917 $macrostring =~ s|%{_sysconfdir}|/etc|g; #/etc
1918 $macrostring =~ s|%{_datadir}|%{_prefix}/share|g; #/usr/share
1919 $macrostring =~ s|%{_libexecdir}|%{_exec_prefix}/libexec|g; #/usr/libexec
1920 $macrostring =~ s|%{_sbindir}|%{_exec_prefix}/sbin|g; #/usr/sbin
1921 $macrostring =~ s|%{_bindir}|%{_exec_prefix}/bin|g; #/usr/bin
1922 $macrostring =~ s|%{_exec_prefix}|%{_prefix}|g; #/usr
1923 $macrostring =~ s|%{_prefix}|/usr|g; #/usr
1924 } # done with config section
1925
1926 # Package data
1927 if ($section =~ /p/) {
1928 $macrostring =~ s/\%\{buildroot\}/$specglobals{buildroot}/gi;
1929 $macrostring =~ s/\%\{source0?}/$topdir\/SOURCES\/$pkgdata{main}{source}/gi;
1930 foreach my $source (keys %{$pkgdata{sources}}) {
1931 $macrostring =~ s/\%\{source$source\}/$topdir\/SOURCES\/$pkgdata{sources}{$source}/gi;
1932 }
1933 $macrostring =~ s/\%\{name\}/$pkgdata{main}{name}/gi;
1934 $macrostring =~ s/\%\{version\}/$pkgdata{main}{version}/gi;
1935 $macrostring =~ s/\%\{release\}/$pkgdata{main}{release}/gi;
1936 }
1937
1938 # Globals, and not-so-globals
1939 if ($section =~ /g/) {
1940
1941 $macrostring =~ s|%{_builddir}|%{_topdir}/BUILD|g;
1942# no longer a valid macro/tag
1943# $macrostring =~ s|%{buildsubdir}|$tarballdir|g;
1944 $macrostring =~ s|%{_topdir}|$topdir|g;
1945 $macrostring =~ s|%{_tmppath}|$tmpdir|g;
1946 $macrostring =~ s'%{_docdir}'%{_datadir}/doc'g;
1947
1948 # Standard FHS locations. More or less.
1949 $macrostring =~ s'%{_bindir}'/usr/bin'g;
1950 $macrostring =~ s'%{_sbindir}'/usr/sbin'g;
1951 $macrostring =~ s'%{_mandir}'%{_datadir}/man'g;
1952 $macrostring =~ s'%{_infodir}'%{_datadir}/info'g;
1953 $macrostring =~ s'%{_includedir}'/usr/include'g;
1954 $macrostring =~ s'%{_libdir}'/usr/lib'g;
1955 $macrostring =~ s'%{_sysconfdir}'/etc'g;
1956 $macrostring =~ s'%{_localstatedir}'/var'g;
1957 $macrostring =~ s'%{_prefix}'/usr'g;
1958
1959 # FHS-ish locations that aren't quite actually FHS-specified.
1960 $macrostring =~ s'%{_datadir}'/usr/share'g;
1961
1962 # special %define's. Handle the general case where we eval anything.
1963 # Even more general: %(...) is a spec-parse-time shell code wrapper.
1964 # Prime example:
1965 #%define perl_vendorlib %(eval "`perl -V:installvendorlib`"; echo $installvendorlib)
1966 if ($macrostring =~ /\%\((.+)\)/) {
1967 my $shellstr = $1;
1968 # Oy vey this gets silly for the perl bits. Executing a shell to
1969 # call Perl to get the vendorlib/sitelib/whatever "core" globals.
1970 # This can do more, but... eww.
1971 $shellstr = qx { /bin/sh -c '$shellstr' }; # Yay! ' characters apparently get properly exscapededed.
1972 $macrostring =~ s/\%\(.+\)/$shellstr/;
1973 }
1974
1975 # support for **some** %if constructs. Note that this breaks somewhat if
1976 # there's no value specified... but so does rpm.
1977
1978 my $tmpcount = 0; # runaway shutdown. Not really sure how else to avoid getting stuck.
1979 while ($macrostring =~ m/\%\{([?!]+)([a-z0-9_.-]+)(?:\:([a-z0-9_.\/\-\\]+)?)?\}/g) { #Whew....
1980 my $qex = $1;
1981 my $macro = $2;
1982 my $value = '';
1983 if (defined($3)) {
1984 $value = $3;
1985 } else {
1986 $value = $specglobals{$macro} if $specglobals{$macro};
1987 }
1988 my $neg = '1' if $qex =~ /\!/;
1989 if ($specglobals{$macro}) {
1990 $value = '' if $neg;
1991 } else {
1992 $value = '' if !$neg;
1993 }
1994 $macrostring =~ s/\%\{[?!]+[a-z0-9_.-]+(?:\:([a-z0-9_.\/\-\\]+)?)?\}/$value/;
1995
1996# not certain about this, but I don't want to run away. It *can* happen if planned carefully. :/
1997$tmpcount++;
1998# %makeinstall has 13 occurrences. D'Oh!
1999die "excessive recursive macro replacement; dying.\n" if $tmpcount > 14;
2000
2001 } # while()
2002
2003 # Misc expansions
2004 $macrostring =~ s|%{_arch}|$hostarch|g;
2005 $macrostring =~ s|%{optflags}|$optflags{$hostarch}|g;
2006 $macrostring =~ s|%{_vendor}|$specglobals{'_vendor'}|g;
2007
2008 # system programs. RPM uses a global config file for these; we'll just
2009 # ASS-U-ME and make life a little simpler.
2010 if ($macrostring =~ /\%\{\_\_([a-z0-9_-]+)\}/) {
2011# see /usr/lib/rpm/macros for most of the list. we should arguably just parse that file, but.. ow.
2012 $macrostring =~ s|%{__([a-z0-9_-]+)}|$1|g;
2013 }
2014
2015# should probably stick a "no runaway" flag in here... Just In Case...
2016 # %define's
2017# note to self: find out valid chars for %define name/label so we can parse them
2018 while (my ($key) = ($macrostring =~ /%{([a-z0-9_]+)}/i) ) {
2019# hrm. This needs thinking.
2020#die "A horrible death! \%{$key}, '$macrostring'\n" if !$specglobals{$key};
2021 $macrostring =~ s|%{$key}|$specglobals{$key}|g;
2022 # wanna limit this to "... if $specglobals{$key}", but need more magic
2023 }
2024
2025 # Perl @INC/...lib locations, and other related bits.
2026 $macrostring =~ s|%{perl_archlib}|$Config{installarchlib}|g;
2027 $macrostring =~ s|%{perl_sitelib}|$Config{installsitelib}|g;
2028 $macrostring =~ s|%{perl_sitearch}|$Config{installsitearch}|g;
2029 $macrostring =~ s|%{perl_vendorlib}|$Config{installvendorlib}|g;
2030 $macrostring =~ s|%{perl_vendorarch}|$Config{installvendorarch}|g;
2031
2032 } # done with globals section
2033
2034 return $macrostring;
2035} # end expandmacros()
2036
2037
2038## unpackcmd()
2039# Prepare the necessary commands for uncompressing and extracting the content
2040# of the source drop according to the file extension.
2041sub unpackcmd {
2042 my ($sourcedrop,$quietunpack) = @_;
2043 my $cmdstring;
2044
2045 if ($sourcedrop =~ /\.zip$/) {
2046 # .zip files are not really tarballs
2047 $cmdstring .= "/usr/bin/unzip".
2048 ( $quietunpack ? ' -qq ' : ' ' ).
2049 "'$topdir/SOURCES/$sourcedrop'";
2050 } elsif ($sourcedrop =~ /\.tar$/) {
2051 # plain .tar files don't need to be uncompressed
2052 $cmdstring .= "/bin/tar -x".
2053 ( $quietunpack ? '' : 'vv' )."f ".
2054 "'$topdir/SOURCES/$sourcedrop'";
2055 } else {
2056 # select the decompressor according to the file extension
2057 $cmdstring .=
2058 ( $sourcedrop =~ /\.(?:tgz|tar\.(?:gz|Z))$/ ? "/bin/gzip" :
2059 $sourcedrop =~ /\.tar\.bz2$/ ? "/bin/bzip2" :
2060 $sourcedrop =~ /\.tar\.xz$/ ? "/usr/bin/xz" :
2061 die("Can't handle unknown file type '$sourcedrop'.") ).
2062 " -dc '$topdir/SOURCES/$sourcedrop' | /bin/tar -x".
2063 ( $quietunpack ? '' : 'vv' )."f - ";
2064 }
2065 $cmdstring .= qq(\nSTATUS=\$?\nif [ \$STATUS -ne 0 ]; then\n exit \$STATUS\nfi\n);
2066
2067 return $cmdstring;
2068} # end unpackcmd()
2069
2070
2071__END__
2072
2073
2074
2075=head1 NAME
2076
2077debbuild - Build Debian-compatible .deb packages from RPM .spec files
2078
2079=head1 SYNOPSIS
2080
2081 debbuild {-ba|-bb|-bp|-bc|-bi|-bl|-bs} [build-options] file.spec
2082
2083 debbuild {-ta|-tb|-tp|-tc|-ti|-tl|-ts} [build-options] file.{tgz|zip|tar.{gz|bz2|xz|Z}}
2084
2085 debbuild --rebuild file.{src.rpm|sdeb}
2086
2087 debbuild --showpkgs
2088
2089 debbuild -i foo.sdeb
2090
2091=head1 DESCRIPTION
2092
2093debbuild attempts to build Debian-friendly semi-native packages from RPM spec files,
2094RPM-friendly tarballs, and RPM source packages (.src.rpm files). It accepts I<most> of the
2095options rpmbuild does, and should be able to interpret most spec files usefully. Perl
2096modules should be handled via CPAN+dh-make-perl instead as it's simpler than even tweaking
2097a .spec template.
2098
2099As far as possible, the command-line options are identical to those from rpmbuild, although
2100several rpmbuild options are not supported:
2101
2102 --recompile
2103 --showrc
2104 --buildroot
2105 --clean
2106 --nobuild
2107 --rmsource
2108 --rmspec
2109 --sign
2110 --target
2111
2112Some of these could probably be trivially added. Feel free to send me a patch. ;)
2113
2114Complex spec files will most likely not work well, if at all. Rewrite them from scratch -
2115you'll have to make heavy modifications anyway.
2116
2117If you see something you don't like, mail me. Send a patch if you feel inspired. I don't
2118promise I'll do anything other than say "Yup, that's broken" or "Got your message".
2119
2120The source package container I invented for debbuild, the .sdeb file, can be "installed"
2121with debbuild -i exactly the same way as a .src.rpm can be installed with "rpm -i". Both
2122will unpack the file and place the source(s) and .spec file in the appropriate places in
2123%_topdir/SOURCES and %_topdir/SPECS respectively.
2124
2125=head1 ASSUMPTIONS
2126
2127As with rpmbuild, debbuild makes some assumptions about your system.
2128
2129=over 4
2130
2131=item *
2132
2133Either you have rights to do as you please under /usr/src/debian, or you have created a file
2134~/.debmacros containing a suitable %_topdir definition.
2135
2136Both rpmbuild and debbuild require the directories %_topdir/{BUILD,SOURCES,SPECS}. However,
2137where rpmbuild requires the %_topdir/{RPMS,SRPMS} directories, debbuild
2138requires %_topdir/{DEBS,SDEBS} instead. Create them in advance;
2139some subdirectories are created automatically as needed, but most are not.
2140
2141=item *
2142
2143/var/tmp must allow script execution - rpmbuild and debbuild both rely on creating and
2144executing shell scripts for much of their functionality. By default, debbuild also creates
2145install trees under /var/tmp - however this is (almost) entirely under the control of the
2146package's .spec file.
2147
2148=item *
2149
2150If you wish to --rebuild a .src.rpm, your %_topdir for both debbuild and rpmbuild must either
2151match, or be suitably symlinked one direction or another so that both programs are effectively
2152working in the same tree. (Or you could just manually wrestle files around your system.)
2153
2154You could symlink ~/.rpmmacros to ~/.debmacros (or vice versa) and save yourself some hassle
2155if you need to rebuild .src.rpm packages on a regular basis. Currently debbuild only uses the
2156%_topdir macro definition, although there are many more things that rpmbuild can use from
2157~/.rpmmacros.
2158
2159=back
2160
2161=head1 ERRATA
2162
2163debbuild deliberately does a few things differently from rpm.
2164
2165=head2 BuildArch or BuildArchitecture
2166
2167rpm takes the last BuildArch entry it finds in the .spec file, whatever it is, and runs with
2168that for all packages. Debian's repository system is fairly heavily designed around the
2169assumption that a single source package may generate small binary (executable) packages
2170for each arch, and large binary arch-all packages containing shared data.
2171
2172debbuild allows this by using the architecture specified by (in order of preference):
2173
2174=over 4
2175
2176=item * Host architecture
2177
2178=item * BuildArch specified in .spec file preamble
2179
2180=item * "Last specified" BuildArch for packages with several subpackages
2181
2182=item * BuildArch specified in the %package section for that subpackage
2183
2184=back
2185
2186=head2 Finding out what packages should be built (--showpkgs)
2187
2188rpmbuild does not include any convenient method I know of to list the packages a spec file
2189will produce. Since I needed this ability for another tool, I added it.
2190
2191It requires the .spec file for the package, and produces a list of full package filenames
2192(without path data) that would be generated by one of --rebuild, -ta, -tb, -ba, or -bb.
2193This includes the .sdeb source package.
2194
2195=head1 AUTHOR
2196
2197debbuild was written by Kris Deugau <kdeugau@deepnet.cx>. A version that approximates
2198current is available at http://www.deepnet.cx/debbuild/.
2199
2200=head1 BUGS
2201
2202Funky Things Happen if you forget a command-line option or two. I've been too lazy to bother
2203fixing this.
2204
2205Many macro expansions are unsupported or incompletely supported.
2206
2207The generated scriptlets don't quite match those from rpmbuild exactly. There are extra
2208environment variables and preprocessing that I haven't needed (yet).
2209
2210Dcumentation, such as it is, will likely remain perpetually out of date.
2211
2212%_topdir and the five "working" directories under %_topdir could arguably be created by
2213debbuild. However, rpmbuild doesn't create these directories either.
2214
2215debbuild's %setup -q is arguably less buggy than rpmbuild's implementation; with rpmbuild
2216it must appear before -a or -b at least to be effective. debbuild does not care.
2217
2218%setup -c, -a, and -b should arguably throw errors if specified together; otherwise the
2219results are almost certainly not what you want to happen.
2220
2221=head1 SEE ALSO
2222
2223rpm(8), rpmbuild(8), and pretty much any document describing how to write a .spec file.
2224
2225=cut
Note: See TracBrowser for help on using the repository browser.