source: trunk/debbuild@ 37

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

/trunk

Tweaked %files handling further to not choke on %config (make
conffile) and %docdir (ignored in Debian) directives

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