source: trunk/debbuild@ 204

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

/trunk

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

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

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