source: trunk/debbuild@ 112

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

/trunk

Add handling for AutoReq/AutoReqProv.

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