source: trunk/debbuild@ 110

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

/trunk

Enhance %files processing: %doc support (mostly)

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