source: trunk/debbuild@ 101

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

/trunk

Clean up end-of-section detection: Check for %[a-z] rather than just %
to avoid tripping on macros at the beginning of lines in a section.

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