source: trunk/debbuild@ 88

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

/trunk

Whoops... forgot to *set* the buildarch for the main package in the case
where there is no buildarch specified at all. Not setting this results
in a package with an *empty* arch specification...

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