source: trunk/debbuild@ 41

Last change on this file since 41 was 41, checked in by kdeugau, 18 years ago

/trunk

Removed some extraneous reference comments
Expanded some description comments
Expanded dependency processing to handle libs that are part of

the package getting built, and (sub)packages that don't contain
executables.

  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author
File size: 33.6 KB
RevLine 
[2]1#!/usr/bin/perl
2# debbuild script
3# Shamlessly steals intreface from rpm's "rpmbuild" to create
4# Debian packages. Please note that such packages are highly
5# unlikely to conform to "Debian Policy".
6###
7# SVN revision info
8# $Date: 2006-02-23 21:14:33 +0000 (Thu, 23 Feb 2006) $
9# SVN revision $Rev: 41 $
10# Last update by $Author: kdeugau $
11###
12
[5]13use strict;
[6]14use warnings;
[7]15use Fcntl; # for sysopen flags
[36]16use Cwd 'abs_path'; # for finding where files really are
[5]17
[10]18# regex debugger
19#use re "debug";
20
[3]21# Program flow:
22# -> Parse/execute "system" config/macros (if any - should be rare)
23# -> Parse/execute "user" config/macros (if any - *my* requirement is %_topdir)
24# -> Parse command line for options, spec file/tarball/.src.deb (NB - also accept .src.rpm)
25
[30]26sub expandmacros;
27
[2]28# User's prefs for dirs, environment, etc,etc,etc.
29# config file ~/.debmacros
30# Default ordered search paths for config/macros:
31# /usr/lib/rpm/rpmrc /usr/lib/rpm/redhat/rpmrc /etc/rpmrc ~/.rpmrc
32# /usr/lib/rpm/macros /usr/lib/rpm/redhat/macros /etc/rpm/macros ~/.rpmmacros
33# **NOTE: May be possible to (ab)use bits of debhelper
34
35# Build tree
36# default is /usr/src/debian/{BUILD,SOURCES,SPECS,DEBS,SDEBS}
37
[3]38# Globals
39my $specfile;
40my $tarball;
41my $srcpkg;
[7]42my $cmdbuildroot;
43my $tarballdir; # This should really be initialized, but the coding makes it, um, ugly.
[23]44my %specglobals; # For %define's in specfile, among other things.
[6]45
46# Initialized globals
[3]47my $verbosity = 0;
[4]48my %cmdopts = (type => '',
49 stage => 'a',
50 short => 'n'
51 );
[6]52my $topdir = "/usr/src/debian";
[13]53my $buildroot = "%{_tmppath}/%{name}-%{version}-%{release}.root".int(rand(99998)+1);
[6]54
55# "Constants"
[4]56my %targets = ('p' => 'Prep',
57 'c' => 'Compile',
58 'i' => 'Install',
59 'l' => 'Verify %files',
60 'a' => 'Build binary and source',
61 'b' => 'Build binary',
62 's' => 'Build source'
63 );
[6]64my $scriptletbase =
65q(#!/bin/sh
[3]66
[6]67 RPM_SOURCE_DIR="%{_topdir}/SOURCES"
68 RPM_BUILD_DIR="%{_topdir}/BUILD"
69 RPM_OPT_FLAGS="-O2 -g -march=i386 -mcpu=i686"
70 RPM_ARCH="i386"
71 RPM_OS="linux"
72 export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS
73 RPM_DOC_DIR="/usr/share/doc"
74 export RPM_DOC_DIR
75 RPM_PACKAGE_NAME="%{name}"
76 RPM_PACKAGE_VERSION="%{version}"
77 RPM_PACKAGE_RELEASE="%{release}"
78 export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE
79 RPM_BUILD_ROOT="%{buildroot}"
80 export RPM_BUILD_ROOT
[10]81);
82foreach (`dpkg-architecture`) {
83 s/=(.+)/="$1"/;
84 $scriptletbase .= " $_";
85}
86$scriptletbase .=
87q(
[6]88 set -x
89 umask 022
90 cd %{_topdir}/BUILD
91);
92
[5]93# Package data
94# This is the form of $pkgdata{pkgname}{meta}
95# meta includes Summary, Name, Version, Release, Group, Copyright,
[38]96# Source, URL, Packager, BuildRoot, Description, BuildReq(uires),
97# Requires, Provides
[6]98# 10/31/2005 Maybe this should be flatter? -kgd
[5]99my %pkgdata;
[27]100my @pkglist = ('main'); #sigh
[23]101# Files listing. Embedding this in %pkgdata would be, um, messy.
102my %filelist;
[40]103my $buildreq = '';
[5]104
[6]105# Scriptlets
106my $prepscript;
107my $buildscript;
[23]108# %install doesn't need the full treatment from %clean; just an empty place to install to.
109# NB - rpm doesn't do this; is it really necessary?
110my $installscript = '[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT'."\n";
[7]111my $cleanscript;
[16]112# pre/post (un)install scripts. Note that these will likely barf as-is. :/
113my $preinstscript = '';
114my $postinstscript = '';
115my $preuninstscript = '';
116my $postuninstscript = '';
[6]117
[5]118die "Not enough arguments\n" if #$argv == 0;
119
[13]120# Snag some environment data
121my $tmpdir;
122if (defined $ENV{TMP} && $ENV{TMP} =~ /^(\/var)?\/tmp$/) {
123 $tmpdir = $ENV{TMP};
124} else {
125 $tmpdir = "/var/tmp";
126}
127
[7]128##main
129
[4]130load_userconfig();
[3]131parse_cmd();
132
[7]133if ($cmdopts{type} eq 'b') {
134 # Need to read the spec file to find the tarball. Note that
135 # this also generates most of the shell script required.
136 parse_spec();
[38]137 die "Can't build $pkgdata{main}{name}: build requirements not met.\n"
138 if !checkbuildreq();
[7]139}
140
[35]141# -> srcpkg if -.s
142if ($cmdopts{stage} eq 's') {
143 srcpackage();
144 exit 0;
145}
146
[4]147# Hokay. Need to:
[14]148# -> prep if -.p OR (-.[cilabs] AND !--short-circuit)
[7]149if ($cmdopts{stage} eq 'p' || ($cmdopts{stage} =~ /[cilabs]/ && $cmdopts{short} ne 'y')) {
150 prep();
151}
[14]152# -> build if -.c OR (-.[ilabs] AND !--short-circuit)
[7]153if ($cmdopts{stage} eq 'c' || ($cmdopts{stage} =~ /[ilabs]/ && $cmdopts{short} ne 'y')) {
154 build();
155}
[14]156# -> install if -.[ilabs]
[28]157#if ($cmdopts{stage} eq 'i' || ($cmdopts{stage} =~ /[labs]/ && $cmdopts{short} ne 'y')) {
158if ($cmdopts{stage} =~ /[ilabs]/) {
[7]159 install();
[30]160#foreach my $pkg (@pkglist) {
161# print "files in $pkg:\n ".$filelist{$pkg}."\n";
162#}
163
[7]164}
[14]165# -> binpkg and srcpkg if -.a
[7]166if ($cmdopts{stage} eq 'a') {
[4]167 binpackage();
[7]168 srcpackage();
[4]169}
[14]170# -> binpkg if -.b
[7]171if ($cmdopts{stage} eq 'b') {
172 binpackage();
173}
[4]174
175# Just in case.
176exit 0;
177
178
179## load_userconfig()
180# Loads user configuration (if any)
181# Currently only handles .debmacros
182# Needs to handle "other files"
183sub load_userconfig {
[5]184 my (undef,undef,undef,undef,undef,undef,undef,$homedir,undef) = getpwuid($<);
[4]185 if (-e "$homedir/.debmacros") {
186 open USERMACROS,"<$homedir/.debmacros";
187 while (<USERMACROS>) {
[7]188 # And we also only handle a few macros at the moment.
[4]189 if (/^\%_topdir/) {
[5]190 my (undef,$tmp) = split /\s+/, $_;
191 $topdir = $tmp;
[4]192 }
193 }
194 }
195} # end load_userconfig()
196
197
[3]198## parse_cmd()
[4]199# Parses command line into global hash %cmdopts, other globals
[3]200# Options based on rpmbuild's options
201sub parse_cmd {
202 # Don't feel like coding my own option parser...
203 #use Getopt::Long;
204 # ... but I may have to: (OTOH, rpm uses popt, so maybe we can too.)
205 #use Getopt::Popt qw(:all);
[4]206 # Or not. >:( Stupid Debian lack of findable Perl module names in packages.
[3]207
208 # Stuff it.
[4]209 my $prevopt = '';
[3]210 foreach (@ARGV) {
211 chomp;
[7]212
[3]213 # Is it an option?
214 if (/^-/) {
[7]215
[3]216 # Is it a long option?
217 if (/^--/) {
[4]218 if (/^--short-circuit/) {
219 $cmdopts{short} = 'y';
[5]220 } elsif (/^--rebuild/) {
221 $cmdopts{type} = 's';
[4]222 } else {
223 print "Long opt $_\n";
224 }
[3]225 } else {
[14]226 # Not a long option
[5]227 if (/^-[bt]/) {
228 if ($cmdopts{stage} eq 's') {
229 # Mutually exclusive options.
230 die "Can't use $_ with --rebuild\n";
231 } else {
[14]232 # Capture the type (from "bare" files or tarball) and the stage (prep, build, etc)
[5]233 ($cmdopts{stage}) = (/^-[bt]([pcilabs])/);
234 ($cmdopts{type}) = (/^-([bt])[pcilabs]/);
235 }
[4]236 } elsif (/^-v/) {
237 # bump verbosity. Not sure what I'll actually do here...
238 } else {
239 die "Bad option $_\n";
240 }
[3]241 }
[14]242
243 } else { # Not an option argument
244
[5]245 # --buildroot is the only option that takes an argument
246 # Therefore, any *other* bare arguments are the spec file,
247 # tarball, or source package we're operating on - depending
248 # on which one we meet.
249 if ($prevopt eq '--buildroot') {
[7]250 $cmdbuildroot = $_;
[5]251 } else {
252 if ($cmdopts{type} eq 's') {
253 # Source package
[7]254 if (!/\.src\.(deb|rpm)$/) {
[5]255 die "Can't --rebuild with $_\n";
256 }
257 } elsif ($cmdopts{type} eq 'b') {
258 $specfile = $_;
259 # Spec file
260 } else {
261 # Tarball
262 }
263 }
[3]264 }
[7]265 $prevopt = $_;
266 } # foreach @ARGV
[4]267
268 # Some cross-checks. rpmbuild limits --short-circuit to just
269 # the "compile" and "install" targets - with good reason IMO.
[14]270 # Note that --short-circuit with -.p is not really an error, just redundant.
[4]271 # NB - this is NOT fatal, just ignored!
[10]272 if ($cmdopts{short} eq 'y' && $cmdopts{stage} =~ /[labs]/) {
[4]273 warn "Can't use --short-circuit for $targets{$cmdopts{stage}} stage. Ignoring.\n";
[28]274 $cmdopts{short} = 'n';
[4]275 }
[14]276
[3]277 # Valid options, with example arguments (if any):
278# Build from .spec file; mutually exclusive:
279 # -bp
280 # -bc
281 # -bi
282 # -bl
283 # -ba
284 # -bb
285 # -bs
286# Build from tarball; mutually exclusive:
287 # -tp
288 # -tc
289 # -ti
290 # -ta
291 # -tb
292 # -ts
293# Build from .src.(deb|rpm)
294 # --rebuild
295 # --recompile
296
297# General options
298 # --buildroot=DIRECTORY
299 # --clean
300 # --nobuild
301 # --nodeps
302 # --nodirtokens
303 # --rmsource
304 # --rmspec
305 # --short-circuit
306 # --target=CPU-VENDOR-OS
307
308 #my $popt = new Getopt::Popt(argv => \@ARGV, options => \@optionsTable);
309
310} # end parse_cmd()
311
[4]312
[5]313## parse_spec()
[14]314# Parse the .spec file.
[5]315sub parse_spec {
316 open SPECFILE,"<$specfile";
317
[6]318LINE: while (<SPECFILE>) {
[14]319 next if /^#/; # Ignore comments...
320 next if /^\s+$/; # ... and blank lines.
321
[5]322 if (/^\%/) {
323 # A macro that needs further processing.
[14]324
[23]325 if (/^\%define\s+([^\s]+)\s+([^\s]+)/) {
326 $specglobals{$1} = expandmacros($2,'g');
327 }
328
[27]329 if (/^\%description(?:\s+(?:-n\s+)?([a-zA-Z0-9_.-]+))?/) {
330 my $subname = "main";
331 if ($1) {
332 if (/-n/) { $subname = $1; } else { $subname = "$pkgdata{main}{name}-$1"; }
333 }
[8]334 while (<SPECFILE>) {
[39]335 next if /^#/; # Messy. Should be possible to do better. :/
[8]336 redo LINE if /^\%/;
[27]337 $pkgdata{$subname}{desc} .= " $_";
[8]338 }
[18]339 }
[27]340 if (/^\%package\s+(?:-n\s+)?([a-zA-Z0-9_.-]+)/) {
341 my $subname;
342 if (/-n/) { $subname = $1; } else { $subname = "$pkgdata{main}{name}-$1"; }
343 push @pkglist, $subname;
344 $pkgdata{$subname}{name} = $subname;
345 $pkgdata{$subname}{version} = $pkgdata{main}{version};
346 while (<SPECFILE>) {
347 redo LINE if /^\%/;
[38]348 if (my ($dname,$dvalue) = (/^(Summary|Group|Version|Requires|Provides):\s+(.+)$/i)) {
[27]349 $dname =~ tr/[A-Z]/[a-z]/;
350 $pkgdata{$subname}{$dname} = $dvalue;
351 }
352 }
353 }
[8]354
[6]355 if (/^\%prep/) {
356 # %prep section. May have %setup macro; may include %patch tags,
357 # may be just a bare shell script.
358
359 # This really should be local-ish, but we need just the filename for the source
360 $pkgdata{main}{source} =~ s|.+/([^/]+)$|$1|;
361
362 # Replace some core macros
[14]363 $pkgdata{main}{source} = expandmacros($pkgdata{main}{source},'gp');
[6]364
365PREPSCRIPT: while (<SPECFILE>) {
366 if (/^\%setup/) {
367 # Parse out the %setup macro. Note that we aren't supporting
[14]368 # many of RPM's %setup features.
[7]369 $prepscript .= "cd $topdir/BUILD\n";
370 if ( /\s+-n\s+([^\s]+)\s+/ ) {
371 $tarballdir = $1;
372 } else {
373 $tarballdir = "$pkgdata{main}{name}-$pkgdata{main}{version}";
374 }
[21]375 $prepscript .= "rm -rf $tarballdir\ntar -".
[6]376 ( $pkgdata{main}{source} =~ /\.tar\.gz$/ ? "z" : "" ).
377 ( $pkgdata{main}{source} =~ /\.tar\.bz2$/ ? "j" : "" ).
[21]378 ( /\s+-q\s+/ ? '' : 'vv' )."xf ".
379 "$topdir/SOURCES/$pkgdata{main}{source}\n".
[6]380 qq(STATUS=\$?\nif [ \$STATUS -ne 0 ]; then\n exit \$STATUS\nfi\n).
381 ( /\s+-n\s+([^\s]+)\s+/ ?
382 "cd $1\n" : "cd $pkgdata{main}{name}-$pkgdata{main}{version}\n" ).
383 qq([ `/usr/bin/id -u` = '0' ] && /bin/chown -Rhf root .\n).
384 qq([ `/usr/bin/id -u` = '0' ] && /bin/chgrp -Rhf root .\n).
385 qq(/bin/chmod -Rf a+rX,g-w,o-w .\n);
[10]386 } elsif (/^\%patch([^:]+)\s+(.+)$/) {
387 $prepscript .= "patch $2 <$topdir/SOURCES/".$pkgdata{main}{"patch$1"}."\n";
[6]388 } else {
389 last PREPSCRIPT if /^\%/;
390 $prepscript .= $_;
391 }
392 }
393 redo LINE;
394 }
[12]395 if (/^\%build/) {
[6]396 # %build. This is pretty much just a shell script. There
397 # *are* a few macros, but we're not going to deal with them yet.
[7]398 $buildscript .= "cd $tarballdir\n";
[10]399BUILDSCRIPT: while (<SPECFILE>) {
400 if (/^\%configure/) {
[12]401 $buildscript .= expandmacros($_,'cgbp');
[25]402 } elsif (/^\%\{__make\}/) {
[12]403 $buildscript .= expandmacros($_,'mgbp');
[10]404 } else {
[24]405 last BUILDSCRIPT if /^\%[^{]/;
[10]406 $buildscript .= $_;
407 }
[6]408 }
[10]409 redo LINE;
[5]410 }
[6]411 if (/^\%install/) {
[7]412 $installscript .= "cd $tarballdir\n";
[12]413INSTALLSCRIPT: while (<SPECFILE>) {
414 if (/^\%makeinstall/) {
415 $installscript .= expandmacros($_,'igbp');
416 } else {
417 last INSTALLSCRIPT if /^\%/;
418 $installscript .= $_;
419 }
420 }
421 redo LINE;
[6]422 }
423 if (/^\%clean/) {
[7]424 while (<SPECFILE>) {
425 redo LINE if /^\%/;
426 $cleanscript .= $_;
427 }
[12]428 $cleanscript = expandmacros($cleanscript,'gp');
[6]429 }
[29]430
[16]431 # pre/post (un)install scripts
432 if (/^\%pre\b/) {
433 while (<SPECFILE>) {
434 redo LINE if /^\%/;
435 $preinstscript .= $_;
436 }
[6]437 }
[16]438 if (/^\%post\b/) {
439 while (<SPECFILE>) {
440 redo LINE if /^\%/;
441 $postinstscript .= $_;
442 }
[6]443 }
[16]444 if (/^\%preun\b/) {
445 while (<SPECFILE>) {
446 redo LINE if /^\%/;
447 $preuninstscript .= $_;
448 }
449 }
450 if (/^\%postun\b/) {
451 while (<SPECFILE>) {
452 redo LINE if /^\%/;
453 $postuninstscript .= $_;
454 }
455 }
[29]456 # done %pre/%post scripts
457
[23]458 if (/^\%files(?:\s+(?:-n\s+)?([a-zA-z0-9]+))?/) {
459 my $pkgname = 'main';
[29]460 if ($1) { # Magic to add entries to the right list of files
[24]461 if (/-n/) { $pkgname = $1; } else { $pkgname = "$pkgdata{main}{name}-$1"; }
[23]462 }
[37]463
464 # Set this now, so it can be flipped a bit later, and used much later.
465 #$pkgdata{$pkgname}{conffiles} = 0;
466
[27]467 while (<SPECFILE>) {
[29]468 chomp;
469 # need to update this to deal (properly) with %dir, %attr, etc
470 next if /^\%dir/;
471 next if /^\%attr/;
472 next if /^\%defattr/;
473
[37]474 # Debian dpkg doesn't speak "%docdir". Meh.
475 next if /^\%docdir/;
476
477 # Conffiles. Note that Debian and RH have similar, but not
478 # *quite* identical ideas of what constitutes a conffile. Nrgh.
479 if (/^\%config\s+(.+)$/) {
480 $pkgdata{$pkgname}{conffiles} = 1; # Flag it for later
481 my $tmp = $1; # Now we can mangleificationate it. And we probably need to. :/
482 if ($tmp !~ /\s+/) {
483 # Simplest case, just a file. Whew.
484 push @{$pkgdata{$pkgname}{conflist}}, $tmp;
485 $filelist{$pkgname} .= " $tmp";
486 } else {
487 # Wot? Spaces? That means extra %-macros. Which, for the most part, can be ignored.
488 ($tmp) = ($tmp =~ /.+\s([^\s]+)/); # Strip everything before the last space
489 $tmp = expandmacros($tmp, 'gp'); # Expand common macros
490 push @{$pkgdata{$pkgname}{conflist}}, $tmp;
491 $filelist{$pkgname} .= " $tmp";
492 }
493 next;
494 }
495
[29]496 # and finally we can fall through %{_<FHS>}-prefixed locations...
[30]497 if (/^\%\{_/) {
498 $filelist{$pkgname} .= " $_";
499 next;
500 }
501 # EW. Necessary to clear up %define expansions before we exit with redo.
502 $_ = expandmacros $_, 'g';
[29]503
504 # ... unknown or "next section" % directives ...
[27]505 redo LINE if /^\%/;
[29]506
507 # ... and "normal" files
[27]508 $filelist{$pkgname} .= " $_";
509 }
[30]510 $filelist{$pkgname} = expandmacros($filelist{$pkgname}, 'g');
[29]511 } # done %file section
512
[18]513 if (/^\%changelog/) {
514 $pkgdata{main}{changelog} = '';
515 while (<SPECFILE>) {
516 redo LINE if /^\%/;
517 $pkgdata{main}{changelog} .= $_;
518 }
519 }
[14]520
521 } else { # Data from the spec file "header"
522
[5]523 if (/^summary:\s+(.+)/i) {
524 $pkgdata{main}{summary} = $1;
525 } elsif (/^name:\s+(.+)/i) {
[24]526 $pkgdata{main}{name} = expandmacros($1,'g');
[5]527 } elsif (/^version:\s+(.+)/i) {
[24]528 $pkgdata{main}{version} = expandmacros($1,'g');
[5]529 } elsif (/^release:\s+(.+)/i) {
[24]530 $pkgdata{main}{release} = expandmacros($1,'g');
[5]531 } elsif (/^group:\s+(.+)/i) {
532 $pkgdata{main}{group} = $1;
533 } elsif (/^copyright:\s+(.+)/i) {
534 $pkgdata{main}{copyright} = $1;
535 } elsif (/^url:\s+(.+)/i) {
536 $pkgdata{main}{url} = $1;
537 } elsif (/^packager:\s+(.+)/i) {
538 $pkgdata{main}{packager} = $1;
[7]539 } elsif (/^buildroot:\s+(.+)/i) {
540 $buildroot = $1;
[5]541 } elsif (/^source:\s+(.+)/i) {
542 $pkgdata{main}{source} = $1;
[6]543 die "Unknown tarball format $1\n" if $1 !~ /\.tar\.(?:gz|bz2)$/;
[15]544 } elsif (/^source([0-9]+):\s+(.+)/i) {
545 $pkgdata{sources}{$1} = $2;
[10]546 } elsif (/^patch([^:]+):\s+(.+)$/i) {
[26]547 my $patchname = "patch$1";
548 $pkgdata{main}{$patchname} = $2;
549 if ($pkgdata{main}{$patchname} =~ /\//) {
550 # URL-style patch. Rare but not unheard-of.
551 my @patchbits = split '/', $pkgdata{main}{$patchname};
552 $pkgdata{main}{$patchname} = $patchbits[$#patchbits];
553 }
[38]554 } elsif (/^buildreq(?:uires)?:\s+(.+)/i) {
555 $buildreq .= ", $1";
556 } elsif (/^requires:\s+(.+)/i) {
557 $pkgdata{main}{requires} .= ", $1";
558 } elsif (/^provides:\s+(.+)/i) {
559 $pkgdata{main}{provides} .= ", $1";
[5]560 }
561#Name: suwrap
562#Version: 0.04
563#Release: 3
564#Group: Applications/System
565#Copyright: WebHart internal ONLY. :(
566#BuildArchitectures: i386
567#BuildRoot: /tmp/%{name}-%{version}
568#Url: http://virtual.webhart.net
569#Packager: Kris Deugau <kdeugau@deepnet.cx>
570#Source: ftp://virtual.webhart.net/%{name}-%{version}.tar.gz
571
572 }
573 }
[7]574
[14]575 # Parse and replace some more macros. More will be replaced even later.
576
[10]577 # Expand macros as necessary.
[12]578 $scriptletbase = expandmacros($scriptletbase,'gp');
[7]579
580 $buildroot = $cmdbuildroot if $cmdbuildroot;
[12]581 $buildroot = expandmacros($buildroot,'gp');
[7]582
[16]583 close SPECFILE;
[5]584} # end parse_spec()
585
586
[7]587## prep()
[14]588# Writes and executes the %prep script (mostly) built while reading the spec file.
[7]589sub prep {
[10]590 # Replace some things here just to make sure.
[12]591 $prepscript = expandmacros($prepscript,'gp');
[10]592
[24]593#print $prepscript; exit 0;
[23]594
[10]595 # create script filename
[13]596 my $prepscriptfile = "$tmpdir/deb-tmp.prep.".int(rand(99998)+1);
[10]597 sysopen(PREPSCRIPT, $prepscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
[7]598 or die $!;
[10]599 print PREPSCRIPT $scriptletbase;
600 print PREPSCRIPT $prepscript;
601 close PREPSCRIPT;
[7]602
[10]603 # execute
604 print "Calling \%prep script $prepscriptfile...\n";
605 system("/bin/sh -e $prepscriptfile") == 0
[14]606 or die "Can't exec: $!\n";
[7]607
[10]608 # and clean up
609 unlink $prepscriptfile;
[7]610} # end prep()
611
612
[5]613## build()
[14]614# Writes and executes the %build script (mostly) built while reading the spec file.
[5]615sub build {
[12]616 # Expand the macros
617 $buildscript = expandmacros($buildscript,'cgbp');
618
[7]619 # create script filename
[13]620 my $buildscriptfile = "$tmpdir/deb-tmp.build.".int(rand(99998)+1);
[7]621 sysopen(BUILDSCRIPT, $buildscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
622 or die $!;
623 print BUILDSCRIPT $scriptletbase;
624 print BUILDSCRIPT $buildscript;
625 close BUILDSCRIPT;
626
627 # execute
628 print "Calling \%build script $buildscriptfile...\n";
629 system("/bin/sh -e $buildscriptfile") == 0
[14]630 or die "Can't exec: $!\n";
[7]631
632 # and clean up
633 unlink $buildscriptfile;
[5]634} # end build()
635
636
[7]637## install()
[14]638# Writes and executes the %install script (mostly) built while reading the spec file.
[7]639sub install {
[12]640 # Expand the macros
641 $installscript = expandmacros($installscript,'igbp');
642
[7]643 # create script filename
[13]644 my $installscriptfile = "$tmpdir/deb-tmp.inst.".int(rand(99998)+1);
[7]645 sysopen(INSTSCRIPT, $installscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
646 or die $!;
647 print INSTSCRIPT $scriptletbase;
[23]648# print INSTSCRIPT $cleanscript; # Clean up our install target before installing into it.
[7]649 print INSTSCRIPT $installscript;
650 close INSTSCRIPT;
651
652 # execute
653 print "Calling \%install script $installscriptfile...\n";
654 system("/bin/sh -e $installscriptfile") == 0
[14]655 or die "Can't exec: $!\n";
[7]656
657 # and clean up
658 unlink $installscriptfile;
659} # end install()
660
661
[8]662## binpackage()
663# Creates the binary .deb package from the installed tree in $buildroot.
[14]664# Writes and executes a shell script to do so.
665# Creates miscellaneous files required by dpkg-deb to actually build the package file.
[27]666# Should handle simple subpackages
[8]667sub binpackage {
[14]668 # Make sure we have somewhere to write the .deb file
[9]669 if (!-e "$topdir/DEBS/i386") {
670 mkdir "$topdir/DEBS/i386";
671 }
[14]672
[27]673 foreach my $pkg (@pkglist) {
[8]674
[27]675 # Gotta do this first, otherwise we don't have a place to move files from %files
676 mkdir "$buildroot/$pkg";
[28]677
[30]678 # Eliminate any lingering % macros
679 $filelist{$pkg} = expandmacros $filelist{$pkg}, 'g';
680
[27]681 my @pkgfilelist = split ' ', $filelist{$pkg};
682 foreach my $pkgfile (@pkgfilelist) {
[37]683 $pkgfile = expandmacros($pkgfile, 'gp');
[31]684 my @filepath = ($pkgfile =~ m|(.+)/([^/]+)$|);
[27]685 qx { mkdir -p $buildroot/$pkg$filepath[0] }
686 if $filepath[0] ne '';
687 qx { mv $buildroot$pkgfile $buildroot/$pkg$filepath[0] };
688 }
[28]689
[38]690 # Get the "Depends" (Requires) a la RPM. Ish. We strip the leading
691 # comma and space here (if needed) in case there were "Requires" specified
692 # in the spec file - those would precede these.
693 ($pkgdata{$pkg}{depends} .= getreqs("$buildroot/$pkg")) =~ s/^, //;
694
695 # Do this here since we're doing {depends}...
[41]696 if (defined($pkgdata{$pkg}{provides})) {
697 $pkgdata{$pkg}{provides} =~ s/^, //;
698 $pkgdata{$pkg}{provides} = expandmacros($pkgdata{$pkg}{provides},'gp');
699 }
[38]700
[27]701 # Gotta do this next, otherwise the control file has nowhere to go. >:(
702 mkdir "$buildroot/$pkg/DEBIAN";
703
[33]704 # Hack the filename for the package into a Debian-tool-compatible format. GRRRRRR!!!!!
705 # Have I mentioned I hate Debian Policy?
706 $pkgdata{$pkg}{name} =~ tr/_/-/;
707
[27]708 # create script filename
709 my $debscriptfile = "$tmpdir/deb-tmp.pkg.".int(rand(99998)+1);
710 sysopen(DEBSCRIPT, $debscriptfile, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW)
[8]711 or die $!;
[27]712 print DEBSCRIPT $scriptletbase;
713 print DEBSCRIPT "fakeroot dpkg-deb -b $buildroot/$pkg $topdir/DEBS/i386/".
714 "$pkgdata{$pkg}{name}_$pkgdata{$pkg}{version}-$pkgdata{main}{release}_i386.deb\n";
715 # %$&$%@#@@#%@@@ Debian and their horrible ugly package names. >:(
716 close DEBSCRIPT;
[8]717
[27]718 my $control = "Package: $pkgdata{$pkg}{name}\n".
719 "Version: $pkgdata{$pkg}{version}-$pkgdata{main}{release}\n".
720 "Section: $pkgdata{$pkg}{group}\n".
[8]721 "Priority: optional\n".
722 "Architecture: i386\n".
723 "Maintainer: $pkgdata{main}{packager}\n".
[41]724 ( $pkgdata{$pkg}{depends} ne '' ? "Depends: $pkgdata{$pkg}{depends}\n" : '' ).
[39]725 ( defined($pkgdata{$pkg}{provides}) ? "Provides: $pkgdata{$pkg}{provides}\n" : '' ).
[27]726 "Description: $pkgdata{$pkg}{summary}\n";
727 $control .= "$pkgdata{$pkg}{desc}\n";
[8]728
[27]729 open CONTROL, ">$buildroot/$pkg/DEBIAN/control";
730 print CONTROL $control;
731 close CONTROL;
[8]732
[37]733 # Iff there are conffiles (as specified in the %files list(s), add'em
734 # in so dpkg-deb can tag them.
735 if ($pkgdata{$pkg}{conffiles}) {
736 open CONFLIST, ">$buildroot/$pkg/DEBIAN/conffiles";
737 foreach my $conffile (@{$pkgdata{$pkg}{conflist}}) {
738 print CONFLIST "$conffile\n";
739 }
740 close CONFLIST;
741 }
742
[32]743 # Can't see much point in scripts on subpackages... although since
744 # it's *possible* I should support it at some point.
745 if ($pkg eq 'main') {
746 if ($preinstscript ne '') {
[34]747 $preinstscript = expandmacros($preinstscript,'g');
[32]748 open PREINST, ">$buildroot/$pkg/DEBIAN/preinst";
749 print PREINST "#!/bin/sh\nset -e\n\n";
750 print PREINST $preinstscript;
751 close PREINST;
752 `chmod 0755 $buildroot/$pkg/DEBIAN/preinst`;
753 }
754 if ($postinstscript ne '') {
[34]755 $postinstscript = expandmacros($postinstscript,'g');
[32]756 open POSTINST, ">$buildroot/$pkg/DEBIAN/postinst";
757 print POSTINST "#!/bin/sh\nset -e\n\n";
758 print POSTINST $postinstscript;
759 close POSTINST;
760 `chmod 0755 $buildroot/$pkg/DEBIAN/postinst`;
761 }
762 if ($preuninstscript ne '') {
[34]763 $preuninstscript = expandmacros($preuninstscript,'g');
[32]764 open PREUNINST, ">$buildroot/$pkg/DEBIAN/prerm";
765 print PREUNINST "#!/bin/sh\nset -e\n\n";
766 print PREUNINST $preuninstscript;
767 close PREUNINST;
768 `chmod 0755 $buildroot/$pkg/DEBIAN/prerm`;
769 }
770 if ($postuninstscript ne '') {
[34]771 $postuninstscript = expandmacros($postuninstscript,'g');
[32]772 open POSTUNINST, ">$buildroot/$pkg/DEBIAN/postrm";
773 print POSTUNINST "#!/bin/sh\nset -e\n\n";
774 print POSTUNINST $postuninstscript;
775 close POSTUNINST;
776 `chmod 0755 $buildroot/$pkg/DEBIAN/postrm`;
777 }
[27]778 }
[16]779
[27]780 # execute
781 print "Calling package creation script $debscriptfile for $pkgdata{$pkg}{name}...\n";
782 system("/bin/sh -e $debscriptfile") == 0
[14]783 or die "Can't exec: $!\n";
[8]784
[27]785 # and clean up
786 unlink $debscriptfile;
787
788 } # subpackage loop
789
[8]790} # end binpackage()
791
792
[35]793## srcpackage()
794# Builds a .src.deb source package. Note that Debian's idea of
795# a "source package" is seriously flawed IMO, because you can't
796# easily copy it as-is.
[36]797# Not quite identical to RPM, but Good Enough (TM).
[35]798sub srcpackage {
[36]799 my $pkgsrcname = "$pkgdata{main}{name}-$pkgdata{main}{version}-$pkgdata{main}{release}.sdeb";
800
801 my $paxcmd;
802
803 # We'll definitely need this later, and *may* need it sooner.
804 (my $barespec = $specfile) =~ s|.+/([^/]+)$|$1|;
805
806 # Copy the specfile to the build tree, but only if it's not there already.
807##buglet: need to deal with silly case where silly user has put the spec
808# file in a subdir of %{_topdir}/SPECS. Ewww. Silly user!
809 if (abs_path($specfile) !~ /^$topdir\/SPECS/) {
810 $paxcmd .= "cp $specfile %{_topdir}/SPECS/; \n"
811 }
812
[35]813 # use pax -w [file] [file] ... >outfile.sdeb
[36]814 $paxcmd = "cd $topdir; pax -w ";
[10]815
[35]816# tweak source entry into usable form. Need it locally somewhere along the line.
817 (my $pkgsrc = $pkgdata{main}{source}) =~ s|.+/([^/]+)$|$1|;
[36]818 $paxcmd .= "SOURCES/$pkgsrc ";
[10]819
[35]820 # create file list: Source[nn], Patch[nn]
821 foreach my $specbit (keys %{$pkgdata{main}} ) {
822 next if $specbit eq 'source';
[36]823 $paxcmd .= "SOURCES/$pkgdata{main}{$specbit} " if $specbit =~ /^(source|patch)/;
824##buglet: need to deal with case where patches are listed as URLs?
825# or other extended pathnames? Silly !@$%^&!%%!%!! user!
[35]826 }
827
[36]828 # add the spec file, source package destination, and cd back where we came from.
829 $paxcmd .= "SPECS/$barespec > $topdir/SDEBS/$pkgsrcname; cd -";
[35]830
[36]831 # In case of %-macros...
[35]832 $paxcmd = expandmacros($paxcmd,'gp');
833
[36]834 system "$paxcmd";
835 print "Wrote source package $pkgsrcname in $topdir/SDEBS.\n";
[35]836}
837
838
[38]839## checkbuildreq()
840# Checks the build requirements (if any)
841# Spits out a rude warning and returns a true-false error if any
842# requirements are not met.
843sub checkbuildreq {
[40]844 return 1 if $buildreq eq ''; # No use doing extra work.
[38]845
846 my $reqflag = 1; # unset iff a buildreq is missing
847
848 $buildreq =~ s/^, //; # Strip the leading comma and space
849 my @reqlist = split /,\s+/, $buildreq;
850
851 foreach my $req (@reqlist) {
852 my ($pkg,$rel,$ver);
853
854 # We have two classes of requirements - versioned and unversioned.
855 if ($req =~ /[><=]/) {
856 # Pick up the details of versioned buildreqs
857 ($pkg,$rel,$ver) = ($req =~ /([a-z0-9._-]+)\s+([><=]+)\s+([a-z0-9._-]+)/);
858 } else {
859 # And the unversioned ones.
860 $pkg = $req;
861 $rel = '>=';
862 $ver = 0;
863 }
864
865 my @pkglist = qx { dpkg-query --showformat '\${status}\t\${version}\n' -W $pkg };
866# need to check if no lines returned - means a bad buildreq
867 my ($reqstat,undef,undef,$reqver) = split /\s+/, $pkglist[0];
868 if ($reqstat !~ /install/) {
869 print " * Missing build-dependency $pkg!\n";
870 $reqflag = 0;
871 } else {
872# gotta be a better way to do this... :/
873 if ($rel eq '>=' && !($reqver ge $ver)) {
874 print " * Buildreq $pkg is installed, but wrong version ($reqver): Need $ver\n";
875 $reqflag = 0;
876 }
877 if ($rel eq '>' && !($reqver gt $ver)) {
878 print " * Buildreq $pkg is installed, but wrong version ($reqver): Need $ver\n";
879 $reqflag = 0;
880 }
881 if ($rel eq '<=' && !($reqver le $ver)) {
882 print " * Buildreq $pkg is installed, but wrong version ($reqver): Need $ver\n";
883 $reqflag = 0;
884 }
885 if ($rel eq '<' && !($reqver lt $ver)) {
886 print " * Buildreq $pkg is installed, but wrong version ($reqver): Need $ver\n";
887 $reqflag = 0;
888 }
889 if ($rel eq '=' && !($reqver eq $ver)) {
890 print " * Buildreq $pkg is installed, but wrong version ($reqver): Need $ver\n";
891 $reqflag = 0;
892 }
893 } # end not installed/installed check
894 } # end req loop
895
896 return $reqflag;
897} # end checkbuildreq()
898
899
900## getreqs()
901# Find out which libraries/packages are required for any
902# executables and libs in a given file tree.
903# (Debian doesn't have soname-level deps; just package-level)
[41]904# Returns an empty string if the tree contains no binaries.
905# Doesn't work well on shell scripts. but those *should* be
906# fine anyway. (Yeah, right...)
[38]907sub getreqs() {
908 my $pkgtree = $_[0];
909
[39]910 print "Checking library requirements...\n";
[41]911 my @binlist = qx { find $pkgtree -type f -perm 755 | grep -v $pkgtree/etc };
[38]912
[41]913 if (scalar(@binlist) == 0) {
914 return '';
915 }
916
917 my @reqlist;
918 foreach (@binlist) {
919 push @reqlist, qx { ldd $_ };
920 }
921
922 # Get the list of libs provided by this package. Still doesn't
923 # handle the case where the lib gets stuffed into a subpackage. :/
924 my @intprovlist = qx { find $pkgtree -type f -name "*.so*" };
925 my $provlist = '';
926 foreach (@intprovlist) {
927 s/$pkgtree//;
928 $provlist .= "$_";
929 }
930
[38]931 my %reqs;
932 my $reqlibs;
933
934 foreach (@reqlist) {
935 next if /^$pkgtree/;
[41]936 next if m|/lib/ld-linux.so|; # Hack! Hack! PTHBTT! (libc suxx0rz)
[38]937
[41]938 my ($req) = (/^\s+([a-z0-9._-]+)/); # dig out the actual library (so)name
939
940 # Ignore libs provided by this package. Note that we don't match
941 # on word-boundary at the *end* of the lib we're looking for, as the
942 # looked-for lib may not have the full soname version. (ie, it may
943 # "just" point to one of the symlinks that get created somewhere.)
944 next if $provlist =~ /\b$req/;
945
[38]946 $reqlibs .= " $req";
947 }
948
949 foreach (qx { dpkg -S $reqlibs }) {
950 my ($libpkg,undef) = split /:\s+/;
951 $reqs{$libpkg} = 1;
952 }
953
954 my $deplist;
955 foreach (keys %reqs) {
956 $deplist .= ", $_";
957 }
958
959# For now, we're done. We're not going to meddle with versions yet.
960# Among other things, it's messier than handling "simple" yes/no "do
961# we have this lib?" deps. >:(
962
963 return $deplist;
964} # end getreqs()
965
966
[10]967## expandmacros()
968# Expands all %{blah} macros in the passed string
[14]969# Split up a bit with some sections so we don't spend time trying to
970# expand macros that are only used in a few specific places.
[10]971sub expandmacros {
972 my $macrostring = shift;
[14]973 my $section = shift;
[10]974
[25]975 # To allow the FHS-ish %configure and %makeinstall to work The Right Way.
[12]976 # (Without clobbering the global $buildroot.)
977 my $prefix = '';
978
[11]979 if ($section =~ /c/) {
[12]980 # %configure macro
[17]981# Don't know what it's for, don't have a useful default replacement
982# --program-prefix=%{_program_prefix} \
983 $macrostring =~ s'%configure'./configure --host=$DEB_HOST_GNU_TYPE \
984 --build=$DEB_BUILD_GNU_TYPE \
985 --prefix=%{_prefix} \
986 --exec-prefix=%{_exec_prefix} \
987 --bindir=%{_bindir} \
988 --sbindir=%{_sbindir} \
989 --sysconfdir=%{_sysconfdir} \
990 --datadir=%{_datadir} \
991 --includedir=%{_includedir} \
992 --libdir=%{_libdir} \
993 --libexecdir=%{_libexecdir} \
994 --localstatedir=%{_localstatedir} \
995 --sharedstatedir=%{_sharedstatedir} \
996 --mandir=%{_mandir} \
997 --infodir=%{_infodir} ';
[12]998 } # done %configure
999
1000 if ($section =~ /m/) {
1001 $macrostring =~ s'%{__make}'make ';
[25]1002 } # done make
[12]1003
1004 if ($section =~ /i/) {
1005 # This is where we need to mangle $prefix.
[24]1006 $macrostring =~ s'%makeinstall'make %{fhs} install';
[12]1007 $prefix = $buildroot;
1008 } # done %install and/or %makeinstall
1009
1010 # Build data
1011 # Note that these are processed in reverse order to get the substitution order right
1012 if ($section =~ /b/) {
[24]1013# $macrostring =~ s'%{fhs}'host=$DEB_HOST_GNU_TYPE \
1014# build=$DEB_BUILD_GNU_TYPE \
1015 $macrostring =~ s'%{fhs}'prefix=%{_prefix} \
[17]1016 exec-prefix=%{_exec_prefix} \
1017 bindir=%{_bindir} \
1018 sbindir=%{_sbindir} \
1019 sysconfdir=%{_sysconfdir} \
1020 datadir=%{_datadir} \
1021 includedir=%{_includedir} \
1022 libdir=%{_libdir} \
1023 libexecdir=%{_libexecdir} \
1024 localstatedir=%{_localstatedir} \
1025 sharedstatedir=%{_sharedstatedir} \
1026 mandir=%{_mandir} \
1027 infodir=%{_infodir} \
1028';
[10]1029
1030 # Note that the above regex terminates with the extra space
[12]1031 # "Just In Case" of user additions, which will then get neatly
1032 # tagged on the end where they take precedence (supposedly)
1033 # over the "default" ones.
[10]1034
[14]1035 # Now we cascade the macros introduced above. >_<
1036 # Wot ot to go theah:
1037 $macrostring =~ s|%{_mandir}|%{_datadir}/man|g; #/usr/share/man
1038 $macrostring =~ s|%{_infodir}|%{_datadir}/info|g; #/usr/share/info
[25]1039 $macrostring =~ s|%{_oldincludedir}|/usr/include|g; #/usr/include
1040 $macrostring =~ s|%{_includedir}|%{_prefix\}/include|g; #/usr/include
1041 $macrostring =~ s|%{_libdir}|%{_exec_prefix}/%{_lib}|g; #/usr/lib
[14]1042 $macrostring =~ s|%{_lib}|lib|g; #?
[25]1043 $macrostring =~ s|%{_localstatedir}|/var|g; #/var
1044 $macrostring =~ s|%{_sharedstatedir}|%{_prefix}/com|g; #/usr/com WTF?
1045 $macrostring =~ s|%{_sysconfdir}|/etc|g; #/etc
1046 $macrostring =~ s|%{_datadir}|%{_prefix}/share|g; #/usr/share
1047 $macrostring =~ s|%{_libexecdir}|%{_exec_prefix}/libexec|g; #/usr/libexec
1048 $macrostring =~ s|%{_sbindir}|%{_exec_prefix}/sbin|g; #/usr/sbin
1049 $macrostring =~ s|%{_bindir}|%{_exec_prefix}/bin|g; #/usr/bin
1050 $macrostring =~ s|%{_exec_prefix}|%{_prefix}|g; #/usr
[14]1051 $macrostring =~ s|%{_prefix}|/usr|g; #/usr
[10]1052 } # done with config section
1053
[12]1054 # Package data
1055 if ($section =~ /p/) {
[15]1056 $macrostring =~ s/\%\{buildroot\}/$buildroot/gi;
1057 foreach my $source (keys %{$pkgdata{sources}}) {
1058 $macrostring =~ s/\%\{source$source\}/$topdir\/SOURCES\/$pkgdata{sources}{$source}/gi;
1059 }
1060 $macrostring =~ s/\%\{name\}/$pkgdata{main}{name}/gi;
1061 $macrostring =~ s/\%\{version\}/$pkgdata{main}{version}/gi;
1062 $macrostring =~ s/\%\{release\}/$pkgdata{main}{release}/gi;
[12]1063 }
1064
1065 # Globals, and not-so-globals
1066 if ($section =~ /g/) {
[29]1067 $macrostring =~ s|%{_builddir}|%{_topdir}/BUILD|g;
1068 $macrostring =~ s|%{_topdir}|$topdir|g;
[13]1069 $macrostring =~ s|%{_tmppath}|$tmpdir|g;
[12]1070 $macrostring =~ s'%{_docdir}'/usr/share/doc'g;
[23]1071
[31]1072 # Standard FHS locations. More or less.
[30]1073 $macrostring =~ s'%{_bindir}'/usr/bin'g;
[31]1074 $macrostring =~ s'%{_sbindir}'/usr/sbin'g;
[30]1075 $macrostring =~ s'%{_mandir}'/usr/share/man'g;
1076 $macrostring =~ s'%{_includedir}'/usr/include'g;
[31]1077 $macrostring =~ s'%{_libdir}'/usr/lib'g;
1078 $macrostring =~ s'%{_sysconfdir}'/etc'g;
1079 $macrostring =~ s'%{_localstatedir}'/var'g;
[30]1080
[23]1081 # %define's
1082 foreach my $key (keys %specglobals) {
1083 $macrostring =~ s|%{$key}|$specglobals{$key}|g;
1084 }
1085
1086 # system programs. RPM uses a global config file for these; we'll just
1087 # ASS-U-ME and make life a little simpler.
1088 if ($macrostring =~ /\%\{\_\_([a-z0-9_-]+)\}/) {
1089 $macrostring =~ s|%{__([a-z0-9_-]+)}|$1|g;
1090 }
[10]1091 } # done with globals section
1092
1093 return $macrostring;
1094} # end expandmacros()
[22]1095
1096
1097
[38]1098__END__
1099
1100
1101
[22]1102=head1 NAME
1103
1104debbuild - Build Debian-compatible packages from RPM spec files
1105
1106=head1 SYNOPSIS
1107
1108 debbuild {-ba|-bb|-bp|-bc|-bi|-bl|-bs} [build-options] file.spec
1109
1110 debbuild {-ta|-tb|-tp|-tc|-ti|-tl|-ts} [build-options] file.tar.{gz|bz2}
1111
1112 debbuild --rebuild file.src.{rpm|deb}
1113
1114=head1 DESCRIPTION
1115
1116This script attempts to build Debian-friendly semi-native packages
1117from RPM spec files, RPM-friendly tarballs, and RPM source packages
1118(.src.rpm). It accepts I<most> of the options rpmbuild does, and
1119should be able to interpret most spec files usefully. Perl modules
1120should be handled via CPAN+dh-make-perl instead; Debian's conventions
1121for such things do not lend themselves to automated conversion.
1122
1123As far as possible, the command-line options are identical to those
1124from rpmbuild, although several rpmbuild options are not supported.
1125
1126=cut
Note: See TracBrowser for help on using the repository browser.