source: trunk/debbuild@ 210

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

/trunk

Support expansion of %{PATCHnn} just like %{SOURCEnn}. Suggested by
Andreas Scherer.

  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author
File size: 81.4 KB
Line 
1#!/usr/bin/perl -w
2# debbuild script
3# Shamelessly steals interface from rpm's "rpmbuild" to create
4# Debian packages. Please note that such packages are highly
5# unlikely to conform to "Debian Policy".
6###
7# SVN revision info
8# $Date: 2015-10-05 02:22:11 +0000 (Mon, 05 Oct 2015) $
9# SVN revision $Rev: 210 $
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 $prepscript .= "rm -rf '$tarballdir'\n" if $deldir;
954 $prepscript .= "/bin/mkdir -p $tarballdir\n" if $changedir;
955
956 if ($deftarball) {
957 $prepscript .= "cd '$tarballdir'\n" if $changedir;
958 $prepscript .= unpackcmd($pkgdata{main}{source},$quietunpack);
959 }
960
961 if ($altsource) {
962 if ($altsource == 1) { # -a
963 $prepscript .= "cd '$tarballdir'\n";
964 $prepscript .= unpackcmd($pkgdata{sources}{$snum},$quietunpack);
965 } # $altsource == 1
966
967 if ($altsource == 2) { # -b
968 $prepscript .= unpackcmd($pkgdata{sources}{$snum},$quietunpack);
969 $prepscript .= "cd '$tarballdir'\n";
970 } # $altsource == 2
971 }
972
973# rpm doesn't seem to do the chowns any more
974# qq([ `/usr/bin/id -u` = '0' ] && /bin/chown -Rhf root .\n).
975# qq([ `/usr/bin/id -u` = '0' ] && /bin/chgrp -Rhf root .\n).
976 $prepscript .=
977 qq(/bin/chmod -Rf a+rX,u+w,g-w,o-w .\n);
978
979 } elsif (/^\%patch(\d*)/) {
980 my $line = $_;
981
982 # Things rpmbuild Does
983 # -> blindly follows Patch(.*): ==> %patch$1
984 # %patch0 does not in fact equal %patch without -P
985 # spaces optional between flag and argument
986 # multiple -P options actually trigger multiple patch events. >_<
987 # can we emulate this?
988 # yes we can!
989 # add patch{nn} to the list
990 my @patchlist;
991 push @patchlist, "$1" if $1;
992
993# options:
994# -P patch number
995# -p path strip. passed to patch as-is
996# -b backup file postfix. literal, if eg "bkfile", backup files will be "filebkfile", not "file.bkfile". Passed to
997# patch as-is, with a minor flag adjustment
998# -E Remove empty files. Passed to patch as-is
999
1000# from /usr/lib/rpm/macros; doesn't seem to be used by rpmbuild currently
1001# Default patch flags
1002#%_default_patch_flags -s
1003
1004 my @pbits = split /\s+/;
1005 my $plev = 0;
1006 my $psuff = '';
1007 my $noempty = 0;
1008 shift @pbits;
1009 my $pnflag = 0;
1010 while (my $popt = shift @pbits) {
1011 if ($popt =~ /^-P(\d*)/) {
1012 $pnflag = 1;
1013 # push the patchnum onto the list
1014 if ($1) {
1015 push @patchlist, "$1";
1016 } else {
1017 my $tmp = shift @pbits;
1018 die "Invalid patch number $tmp: $line" if $tmp !~ /^\d+$/;
1019 push @patchlist, $tmp;
1020 }
1021 } elsif ($popt =~ (/^-b([^\s]*)/) ) {
1022 if ($1) {
1023 $psuff = "-b --suffix $1";
1024 } else {
1025 $psuff = "-b --suffix ".shift(@pbits);
1026 }
1027 } elsif ($popt =~ (/^-p([^\s]*)/) ) {
1028 if ($1) {
1029 $plev = $1;
1030 } else {
1031 $plev = shift @pbits;
1032 }
1033 } elsif ($popt =~ (/^-E/) ) {
1034 $noempty = 1;
1035 } elsif ($popt =~ (/^(-[^s]+)/) ) {
1036 die "Unknown \%patch option $1: $line\n";
1037 }
1038 } # while (shift @pbits)
1039
1040 # add the "null" patch to the list unless we've got a -P flag, or there's already a patch on the list
1041 push @patchlist, '' unless $pnflag || @patchlist;
1042
1043 my $patchopts = " -p$plev $psuff";
1044 $patchopts .= " --fuzz=".$specglobals{_default_patch_fuzz};
1045 $patchopts .= " -E" if $noempty;
1046
1047 foreach my $pnum (@patchlist) {
1048 $prepscript .= qq(echo "Patch ).($pnum eq '' ? '' : "#$pnum ").qq(($pkgdata{main}{$pnum}):"\n);
1049 if ( $pkgdata{main}{$pnum} =~ /\.(?:Z|gz|bz2|xz)$/ ) {
1050 # Compressed patch. You weirdo.
1051 my $decompressor;
1052 $decompressor = '/bin/gzip' if $pkgdata{main}{$pnum} =~ /\.(?:Z|gz)$/;
1053 $decompressor = '/bin/bzip2' if $pkgdata{main}{$pnum} =~ /\.bz2$/;
1054 $decompressor = '/usr/bin/xz' if $pkgdata{main}{$pnum} =~ /\.xz$/;
1055 $prepscript .= qq($decompressor -dc $topdir/SOURCES/$pkgdata{main}{$pnum} | /usr/bin/patch $patchopts\n\n);
1056 } elsif ( $pkgdata{main}{$pnum} =~ /\.zip$/ ) {
1057 # .zip'ed patch. *backs away slowly*
1058 $prepscript .= qq(/usr/bin/unzip $topdir/SOURCES/$pkgdata{main}{$pnum} | /usr/bin/patch $patchopts\n\n);
1059 } else {
1060 $prepscript .= "/bin/cat $topdir/SOURCES/$pkgdata{main}{$pnum} | /usr/bin/patch $patchopts\n\n";
1061 }
1062 }
1063
1064 } else {
1065 $prepscript .= expandmacros($_,'gp');
1066 }
1067 next LINE;
1068 } # prep
1069
1070 if ($stage eq 'build') {
1071 # %build. This is pretty much just a shell script. There
1072 # aren't many local macros to deal with.
1073 if (/^\%configure/) {
1074 $buildscript .= expandmacros($_,'cgbp');
1075 } elsif (/^\%\{__make\}/) {
1076 $buildscript .= expandmacros($_,'mgbp');
1077 } else {
1078 $buildscript .= expandmacros($_,'gp');
1079 }
1080 next LINE;
1081 } # build
1082
1083 if ($stage eq 'install') {
1084 if (/^\%makeinstall/) {
1085 $installscript .= expandmacros($_,'igbp');
1086 } else {
1087 $installscript .= expandmacros($_,'gp');
1088 }
1089 next LINE;
1090 } # install
1091
1092 if ($stage eq 'clean') {
1093 $cleanscript .= expandmacros($_,'gp');
1094 next LINE;
1095 } # clean
1096
1097 if ($stage eq 'prepost') {
1098 $pkgdata{$subname}{$scriptlet} .= expandmacros($_,'gp');
1099 next LINE;
1100 } # prepost
1101
1102 if ($stage eq 'files') {
1103 # need to deal with these someday
1104 next LINE if /^\%dir/;
1105 next LINE if /^\%defattr/;
1106 next LINE if /^\%verify/;
1107 # dunno what to do with this; not sure if there's space in Debian's package structure for it.
1108 next LINE if /^\%ghost/;
1109 # Debian dpkg doesn't speak "%docdir". Meh.
1110 next LINE if /^\%docdir/;
1111# my $singleton = 0; # don't recall what this was for
1112 next LINE if /^\s*#/;
1113 next LINE if /^\s*$/;
1114
1115# create and initialize flags
1116 my ($perms, $owner, $group, $conf, $filesline);
1117 $perms = $owner = $group = $conf = '-';
1118
1119 $filesline = $_;
1120
1121 # strip and flag %attr constructs
1122 if ($filesline =~ /\%attr\b/) {
1123 # Extract %attr...
1124 my ($args) = (/(\%attr\s*\(\s*[\d-]+\s*,\s*["a-zA-Z0-9-]+\s*,\s*["a-zA-Z0-9-]+\s*\))/);
1125 $args =~ s/\s+//g;
1126 $args =~ s/"//g; # don't think quotes are ever necessary, but they're *allowed*
1127 # ... and parse it ...
1128 ($perms,$owner,$group) = ($args =~ /\(([\d-]+),([a-zA-Z0-9-]+),([a-zA-Z0-9-]+)/);
1129 # ... and wipe it when we're done.
1130 $filesline =~ s/\%attr\s*\(\s*[\d-]+\s*,\s*["a-zA-Z0-9-]+\s*,\s*["a-zA-Z0-9-]+\s*\)//;
1131 }
1132
1133 # Conffiles. Note that Debian and RH have similar, but not
1134 # *quite* identical ideas of what constitutes a conffile. Nrgh.
1135 # Note that dpkg will always ask if you want to replace the file - noreplace
1136 # is more or less permanently enabled.
1137##fixme
1138# also need to handle missingok (file that doesn't exist, but should be removed on uninstall)
1139# hmm. not sure if such is **POSSIBLE** with Debian... maybe an addition to %post?
1140 if ($filesline =~ /\%config\b(?:\s*\(\s*noreplace\s*\)\s*)?/) {
1141 $pkgdata{$subname}{conffiles} = 1; # Flag it for later
1142 $conf = 'y';
1143 $filesline =~ s/\%config\b(?:\s*\(\s*noreplace\s*\)\s*)?//;
1144 }
1145
1146 # %doc needs extra processing, because it can be a space-separated list, and may
1147 # include both full and partial pathnames. The partial pathnames must be fiddled
1148 # into place in the %install script, because Debian doesn't really have the concept
1149 # of "documentation file" that rpm does. (Debian "documentation files" are files
1150 # in /usr/share/doc/<packagename>.)
1151##fixme: unhandled case: %doc %defattr. Eeep.
1152# don't really know what to do with %defattr, generally. :(
1153 if ($filesline =~ /\%doc\b/) {
1154 $filesline =~ s/\s*\%doc\s+//;
1155
1156# this could probably go elsewhere.
1157 my $pkgname = $pkgdata{$subname}{name};
1158 $pkgname =~ tr/_/-/;
1159
1160 # have to extract the partial pathnames that %doc installs automagically
1161 foreach (split /\s+/, $filesline) {
1162 if (! (/^\%/ or m|^/|) ) {
1163 $doclist{$subname} .= " $_";
1164 my ($element) = m|([^/\s]+/?)$|;
1165 $filesline =~ s|$_|\%{_docdir}/$pkgname/$element|;
1166 }
1167 }
1168 } # $filesline =~ /\%doc\b/
1169
1170 $filesline =~ s/^\s*//; # Just In Case. For, uh, neatness.
1171
1172# due to Debian's total lack of real permissions-processing in its actual package
1173# handling component (dpkg-deb), this can't really be done "properly". We'll have
1174# to add chown/chmod commands to the postinst instead. Feh.
1175 $pkgdata{$subname}{'post'} .= "chown $owner $filesline\n" if $owner ne '-';
1176 $pkgdata{$subname}{'post'} .= "chgrp $group $filesline\n" if $group ne '-';
1177 $pkgdata{$subname}{'post'} .= "chmod $perms $filesline\n" if $perms ne '-';
1178
1179##fixme
1180# need hackery to assure only one filespec per %config. NB: "*" is one filespec. <g>
1181 push @{$pkgdata{$subname}{conflist}}, $filesline if $conf ne '-';
1182
1183 # now that we've got the specials out of the way, we can add things to the appropriate list of files.
1184 # ... and finally everything else
1185 $filelist{$subname} .= " $filesline";
1186
1187 next LINE;
1188 } # files
1189
1190 if ($stage eq 'changelog') {
1191 # this is one of the few places we do NOT generally want to replace macros...
1192 $pkgdata{main}{changelog} .= $_;
1193 }
1194
1195 if ($stage eq 'preamble') {
1196 if (/^summary:\s*(.+)/i) {
1197 $pkgdata{main}{summary} = $1;
1198 } elsif (/^name:\s*(.+)/i) {
1199 $pkgdata{main}{name} = expandmacros($1,'g');
1200 } elsif (/^epoch:\s*(.+)/i) {
1201 $pkgdata{main}{epoch} = expandmacros($1,'g');
1202 } elsif (/^version:\s*(.+)/i) {
1203 $pkgdata{main}{version} = expandmacros($1,'g');
1204 } elsif (/^release:\s*(.+)/i) {
1205 $pkgdata{main}{release} = expandmacros($1,'g');
1206 } elsif (/^group:\s*(.+)/i) {
1207 $pkgdata{main}{group} = $1;
1208 } elsif (/^copyright:\s*(.+)/i) {
1209 $pkgdata{main}{copyright} = $1;
1210 } elsif (/^url:\s*(.+)/i) {
1211 $pkgdata{main}{url} = $1;
1212 } elsif (/^packager:\s*(.+)/i) {
1213 $pkgdata{main}{packager} = $1;
1214 } elsif (/^vendor:\s*(.+)/i) {
1215 $specglobals{vendor} = $1;
1216 } elsif (/^buildroot:\s*(.+)/i) {
1217 $specglobals{buildroot} = $1;
1218 } elsif (my ($srcnum, $src) = (/^source(\d*):\s*(.+)/i)) {
1219 $src =~ s/\s*$//;
1220 $srcnum = 0 unless $srcnum;
1221 $pkgdata{sources}{$srcnum} = basename($src);
1222 $pkgdata{main}{source} = $pkgdata{sources}{0} if 0 == $srcnum;
1223 } elsif (my ($patchnum, $patch) = (/^patch(\d*):\s*(.+)/i)) {
1224 $patch =~ s/\s*$//;
1225 $patchnum = '' if !defined($patchnum);
1226 $pkgdata{main}{$patchnum} = basename($patch);
1227 } elsif (/^buildarch(?:itecture)?:\s*(.+)/i) {
1228 $pkgdata{main}{arch} = $1;
1229 $pkgdata{main}{arch} =~ s/^noarch$/all/;
1230 $buildarch = $pkgdata{main}{arch};
1231 } elsif (/^buildrequires:\s*(.+)/i) {
1232 $buildreq .= ", $1";
1233 } elsif (/^requires:\s*(.+)/i) {
1234 $pkgdata{main}{requires} .= ", ".expandmacros("$1", 'gp');
1235 } elsif (/^provides:\s*(.+)/i) {
1236 $pkgdata{main}{provides} .= ", $1";
1237 } elsif (/^conflicts:\s*(.+)/i) {
1238 $pkgdata{main}{conflicts} .= ", $1";
1239 } elsif (/^recommends:\s*(.+)/i) {
1240 $pkgdata{main}{recommends} .= ", $1";
1241 warn "Warning: Debian-specific 'Recommends:' outside \%if wrapper\n" if $iflevel == 0;
1242# As of sometime between RHEL 6 and RHEL 7 or so, support was added for Recommends: and Enhances:,
1243# along with shiny new tag Supplements:. We'll continue to warn about them for a while.
1244 } elsif (/^suggests:\s*(.+)/i) {
1245 $pkgdata{main}{suggests} .= ", $1";
1246 warn "Warning: 'Suggests:' outside \%if wrapper\n" if $iflevel == 0;
1247 } elsif (/^enhances:\s*(.+)/i) {
1248 $pkgdata{main}{enhances} .= ", $1";
1249 warn "Warning: 'Enhances:' outside \%if wrapper\n" if $iflevel == 0;
1250 } elsif (/^supplements:\s*(.+)/i) {
1251 $pkgdata{main}{enhances} .= ", $1";
1252 warn "Warning: 'Supplements:' is not natively supported by .deb packages. Downgrading relationship to Enhances:.\n";
1253 } elsif (/^replaces:\s*(.+)/i) {
1254 $pkgdata{main}{replaces} .= ", $1";
1255 warn "Warning: 'Replaces:' outside \%if wrapper\n" if $iflevel == 0;
1256 } elsif (/^obsoletes:\s*(.+)/i) {
1257 $pkgdata{main}{replaces} .= ", $1";
1258 } elsif (/^autoreq(?:prov)?:\s*(.+)/i) {
1259 # we don't handle auto-provides (yet)
1260 $NoAutoReq = 1 if $1 =~ /(?:no|0)/i;
1261 }
1262 next LINE;
1263 } # preamble
1264
1265 } # while <SPEC>
1266
1267 # Parse and replace some more macros. More will be replaced even later.
1268
1269 # Expand macros as necessary.
1270 $scriptletbase = expandmacros($scriptletbase,'gp');
1271
1272 $cleanscript = expandmacros($cleanscript,'gp');
1273
1274 $specglobals{buildroot} = $cmdbuildroot if $cmdbuildroot;
1275 $specglobals{buildroot} = expandmacros($specglobals{buildroot},'gp');
1276
1277 close SPECFILE;
1278} # end parse_spec()
1279
1280
1281## prep()
1282# Writes and executes the %prep script (mostly) built while reading the spec file.
1283sub prep {
1284 # Replace some things here just to make sure.
1285 $prepscript = expandmacros($prepscript,'gp');
1286
1287 # create script filename
1288 my $prepscriptfile = "$tmpdir/deb-tmp.prep.".int(rand(99998)+1);
1289 sysopen(PREPSCRIPT, $prepscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
1290 or die "Can't open/create prep script file $prepscriptfile: $!\n";
1291 print PREPSCRIPT $scriptletbase;
1292 print PREPSCRIPT $prepscript;
1293 close PREPSCRIPT;
1294
1295 # execute
1296 print "Calling \%prep script $prepscriptfile...\n";
1297 system("/bin/sh -e $prepscriptfile") == 0
1298 or die "Can't exec: $!\n";
1299
1300 # and clean up
1301 unlink $prepscriptfile;
1302} # end prep()
1303
1304
1305## build()
1306# Writes and executes the %build script (mostly) built while reading the spec file.
1307sub build {
1308 # Expand the macros
1309 $buildscript = expandmacros($buildscript,'cgbp');
1310
1311 # create script filename
1312 my $buildscriptfile = "$tmpdir/deb-tmp.build.".int(rand(99998)+1);
1313 sysopen(BUILDSCRIPT, $buildscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
1314 or die "Can't open/create build script file $buildscriptfile: $!\n";
1315 print BUILDSCRIPT $scriptletbase;
1316 print BUILDSCRIPT $buildscript;
1317 close BUILDSCRIPT;
1318
1319 # execute
1320 print "Calling \%build script $buildscriptfile...\n";
1321 system("/bin/sh -e $buildscriptfile") == 0
1322 or die "Can't exec: $!\n";
1323
1324 # and clean up
1325 unlink $buildscriptfile;
1326} # end build()
1327
1328
1329## install()
1330# Writes and executes the %install script (mostly) built while reading the spec file.
1331sub install {
1332
1333 # munge %doc entries into place
1334 # rpm handles this with a separate executed %doc script, we're not going to bother.
1335 foreach my $docpkg (keys %doclist) {
1336 my $pkgname = $pkgdata{$docpkg}{name};
1337 $pkgname =~ s/_/-/g;
1338
1339 $installscript .= "DOCDIR=\$RPM_BUILD_ROOT\%{_docdir}/$pkgname\nexport DOCDIR\n";
1340 $installscript .= "mkdir -p \$DOCDIR\n";
1341 $doclist{$docpkg} =~ s/^\s*//;
1342 foreach (split(' ',$doclist{$docpkg})) {
1343 $installscript .= "cp -pr $_ \$DOCDIR/\n";
1344 }
1345 }
1346
1347 # Expand the macros
1348 $installscript = expandmacros($installscript,'igbp');
1349
1350 # create script filename
1351 my $installscriptfile = "$tmpdir/deb-tmp.inst.".int(rand(99998)+1);
1352 sysopen(INSTSCRIPT, $installscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
1353 or die "Can't open/create install script file $installscriptfile: $!\n";
1354 print INSTSCRIPT $scriptletbase;
1355 print INSTSCRIPT $installscript;
1356 close INSTSCRIPT;
1357
1358 # execute
1359 print "Calling \%install script $installscriptfile...\n";
1360 system("/bin/sh -e $installscriptfile") == 0
1361 or die "Can't exec: $!\n";
1362
1363 # and clean up
1364 unlink $installscriptfile;
1365
1366 # final bit: compress manpages if present
1367 # done here cuz I don't grok shell well
1368 # should probably error-check all kinds of things. <g>
1369 if (opendir MANROOT, "$specglobals{buildroot}/usr/share/man") {
1370 my @mansects = readdir MANROOT;
1371 closedir MANROOT;
1372 foreach my $mandir (@mansects) {
1373 next if $mandir !~ /^man/;
1374 opendir MANPAGES, "$specglobals{buildroot}/usr/share/man/$mandir";
1375 my @pagelist = readdir MANPAGES;
1376 closedir MANPAGES; # Slightly safer to to this; no accidental recursion. O_o
1377 foreach my $manpage (@pagelist) {
1378 $manpage = "$specglobals{buildroot}/usr/share/man/$mandir/$manpage";
1379 if ( -f $manpage) {
1380 if ($manpage =~ /^(.+)\.(?:Z|gz|bz2)\n?$/) {
1381 my $newpage = $1;
1382 `gunzip $manpage` if $manpage =~ /\.(?:Z|gz)$/;
1383 `bunzip2 $manpage` if $manpage =~ /\.bz2$/;
1384 $manpage = $newpage;
1385 }
1386 `gzip -9 -n $manpage`;
1387 } elsif ( -l $manpage) {
1388 my $linkdest = readlink $manpage;
1389 $linkdest =~ s/\.(?:Z|gz|bz2)//;
1390 unlink $manpage;
1391 $manpage =~ s/\.(?:Z|gz|bz2)//;
1392 symlink "$linkdest.gz", "$manpage.gz" or print "DEBUG: wibble: symlinking manpage failed: $!\n";
1393 }
1394 }
1395 }
1396 } # if opendir MANROOT
1397} # end install()
1398
1399
1400## binpackage()
1401# Creates the binary .deb package from the installed tree in $specglobals{buildroot}.
1402# Writes and executes a shell script to do so.
1403# Creates miscellaneous files required by dpkg-deb to actually build the package file.
1404# Should handle simple subpackages
1405sub binpackage {
1406
1407 foreach my $pkg (@pkglist) {
1408
1409 $pkgdata{$pkg}{arch} = $hostarch if !$pkgdata{$pkg}{arch}; # Just In Case.
1410
1411 # Make sure we have somewhere to write the .deb file
1412 if (!-e "$topdir/DEBS/$pkgdata{$pkg}{arch}") {
1413 mkdir "$topdir/DEBS/$pkgdata{$pkg}{arch}";
1414 }
1415
1416 # Skip building a package that doesn't have any files or dependencies. True
1417 # metapackages don't have any files, but they depend on a bunch of things.
1418 # Packages with neither have, essentially, no content.
1419 next if
1420 (!$filelist{$pkg} or $filelist{$pkg} =~ /^\s*$/) &&
1421 (!$pkgdata{$pkg}{requires});
1422 $filelist{$pkg} = '' if !$filelist{$pkg};
1423
1424 # Gotta do this first, otherwise we don't have a place to move files from %files
1425 mkdir "$specglobals{buildroot}/$pkg";
1426
1427 # Eliminate any lingering % macros
1428 $filelist{$pkg} = expandmacros $filelist{$pkg}, 'gp';
1429
1430 my @pkgfilelist = split ' ', $filelist{$pkg};
1431 foreach my $pkgfile (@pkgfilelist) {
1432 $pkgfile = expandmacros($pkgfile, 'gp');
1433
1434 # Feh. Manpages don't **NEED** to be gzipped, but rpmbuild does, and so shall we.
1435 # ... and your little info page too!
1436 if ($pkgfile =~ m{/usr/share/(?:man/man|info)}) {
1437 # need to check to see if manpage is gzipped
1438 if (-e "$specglobals{buildroot}$pkgfile") {
1439 # if we've just been pointed to a manpage section with "many" pages,
1440 # we need to gzip them all.
1441 # fortunately, we do NOT need to explicitly track each file for the
1442 # purpose of stuffing them in the package... the original %files
1443 # entry will do just fine.
1444 if ( -d "$specglobals{buildroot}$pkgfile") {
1445 foreach my $globfile (glob("$specglobals{buildroot}$pkgfile/*")) {
1446 gzip $globfile if $globfile !~ m|\.gz$|;
1447 }
1448 } else {
1449 if ($pkgfile !~ m|\.gz$|) {
1450 qx { gzip $specglobals{buildroot}$pkgfile };
1451 $pkgfile .= ".gz";
1452 }
1453 }
1454 } else {
1455 if ($pkgfile !~ m|\.gz$|) {
1456 $pkgfile .= ".gz";
1457 } else {
1458 $pkgfile =~ s/\.gz$//;
1459 qx { gzip $specglobals{buildroot}$pkgfile };
1460 $pkgfile .= ".gz";
1461 }
1462 }
1463 }
1464
1465 my ($fpath,$fname) = ($pkgfile =~ m|(.+?/?)?([^/]+/?)$|); # We don't need $fname now, but we might.
1466 qx { mkdir -p $specglobals{buildroot}/$pkg$fpath }
1467 if $fpath && $fpath ne '';
1468 qx { mv $specglobals{buildroot}$pkgfile $specglobals{buildroot}/$pkg$fpath };
1469 }
1470
1471 # Get the "Depends" (Requires) a la RPM. Ish. We strip the leading
1472 # comma and space here (if needed) in case there were "Requires" specified
1473 # in the spec file - those would precede these.
1474 $pkgdata{$pkg}{requires} .= getreqs("$specglobals{buildroot}/$pkg") if ! $NoAutoReq;
1475
1476 # magic needed to properly version dependencies...
1477 # only provided deps will really be included
1478 $pkgdata{$pkg}{requires} =~ s/^, //; # Still have to do this here.
1479 $pkgdata{$pkg}{requires} =~ s/\s+//g;
1480 my @deps = split /,/, $pkgdata{$pkg}{requires};
1481 my $tmp = '';
1482 foreach my $dep (@deps) {
1483 # Hack up the perl(Class::SubClass) deps into something dpkg can understand.
1484 # May or may not be versioned.
1485 # We do this first so the version rewriter can do its magic next.
1486 if (my ($mod,$ver) = ($dep =~ /^perl\(([A-Za-z0-9\:\-]+)\)([><=]+.+)?/) ) {
1487 $mod =~ s/^perl\(//;
1488 $mod =~ s/\)$//;
1489 $mod =~ s/::/-/g;
1490 $mod =~ tr/A-Z/a-z/;
1491 $mod = "lib$mod-perl";
1492 $mod .= $ver if $ver;
1493 $dep = $mod;
1494 }
1495 if (my ($name,$rel,$value) = ($dep =~ /^([a-zA-Z0-9._-]+)([><=]+)([a-zA-Z0-9._-]+)$/)) {
1496 $tmp .= ", $name ($rel $value)";
1497 } else {
1498 $tmp .= ", $dep";
1499 }
1500 }
1501 ($pkgdata{$pkg}{requires} = $tmp) =~ s/^, //;
1502
1503 # Do this here since we're doing {depends}...
1504 if (defined($pkgdata{$pkg}{provides})) {
1505 $pkgdata{$pkg}{provides} =~ s/^, //;
1506 $pkgdata{$pkg}{provides} = expandmacros($pkgdata{$pkg}{provides},'gp');
1507 }
1508 if (defined($pkgdata{$pkg}{conflicts})) {
1509 $pkgdata{$pkg}{conflicts} =~ s/^, //;
1510 $pkgdata{$pkg}{conflicts} = expandmacros($pkgdata{$pkg}{conflicts},'gp');
1511 }
1512
1513# These are Debian-specific!
1514 if (defined($pkgdata{$pkg}{recommends})) {
1515 $pkgdata{$pkg}{recommends} =~ s/^, //;
1516 $pkgdata{$pkg}{recommends} = expandmacros($pkgdata{$pkg}{recommends},'gp');
1517 }
1518 if (defined($pkgdata{$pkg}{suggests})) {
1519 $pkgdata{$pkg}{suggests} =~ s/^, //;
1520 $pkgdata{$pkg}{suggests} = expandmacros($pkgdata{$pkg}{suggests},'gp');
1521 }
1522 if (defined($pkgdata{$pkg}{enhances})) {
1523 $pkgdata{$pkg}{enhances} =~ s/^, //;
1524 $pkgdata{$pkg}{enhances} = expandmacros($pkgdata{$pkg}{enhances},'gp');
1525 }
1526 if (defined($pkgdata{$pkg}{replaces})) {
1527 $pkgdata{$pkg}{replaces} =~ s/^, //;
1528 $pkgdata{$pkg}{replaces} = expandmacros($pkgdata{$pkg}{replaces},'gp');
1529 }
1530
1531 # Gotta do this next, otherwise the control file has nowhere to go. >:(
1532 mkdir "$specglobals{buildroot}/$pkg/DEBIAN";
1533
1534 # Hack the filename for the package into a Debian-tool-compatible format. GRRRRRR!!!!!
1535 # Have I mentioned I hate Debian Policy?
1536 $pkgdata{$pkg}{name} =~ tr/_/-/;
1537
1538 # create script filename
1539 my $debscriptfile = "$tmpdir/deb-tmp.pkg.".int(rand(99998)+1);
1540 sysopen(DEBSCRIPT, $debscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
1541 or die "Can't open/create package-creation script file $debscriptfile: $!\n";
1542 print DEBSCRIPT $scriptletbase;
1543 print DEBSCRIPT "fakeroot -- dpkg-deb -b $specglobals{buildroot}/$pkg $topdir/DEBS/$pkgdata{$pkg}{arch}/".
1544 "$pkgdata{$pkg}{name}_".
1545 (defined($pkgdata{main}{epoch}) ? "$pkgdata{main}{epoch}:" : '').
1546 "$pkgdata{$pkg}{version}-$pkgdata{main}{release}_$pkgdata{$pkg}{arch}.deb\n";
1547 # %$&$%@#@@#%@@@ Debian and their horrible ugly package names. >:(
1548 close DEBSCRIPT;
1549
1550 $pkgdata{$pkg}{summary} = expandmacros($pkgdata{$pkg}{summary}, 'gp');
1551 my $control = "Package: $pkgdata{$pkg}{name}\n".
1552 "Version: ".(defined($pkgdata{main}{epoch}) ? "$pkgdata{main}{epoch}:" : '').
1553 "$pkgdata{$pkg}{version}-$pkgdata{main}{release}\n".
1554 "Section: ".($pkgdata{$pkg}{group} ? $pkgdata{$pkg}{group} : $pkgdata{main}{group})."\n".
1555 "Priority: optional\n".
1556 "Architecture: $pkgdata{$pkg}{arch}\n".
1557 "Maintainer: $pkgdata{main}{packager}\n".
1558 ( $pkgdata{$pkg}{requires} ne '' ? "Depends: $pkgdata{$pkg}{requires}\n" : '' ).
1559 ( defined($pkgdata{$pkg}{provides}) ? "Provides: $pkgdata{$pkg}{provides}\n" : '' ).
1560 ( defined($pkgdata{$pkg}{conflicts}) ? "Conflicts: $pkgdata{$pkg}{conflicts}\n" : '' ).
1561 ( defined($pkgdata{$pkg}{recommends}) ? "Recommends: $pkgdata{$pkg}{recommends}\n" : '' ).
1562 ( defined($pkgdata{$pkg}{suggests}) ? "Suggests: $pkgdata{$pkg}{suggests}\n" : '' ).
1563 ( defined($pkgdata{$pkg}{enhances}) ? "Enhances: $pkgdata{$pkg}{enhances}\n" : '' ).
1564 ( defined($pkgdata{$pkg}{replaces}) ? "Replaces: $pkgdata{$pkg}{replaces}\n" : '' ).
1565 "Description: $pkgdata{$pkg}{summary}\n";
1566 $pkgdata{$pkg}{desc} = expandmacros($pkgdata{$pkg}{desc}, 'gp');
1567 # Munge things so that Debian tools don't choke on errant blank lines
1568 $pkgdata{$pkg}{desc} =~ s/\s+$//g; # Trim trailing blanks
1569 $pkgdata{$pkg}{desc} =~ s/^ $/ ./mg; # Replace lines consisting of " \n" with " .\n"
1570 $control .= "$pkgdata{$pkg}{desc}\n";
1571
1572 open CONTROL, ">$specglobals{buildroot}/$pkg/DEBIAN/control";
1573 print CONTROL $control;
1574 close CONTROL;
1575
1576 # Iff there are conffiles (as specified in the %files list(s), add'em
1577 # in so dpkg-deb can tag them.
1578 if ($pkgdata{$pkg}{conffiles}) {
1579 open CONFLIST, ">$specglobals{buildroot}/$pkg/DEBIAN/conffiles";
1580 foreach my $conffile (@{$pkgdata{$pkg}{conflist}}) {
1581 $conffile = expandmacros($conffile, 'g');
1582 my @tmp = glob "$specglobals{buildroot}/$pkg/$conffile";
1583 foreach (@tmp) {
1584 s|$specglobals{buildroot}/$pkg/||g; # nrgl. gotta be a better way to do this...
1585 s/\s+/\n/g; # Not gonna support spaces in filenames. Ewww.
1586 print CONFLIST "$_\n";
1587 }
1588 }
1589 close CONFLIST;
1590 }
1591
1592 # found the point of scripts on subpackages.
1593 if ($pkgdata{$pkg}{'pre'}) {
1594 $pkgdata{$pkg}{'pre'} = expandmacros($pkgdata{$pkg}{'pre'},'gp');
1595 open PREINST, ">$specglobals{buildroot}/$pkg/DEBIAN/preinst";
1596 print PREINST "#!/bin/sh\nset -e\n\n";
1597 print PREINST $pkgdata{$pkg}{'pre'};
1598 close PREINST;
1599 chmod 0755, "$specglobals{buildroot}/$pkg/DEBIAN/preinst";
1600 }
1601 if ($pkgdata{$pkg}{'post'}) {
1602 $pkgdata{$pkg}{'post'} = expandmacros($pkgdata{$pkg}{'post'},'gp');
1603 open POSTINST, ">$specglobals{buildroot}/$pkg/DEBIAN/postinst";
1604 print POSTINST "#!/bin/sh\nset -e\n\n";
1605 print POSTINST $pkgdata{$pkg}{'post'};
1606 close POSTINST;
1607 chmod 0755, "$specglobals{buildroot}/$pkg/DEBIAN/postinst";
1608 }
1609 if ($pkgdata{$pkg}{'preun'}) {
1610 $pkgdata{$pkg}{'pre'} = expandmacros($pkgdata{$pkg}{'preun'},'gp');
1611 open PREUNINST, ">$specglobals{buildroot}/$pkg/DEBIAN/prerm";
1612 print PREUNINST "#!/bin/sh\nset -e\n\n";
1613 print PREUNINST $pkgdata{$pkg}{'preun'};
1614 close PREUNINST;
1615 chmod 0755, "$specglobals{buildroot}/$pkg/DEBIAN/prerm";
1616 }
1617 if ($pkgdata{$pkg}{'postun'}) {
1618 $pkgdata{$pkg}{'postun'} = expandmacros($pkgdata{$pkg}{'postun'},'gp');
1619 open POSTUNINST, ">$specglobals{buildroot}/$pkg/DEBIAN/postrm";
1620 print POSTUNINST "#!/bin/sh\nset -e\n\n";
1621 print POSTUNINST $pkgdata{$pkg}{'postun'};
1622 close POSTUNINST;
1623 chmod 0755, "$specglobals{buildroot}/$pkg/DEBIAN/postrm";
1624 }
1625
1626 # execute
1627 print "Calling package creation script $debscriptfile for $pkgdata{$pkg}{name}...\n";
1628 system("/bin/sh -e $debscriptfile") == 0
1629 or die "Can't exec: $!\n";
1630
1631 $finalmessages .= "Wrote binary package ".
1632 "$pkgdata{$pkg}{name}_".
1633 (defined($pkgdata{main}{epoch}) ? "$pkgdata{main}{epoch}:" : '').
1634 "$pkgdata{$pkg}{version}-$pkgdata{main}{release}_$pkgdata{$pkg}{arch}.deb".
1635 " in $topdir/DEBS/$pkgdata{$pkg}{arch}\n";
1636 # and clean up
1637 unlink $debscriptfile;
1638
1639 } # subpackage loop
1640
1641} # end binpackage()
1642
1643
1644## srcpackage()
1645# Builds a .src.deb source package. Note that Debian's idea of
1646# a "source package" is seriously flawed IMO, because you can't
1647# easily copy it as-is.
1648# Not quite identical to RPM, but Good Enough (TM).
1649sub srcpackage {
1650 # In case we were called with -bs.
1651 $pkgdata{main}{name} =~ tr/_/-/;
1652 my $pkgsrcname = "$pkgdata{main}{name}-".
1653 (defined($pkgdata{main}{epoch}) ? "$pkgdata{main}{epoch}:" : '').
1654 "$pkgdata{main}{version}-$pkgdata{main}{release}.sdeb";
1655
1656 my $paxcmd;
1657
1658 # We'll definitely need this later, and *may* need it sooner.
1659 (my $barespec = $specfile) =~ s|.+/([^/]+)$|$1|;
1660
1661 # Copy the specfile to the build tree, but only if it's not there already.
1662##buglet: need to deal with silly case where silly user has put the spec
1663# file in a subdir of %{_topdir}/SPECS. Ewww. Silly user!
1664 if (abs_path($specfile) !~ /^$topdir\/SPECS/) {
1665 $paxcmd .= "cp $specfile %{_topdir}/SPECS/; \n"
1666 }
1667
1668 # use pax -w [file] [file] ... >outfile.sdeb
1669 $paxcmd = "cd $topdir; pax -w ";
1670
1671 # some packages may not have a "main" source.
1672 $paxcmd .= "SOURCES/$pkgdata{main}{source} " if $pkgdata{main}{source};
1673
1674 # create file list: Source[nn], Patch[nn]
1675 foreach my $specbit (keys %{$pkgdata{main}} ) {
1676 next if $specbit eq 'source';
1677 $paxcmd .= "SOURCES/$pkgdata{main}{$specbit} " if $specbit =~ /^patch/;
1678##buglet: need to deal with case where patches are listed as URLs?
1679# or other extended pathnames? Silly !@$%^&!%%!%!! user!
1680 }
1681
1682 foreach my $source (keys %{$pkgdata{sources}}) {
1683 # Skip Source0, since it's also $pkgdata{main}{source}. Could arguably
1684 # just remove that instead, but I think that might backfire.
1685 next if $source eq '0';
1686 $paxcmd .= "SOURCES/$pkgdata{sources}{$source} ";
1687 }
1688
1689 # add the spec file, source package destination, and cd back where we came from.
1690 $paxcmd .= "SPECS/$barespec > $topdir/SDEBS/$pkgsrcname; cd -";
1691
1692 # In case of %-macros...
1693 $paxcmd = expandmacros($paxcmd,'gp');
1694
1695 system "$paxcmd";
1696 $finalmessages .= "Wrote source package $pkgsrcname in $topdir/SDEBS.\n";
1697} # end srcpackage()
1698
1699
1700## clean()
1701# Writes and executes the %clean script (mostly) built while reading the spec file.
1702sub clean {
1703 # Replace some things here just to make sure.
1704 $cleanscript = expandmacros($cleanscript,'gp');
1705
1706 # create script filename
1707 my $cleanscriptfile = "$tmpdir/deb-tmp.clean.".int(rand(99998)+1);
1708 sysopen(CLEANSCRIPT, $cleanscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
1709 or die $!;
1710 print CLEANSCRIPT $scriptletbase;
1711 print CLEANSCRIPT $cleanscript;
1712 close CLEANSCRIPT;
1713
1714 # execute
1715 print "Calling \%clean script $cleanscriptfile...\n";
1716 system("/bin/sh -e $cleanscriptfile") == 0
1717 or die "Can't exec: $!\n";
1718
1719 # and clean up
1720 unlink $cleanscriptfile;
1721} # end clean()
1722
1723
1724## checkbuildreq()
1725# Checks the build requirements (if any)
1726# Spits out a rude warning and returns a true-false error if any
1727# requirements are not met.
1728sub checkbuildreq {
1729 return 1 if $buildreq eq ''; # No use doing extra work.
1730
1731 # expand macros
1732 $buildreq = expandmacros($buildreq,'gp');
1733
1734 if ( ! -e "/usr/bin/dpkg-query" ) {
1735 print "**WARNING** dpkg-query not found. Can't check build-deps.\n".
1736 " Required for sucessful build:\n".$buildreq."\n".
1737 " Continuing anyway.\n";
1738 return 1;
1739 }
1740
1741 my $reqflag = 1; # unset iff a buildreq is missing
1742
1743 $buildreq =~ s/^, //; # Strip the leading comma and space
1744 my @reqlist = split /,\s+/, $buildreq;
1745
1746 my @missinglist;
1747 foreach my $req (@reqlist) {
1748 # from rpmbuild error message
1749 # Dependency tokens must begin with alpha-numeric, '_' or '/'
1750##fixme: check for suitable whitespace around $rel
1751 my ($pkg,$rel,$ver);
1752
1753 # We have two classes of requirements - versioned and unversioned.
1754 if ($req =~ /[><=]/) {
1755 # Pick up the details of versioned buildreqs
1756 ($pkg,$rel,$ver) = ($req =~ /([a-z0-9._-]+)\s+([><=]+)\s+([a-z0-9._-]+)/);
1757 } else {
1758 # And the unversioned ones.
1759 $pkg = $req;
1760 $rel = '>=';
1761 $ver = 0;
1762 }
1763
1764## Apparently a package that has been installed, then uninstalled, has a "known" dpkg status of
1765## "unknown ok not-installed" vs a package that has never been installed which returns nothing. O_o
1766## Virtual packages, of course, *also* show as "not installed" like this (WTF?)
1767## This causes real packages to be misdetected as installed "possible virtual packages" instead of "missing
1768## packages". I don't think there's really a solution until/unless Debian's tools properly register virtual
1769## packages as installed.
1770 my @pkglist = qx { dpkg-query --showformat '\${status}\t\${version}\n' -W $pkg };
1771 if (!$pkglist[0]) {
1772 print " * Missing build-dependency $pkg!\n $pkglist[0]";
1773 $reqflag = 0;
1774 push @missinglist, $pkg;
1775 } else {
1776# real package, installed
1777#kdeugau:~$ dpkg-query --showformat '${status}\t${version}\n' -W libc-client2007e-dev 2>&1
1778#install ok installed 8:2007f~dfsg-1
1779# virtual package, provided by ???
1780#kdeugau:~$ dpkg-query --showformat '${status}\t${version}\n' -W libc-client-dev 2>&1
1781#unknown ok not-installed
1782# real package or virtual package not installed or provided
1783#kdeugau:~$ dpkg-query --showformat '${status}\t${version}\n' -W libdb4.8-dbg 2>&1
1784#dpkg-query: no packages found matching libdb4.8-dbg
1785
1786 my ($reqstat,undef,undef,$reqver) = split /\s+/, $pkglist[0];
1787 if ($reqstat =~ /^unknown/) {
1788 # this seems to be a virtual package.
1789 print " * Warning: $pkg is probably installed but seems to be a virtual package.\n";
1790 } elsif ($reqstat =~ /^install/) {
1791 my ($resp) = qx { dpkg --compare-versions $reqver '$rel' $ver && echo "ok" };
1792 if ($resp !~ /^ok/) {
1793 $reqflag = 0;
1794 print " * Buildreq $pkg is installed, but wrong version ($reqver): Need $ver\n"
1795 }
1796 } else {
1797 # whatever state it's in, it's not completely installed, therefore it's missing.
1798 print " * Missing build-dependency $pkg!\n $pkglist[0]";
1799 $reqflag = 0;
1800 push @missinglist, $pkg;
1801 } # end not installed/installed check
1802 }
1803 } # end req loop
1804
1805 print "To install all missing dependencies, run 'apt-get install ".join(' ', @missinglist)."'.\n" unless $reqflag;
1806
1807 return $reqflag;
1808} # end checkbuildreq()
1809
1810
1811## getreqs()
1812# Find out which libraries/packages are required for any
1813# executables and libs in a given file tree.
1814# (Debian doesn't have soname-level deps; just package-level)
1815# Returns an empty string if the tree contains no binaries.
1816# Doesn't work well on shell scripts. but those *should* be
1817# fine anyway. (Yeah, right...)
1818sub getreqs() {
1819 my $pkgtree = $_[0];
1820
1821 print "Checking library requirements...\n";
1822 my @binlist = qx { find $pkgtree -type f -perm 755 };
1823
1824 if (scalar(@binlist) == 0) {
1825 return '';
1826 }
1827
1828 my @reqlist;
1829 foreach (@binlist) {
1830 push @reqlist, qx { LANG=C ldd $_ };
1831 }
1832
1833 # Get the list of libs provided by this package. Still doesn't
1834 # handle the case where the lib gets stuffed into a subpackage. :/
1835 my @intprovlist = qx { find $pkgtree -type f -name "*.so*" };
1836 my $provlist = '';
1837 foreach (@intprovlist) {
1838 s/$pkgtree//;
1839 $provlist .= "$_";
1840 }
1841
1842 my %reqs;
1843 my $reqlibs = '';
1844 my %reqliblist;
1845
1846 foreach (@reqlist) {
1847 next if /^$pkgtree/;
1848 next if /not a dynamic executable/;
1849 next if m|/lib(?:64)?/ld-linux|; # Hack! Hack! PTHBTT! (libc suxx0rz)
1850 next if /linux-gate.so/; # Kernel hackery for teh W1n!!1!1eleventy-one!1 (Don't ask. Feh.)
1851 next if /linux-vdso.so/; # More kernel hackery. Whee!
1852
1853 # Whee! more hackery to detect provided-here libs. Some apparently return from ldd as "not found".
1854 my ($a,$b) = split / => /;
1855 $a =~ s/\s*//g;
1856 if ($b =~ /not found/) {
1857 next if qx { find $specglobals{buildroot} -name "*$a" };
1858 }
1859
1860 my ($req) = (m|=\>\s+([a-zA-Z0-9._/+-]+)|); # dig out the actual library (so)name.
1861 # And feh, we need the *path*, since I've discovered a new edge case where
1862 # the same libnnn.1.2.3 *file*name is found across *several* lib dirs. >:(
1863
1864 # Ignore libs provided by this package. Note that we don't match
1865 # on word-boundary at the *end* of the lib we're looking for, as the
1866 # looked-for lib may not have the full soname version. (ie, it may
1867 # "just" point to one of the symlinks that get created somewhere.)
1868 next if $provlist =~ /\b$req/;
1869
1870 $reqlibs .= " $req";
1871 $reqliblist{$req} = 1;
1872 }
1873
1874 if (%reqliblist) {
1875 foreach my $rlib (keys %reqliblist) {
1876 my $libpkg = qx { dpkg -S $rlib };
1877 ($libpkg,undef) = split /:/, $libpkg;
1878 $reqs{$libpkg} = 1;
1879 }
1880 }
1881
1882 my $deplist = '';
1883 foreach (keys %reqs) {
1884 $deplist .= ", $_";
1885 }
1886
1887# For now, we're done. We're not going to meddle with versions yet.
1888# Among other things, it's messier than handling "simple" yes/no "do
1889# we have this lib?" deps. >:(
1890
1891 return $deplist;
1892} # end getreqs()
1893
1894
1895## install_sdeb()
1896# Extracts .sdeb contents to %_topdir as appropriate
1897sub install_sdeb {
1898 $srcpkg = abs_path($srcpkg);
1899
1900 my $paxcmd = "cd $topdir; pax -r <$srcpkg; cd -";
1901
1902 # In case of %-macros...
1903 $paxcmd = expandmacros($paxcmd,'gp');
1904
1905 system "$paxcmd";
1906 print "Extracted source package $srcpkg to $topdir.\n";
1907} # end install_sdeb()
1908
1909
1910## expandmacros()
1911# Expands all %{blah} macros in the passed string
1912# Split up a bit with some sections so we don't spend time trying to
1913# expand macros that are only used in a few specific places.
1914sub expandmacros {
1915 my $macrostring = shift;
1916 my $section = shift;
1917
1918 # To allow the FHS-ish %configure and %makeinstall to work The Right Way.
1919 # (Without clobbering the global $specglobals{buildroot}.)
1920 my $prefix = '';
1921
1922 if ($section =~ /c/) {
1923 # %configure macro
1924# Don't know what it's for, don't have a useful default replacement
1925# --program-prefix=%{_program_prefix} \
1926 $macrostring =~ s'%configure'./configure --host=$DEB_HOST_GNU_TYPE \
1927 --build=$DEB_BUILD_GNU_TYPE \
1928 --prefix=%{_prefix} \
1929 --exec-prefix=%{_exec_prefix} \
1930 --bindir=%{_bindir} \
1931 --sbindir=%{_sbindir} \
1932 --sysconfdir=%{_sysconfdir} \
1933 --datadir=%{_datadir} \
1934 --includedir=%{_includedir} \
1935 --libdir=%{_libdir} \
1936 --libexecdir=%{_libexecdir} \
1937 --localstatedir=%{_localstatedir} \
1938 --sharedstatedir=%{_sharedstatedir} \
1939 --mandir=%{_mandir} \
1940 --infodir=%{_infodir} ';
1941 } # done %configure
1942
1943 if ($section =~ /m/) {
1944 $macrostring =~ s'%{__make}'make ';
1945 } # done make
1946
1947# %makeinstall expands with recursive macros in rpm. whee.
1948 if ($section =~ /i/) {
1949 # This is where we need to mangle $prefix.
1950 $macrostring =~ s'%makeinstall'make \
1951 prefix=%{?buildroot:%{buildroot}}%{_prefix} \
1952 exec_prefix=%{?buildroot:%{buildroot}}%{_exec_prefix} \
1953 bindir=%{?buildroot:%{buildroot}}%{_bindir} \
1954 sbindir=%{?buildroot:%{buildroot}}%{_sbindir} \
1955 sysconfdir=%{?buildroot:%{buildroot}}%{_sysconfdir} \
1956 datadir=%{?buildroot:%{buildroot}}%{_datadir} \
1957 includedir=%{?buildroot:%{buildroot}}%{_includedir} \
1958 libdir=%{?buildroot:%{buildroot}}%{_libdir} \
1959 libexecdir=%{?buildroot:%{buildroot}}%{_libexecdir} \
1960 localstatedir=%{?buildroot:%{buildroot}}%{_localstatedir} \
1961 sharedstatedir=%{?buildroot:%{buildroot}}%{_sharedstatedir} \
1962 mandir=%{?buildroot:%{buildroot}}%{_mandir} \
1963 infodir=%{?buildroot:%{buildroot}}%{_infodir} \
1964 install ';
1965 $prefix = $specglobals{buildroot};
1966 } # done %install and/or %makeinstall
1967
1968 # Build data
1969 # Note that these are processed in reverse order to get the substitution order right
1970 if ($section =~ /b/) {
1971# $macrostring =~ s'%{fhs}'host=$DEB_HOST_GNU_TYPE \
1972# build=$DEB_BUILD_GNU_TYPE \
1973 $macrostring =~ s'%{fhs}'prefix=%{_prefix} \
1974 exec-prefix=%{_exec_prefix} \
1975 bindir=%{_bindir} \
1976 sbindir=%{_sbindir} \
1977 sysconfdir=%{_sysconfdir} \
1978 datadir=%{_datadir} \
1979 includedir=%{_includedir} \
1980 libdir=%{_libdir} \
1981 libexecdir=%{_libexecdir} \
1982 localstatedir=%{_localstatedir} \
1983 sharedstatedir=%{_sharedstatedir} \
1984 mandir=%{_mandir} \
1985 infodir=%{_infodir} \
1986';
1987
1988 # Note that the above regex terminates with the extra space
1989 # "Just In Case" of user additions, which will then get neatly
1990 # tagged on the end where they take precedence (supposedly)
1991 # over the "default" ones.
1992
1993 # Now we cascade the macros introduced above. >_<
1994 # Wot ot to go theah:
1995 $macrostring =~ s|%{_mandir}|%{_datadir}/man|g; #/usr/share/man
1996 $macrostring =~ s|%{_infodir}|%{_datadir}/info|g; #/usr/share/info
1997 $macrostring =~ s|%{_oldincludedir}|/usr/include|g; #/usr/include
1998 $macrostring =~ s|%{_includedir}|%{_prefix}/include|g; #/usr/include
1999 $macrostring =~ s|%{_libdir}|%{_exec_prefix}/%{_lib}|g; #/usr/lib
2000 $macrostring =~ s|%{_lib}|lib|g; #?
2001 $macrostring =~ s|%{_localstatedir}|/var|g; #/var
2002 $macrostring =~ s|%{_sharedstatedir}|%{_prefix}/com|g; #/usr/com WTF?
2003 $macrostring =~ s|%{_sysconfdir}|/etc|g; #/etc
2004 $macrostring =~ s|%{_datadir}|%{_prefix}/share|g; #/usr/share
2005 $macrostring =~ s|%{_libexecdir}|%{_exec_prefix}/libexec|g; #/usr/libexec
2006 $macrostring =~ s|%{_sbindir}|%{_exec_prefix}/sbin|g; #/usr/sbin
2007 $macrostring =~ s|%{_bindir}|%{_exec_prefix}/bin|g; #/usr/bin
2008 $macrostring =~ s|%{_exec_prefix}|%{_prefix}|g; #/usr
2009 $macrostring =~ s|%{_prefix}|/usr|g; #/usr
2010 } # done with config section
2011
2012 # Package data
2013 if ($section =~ /p/) {
2014 $macrostring =~ s/\%\{buildroot\}/$specglobals{buildroot}/gi;
2015 $macrostring =~ s/\%\{source0?}/$topdir\/SOURCES\/$pkgdata{main}{source}/gi;
2016 foreach my $source (keys %{$pkgdata{sources}}) {
2017 $macrostring =~ s/\%\{source$source\}/$topdir\/SOURCES\/$pkgdata{sources}{$source}/gi;
2018 }
2019 $macrostring =~ s/\%\{patch([\d]+)}/$topdir\/SOURCES\/$pkgdata{main}{"patch$1"}/gi;
2020 $macrostring =~ s/\%\{name\}/$pkgdata{main}{name}/gi;
2021 $macrostring =~ s/\%\{version\}/$pkgdata{main}{version}/gi;
2022 $macrostring =~ s/\%\{release\}/$pkgdata{main}{release}/gi;
2023 }
2024
2025 # Globals, and not-so-globals
2026 if ($section =~ /g/) {
2027
2028 $macrostring =~ s|%{_builddir}|%{_topdir}/BUILD|g;
2029# Not predefined in an eternal file; defaults to %{name}-%{version}
2030 $macrostring =~ s|%{buildsubdir}|$tarballdir|g;
2031 $macrostring =~ s|%{_topdir}|$topdir|g;
2032 $macrostring =~ s|%{_tmppath}|$tmpdir|g;
2033 $macrostring =~ s'%{_docdir}'%{_datadir}/doc'g;
2034
2035 # Standard FHS locations. More or less.
2036 $macrostring =~ s'%{_bindir}'/usr/bin'g;
2037 $macrostring =~ s'%{_sbindir}'/usr/sbin'g;
2038 $macrostring =~ s'%{_mandir}'%{_datadir}/man'g;
2039 $macrostring =~ s'%{_infodir}'%{_datadir}/info'g;
2040 $macrostring =~ s'%{_includedir}'/usr/include'g;
2041 $macrostring =~ s'%{_libdir}'/usr/lib'g;
2042 $macrostring =~ s'%{_sysconfdir}'/etc'g;
2043 $macrostring =~ s'%{_localstatedir}'/var'g;
2044 $macrostring =~ s'%{_prefix}'/usr'g;
2045
2046 # FHS-ish locations that aren't quite actually FHS-specified.
2047 $macrostring =~ s'%{_datadir}'/usr/share'g;
2048
2049 # special %define's. Handle the general case where we eval anything.
2050 # Even more general: %(...) is a spec-parse-time shell code wrapper.
2051 # Prime example:
2052 #%define perl_vendorlib %(eval "`perl -V:installvendorlib`"; echo $installvendorlib)
2053 if ($macrostring =~ /\%\((.+)\)/) {
2054 my $shellstr = $1;
2055 # Oy vey this gets silly for the perl bits. Executing a shell to
2056 # call Perl to get the vendorlib/sitelib/whatever "core" globals.
2057 # This can do more, but... eww.
2058 $shellstr = qx { /bin/sh -c '$shellstr' }; # Yay! ' characters apparently get properly exscapededed.
2059 $macrostring =~ s/\%\(.+\)/$shellstr/;
2060 }
2061
2062 # support for **some** %if constructs. Note that this breaks somewhat if
2063 # there's no value specified... but so does rpm.
2064
2065 my $tmpcount = 0; # runaway shutdown. Not really sure how else to avoid getting stuck.
2066 while ($macrostring =~ m/\%\{([?!]+)([a-z0-9_.-]+)(?:\:([a-z0-9_.\/\-\\]+)?)?\}/g) { #Whew....
2067 my $qex = $1;
2068 my $macro = $2;
2069 my $value = '';
2070 if (defined($3)) {
2071 $value = $3;
2072 } else {
2073 $value = $specglobals{$macro} if $specglobals{$macro};
2074 }
2075 my $neg = '1' if $qex =~ /\!/;
2076 if ($specglobals{$macro}) {
2077 $value = '' if $neg;
2078 } else {
2079 $value = '' if !$neg;
2080 }
2081 $macrostring =~ s/\%\{[?!]+[a-z0-9_.-]+(?:\:([a-z0-9_.\/\-\\]+)?)?\}/$value/;
2082
2083# not certain about this, but I don't want to run away. It *can* happen if planned carefully. :/
2084$tmpcount++;
2085# %makeinstall has 13 occurrences. D'Oh!
2086die "excessive recursive macro replacement; dying.\n" if $tmpcount > 14;
2087
2088 } # while()
2089
2090 # Misc expansions
2091 $macrostring =~ s|%{_arch}|$hostarch|g;
2092 $macrostring =~ s|%{optflags}|$optflags{$hostarch}|g;
2093 $macrostring =~ s|%{_vendor}|$specglobals{'_vendor'}|g;
2094
2095 # system programs. RPM uses a global config file for these; we'll just
2096 # ASS-U-ME and make life a little simpler.
2097 if ($macrostring =~ /\%\{\_\_([a-z0-9_-]+)\}/) {
2098# see /usr/lib/rpm/macros for most of the list. we should arguably just parse that file, but.. ow.
2099 $macrostring =~ s|%{__([a-z0-9_-]+)}|$1|g;
2100 }
2101
2102# should probably stick a "no runaway" flag in here... Just In Case...
2103 # %define's
2104# note to self: find out valid chars for %define name/label so we can parse them
2105 while (my ($key) = ($macrostring =~ /%{([a-z0-9_]+)}/i) ) {
2106# hrm. This needs thinking.
2107#die "A horrible death! \%{$key}, '$macrostring'\n" if !$specglobals{$key};
2108 $macrostring =~ s|%{$key}|$specglobals{$key}|g;
2109 # wanna limit this to "... if $specglobals{$key}", but need more magic
2110 }
2111
2112 # Perl @INC/...lib locations, and other related bits.
2113 $macrostring =~ s|%{perl_archlib}|$Config{installarchlib}|g;
2114 $macrostring =~ s|%{perl_sitelib}|$Config{installsitelib}|g;
2115 $macrostring =~ s|%{perl_sitearch}|$Config{installsitearch}|g;
2116 $macrostring =~ s|%{perl_vendorlib}|$Config{installvendorlib}|g;
2117 $macrostring =~ s|%{perl_vendorarch}|$Config{installvendorarch}|g;
2118
2119 } # done with globals section
2120
2121 return $macrostring;
2122} # end expandmacros()
2123
2124
2125## unpackcmd()
2126# Prepare the necessary commands for uncompressing and extracting the content
2127# of the source drop according to the file extension.
2128sub unpackcmd {
2129 my ($sourcedrop,$quietunpack) = @_;
2130 my $cmdstring;
2131
2132 if ($sourcedrop =~ /\.zip$/) {
2133 # .zip files are not really tarballs
2134 $cmdstring .= "/usr/bin/unzip".
2135 ( $quietunpack ? ' -qq ' : ' ' ).
2136 "'$topdir/SOURCES/$sourcedrop'";
2137 } elsif ($sourcedrop =~ /\.tar$/) {
2138 # plain .tar files don't need to be uncompressed
2139 $cmdstring .= "/bin/tar -x".
2140 ( $quietunpack ? '' : 'vv' )."f ".
2141 "'$topdir/SOURCES/$sourcedrop'";
2142 } else {
2143 # select the decompressor according to the file extension
2144 $cmdstring .=
2145 ( $sourcedrop =~ /\.(?:tgz|tar\.(?:gz|Z))$/ ? "/bin/gzip" :
2146 $sourcedrop =~ /\.tar\.bz2$/ ? "/bin/bzip2" :
2147 $sourcedrop =~ /\.tar\.xz$/ ? "/usr/bin/xz" :
2148 die("Can't handle unknown file type '$sourcedrop'.") ).
2149 " -dc '$topdir/SOURCES/$sourcedrop' | /bin/tar -x".
2150 ( $quietunpack ? '' : 'vv' )."f - ";
2151 }
2152 $cmdstring .= qq(\nSTATUS=\$?\nif [ \$STATUS -ne 0 ]; then\n exit \$STATUS\nfi\n);
2153
2154 return $cmdstring;
2155} # end unpackcmd()
2156
2157
2158__END__
2159
2160
2161
2162=head1 NAME
2163
2164debbuild - Build Debian-compatible .deb packages from RPM .spec files
2165
2166=head1 SYNOPSIS
2167
2168 debbuild {-ba|-bb|-bp|-bc|-bi|-bl|-bs} [build-options] file.spec
2169
2170 debbuild {-ta|-tb|-tp|-tc|-ti|-tl|-ts} [build-options] file.{tgz|zip|tar.{gz|bz2|xz|Z}}
2171
2172 debbuild --rebuild file.{src.rpm|sdeb}
2173
2174 debbuild --showpkgs
2175
2176 debbuild -i foo.sdeb
2177
2178=head1 DESCRIPTION
2179
2180debbuild attempts to build Debian-friendly semi-native packages from RPM spec files,
2181RPM-friendly tarballs, and RPM source packages (.src.rpm files). It accepts I<most> of the
2182options rpmbuild does, and should be able to interpret most spec files usefully. Perl
2183modules should be handled via CPAN+dh-make-perl instead as it's simpler than even tweaking
2184a .spec template.
2185
2186As far as possible, the command-line options are identical to those from rpmbuild, although
2187several rpmbuild options are not supported:
2188
2189 --recompile
2190 --showrc
2191 --buildroot
2192 --clean
2193 --nobuild
2194 --rmsource
2195 --rmspec
2196 --sign
2197 --target
2198
2199Some of these could probably be trivially added. Feel free to send me a patch. ;)
2200
2201Complex spec files will most likely not work well, if at all. Rewrite them from scratch -
2202you'll have to make heavy modifications anyway.
2203
2204If you see something you don't like, mail me. Send a patch if you feel inspired. I don't
2205promise I'll do anything other than say "Yup, that's broken" or "Got your message".
2206
2207The source package container I invented for debbuild, the .sdeb file, can be "installed"
2208with debbuild -i exactly the same way as a .src.rpm can be installed with "rpm -i". Both
2209will unpack the file and place the source(s) and .spec file in the appropriate places in
2210%_topdir/SOURCES and %_topdir/SPECS respectively.
2211
2212=head1 ASSUMPTIONS
2213
2214As with rpmbuild, debbuild makes some assumptions about your system.
2215
2216=over 4
2217
2218=item *
2219
2220Either you have rights to do as you please under /usr/src/debian, or you have created a file
2221~/.debmacros containing a suitable %_topdir definition.
2222
2223Both rpmbuild and debbuild require the directories %_topdir/{BUILD,SOURCES,SPECS}. However,
2224where rpmbuild requires the %_topdir/{RPMS,SRPMS} directories, debbuild
2225requires %_topdir/{DEBS,SDEBS} instead. Create them in advance;
2226some subdirectories are created automatically as needed, but most are not.
2227
2228=item *
2229
2230/var/tmp must allow script execution - rpmbuild and debbuild both rely on creating and
2231executing shell scripts for much of their functionality. By default, debbuild also creates
2232install trees under /var/tmp - however this is (almost) entirely under the control of the
2233package's .spec file.
2234
2235=item *
2236
2237If you wish to --rebuild a .src.rpm, your %_topdir for both debbuild and rpmbuild must either
2238match, or be suitably symlinked one direction or another so that both programs are effectively
2239working in the same tree. (Or you could just manually wrestle files around your system.)
2240
2241You could symlink ~/.rpmmacros to ~/.debmacros (or vice versa) and save yourself some hassle
2242if you need to rebuild .src.rpm packages on a regular basis. Currently debbuild only uses the
2243%_topdir macro definition, although there are many more things that rpmbuild can use from
2244~/.rpmmacros.
2245
2246=back
2247
2248=head1 ERRATA
2249
2250debbuild deliberately does a few things differently from rpm.
2251
2252=head2 BuildArch or BuildArchitecture
2253
2254rpm takes the last BuildArch entry it finds in the .spec file, whatever it is, and runs with
2255that for all packages. Debian's repository system is fairly heavily designed around the
2256assumption that a single source package may generate small binary (executable) packages
2257for each arch, and large binary arch-all packages containing shared data.
2258
2259debbuild allows this by using the architecture specified by (in order of preference):
2260
2261=over 4
2262
2263=item * Host architecture
2264
2265=item * BuildArch specified in .spec file preamble
2266
2267=item * "Last specified" BuildArch for packages with several subpackages
2268
2269=item * BuildArch specified in the %package section for that subpackage
2270
2271=back
2272
2273=head2 Finding out what packages should be built (--showpkgs)
2274
2275rpmbuild does not include any convenient method I know of to list the packages a spec file
2276will produce. Since I needed this ability for another tool, I added it.
2277
2278It requires the .spec file for the package, and produces a list of full package filenames
2279(without path data) that would be generated by one of --rebuild, -ta, -tb, -ba, or -bb.
2280This includes the .sdeb source package.
2281
2282=head1 AUTHOR
2283
2284debbuild was written by Kris Deugau <kdeugau@deepnet.cx>. A version that approximates
2285current is available at http://www.deepnet.cx/debbuild/.
2286
2287=head1 BUGS
2288
2289Funky Things Happen if you forget a command-line option or two. I've been too lazy to bother
2290fixing this.
2291
2292Many macro expansions are unsupported or incompletely supported.
2293
2294The generated scriptlets don't quite match those from rpmbuild exactly. There are extra
2295environment variables and preprocessing that I haven't needed (yet).
2296
2297Dcumentation, such as it is, will likely remain perpetually out of date.
2298
2299%_topdir and the five "working" directories under %_topdir could arguably be created by
2300debbuild. However, rpmbuild doesn't create these directories either.
2301
2302debbuild's %setup -q is arguably less buggy than rpmbuild's implementation; with rpmbuild
2303it must appear before -a or -b at least to be effective. debbuild does not care.
2304
2305%setup -c, -a, and -b should arguably throw errors if specified together; otherwise the
2306results are almost certainly not what you want to happen.
2307
2308=head1 SEE ALSO
2309
2310rpm(8), rpmbuild(8), and pretty much any document describing how to write a .spec file.
2311
2312=cut
Note: See TracBrowser for help on using the repository browser.