source: trunk/debbuild@ 207

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

/trunk

Rewrite %patch handling. Include fragment from Andreas Scherer's suggested
patch to support .zip'ed patches.

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