source: trunk/debbuild@ 111

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

/trunk

Add basic epoch support

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