source: trunk/debbuild@ 82

Last change on this file since 82 was 82, checked in by kdeugau, 17 years ago

/trunk

Bugfix in %files parse - don't skip everything after a line starting
with %attr. *sigh*

  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author
File size: 44.8 KB
RevLine 
[2]1#!/usr/bin/perl
2# debbuild script
3# Shamlessly steals intreface from rpm's "rpmbuild" to create
4# Debian packages. Please note that such packages are highly
5# unlikely to conform to "Debian Policy".
6###
7# SVN revision info
8# $Date: 2007-02-12 18:11:04 +0000 (Mon, 12 Feb 2007) $
9# SVN revision $Rev: 82 $
10# Last update by $Author: kdeugau $
11###
[55]12# Copyright 2005,2006 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
[5]32
[10]33# regex debugger
34#use re "debug";
35
[3]36# Program flow:
37# -> Parse/execute "system" config/macros (if any - should be rare)
38# -> Parse/execute "user" config/macros (if any - *my* requirement is %_topdir)
39# -> Parse command line for options, spec file/tarball/.src.deb (NB - also accept .src.rpm)
40
[30]41sub expandmacros;
42
[2]43# User's prefs for dirs, environment, etc,etc,etc.
44# config file ~/.debmacros
45# Default ordered search paths for config/macros:
46# /usr/lib/rpm/rpmrc /usr/lib/rpm/redhat/rpmrc /etc/rpmrc ~/.rpmrc
47# /usr/lib/rpm/macros /usr/lib/rpm/redhat/macros /etc/rpm/macros ~/.rpmmacros
48# **NOTE: May be possible to (ab)use bits of debhelper
49
50# Build tree
51# default is /usr/src/debian/{BUILD,SOURCES,SPECS,DEBS,SDEBS}
52
[3]53# Globals
[77]54my $finalmessages = ''; # A place to stuff messages that I want printed at the *very* end of any processing.
[3]55my $specfile;
56my $tarball;
57my $srcpkg;
[7]58my $cmdbuildroot;
59my $tarballdir; # This should really be initialized, but the coding makes it, um, ugly.
[23]60my %specglobals; # For %define's in specfile, among other things.
[6]61
62# Initialized globals
[3]63my $verbosity = 0;
[4]64my %cmdopts = (type => '',
65 stage => 'a',
66 short => 'n'
67 );
[6]68my $topdir = "/usr/src/debian";
[13]69my $buildroot = "%{_tmppath}/%{name}-%{version}-%{release}.root".int(rand(99998)+1);
[6]70
71# "Constants"
[4]72my %targets = ('p' => 'Prep',
73 'c' => 'Compile',
74 'i' => 'Install',
75 'l' => 'Verify %files',
76 'a' => 'Build binary and source',
77 'b' => 'Build binary',
78 's' => 'Build source'
79 );
[6]80my $scriptletbase =
81q(#!/bin/sh
[3]82
[6]83 RPM_SOURCE_DIR="%{_topdir}/SOURCES"
84 RPM_BUILD_DIR="%{_topdir}/BUILD"
85 RPM_OPT_FLAGS="-O2 -g -march=i386 -mcpu=i686"
86 RPM_ARCH="i386"
87 RPM_OS="linux"
88 export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS
89 RPM_DOC_DIR="/usr/share/doc"
90 export RPM_DOC_DIR
91 RPM_PACKAGE_NAME="%{name}"
92 RPM_PACKAGE_VERSION="%{version}"
93 RPM_PACKAGE_RELEASE="%{release}"
94 export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE
95 RPM_BUILD_ROOT="%{buildroot}"
96 export RPM_BUILD_ROOT
[10]97);
98foreach (`dpkg-architecture`) {
99 s/=(.+)/="$1"/;
100 $scriptletbase .= " $_";
101}
102$scriptletbase .=
103q(
[6]104 set -x
105 umask 022
106 cd %{_topdir}/BUILD
107);
108
[5]109# Package data
110# This is the form of $pkgdata{pkgname}{meta}
111# meta includes Summary, Name, Version, Release, Group, Copyright,
[38]112# Source, URL, Packager, BuildRoot, Description, BuildReq(uires),
113# Requires, Provides
[6]114# 10/31/2005 Maybe this should be flatter? -kgd
[5]115my %pkgdata;
[27]116my @pkglist = ('main'); #sigh
[23]117# Files listing. Embedding this in %pkgdata would be, um, messy.
118my %filelist;
[40]119my $buildreq = '';
[5]120
[6]121# Scriptlets
[48]122my $prepscript = '';
123my $buildscript = '';
[23]124# %install doesn't need the full treatment from %clean; just an empty place to install to.
125# NB - rpm doesn't do this; is it really necessary?
126my $installscript = '[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT'."\n";
[48]127my $cleanscript = '';
[6]128
[5]129die "Not enough arguments\n" if #$argv == 0;
130
[13]131# Snag some environment data
132my $tmpdir;
133if (defined $ENV{TMP} && $ENV{TMP} =~ /^(\/var)?\/tmp$/) {
134 $tmpdir = $ENV{TMP};
135} else {
136 $tmpdir = "/var/tmp";
137}
138
[7]139##main
140
[4]141load_userconfig();
[3]142parse_cmd();
143
[50]144if ($cmdopts{install}) {
145 install_sdeb();
146 exit 0;
147}
148
[81]149# output stage of --showpkgs
[71]150if ($cmdopts{type} eq 'd') {
151 parse_spec();
152 foreach my $pkg (@pkglist) {
153 $pkgdata{$pkg}{name} =~ tr/_/-/;
154
155 my $pkgfullname = "$pkgdata{$pkg}{name}_$pkgdata{$pkg}{version}-$pkgdata{main}{release}_i386.deb";
156
[76]157 print "$pkgfullname\n" if $filelist{$pkg};
[79]158
[71]159 }
[80]160 # Source package
161 print "$pkgdata{main}{name}_$pkgdata{main}{version}-$pkgdata{main}{release}.sdeb\n";
[71]162 exit 0;
163}
164
[50]165# Stick --rebuild handling in here - basically install_sdeb()
166# followed by tweaking options to run with -ba
[54]167if ($cmdopts{type} eq 's') {
[55]168 if ($srcpkg =~ /\.src\.rpm$/) {
[58]169 my @srclist = qx { rpm -qlp $srcpkg };
[55]170 foreach (@srclist) {
[54]171 chomp;
[55]172 $specfile = "$topdir/SPECS/$_" if /\.spec$/;
[54]173 }
[55]174 qx { rpm -i $srcpkg };
175 } else {
176 install_sdeb();
177 my @srclist = qx { pax < $srcpkg };
178 foreach (@srclist) {
179 chomp;
180 $specfile = "$topdir/$_" if /SPECS/;
181 }
[54]182 }
[55]183 $cmdopts{type} = 'b';
184 $cmdopts{stage} = 'a';
[54]185}
[50]186
[7]187if ($cmdopts{type} eq 'b') {
188 # Need to read the spec file to find the tarball. Note that
189 # this also generates most of the shell script required.
190 parse_spec();
[38]191 die "Can't build $pkgdata{main}{name}: build requirements not met.\n"
192 if !checkbuildreq();
[7]193}
194
[65]195if ($cmdopts{type} eq 't') {
196 # Need to unpack the tarball to find the spec file. Sort of the inverse of -b above.
197 # zcat $tarball |tar -t |grep .spec
198 # collect some info about the tarball
199 $specfile = "$topdir/BUILD/". qx { zcat $tarball |tar -t |grep .spec\$ };
200 chomp $specfile;
201 my ($fileonly, $dirname) = ($tarball =~ /(([a-zA-Z0-9._-]+)\.tar\.(?:gz|bz2))$/);
202
203 $tarball = abs_path($tarball);
204 my $unpackcmd = "cd $topdir/BUILD; tar -".
205 ( $tarball =~ /\.tar\.gz$/ ? "z" : "" ).
206 ( $tarball =~ /\.tar\.bz2$/ ? "j" : "" ). "xf $tarball";
207 system "$unpackcmd";
208 system "cp $tarball $topdir/SOURCES/$fileonly";
209 system "cp $specfile $topdir/SPECS/";
210 parse_spec();
211 die "Can't build $pkgdata{main}{name}: build requirements not met.\n"
212 if !checkbuildreq();
213}
214
[35]215# -> srcpkg if -.s
216if ($cmdopts{stage} eq 's') {
217 srcpackage();
218 exit 0;
219}
220
[4]221# Hokay. Need to:
[14]222# -> prep if -.p OR (-.[cilabs] AND !--short-circuit)
[7]223if ($cmdopts{stage} eq 'p' || ($cmdopts{stage} =~ /[cilabs]/ && $cmdopts{short} ne 'y')) {
224 prep();
225}
[14]226# -> build if -.c OR (-.[ilabs] AND !--short-circuit)
[7]227if ($cmdopts{stage} eq 'c' || ($cmdopts{stage} =~ /[ilabs]/ && $cmdopts{short} ne 'y')) {
228 build();
229}
[14]230# -> install if -.[ilabs]
[28]231#if ($cmdopts{stage} eq 'i' || ($cmdopts{stage} =~ /[labs]/ && $cmdopts{short} ne 'y')) {
232if ($cmdopts{stage} =~ /[ilabs]/) {
[7]233 install();
[30]234#foreach my $pkg (@pkglist) {
235# print "files in $pkg:\n ".$filelist{$pkg}."\n";
236#}
237
[7]238}
[14]239# -> binpkg and srcpkg if -.a
[7]240if ($cmdopts{stage} eq 'a') {
[4]241 binpackage();
[7]242 srcpackage();
[4]243}
[14]244# -> binpkg if -.b
[7]245if ($cmdopts{stage} eq 'b') {
246 binpackage();
247}
[4]248
[77]249# Spit out any closing remarks
250print $finalmessages;
251
[4]252# Just in case.
253exit 0;
254
255
256## load_userconfig()
257# Loads user configuration (if any)
258# Currently only handles .debmacros
259# Needs to handle "other files"
260sub load_userconfig {
[5]261 my (undef,undef,undef,undef,undef,undef,undef,$homedir,undef) = getpwuid($<);
[4]262 if (-e "$homedir/.debmacros") {
263 open USERMACROS,"<$homedir/.debmacros";
264 while (<USERMACROS>) {
[7]265 # And we also only handle a few macros at the moment.
[4]266 if (/^\%_topdir/) {
[5]267 my (undef,$tmp) = split /\s+/, $_;
268 $topdir = $tmp;
[4]269 }
270 }
271 }
272} # end load_userconfig()
273
274
[3]275## parse_cmd()
[4]276# Parses command line into global hash %cmdopts, other globals
[3]277# Options based on rpmbuild's options
278sub parse_cmd {
279 # Don't feel like coding my own option parser...
280 #use Getopt::Long;
281 # ... but I may have to: (OTOH, rpm uses popt, so maybe we can too.)
282 #use Getopt::Popt qw(:all);
[4]283 # Or not. >:( Stupid Debian lack of findable Perl module names in packages.
[3]284
285 # Stuff it.
[4]286 my $prevopt = '';
[3]287 foreach (@ARGV) {
288 chomp;
[7]289
[3]290 # Is it an option?
291 if (/^-/) {
[7]292
[3]293 # Is it a long option?
294 if (/^--/) {
[4]295 if (/^--short-circuit/) {
296 $cmdopts{short} = 'y';
[5]297 } elsif (/^--rebuild/) {
298 $cmdopts{type} = 's';
[71]299 } elsif (/^--showpkgs/) {
300 $cmdopts{type} = 'd'; # d for 'diagnostic' or 'debug' or 'dump'
[4]301 } else {
302 print "Long opt $_\n";
303 }
[3]304 } else {
[14]305 # Not a long option
[5]306 if (/^-[bt]/) {
307 if ($cmdopts{stage} eq 's') {
308 # Mutually exclusive options.
309 die "Can't use $_ with --rebuild\n";
310 } else {
[14]311 # Capture the type (from "bare" files or tarball) and the stage (prep, build, etc)
[5]312 ($cmdopts{stage}) = (/^-[bt]([pcilabs])/);
313 ($cmdopts{type}) = (/^-([bt])[pcilabs]/);
314 }
[4]315 } elsif (/^-v/) {
316 # bump verbosity. Not sure what I'll actually do here...
[50]317 } elsif (/^-i/) {
318 $cmdopts{install} = 1;
319 $prevopt = '-i';
[4]320 } else {
321 die "Bad option $_\n";
322 }
[3]323 }
[14]324
325 } else { # Not an option argument
326
[5]327 # --buildroot is the only option that takes an argument
328 # Therefore, any *other* bare arguments are the spec file,
329 # tarball, or source package we're operating on - depending
330 # on which one we meet.
331 if ($prevopt eq '--buildroot') {
[7]332 $cmdbuildroot = $_;
[50]333 } elsif ($prevopt eq '-i') {
334 $srcpkg = $_;
[5]335 } else {
336 if ($cmdopts{type} eq 's') {
337 # Source package
[50]338 if (!/(sdeb|\.src\.rpm)$/) {
[5]339 die "Can't --rebuild with $_\n";
340 }
[50]341 $srcpkg = $_;
[71]342 } elsif ($cmdopts{type} eq 'b' || $cmdopts{type} eq 'd') {
[65]343 # Spec file
[5]344 $specfile = $_;
345 } else {
[65]346 # Tarball build. Need to extract tarball to find spec file. Whee.
347 $tarball = $_;
[5]348 }
349 }
[3]350 }
[7]351 $prevopt = $_;
352 } # foreach @ARGV
[4]353
354 # Some cross-checks. rpmbuild limits --short-circuit to just
355 # the "compile" and "install" targets - with good reason IMO.
[14]356 # Note that --short-circuit with -.p is not really an error, just redundant.
[4]357 # NB - this is NOT fatal, just ignored!
[10]358 if ($cmdopts{short} eq 'y' && $cmdopts{stage} =~ /[labs]/) {
[4]359 warn "Can't use --short-circuit for $targets{$cmdopts{stage}} stage. Ignoring.\n";
[28]360 $cmdopts{short} = 'n';
[4]361 }
[14]362
[3]363 # Valid options, with example arguments (if any):
364# Build from .spec file; mutually exclusive:
365 # -bp
366 # -bc
367 # -bi
368 # -bl
369 # -ba
370 # -bb
371 # -bs
372# Build from tarball; mutually exclusive:
373 # -tp
374 # -tc
375 # -ti
376 # -ta
377 # -tb
378 # -ts
379# Build from .src.(deb|rpm)
380 # --rebuild
381 # --recompile
382
383# General options
384 # --buildroot=DIRECTORY
385 # --clean
386 # --nobuild
387 # --nodeps
388 # --nodirtokens
389 # --rmsource
390 # --rmspec
391 # --short-circuit
392 # --target=CPU-VENDOR-OS
393
394 #my $popt = new Getopt::Popt(argv => \@ARGV, options => \@optionsTable);
395
396} # end parse_cmd()
397
[4]398
[5]399## parse_spec()
[14]400# Parse the .spec file.
[5]401sub parse_spec {
[65]402 open SPECFILE,"<$specfile" or die "specfile ($specfile) barfed: $!";
[5]403
[6]404LINE: while (<SPECFILE>) {
[14]405 next if /^#/; # Ignore comments...
406 next if /^\s+$/; # ... and blank lines.
407
[5]408 if (/^\%/) {
409 # A macro that needs further processing.
[14]410
[60]411 if (my ($key, $def) = (/^\%define\s+([^\s]+)\s+(.+)$/) ) {
412 $specglobals{$key} = expandmacros($def,'g');
[23]413 }
414
[62]415 if (/^\%description(?:\s+(?:-n\s+)?(.+))?/) {
[27]416 my $subname = "main";
417 if ($1) {
[62]418 my $tmp = expandmacros("$1", 'g');
[49]419 if (/-n/) { $subname = $tmp; } else { $subname = "$pkgdata{main}{name}-$tmp"; }
[27]420 }
[8]421 while (<SPECFILE>) {
[39]422 next if /^#/; # Messy. Should be possible to do better. :/
[8]423 redo LINE if /^\%/;
[27]424 $pkgdata{$subname}{desc} .= " $_";
[8]425 }
[18]426 }
[62]427 if (/^\%package\s+(?:-n\s+)?(.+)/) {
428 # gotta expand %defines here. Whee.
429 my $subname = expandmacros("$1", 'g');
[49]430 if (! /-n/) { $subname = "$pkgdata{main}{name}-$1"; }
[27]431 push @pkglist, $subname;
432 $pkgdata{$subname}{name} = $subname;
433 $pkgdata{$subname}{version} = $pkgdata{main}{version};
434 while (<SPECFILE>) {
435 redo LINE if /^\%/;
[38]436 if (my ($dname,$dvalue) = (/^(Summary|Group|Version|Requires|Provides):\s+(.+)$/i)) {
[27]437 $dname =~ tr/[A-Z]/[a-z]/;
[63]438 $pkgdata{$subname}{$dname} = expandmacros($dvalue, 'gp');
[27]439 }
440 }
441 }
[8]442
[6]443 if (/^\%prep/) {
444 # %prep section. May have %setup macro; may include %patch tags,
445 # may be just a bare shell script.
446
447 # This really should be local-ish, but we need just the filename for the source
448 $pkgdata{main}{source} =~ s|.+/([^/]+)$|$1|;
449
450 # Replace some core macros
[14]451 $pkgdata{main}{source} = expandmacros($pkgdata{main}{source},'gp');
[6]452
453PREPSCRIPT: while (<SPECFILE>) {
454 if (/^\%setup/) {
455 # Parse out the %setup macro. Note that we aren't supporting
[14]456 # many of RPM's %setup features.
[7]457 $prepscript .= "cd $topdir/BUILD\n";
458 if ( /\s+-n\s+([^\s]+)\s+/ ) {
459 $tarballdir = $1;
460 } else {
461 $tarballdir = "$pkgdata{main}{name}-$pkgdata{main}{version}";
462 }
[69]463 $tarballdir = expandmacros($tarballdir,'gp');
464 $prepscript .= "rm -rf $tarballdir\n";
465 if (/\s+-c\s+/) {
466 $prepscript .= "mkdir $tarballdir\ncd $tarballdir\n";
467 }
468 $prepscript .= "tar -".
[6]469 ( $pkgdata{main}{source} =~ /\.tar\.gz$/ ? "z" : "" ).
470 ( $pkgdata{main}{source} =~ /\.tar\.bz2$/ ? "j" : "" ).
[21]471 ( /\s+-q\s+/ ? '' : 'vv' )."xf ".
472 "$topdir/SOURCES/$pkgdata{main}{source}\n".
[6]473 qq(STATUS=\$?\nif [ \$STATUS -ne 0 ]; then\n exit \$STATUS\nfi\n).
[69]474 "cd $topdir/BUILD/$tarballdir\n".
[6]475 qq([ `/usr/bin/id -u` = '0' ] && /bin/chown -Rhf root .\n).
476 qq([ `/usr/bin/id -u` = '0' ] && /bin/chgrp -Rhf root .\n).
477 qq(/bin/chmod -Rf a+rX,g-w,o-w .\n);
[67]478 } elsif ( my ($patchnum,$patchopts) = (/^\%patch([^\s]+)(\s+.+)?$/) ) {
479 chomp $patchnum;
[70]480 $prepscript .= qq(echo "Patch #$patchnum ($pkgdata{main}{"patch$patchnum"}):"\n).
481 "patch ";
482 # If there are options passed, use'em.
483 # Otherwise, catch a bare %patch and ASS-U-ME it's '-p0'-able.
484 # Will break on options that don't provide -pnn, but what the hell.
[66]485 $prepscript .= $patchopts if $patchopts;
[70]486 $prepscript .= "-p0" if !$patchopts;
487 $prepscript .= " -s <$topdir/SOURCES/".$pkgdata{main}{"patch$patchnum"}."\n";
[6]488 } else {
489 last PREPSCRIPT if /^\%/;
490 $prepscript .= $_;
491 }
492 }
493 redo LINE;
494 }
[12]495 if (/^\%build/) {
[6]496 # %build. This is pretty much just a shell script. There
497 # *are* a few macros, but we're not going to deal with them yet.
[7]498 $buildscript .= "cd $tarballdir\n";
[10]499BUILDSCRIPT: while (<SPECFILE>) {
500 if (/^\%configure/) {
[12]501 $buildscript .= expandmacros($_,'cgbp');
[25]502 } elsif (/^\%\{__make\}/) {
[12]503 $buildscript .= expandmacros($_,'mgbp');
[10]504 } else {
[24]505 last BUILDSCRIPT if /^\%[^{]/;
[10]506 $buildscript .= $_;
507 }
[6]508 }
[10]509 redo LINE;
[5]510 }
[6]511 if (/^\%install/) {
[7]512 $installscript .= "cd $tarballdir\n";
[12]513INSTALLSCRIPT: while (<SPECFILE>) {
514 if (/^\%makeinstall/) {
515 $installscript .= expandmacros($_,'igbp');
516 } else {
517 last INSTALLSCRIPT if /^\%/;
518 $installscript .= $_;
519 }
520 }
521 redo LINE;
[6]522 }
523 if (/^\%clean/) {
[7]524 while (<SPECFILE>) {
525 redo LINE if /^\%/;
526 $cleanscript .= $_;
527 }
[12]528 $cleanscript = expandmacros($cleanscript,'gp');
[6]529 }
[29]530
[75]531 # pre/post (un)install scripts. Note that we expand macros later anyway, so we'll leave them unexpanded here.
532 if (/^\%(pre|post|preun|postun)\b(?:\s+(?:-n\s+)?(.+))?/i) {
533 my $scriptlet = lc $1;
534 my $pkgname = 'main';
535 if ($2) { # Magic to add entries to the right list of files
536 my $tmp = expandmacros("$2", 'g');
537 if (/-n/) { $pkgname = $tmp; } else { $pkgname = "$pkgdata{main}{name}-$tmp"; }
[16]538 }
539 while (<SPECFILE>) {
540 redo LINE if /^\%/;
[75]541 $pkgdata{$pkgname}{$scriptlet} .= $_;
[16]542 }
[6]543 }
[29]544 # done %pre/%post scripts
545
[62]546 if (/^\%files(?:\s+(?:-n\s+)?(.+))?/) {
[23]547 my $pkgname = 'main';
[29]548 if ($1) { # Magic to add entries to the right list of files
[62]549 my $tmp = expandmacros("$1", 'g');
[49]550 if (/-n/) { $pkgname = $tmp; } else { $pkgname = "$pkgdata{main}{name}-$tmp"; }
[23]551 }
[37]552
553 # Set this now, so it can be flipped a bit later, and used much later.
554 #$pkgdata{$pkgname}{conffiles} = 0;
555
[27]556 while (<SPECFILE>) {
[29]557 chomp;
[45]558 next if /^#/;
[29]559 # need to update this to deal (properly) with %dir, %attr, etc
560 next if /^\%dir/;
561 next if /^\%defattr/;
562
[37]563 # Debian dpkg doesn't speak "%docdir". Meh.
564 next if /^\%docdir/;
565
[76]566##fixme
567# Note that big chunks of this section don't match rpm's behaviour; among other things,
568# rpm accepts more than one %-directive on one line for a file or set of files.
569 # make sure files get suitable permissions and so on
570 if (/^\%attr/) {
571 # We're going to collapse whitespace before processing. PTHBT.
572 # While this breaks pathnames with spaces, anyone expecting command-line
573 # tools with spaces to work (never mind work *properly* or *well*) under
574 # any *nix has their head so far up their ass they can see out their mouth.
575 my ($args,$filelist) = split /\)/;
576 $filelist{$pkgname} .= " $filelist";
577 $args =~ s/\s+//g;
578 $args =~ s/"//g; # don't think quotes are ever necessary, but they're *allowed*
579 my ($perms,$owner,$group) = ($args =~ /\((\d+),([a-zA-Z0-9-]+),([a-zA-Z0-9-]+)/);
580# due to Debian's total lack of real permissions-processing in its actual package
581# handling component (dpkg-deb), this can't really be done "properly". We'll have
582# to add chown/chmod commands to the postinst instead. Feh.
583 $pkgdata{$pkgname}{'post'} .= "chown $owner $filelist\n" if $owner ne '-';
584 $pkgdata{$pkgname}{'post'} .= "chgrp $group $filelist\n" if $group ne '-';
[78]585 $pkgdata{$pkgname}{'post'} .= "chmod $perms $filelist\n" if $perms ne '-';
[82]586 next;
[76]587 }
588
[72]589 # %doc needs extra processing, because it can be a space-separated list.
590 if (/^\%doc/) {
591 s/^\%doc\s+//;
592 foreach (split()) {
593 $filelist{$pkgname} .= " %{_docdir}/$_";
594 }
595 next;
596 }
597
[37]598 # Conffiles. Note that Debian and RH have similar, but not
599 # *quite* identical ideas of what constitutes a conffile. Nrgh.
600 if (/^\%config\s+(.+)$/) {
601 $pkgdata{$pkgname}{conffiles} = 1; # Flag it for later
602 my $tmp = $1; # Now we can mangleificationate it. And we probably need to. :/
[46]603 $tmp = expandmacros($tmp, 'gp'); # Expand common macros
[37]604 if ($tmp !~ /\s+/) {
605 # Simplest case, just a file. Whew.
606 push @{$pkgdata{$pkgname}{conflist}}, $tmp;
607 $filelist{$pkgname} .= " $tmp";
608 } else {
609 # Wot? Spaces? That means extra %-macros. Which, for the most part, can be ignored.
610 ($tmp) = ($tmp =~ /.+\s([^\s]+)/); # Strip everything before the last space
611 push @{$pkgdata{$pkgname}{conflist}}, $tmp;
612 $filelist{$pkgname} .= " $tmp";
613 }
614 next;
615 }
616
[29]617 # and finally we can fall through %{_<FHS>}-prefixed locations...
[30]618 if (/^\%\{_/) {
619 $filelist{$pkgname} .= " $_";
620 next;
621 }
622 # EW. Necessary to clear up %define expansions before we exit with redo.
623 $_ = expandmacros $_, 'g';
[29]624
625 # ... unknown or "next section" % directives ...
[27]626 redo LINE if /^\%/;
[29]627
628 # ... and "normal" files
[27]629 $filelist{$pkgname} .= " $_";
630 }
[46]631 $filelist{$pkgname} = expandmacros($filelist{$pkgname}, 'gp');
[29]632 } # done %file section
633
[18]634 if (/^\%changelog/) {
635 $pkgdata{main}{changelog} = '';
636 while (<SPECFILE>) {
637 redo LINE if /^\%/;
638 $pkgdata{main}{changelog} .= $_;
639 }
640 }
[14]641
642 } else { # Data from the spec file "header"
643
[5]644 if (/^summary:\s+(.+)/i) {
645 $pkgdata{main}{summary} = $1;
646 } elsif (/^name:\s+(.+)/i) {
[24]647 $pkgdata{main}{name} = expandmacros($1,'g');
[5]648 } elsif (/^version:\s+(.+)/i) {
[24]649 $pkgdata{main}{version} = expandmacros($1,'g');
[5]650 } elsif (/^release:\s+(.+)/i) {
[24]651 $pkgdata{main}{release} = expandmacros($1,'g');
[5]652 } elsif (/^group:\s+(.+)/i) {
653 $pkgdata{main}{group} = $1;
654 } elsif (/^copyright:\s+(.+)/i) {
655 $pkgdata{main}{copyright} = $1;
656 } elsif (/^url:\s+(.+)/i) {
657 $pkgdata{main}{url} = $1;
658 } elsif (/^packager:\s+(.+)/i) {
659 $pkgdata{main}{packager} = $1;
[7]660 } elsif (/^buildroot:\s+(.+)/i) {
661 $buildroot = $1;
[59]662 } elsif (/^source0?:\s+(.+)/i) {
[5]663 $pkgdata{main}{source} = $1;
[6]664 die "Unknown tarball format $1\n" if $1 !~ /\.tar\.(?:gz|bz2)$/;
[15]665 } elsif (/^source([0-9]+):\s+(.+)/i) {
666 $pkgdata{sources}{$1} = $2;
[10]667 } elsif (/^patch([^:]+):\s+(.+)$/i) {
[26]668 my $patchname = "patch$1";
669 $pkgdata{main}{$patchname} = $2;
670 if ($pkgdata{main}{$patchname} =~ /\//) {
671 # URL-style patch. Rare but not unheard-of.
672 my @patchbits = split '/', $pkgdata{main}{$patchname};
673 $pkgdata{main}{$patchname} = $patchbits[$#patchbits];
674 }
[66]675 chomp $pkgdata{main}{$patchname};
[38]676 } elsif (/^buildreq(?:uires)?:\s+(.+)/i) {
677 $buildreq .= ", $1";
678 } elsif (/^requires:\s+(.+)/i) {
[63]679 $pkgdata{main}{requires} .= ", ".expandmacros("$1", 'gp');
[38]680 } elsif (/^provides:\s+(.+)/i) {
681 $pkgdata{main}{provides} .= ", $1";
[51]682 } elsif (/^conflicts:\s+(.+)/i) {
683 $pkgdata{main}{conflicts} .= ", $1";
[5]684 }
685#Name: suwrap
686#Version: 0.04
687#Release: 3
688#Group: Applications/System
689#Copyright: WebHart internal ONLY. :(
690#BuildArchitectures: i386
691#BuildRoot: /tmp/%{name}-%{version}
692#Url: http://virtual.webhart.net
693#Packager: Kris Deugau <kdeugau@deepnet.cx>
694#Source: ftp://virtual.webhart.net/%{name}-%{version}.tar.gz
695
696 }
697 }
[7]698
[14]699 # Parse and replace some more macros. More will be replaced even later.
700
[10]701 # Expand macros as necessary.
[12]702 $scriptletbase = expandmacros($scriptletbase,'gp');
[7]703
704 $buildroot = $cmdbuildroot if $cmdbuildroot;
[12]705 $buildroot = expandmacros($buildroot,'gp');
[7]706
[16]707 close SPECFILE;
[5]708} # end parse_spec()
709
710
[7]711## prep()
[14]712# Writes and executes the %prep script (mostly) built while reading the spec file.
[7]713sub prep {
[10]714 # Replace some things here just to make sure.
[12]715 $prepscript = expandmacros($prepscript,'gp');
[10]716
[24]717#print $prepscript; exit 0;
[23]718
[10]719 # create script filename
[13]720 my $prepscriptfile = "$tmpdir/deb-tmp.prep.".int(rand(99998)+1);
[10]721 sysopen(PREPSCRIPT, $prepscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
[7]722 or die $!;
[10]723 print PREPSCRIPT $scriptletbase;
724 print PREPSCRIPT $prepscript;
725 close PREPSCRIPT;
[7]726
[10]727 # execute
728 print "Calling \%prep script $prepscriptfile...\n";
729 system("/bin/sh -e $prepscriptfile") == 0
[14]730 or die "Can't exec: $!\n";
[7]731
[10]732 # and clean up
733 unlink $prepscriptfile;
[7]734} # end prep()
735
736
[5]737## build()
[14]738# Writes and executes the %build script (mostly) built while reading the spec file.
[5]739sub build {
[12]740 # Expand the macros
741 $buildscript = expandmacros($buildscript,'cgbp');
742
[7]743 # create script filename
[13]744 my $buildscriptfile = "$tmpdir/deb-tmp.build.".int(rand(99998)+1);
[7]745 sysopen(BUILDSCRIPT, $buildscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
746 or die $!;
747 print BUILDSCRIPT $scriptletbase;
748 print BUILDSCRIPT $buildscript;
749 close BUILDSCRIPT;
750
751 # execute
752 print "Calling \%build script $buildscriptfile...\n";
753 system("/bin/sh -e $buildscriptfile") == 0
[14]754 or die "Can't exec: $!\n";
[7]755
756 # and clean up
757 unlink $buildscriptfile;
[5]758} # end build()
759
760
[7]761## install()
[14]762# Writes and executes the %install script (mostly) built while reading the spec file.
[7]763sub install {
[12]764 # Expand the macros
765 $installscript = expandmacros($installscript,'igbp');
766
[7]767 # create script filename
[13]768 my $installscriptfile = "$tmpdir/deb-tmp.inst.".int(rand(99998)+1);
[7]769 sysopen(INSTSCRIPT, $installscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
770 or die $!;
771 print INSTSCRIPT $scriptletbase;
[23]772# print INSTSCRIPT $cleanscript; # Clean up our install target before installing into it.
[7]773 print INSTSCRIPT $installscript;
774 close INSTSCRIPT;
775
776 # execute
777 print "Calling \%install script $installscriptfile...\n";
778 system("/bin/sh -e $installscriptfile") == 0
[14]779 or die "Can't exec: $!\n";
[7]780
781 # and clean up
782 unlink $installscriptfile;
783} # end install()
784
785
[8]786## binpackage()
787# Creates the binary .deb package from the installed tree in $buildroot.
[14]788# Writes and executes a shell script to do so.
789# Creates miscellaneous files required by dpkg-deb to actually build the package file.
[27]790# Should handle simple subpackages
[8]791sub binpackage {
[14]792 # Make sure we have somewhere to write the .deb file
[9]793 if (!-e "$topdir/DEBS/i386") {
794 mkdir "$topdir/DEBS/i386";
795 }
[14]796
[27]797 foreach my $pkg (@pkglist) {
[8]798
[73]799 # Skip building a package if it doesn't actually have any files. NB: This
800 # differs slightly from rpm's behaviour where a package *will* be built -
801 # even without any files - if %files is specified anywhere. I can think
802 # of odd corner cases where that *may* be desireable.
[74]803 next if (!$filelist{$pkg} or $filelist{$pkg} =~ /^\s*$/);
[73]804
[27]805 # Gotta do this first, otherwise we don't have a place to move files from %files
806 mkdir "$buildroot/$pkg";
[28]807
[30]808 # Eliminate any lingering % macros
809 $filelist{$pkg} = expandmacros $filelist{$pkg}, 'g';
810
[27]811 my @pkgfilelist = split ' ', $filelist{$pkg};
812 foreach my $pkgfile (@pkgfilelist) {
[37]813 $pkgfile = expandmacros($pkgfile, 'gp');
[44]814 my ($fpath,$fname) = ($pkgfile =~ m|(.+?/?)?([^/]+)$|); # We don't need $fname now, but we might.
815 qx { mkdir -p $buildroot/$pkg$fpath }
816 if $fpath && $fpath ne '';
817 qx { mv $buildroot$pkgfile $buildroot/$pkg$fpath };
[27]818 }
[28]819
[38]820 # Get the "Depends" (Requires) a la RPM. Ish. We strip the leading
821 # comma and space here (if needed) in case there were "Requires" specified
822 # in the spec file - those would precede these.
[64]823 $pkgdata{$pkg}{requires} .= getreqs("$buildroot/$pkg");
[38]824
[64]825 # magic needed to properly version dependencies...
826 # only provided deps will really be included
[65]827 $pkgdata{$pkg}{requires} =~ s/^, //; # Still have to do this here.
[64]828 $pkgdata{$pkg}{requires} =~ s/\s+//g;
829 my @deps = split /,/, $pkgdata{$pkg}{requires};
830 my $tmp = '';
831 foreach my $dep (@deps) {
[68]832 # Hack up the perl(Class::SubClass) deps into something dpkg can understand.
833 # May or may not be versioned.
834 # We do this first so the version rewriter can do its magic next.
835 if (my ($mod,$ver) = ($dep =~ /^perl\(([A-Za-z0-9\:\-]+)\)([><=]+.+)?/) ) {
836 $mod =~ s/^perl\(//;
837 $mod =~ s/\)$//;
838 $mod =~ s/::/-/g;
839 $mod =~ tr/A-Z/a-z/;
840 $mod = "lib$mod-perl";
841 $mod .= $ver if $ver;
842 $dep = $mod;
843 }
[64]844 if (my ($name,$rel,$value) = ($dep =~ /^([a-zA-Z0-9._-]+)([><=]+)([a-zA-Z0-9._-]+)$/)) {
845 $tmp .= ", $name ($rel $value)";
846 } else {
847 $tmp .= ", $dep";
848 }
849 }
850 ($pkgdata{$pkg}{requires} = $tmp) =~ s/^, //;
851
[38]852 # Do this here since we're doing {depends}...
[41]853 if (defined($pkgdata{$pkg}{provides})) {
854 $pkgdata{$pkg}{provides} =~ s/^, //;
855 $pkgdata{$pkg}{provides} = expandmacros($pkgdata{$pkg}{provides},'gp');
856 }
[51]857 if (defined($pkgdata{$pkg}{conflicts})) {
858 $pkgdata{$pkg}{conflicts} =~ s/^, //;
859 $pkgdata{$pkg}{conflicts} = expandmacros($pkgdata{$pkg}{conflicts},'gp');
860 }
[38]861
[27]862 # Gotta do this next, otherwise the control file has nowhere to go. >:(
863 mkdir "$buildroot/$pkg/DEBIAN";
864
[33]865 # Hack the filename for the package into a Debian-tool-compatible format. GRRRRRR!!!!!
866 # Have I mentioned I hate Debian Policy?
867 $pkgdata{$pkg}{name} =~ tr/_/-/;
868
[27]869 # create script filename
870 my $debscriptfile = "$tmpdir/deb-tmp.pkg.".int(rand(99998)+1);
871 sysopen(DEBSCRIPT, $debscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
[8]872 or die $!;
[27]873 print DEBSCRIPT $scriptletbase;
874 print DEBSCRIPT "fakeroot dpkg-deb -b $buildroot/$pkg $topdir/DEBS/i386/".
875 "$pkgdata{$pkg}{name}_$pkgdata{$pkg}{version}-$pkgdata{main}{release}_i386.deb\n";
876 # %$&$%@#@@#%@@@ Debian and their horrible ugly package names. >:(
877 close DEBSCRIPT;
[8]878
[27]879 my $control = "Package: $pkgdata{$pkg}{name}\n".
880 "Version: $pkgdata{$pkg}{version}-$pkgdata{main}{release}\n".
881 "Section: $pkgdata{$pkg}{group}\n".
[8]882 "Priority: optional\n".
883 "Architecture: i386\n".
884 "Maintainer: $pkgdata{main}{packager}\n".
[47]885 ( $pkgdata{$pkg}{requires} ne '' ? "Depends: $pkgdata{$pkg}{requires}\n" : '' ).
[39]886 ( defined($pkgdata{$pkg}{provides}) ? "Provides: $pkgdata{$pkg}{provides}\n" : '' ).
[51]887 ( defined($pkgdata{$pkg}{conflicts}) ? "Conflicts: $pkgdata{$pkg}{conflicts}\n" : '' ).
[27]888 "Description: $pkgdata{$pkg}{summary}\n";
889 $control .= "$pkgdata{$pkg}{desc}\n";
[8]890
[27]891 open CONTROL, ">$buildroot/$pkg/DEBIAN/control";
892 print CONTROL $control;
893 close CONTROL;
[8]894
[37]895 # Iff there are conffiles (as specified in the %files list(s), add'em
896 # in so dpkg-deb can tag them.
897 if ($pkgdata{$pkg}{conffiles}) {
898 open CONFLIST, ">$buildroot/$pkg/DEBIAN/conffiles";
899 foreach my $conffile (@{$pkgdata{$pkg}{conflist}}) {
900 print CONFLIST "$conffile\n";
901 }
902 close CONFLIST;
903 }
904
[75]905 # found the point of scripts on subpackages.
906 if ($pkgdata{$pkg}{'pre'}) {
907 $pkgdata{$pkg}{'pre'} = expandmacros($pkgdata{$pkg}{'pre'},'gp');
908 open PREINST, ">$buildroot/$pkg/DEBIAN/preinst";
909 print PREINST "#!/bin/sh\nset -e\n\n";
910 print PREINST $pkgdata{$pkg}{'pre'};
911 close PREINST;
912 `chmod 0755 $buildroot/$pkg/DEBIAN/preinst`;
[27]913 }
[75]914 if ($pkgdata{$pkg}{'post'}) {
915 $pkgdata{$pkg}{'post'} = expandmacros($pkgdata{$pkg}{'post'},'gp');
916 open PREINST, ">$buildroot/$pkg/DEBIAN/postinst";
917 print PREINST "#!/bin/sh\nset -e\n\n";
918 print PREINST $pkgdata{$pkg}{'post'};
919 close PREINST;
920 `chmod 0755 $buildroot/$pkg/DEBIAN/postinst`;
921 }
922 if ($pkgdata{$pkg}{'preun'}) {
923 $pkgdata{$pkg}{'pre'} = expandmacros($pkgdata{$pkg}{'preun'},'gp');
924 open PREINST, ">$buildroot/$pkg/DEBIAN/prerm";
925 print PREINST "#!/bin/sh\nset -e\n\n";
926 print PREINST $pkgdata{$pkg}{'preun'};
927 close PREINST;
928 `chmod 0755 $buildroot/$pkg/DEBIAN/prerm`;
929 }
930 if ($pkgdata{$pkg}{'postun'}) {
931 $pkgdata{$pkg}{'postun'} = expandmacros($pkgdata{$pkg}{'postun'},'gp');
932 open PREINST, ">$buildroot/$pkg/DEBIAN/postrm";
933 print PREINST "#!/bin/sh\nset -e\n\n";
934 print PREINST $pkgdata{$pkg}{'postun'};
935 close PREINST;
936 `chmod 0755 $buildroot/$pkg/DEBIAN/postrm`;
937 }
[16]938
[27]939 # execute
940 print "Calling package creation script $debscriptfile for $pkgdata{$pkg}{name}...\n";
941 system("/bin/sh -e $debscriptfile") == 0
[14]942 or die "Can't exec: $!\n";
[8]943
[77]944 $finalmessages .= "Wrote binary package ".
945 "$pkgdata{$pkg}{name}_$pkgdata{$pkg}{version}-$pkgdata{main}{release}_i386.deb".
946 " in $topdir/DEBS/i386\n";
[27]947 # and clean up
948 unlink $debscriptfile;
949
950 } # subpackage loop
951
[8]952} # end binpackage()
953
954
[35]955## srcpackage()
956# Builds a .src.deb source package. Note that Debian's idea of
957# a "source package" is seriously flawed IMO, because you can't
958# easily copy it as-is.
[36]959# Not quite identical to RPM, but Good Enough (TM).
[35]960sub srcpackage {
[54]961 # In case we were called with -bs.
962 $pkgdata{main}{name} =~ tr/_/-/;
[36]963 my $pkgsrcname = "$pkgdata{main}{name}-$pkgdata{main}{version}-$pkgdata{main}{release}.sdeb";
964
965 my $paxcmd;
966
967 # We'll definitely need this later, and *may* need it sooner.
968 (my $barespec = $specfile) =~ s|.+/([^/]+)$|$1|;
969
970 # Copy the specfile to the build tree, but only if it's not there already.
971##buglet: need to deal with silly case where silly user has put the spec
972# file in a subdir of %{_topdir}/SPECS. Ewww. Silly user!
973 if (abs_path($specfile) !~ /^$topdir\/SPECS/) {
974 $paxcmd .= "cp $specfile %{_topdir}/SPECS/; \n"
975 }
976
[35]977 # use pax -w [file] [file] ... >outfile.sdeb
[36]978 $paxcmd = "cd $topdir; pax -w ";
[10]979
[35]980# tweak source entry into usable form. Need it locally somewhere along the line.
981 (my $pkgsrc = $pkgdata{main}{source}) =~ s|.+/([^/]+)$|$1|;
[36]982 $paxcmd .= "SOURCES/$pkgsrc ";
[10]983
[35]984 # create file list: Source[nn], Patch[nn]
985 foreach my $specbit (keys %{$pkgdata{main}} ) {
986 next if $specbit eq 'source';
[53]987 $paxcmd .= "SOURCES/$pkgdata{main}{$specbit} " if $specbit =~ /^patch/;
[36]988##buglet: need to deal with case where patches are listed as URLs?
989# or other extended pathnames? Silly !@$%^&!%%!%!! user!
[35]990 }
991
[53]992 foreach my $source (keys %{$pkgdata{sources}}) {
993 $paxcmd .= "SOURCES/$pkgdata{sources}{$source} ";
994 }
995
[36]996 # add the spec file, source package destination, and cd back where we came from.
997 $paxcmd .= "SPECS/$barespec > $topdir/SDEBS/$pkgsrcname; cd -";
[35]998
[36]999 # In case of %-macros...
[35]1000 $paxcmd = expandmacros($paxcmd,'gp');
1001
[36]1002 system "$paxcmd";
[77]1003 $finalmessages .= "Wrote source package $pkgsrcname in $topdir/SDEBS.\n";
[35]1004}
1005
1006
[38]1007## checkbuildreq()
1008# Checks the build requirements (if any)
1009# Spits out a rude warning and returns a true-false error if any
1010# requirements are not met.
1011sub checkbuildreq {
[40]1012 return 1 if $buildreq eq ''; # No use doing extra work.
[38]1013
[52]1014 if ( ! -e "/usr/bin/dpkg-query" ) {
1015 print "**WARNING** dpkg-query not found. Can't check build-deps.\n".
1016 " Required for sucessful build:\n".$buildreq."\n".
1017 " Continuing anyway.\n";
1018 return 1;
1019 }
1020
[38]1021 my $reqflag = 1; # unset iff a buildreq is missing
1022
1023 $buildreq =~ s/^, //; # Strip the leading comma and space
1024 my @reqlist = split /,\s+/, $buildreq;
1025
1026 foreach my $req (@reqlist) {
1027 my ($pkg,$rel,$ver);
1028
1029 # We have two classes of requirements - versioned and unversioned.
1030 if ($req =~ /[><=]/) {
1031 # Pick up the details of versioned buildreqs
1032 ($pkg,$rel,$ver) = ($req =~ /([a-z0-9._-]+)\s+([><=]+)\s+([a-z0-9._-]+)/);
1033 } else {
1034 # And the unversioned ones.
1035 $pkg = $req;
1036 $rel = '>=';
1037 $ver = 0;
1038 }
1039
1040 my @pkglist = qx { dpkg-query --showformat '\${status}\t\${version}\n' -W $pkg };
1041# need to check if no lines returned - means a bad buildreq
1042 my ($reqstat,undef,undef,$reqver) = split /\s+/, $pkglist[0];
1043 if ($reqstat !~ /install/) {
1044 print " * Missing build-dependency $pkg!\n";
1045 $reqflag = 0;
1046 } else {
1047# gotta be a better way to do this... :/
1048 if ($rel eq '>=' && !($reqver ge $ver)) {
1049 print " * Buildreq $pkg is installed, but wrong version ($reqver): Need $ver\n";
1050 $reqflag = 0;
1051 }
1052 if ($rel eq '>' && !($reqver gt $ver)) {
1053 print " * Buildreq $pkg is installed, but wrong version ($reqver): Need $ver\n";
1054 $reqflag = 0;
1055 }
1056 if ($rel eq '<=' && !($reqver le $ver)) {
1057 print " * Buildreq $pkg is installed, but wrong version ($reqver): Need $ver\n";
1058 $reqflag = 0;
1059 }
1060 if ($rel eq '<' && !($reqver lt $ver)) {
1061 print " * Buildreq $pkg is installed, but wrong version ($reqver): Need $ver\n";
1062 $reqflag = 0;
1063 }
1064 if ($rel eq '=' && !($reqver eq $ver)) {
1065 print " * Buildreq $pkg is installed, but wrong version ($reqver): Need $ver\n";
1066 $reqflag = 0;
1067 }
1068 } # end not installed/installed check
1069 } # end req loop
1070
1071 return $reqflag;
1072} # end checkbuildreq()
1073
1074
1075## getreqs()
1076# Find out which libraries/packages are required for any
1077# executables and libs in a given file tree.
1078# (Debian doesn't have soname-level deps; just package-level)
[41]1079# Returns an empty string if the tree contains no binaries.
1080# Doesn't work well on shell scripts. but those *should* be
1081# fine anyway. (Yeah, right...)
[38]1082sub getreqs() {
1083 my $pkgtree = $_[0];
1084
[39]1085 print "Checking library requirements...\n";
[43]1086 my @binlist = qx { find $pkgtree -type f -perm 755 };
[38]1087
[41]1088 if (scalar(@binlist) == 0) {
1089 return '';
1090 }
1091
1092 my @reqlist;
1093 foreach (@binlist) {
1094 push @reqlist, qx { ldd $_ };
1095 }
1096
1097 # Get the list of libs provided by this package. Still doesn't
1098 # handle the case where the lib gets stuffed into a subpackage. :/
1099 my @intprovlist = qx { find $pkgtree -type f -name "*.so*" };
1100 my $provlist = '';
1101 foreach (@intprovlist) {
1102 s/$pkgtree//;
1103 $provlist .= "$_";
1104 }
1105
[38]1106 my %reqs;
[43]1107 my $reqlibs = '';
[38]1108
1109 foreach (@reqlist) {
1110 next if /^$pkgtree/;
[42]1111 next if /not a dynamic executable/;
[41]1112 next if m|/lib/ld-linux.so|; # Hack! Hack! PTHBTT! (libc suxx0rz)
[38]1113
[41]1114 my ($req) = (/^\s+([a-z0-9._-]+)/); # dig out the actual library (so)name
1115
1116 # Ignore libs provided by this package. Note that we don't match
1117 # on word-boundary at the *end* of the lib we're looking for, as the
1118 # looked-for lib may not have the full soname version. (ie, it may
1119 # "just" point to one of the symlinks that get created somewhere.)
1120 next if $provlist =~ /\b$req/;
1121
[38]1122 $reqlibs .= " $req";
1123 }
1124
[43]1125 if ($reqlibs ne '') {
1126 foreach (qx { dpkg -S $reqlibs }) {
1127 my ($libpkg,undef) = split /:\s+/;
1128 $reqs{$libpkg} = 1;
1129 }
[38]1130 }
1131
[43]1132 my $deplist = '';
[38]1133 foreach (keys %reqs) {
1134 $deplist .= ", $_";
1135 }
1136
1137# For now, we're done. We're not going to meddle with versions yet.
1138# Among other things, it's messier than handling "simple" yes/no "do
1139# we have this lib?" deps. >:(
1140
1141 return $deplist;
1142} # end getreqs()
1143
1144
[50]1145## install_sdeb()
1146# Extracts .sdeb contents to %_topdir as appropriate
1147sub install_sdeb {
1148 my $paxcmd = "cd $topdir; pax -r <$srcpkg; cd -";
1149
1150 # In case of %-macros...
1151 $paxcmd = expandmacros($paxcmd,'gp');
1152
1153 system "$paxcmd";
1154 print "Extracted source package $srcpkg to $topdir.\n";
1155} # end install_sdeb()
1156
1157
[10]1158## expandmacros()
1159# Expands all %{blah} macros in the passed string
[14]1160# Split up a bit with some sections so we don't spend time trying to
1161# expand macros that are only used in a few specific places.
[10]1162sub expandmacros {
1163 my $macrostring = shift;
[14]1164 my $section = shift;
[10]1165
[25]1166 # To allow the FHS-ish %configure and %makeinstall to work The Right Way.
[12]1167 # (Without clobbering the global $buildroot.)
1168 my $prefix = '';
1169
[11]1170 if ($section =~ /c/) {
[12]1171 # %configure macro
[17]1172# Don't know what it's for, don't have a useful default replacement
1173# --program-prefix=%{_program_prefix} \
1174 $macrostring =~ s'%configure'./configure --host=$DEB_HOST_GNU_TYPE \
1175 --build=$DEB_BUILD_GNU_TYPE \
1176 --prefix=%{_prefix} \
1177 --exec-prefix=%{_exec_prefix} \
1178 --bindir=%{_bindir} \
1179 --sbindir=%{_sbindir} \
1180 --sysconfdir=%{_sysconfdir} \
1181 --datadir=%{_datadir} \
1182 --includedir=%{_includedir} \
1183 --libdir=%{_libdir} \
1184 --libexecdir=%{_libexecdir} \
1185 --localstatedir=%{_localstatedir} \
1186 --sharedstatedir=%{_sharedstatedir} \
1187 --mandir=%{_mandir} \
1188 --infodir=%{_infodir} ';
[12]1189 } # done %configure
1190
1191 if ($section =~ /m/) {
1192 $macrostring =~ s'%{__make}'make ';
[25]1193 } # done make
[12]1194
1195 if ($section =~ /i/) {
1196 # This is where we need to mangle $prefix.
[24]1197 $macrostring =~ s'%makeinstall'make %{fhs} install';
[12]1198 $prefix = $buildroot;
1199 } # done %install and/or %makeinstall
1200
1201 # Build data
1202 # Note that these are processed in reverse order to get the substitution order right
1203 if ($section =~ /b/) {
[24]1204# $macrostring =~ s'%{fhs}'host=$DEB_HOST_GNU_TYPE \
1205# build=$DEB_BUILD_GNU_TYPE \
1206 $macrostring =~ s'%{fhs}'prefix=%{_prefix} \
[17]1207 exec-prefix=%{_exec_prefix} \
1208 bindir=%{_bindir} \
1209 sbindir=%{_sbindir} \
1210 sysconfdir=%{_sysconfdir} \
1211 datadir=%{_datadir} \
1212 includedir=%{_includedir} \
1213 libdir=%{_libdir} \
1214 libexecdir=%{_libexecdir} \
1215 localstatedir=%{_localstatedir} \
1216 sharedstatedir=%{_sharedstatedir} \
1217 mandir=%{_mandir} \
1218 infodir=%{_infodir} \
1219';
[10]1220
1221 # Note that the above regex terminates with the extra space
[12]1222 # "Just In Case" of user additions, which will then get neatly
1223 # tagged on the end where they take precedence (supposedly)
1224 # over the "default" ones.
[10]1225
[14]1226 # Now we cascade the macros introduced above. >_<
1227 # Wot ot to go theah:
1228 $macrostring =~ s|%{_mandir}|%{_datadir}/man|g; #/usr/share/man
1229 $macrostring =~ s|%{_infodir}|%{_datadir}/info|g; #/usr/share/info
[25]1230 $macrostring =~ s|%{_oldincludedir}|/usr/include|g; #/usr/include
1231 $macrostring =~ s|%{_includedir}|%{_prefix\}/include|g; #/usr/include
1232 $macrostring =~ s|%{_libdir}|%{_exec_prefix}/%{_lib}|g; #/usr/lib
[14]1233 $macrostring =~ s|%{_lib}|lib|g; #?
[25]1234 $macrostring =~ s|%{_localstatedir}|/var|g; #/var
1235 $macrostring =~ s|%{_sharedstatedir}|%{_prefix}/com|g; #/usr/com WTF?
1236 $macrostring =~ s|%{_sysconfdir}|/etc|g; #/etc
1237 $macrostring =~ s|%{_datadir}|%{_prefix}/share|g; #/usr/share
1238 $macrostring =~ s|%{_libexecdir}|%{_exec_prefix}/libexec|g; #/usr/libexec
1239 $macrostring =~ s|%{_sbindir}|%{_exec_prefix}/sbin|g; #/usr/sbin
1240 $macrostring =~ s|%{_bindir}|%{_exec_prefix}/bin|g; #/usr/bin
1241 $macrostring =~ s|%{_exec_prefix}|%{_prefix}|g; #/usr
[14]1242 $macrostring =~ s|%{_prefix}|/usr|g; #/usr
[10]1243 } # done with config section
1244
[12]1245 # Package data
1246 if ($section =~ /p/) {
[15]1247 $macrostring =~ s/\%\{buildroot\}/$buildroot/gi;
1248 foreach my $source (keys %{$pkgdata{sources}}) {
1249 $macrostring =~ s/\%\{source$source\}/$topdir\/SOURCES\/$pkgdata{sources}{$source}/gi;
1250 }
1251 $macrostring =~ s/\%\{name\}/$pkgdata{main}{name}/gi;
1252 $macrostring =~ s/\%\{version\}/$pkgdata{main}{version}/gi;
1253 $macrostring =~ s/\%\{release\}/$pkgdata{main}{release}/gi;
[12]1254 }
1255
1256 # Globals, and not-so-globals
1257 if ($section =~ /g/) {
[60]1258
1259 # special %define's. Handle the general case where we eval anything.
1260 # Prime example:
1261 #%define perl_vendorlib %(eval "`perl -V:installvendorlib`"; echo $installvendorlib)
1262 if ($macrostring =~ /^\%\(eval.+\)$/) {
1263 $macrostring =~ s/^\%\(//;
1264 $macrostring =~ s/\)$//;
1265 # Oy vey this gets silly for the perl bits. Executing a shell to
1266 # call Perl to get the vendorlib/sitelib/whatever "core" globals.
1267 # This can do more, but... eww.
1268 # Next line is non-optimal - what if $macrostring contains ' characters?
1269 $macrostring = qx { /bin/sh -c '$macrostring' };
1270 }
1271
[29]1272 $macrostring =~ s|%{_builddir}|%{_topdir}/BUILD|g;
1273 $macrostring =~ s|%{_topdir}|$topdir|g;
[13]1274 $macrostring =~ s|%{_tmppath}|$tmpdir|g;
[12]1275 $macrostring =~ s'%{_docdir}'/usr/share/doc'g;
[23]1276
[31]1277 # Standard FHS locations. More or less.
[30]1278 $macrostring =~ s'%{_bindir}'/usr/bin'g;
[31]1279 $macrostring =~ s'%{_sbindir}'/usr/sbin'g;
[30]1280 $macrostring =~ s'%{_mandir}'/usr/share/man'g;
1281 $macrostring =~ s'%{_includedir}'/usr/include'g;
[31]1282 $macrostring =~ s'%{_libdir}'/usr/lib'g;
1283 $macrostring =~ s'%{_sysconfdir}'/etc'g;
1284 $macrostring =~ s'%{_localstatedir}'/var'g;
[30]1285
[23]1286 # %define's
1287 foreach my $key (keys %specglobals) {
1288 $macrostring =~ s|%{$key}|$specglobals{$key}|g;
1289 }
1290
1291 # system programs. RPM uses a global config file for these; we'll just
1292 # ASS-U-ME and make life a little simpler.
1293 if ($macrostring =~ /\%\{\_\_([a-z0-9_-]+)\}/) {
1294 $macrostring =~ s|%{__([a-z0-9_-]+)}|$1|g;
1295 }
[10]1296 } # done with globals section
1297
1298 return $macrostring;
1299} # end expandmacros()
[22]1300
1301
1302
[38]1303__END__
1304
1305
1306
[22]1307=head1 NAME
1308
1309debbuild - Build Debian-compatible packages from RPM spec files
1310
1311=head1 SYNOPSIS
1312
1313 debbuild {-ba|-bb|-bp|-bc|-bi|-bl|-bs} [build-options] file.spec
1314
1315 debbuild {-ta|-tb|-tp|-tc|-ti|-tl|-ts} [build-options] file.tar.{gz|bz2}
1316
[55]1317 debbuild --rebuild file.{src.rpm|sdeb}
[22]1318
1319=head1 DESCRIPTION
1320
[55]1321This script attempts to build Debian-friendly semi-native packages from RPM spec files,
1322RPM-friendly tarballs, and RPM source packages (.src.rpm files). It accepts I<most> of the
1323options rpmbuild does, and should be able to interpret most spec files usefully. Perl
1324modules should be handled via CPAN+dh-make-perl instead; Debian's conventions for such
1325things do not lend themselves to automated conversion.
[22]1326
[55]1327As far as possible, the command-line options are identical to those from rpmbuild, although
[57]1328several rpmbuild options are not supported:
[22]1329
[57]1330 --recompile
1331 --showrc
1332 --buildroot
1333 --clean
1334 --nobuild
1335 --rmsource
1336 --rmspec
1337 --sign
1338 --target
1339
1340Some of these could probably be trivially added. Feel free to send me a patch. ;)
1341
1342Complex spec files will most likely not work well, if at all. Rewrite them from scratch -
1343you'll have to make heavy modifications anyway.
1344
1345If you see something you don't like, mail me. Send a patch if you feel inspired. I don't
1346promise I'll do anything other than say "Yup, that's broken" or "Got your message".
1347
[55]1348=head1 ASSUMPTIONS
1349
1350As with rpmbuild, debbuild makes some assumptions about your system.
1351
1352=over 4
1353
1354=item *
1355
1356Either you have rights to do as you please under /usr/src/debian, or you have created a file
1357~/.debmacros containing a suitable %_topdir definition.
1358
[57]1359Both rpmbuild and debbuild require the directories %_topdir/{BUILD,SOURCES,SPECS}. However,
1360where rpmbuild requires the %_topdir/{RPMS,SRPMS} directories, debbuild
1361requires %_topdir/{DEBS,SDEBS} instead. Create them in advance;
[55]1362some subdirectories are created automatically as needed, but most are not.
1363
1364=item *
1365
1366/var/tmp must allow script execution - rpmbuild and debbuild both rely on creating and
1367executing shell scripts for much of their functionality. By default, debbuild also creates
1368install trees under /var/tmp - however this is (almost) entirely under the control of the
1369package's .spec file.
1370
1371=item *
1372
1373If you wish to --rebuild a .src.rpm, your %_topdir for both debbuild and rpmbuild must either
1374match, or be suitably symlinked one direction or another so that both programs are effectively
1375working in the same tree. (Or you could just manually wrestle files around your system.)
1376
1377You could symlink ~/.rpmmacros to ~/.debmacros (or vice versa) and save yourself some hassle
1378if you need to rebuild .src.rpm packages on a regular basis. Currently debbuild only uses the
1379%_topdir macro definition, although there are many more things that rpmbuild can use from
1380~/.rpmmacros.
1381
1382=back
1383
[57]1384=head1 AUTHOR
[55]1385
[57]1386debbuild was written by Kris Deugau <kdeugau@deepnet.cx>. A version that approximates
1387current is available at http://www.deepnet.cx/debbuild/.
[55]1388
1389=head1 BUGS
1390
[57]1391Funky Things Happen if you forget a command-line option or two. I've been too lazy to bother
1392fixing this.
[55]1393
[57]1394Many macro expansions are unsupported or incompletely supported.
1395
1396The generated scriptlets don't quite match those from rpmbuild exactly. There are extra
1397environment variables and preprocessing that I haven't needed (yet).
1398
1399Dcumentation, such as it is, will likely remain perpetually out of date.
1400
1401%_topdir and the five "working" directories under %_topdir could arguably be created by
1402debbuild. However, rpmbuild doesn't create these directories either.
1403
1404=head1 SEE ALSO
1405
1406rpm(8), rpmbuild(8), and pretty much any document describing how to write a .spec file.
1407
[22]1408=cut
Note: See TracBrowser for help on using the repository browser.