source: trunk/debbuild@ 94

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

/trunk

Add basic support for --define option

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