source: trunk/debbuild@ 198

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

/trunk

Add support for .zip files as "tarballs".

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