source: trunk/debbuild@ 97

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

/trunk

Execute %clean script on build-all or build-binary (-ta, -tb, -ba, -bb)

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