source: trunk/debbuild@ 208

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

/trunk

Remove -o from unzip options that snuck in in r205. -o forcibly and
blindly overwrites target files; at least in %setup rpmbuild does not
do this and in general this is not safe for automation.

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