source: trunk/debbuild@ 203

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

/trunk

Fix from Andreas Scherer for minor snafu in previous patch:

Numbered "sources" might have non-standard file formats, i.e., they do
not have to be (compressed) "tarballs".

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