source: trunk/debbuild@ 98

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

/trunk

Further expand support for %if constructs - a == b and other
logical structures are now supported

  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author
File size: 50.4 KB
Line 
1#!/usr/bin/perl -w
2# debbuild script
3# Shamelessly steals interface from rpm's "rpmbuild" to create
4# Debian packages. Please note that such packages are highly
5# unlikely to conform to "Debian Policy".
6###
7# SVN revision info
8# $Date: 2007-05-11 17:49:18 +0000 (Fri, 11 May 2007) $
9# SVN revision $Rev: 98 $
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 .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 /^\%/;
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 /^\%/;
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 /^\%/;
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 /^\%/;
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 /^\%/;
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 /^\%/;
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
1231 my ($req) = (/^\s+([a-z0-9._-]+)/); # dig out the actual library (so)name
1232
1233 # Ignore libs provided by this package. Note that we don't match
1234 # on word-boundary at the *end* of the lib we're looking for, as the
1235 # looked-for lib may not have the full soname version. (ie, it may
1236 # "just" point to one of the symlinks that get created somewhere.)
1237 next if $provlist =~ /\b$req/;
1238
1239 $reqlibs .= " $req";
1240 }
1241
1242 if ($reqlibs ne '') {
1243 foreach (qx { dpkg -S $reqlibs }) {
1244 my ($libpkg,undef) = split /:\s+/;
1245 $reqs{$libpkg} = 1;
1246 }
1247 }
1248
1249 my $deplist = '';
1250 foreach (keys %reqs) {
1251 $deplist .= ", $_";
1252 }
1253
1254# For now, we're done. We're not going to meddle with versions yet.
1255# Among other things, it's messier than handling "simple" yes/no "do
1256# we have this lib?" deps. >:(
1257
1258 return $deplist;
1259} # end getreqs()
1260
1261
1262## install_sdeb()
1263# Extracts .sdeb contents to %_topdir as appropriate
1264sub install_sdeb {
1265 $srcpkg = abs_path($srcpkg);
1266
1267 my $paxcmd = "cd $topdir; pax -r <$srcpkg; cd -";
1268
1269 # In case of %-macros...
1270 $paxcmd = expandmacros($paxcmd,'gp');
1271
1272 system "$paxcmd";
1273 print "Extracted source package $srcpkg to $topdir.\n";
1274} # end install_sdeb()
1275
1276
1277## expandmacros()
1278# Expands all %{blah} macros in the passed string
1279# Split up a bit with some sections so we don't spend time trying to
1280# expand macros that are only used in a few specific places.
1281sub expandmacros {
1282 my $macrostring = shift;
1283 my $section = shift;
1284
1285 # To allow the FHS-ish %configure and %makeinstall to work The Right Way.
1286 # (Without clobbering the global $buildroot.)
1287 my $prefix = '';
1288
1289 if ($section =~ /c/) {
1290 # %configure macro
1291# Don't know what it's for, don't have a useful default replacement
1292# --program-prefix=%{_program_prefix} \
1293 $macrostring =~ s'%configure'./configure --host=$DEB_HOST_GNU_TYPE \
1294 --build=$DEB_BUILD_GNU_TYPE \
1295 --prefix=%{_prefix} \
1296 --exec-prefix=%{_exec_prefix} \
1297 --bindir=%{_bindir} \
1298 --sbindir=%{_sbindir} \
1299 --sysconfdir=%{_sysconfdir} \
1300 --datadir=%{_datadir} \
1301 --includedir=%{_includedir} \
1302 --libdir=%{_libdir} \
1303 --libexecdir=%{_libexecdir} \
1304 --localstatedir=%{_localstatedir} \
1305 --sharedstatedir=%{_sharedstatedir} \
1306 --mandir=%{_mandir} \
1307 --infodir=%{_infodir} ';
1308 } # done %configure
1309
1310 if ($section =~ /m/) {
1311 $macrostring =~ s'%{__make}'make ';
1312 } # done make
1313
1314 if ($section =~ /i/) {
1315 # This is where we need to mangle $prefix.
1316 $macrostring =~ s'%makeinstall'make %{fhs} install';
1317 $prefix = $buildroot;
1318 } # done %install and/or %makeinstall
1319
1320 # Build data
1321 # Note that these are processed in reverse order to get the substitution order right
1322 if ($section =~ /b/) {
1323# $macrostring =~ s'%{fhs}'host=$DEB_HOST_GNU_TYPE \
1324# build=$DEB_BUILD_GNU_TYPE \
1325 $macrostring =~ s'%{fhs}'prefix=%{_prefix} \
1326 exec-prefix=%{_exec_prefix} \
1327 bindir=%{_bindir} \
1328 sbindir=%{_sbindir} \
1329 sysconfdir=%{_sysconfdir} \
1330 datadir=%{_datadir} \
1331 includedir=%{_includedir} \
1332 libdir=%{_libdir} \
1333 libexecdir=%{_libexecdir} \
1334 localstatedir=%{_localstatedir} \
1335 sharedstatedir=%{_sharedstatedir} \
1336 mandir=%{_mandir} \
1337 infodir=%{_infodir} \
1338';
1339
1340 # Note that the above regex terminates with the extra space
1341 # "Just In Case" of user additions, which will then get neatly
1342 # tagged on the end where they take precedence (supposedly)
1343 # over the "default" ones.
1344
1345 # Now we cascade the macros introduced above. >_<
1346 # Wot ot to go theah:
1347 $macrostring =~ s|%{_mandir}|%{_datadir}/man|g; #/usr/share/man
1348 $macrostring =~ s|%{_infodir}|%{_datadir}/info|g; #/usr/share/info
1349 $macrostring =~ s|%{_oldincludedir}|/usr/include|g; #/usr/include
1350 $macrostring =~ s|%{_includedir}|%{_prefix}/include|g; #/usr/include
1351 $macrostring =~ s|%{_libdir}|%{_exec_prefix}/%{_lib}|g; #/usr/lib
1352 $macrostring =~ s|%{_lib}|lib|g; #?
1353 $macrostring =~ s|%{_localstatedir}|/var|g; #/var
1354 $macrostring =~ s|%{_sharedstatedir}|%{_prefix}/com|g; #/usr/com WTF?
1355 $macrostring =~ s|%{_sysconfdir}|/etc|g; #/etc
1356 $macrostring =~ s|%{_datadir}|%{_prefix}/share|g; #/usr/share
1357 $macrostring =~ s|%{_libexecdir}|%{_exec_prefix}/libexec|g; #/usr/libexec
1358 $macrostring =~ s|%{_sbindir}|%{_exec_prefix}/sbin|g; #/usr/sbin
1359 $macrostring =~ s|%{_bindir}|%{_exec_prefix}/bin|g; #/usr/bin
1360 $macrostring =~ s|%{_exec_prefix}|%{_prefix}|g; #/usr
1361 $macrostring =~ s|%{_prefix}|/usr|g; #/usr
1362 } # done with config section
1363
1364 # Package data
1365 if ($section =~ /p/) {
1366 $macrostring =~ s/\%\{buildroot\}/$buildroot/gi;
1367 foreach my $source (keys %{$pkgdata{sources}}) {
1368 $macrostring =~ s/\%\{source$source\}/$topdir\/SOURCES\/$pkgdata{sources}{$source}/gi;
1369 }
1370 $macrostring =~ s/\%\{name\}/$pkgdata{main}{name}/gi;
1371 $macrostring =~ s/\%\{version\}/$pkgdata{main}{version}/gi;
1372 $macrostring =~ s/\%\{release\}/$pkgdata{main}{release}/gi;
1373 }
1374
1375 # Globals, and not-so-globals
1376 if ($section =~ /g/) {
1377
1378 $macrostring =~ s|%{_builddir}|%{_topdir}/BUILD|g;
1379 $macrostring =~ s|%{_topdir}|$topdir|g;
1380 $macrostring =~ s|%{_tmppath}|$tmpdir|g;
1381 $macrostring =~ s'%{_docdir}'%{_datadir}/doc'g;
1382
1383 # Standard FHS locations. More or less.
1384 $macrostring =~ s'%{_bindir}'/usr/bin'g;
1385 $macrostring =~ s'%{_sbindir}'/usr/sbin'g;
1386 $macrostring =~ s'%{_mandir}'%{_datadir}/man'g;
1387 $macrostring =~ s'%{_includedir}'/usr/include'g;
1388 $macrostring =~ s'%{_libdir}'/usr/lib'g;
1389 $macrostring =~ s'%{_sysconfdir}'/etc'g;
1390 $macrostring =~ s'%{_localstatedir}'/var'g;
1391
1392 # FHS-ish locations that aren't quite actually FHS-specified.
1393 $macrostring =~ s'%{_datadir}'/usr/share'g;
1394
1395 # %define's
1396 foreach my $key (keys %specglobals) {
1397 $macrostring =~ s|%{$key}|$specglobals{$key}|g;
1398 }
1399
1400 # special %define's. Handle the general case where we eval anything.
1401 # Even more general: %(...) is a spec-parse-time shell code wrapper.
1402 # Prime example:
1403 #%define perl_vendorlib %(eval "`perl -V:installvendorlib`"; echo $installvendorlib)
1404 if ($macrostring =~ /\%\((.+)\)/) {
1405 my $shellstr = $1;
1406 # Oy vey this gets silly for the perl bits. Executing a shell to
1407 # call Perl to get the vendorlib/sitelib/whatever "core" globals.
1408 # This can do more, but... eww.
1409 $shellstr = qx { /bin/sh -c '$shellstr' }; # Yay! ' characters apparently get properly exscapededed.
1410 $macrostring =~ s/\%\(.+\)/$shellstr/;
1411 }
1412
1413 # support for **some** %if constructs. Note that this breaks somewhat if
1414 # there's no value specified... but so does rpm.
1415 while ($macrostring =~ /\%\{\?(\!)?([a-z0-9_.-]+)(?:\:([a-z0-9_.-]+))?\}/) { #Whew....
1416 my $neg = $1;
1417 my $macro = $2;
1418 my $value = $3;
1419 if ($specglobals{$macro}) {
1420 $value = '' if $neg;
1421 } else {
1422 $value = '' if !$neg;
1423 }
1424 $macrostring =~ s/\%\{\?\!?[a-z0-9_.-]+(?:\:[a-z0-9_.-]+)?\}/$value/;
1425 }
1426
1427 # system programs. RPM uses a global config file for these; we'll just
1428 # ASS-U-ME and make life a little simpler.
1429 if ($macrostring =~ /\%\{\_\_([a-z0-9_-]+)\}/) {
1430 $macrostring =~ s|%{__([a-z0-9_-]+)}|$1|g;
1431 }
1432
1433 # Misc expansions
1434 $macrostring =~ s|%{_arch}|$hostarch|g;
1435 $macrostring =~ s|%{optflags}|$optflags{$hostarch}|g;
1436
1437 } # done with globals section
1438
1439 return $macrostring;
1440} # end expandmacros()
1441
1442
1443
1444__END__
1445
1446
1447
1448=head1 NAME
1449
1450debbuild - Build Debian-compatible packages from RPM spec files
1451
1452=head1 SYNOPSIS
1453
1454 debbuild {-ba|-bb|-bp|-bc|-bi|-bl|-bs} [build-options] file.spec
1455
1456 debbuild {-ta|-tb|-tp|-tc|-ti|-tl|-ts} [build-options] file.tar.{gz|bz2}
1457
1458 debbuild --rebuild file.{src.rpm|sdeb}
1459
1460 debbuild --showpkgs
1461
1462=head1 DESCRIPTION
1463
1464This script attempts to build Debian-friendly semi-native packages from RPM spec files,
1465RPM-friendly tarballs, and RPM source packages (.src.rpm files). It accepts I<most> of the
1466options rpmbuild does, and should be able to interpret most spec files usefully. Perl
1467modules should be handled via CPAN+dh-make-perl instead; Debian's conventions for such
1468things do not lend themselves to automated conversion.
1469
1470As far as possible, the command-line options are identical to those from rpmbuild, although
1471several rpmbuild options are not supported:
1472
1473 --recompile
1474 --showrc
1475 --buildroot
1476 --clean
1477 --nobuild
1478 --rmsource
1479 --rmspec
1480 --sign
1481 --target
1482
1483Some of these could probably be trivially added. Feel free to send me a patch. ;)
1484
1485Complex spec files will most likely not work well, if at all. Rewrite them from scratch -
1486you'll have to make heavy modifications anyway.
1487
1488If you see something you don't like, mail me. Send a patch if you feel inspired. I don't
1489promise I'll do anything other than say "Yup, that's broken" or "Got your message".
1490
1491=head1 ASSUMPTIONS
1492
1493As with rpmbuild, debbuild makes some assumptions about your system.
1494
1495=over 4
1496
1497=item *
1498
1499Either you have rights to do as you please under /usr/src/debian, or you have created a file
1500~/.debmacros containing a suitable %_topdir definition.
1501
1502Both rpmbuild and debbuild require the directories %_topdir/{BUILD,SOURCES,SPECS}. However,
1503where rpmbuild requires the %_topdir/{RPMS,SRPMS} directories, debbuild
1504requires %_topdir/{DEBS,SDEBS} instead. Create them in advance;
1505some subdirectories are created automatically as needed, but most are not.
1506
1507=item *
1508
1509/var/tmp must allow script execution - rpmbuild and debbuild both rely on creating and
1510executing shell scripts for much of their functionality. By default, debbuild also creates
1511install trees under /var/tmp - however this is (almost) entirely under the control of the
1512package's .spec file.
1513
1514=item *
1515
1516If you wish to --rebuild a .src.rpm, your %_topdir for both debbuild and rpmbuild must either
1517match, or be suitably symlinked one direction or another so that both programs are effectively
1518working in the same tree. (Or you could just manually wrestle files around your system.)
1519
1520You could symlink ~/.rpmmacros to ~/.debmacros (or vice versa) and save yourself some hassle
1521if you need to rebuild .src.rpm packages on a regular basis. Currently debbuild only uses the
1522%_topdir macro definition, although there are many more things that rpmbuild can use from
1523~/.rpmmacros.
1524
1525=back
1526
1527=head1 ERRATA
1528
1529debbuild deliberately does a few things differently from rpm.
1530
1531=head2 BuildArch or BuildArchitecture
1532
1533rpm takes the last BuildArch entry it finds in the .spec file, whatever it is, and runs with
1534that for all packages. Debian's repository system is fairly heavily designed around the
1535assumption that a single source package may generate small binary (executable) packages
1536for each arch, and large binary arch-all packages containing shared data.
1537
1538debbuild allows this by using the architecture specified by (in order of preference):
1539
1540=over 4
1541
1542=item * Host architecture
1543
1544=item * BuildArch specified in .spec file preamble
1545
1546=item * "Last specified" BuildArch for packages with several subpackages
1547
1548=item * BuildArch specified in the %package section for that subpackage
1549
1550=back
1551
1552=head2 Finding out what packages should be built (--showpkgs)
1553
1554rpmbuild does not include any convenient method I know of to list the packages a spec file
1555will produce. Since I needed this ability for another tool, I added it.
1556
1557It requires the .spec file for the package, and produces a list of full package filenames
1558(without path data) that would be generated by one of --rebuild, -ta, -tb, -ba, or -bb.
1559This includes the .sdeb source package.
1560
1561=head1 AUTHOR
1562
1563debbuild was written by Kris Deugau <kdeugau@deepnet.cx>. A version that approximates
1564current is available at http://www.deepnet.cx/debbuild/.
1565
1566=head1 BUGS
1567
1568Funky Things Happen if you forget a command-line option or two. I've been too lazy to bother
1569fixing this.
1570
1571Many macro expansions are unsupported or incompletely supported.
1572
1573The generated scriptlets don't quite match those from rpmbuild exactly. There are extra
1574environment variables and preprocessing that I haven't needed (yet).
1575
1576Dcumentation, such as it is, will likely remain perpetually out of date.
1577
1578%_topdir and the five "working" directories under %_topdir could arguably be created by
1579debbuild. However, rpmbuild doesn't create these directories either.
1580
1581=head1 SEE ALSO
1582
1583rpm(8), rpmbuild(8), and pretty much any document describing how to write a .spec file.
1584
1585=cut
Note: See TracBrowser for help on using the repository browser.