File Coverage

lib/CPANPLUS/Dist/Deb.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package CPANPLUS::Dist::Deb;
2              
3 3     3   990899 use strict;
  3         6  
  3         78  
4 3     3   11 use vars qw[@ISA $VERSION];
  3         3  
  3         141  
5             @ISA = qw[CPANPLUS::Dist];
6             $VERSION = '0.03_01';
7              
8 3     3   2715 use CPANPLUS::inc;
  0            
  0            
9             use CPANPLUS::Error;
10             use CPANPLUS::Internals::Constants;
11             use CPANPLUS::Dist::Deb::Constants;
12              
13             use FileHandle;
14             use File::Basename;
15             use File::Find;
16             use File::Path;
17             use Cwd;
18              
19             use IPC::Cmd qw[run can_run];
20             use Params::Check qw[check];
21             use File::Basename qw[dirname];
22             use Module::Load::Conditional qw[can_load check_install];
23             use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext';
24              
25             local $Params::Check::VERBOSE = 1;
26              
27              
28             =pod
29              
30             =head1 NAME
31              
32             CPANPLUS::Dist::Deb
33              
34             =head1 SYNOPSIS
35              
36             my $cb = CPANPLUS::Backend->new;
37             my $modobj = $cb->module_tree('Some::Module');
38              
39              
40             ### as an option to ->install()
41             $modobj->install( format => 'CPANPLUS::Dist::Deb' );
42              
43              
44             ### just to create the debs, don't install
45             $modobj->install( format => 'CPANPLUS::Dist::Deb',
46             target => 'create',
47             prereq_target => 'create' );
48              
49              
50             ### the long way around
51             $mobobj->fetch;
52             $modobj->extract;
53              
54             my $deb = CPANPLUS::Dist->new(
55             format => 'CPANPLUS::Dist::Deb',
56             module => $modobj,
57             %extra_opts,
58             );
59            
60             $bool = $deb->create; # create a .deb file
61             $bool = $deb->install; # installs the .deb file
62              
63             $where = $deb->status->dist; # from the dist obj
64             $where = $modobj->status->dist->status->dist; # from the mod obj
65              
66              
67             ### from the CPANPLUS Default shell
68             CPAN Terminal> i --format=CPANPLUS::Dist::Deb Some::Module
69              
70            
71             ### using the commandline tool
72             cpan2dist -f CPANPLUS::Dist::Deb Some::Module
73            
74             =head1 DESCRIPTION
75              
76             C is a distribution class to create C
77             packages from C modules, and all it's dependencies. This allows
78             you to have the most recent copies of C modules installed,
79             using your package manager of choice, but without having to wait for
80             central repositories to be updated.
81              
82             You can either install them using the API provided in this package,
83             or manually via C.
84              
85             Some of the bleading edge C modules have already been turned
86             into debian packages for you, and you can make use of them by adding
87             the following line to your C file:
88            
89             deb http://debian.pkgs.cpan.org/debian unstable main
90              
91             Note that these packages are built automatically from CPAN and are
92             assumed to have the same license as perl and come without support.
93             Please always refer to the original C package if you have
94             questions.
95              
96             =cut
97              
98              
99             =head1 ACCESSORS
100              
101             =over 4
102              
103             =item parent()
104              
105             Returns the C object that parented this object.
106              
107             =item status()
108              
109             Returns the C object that keeps the status for
110             this module.
111              
112             Look at C for a list of standard accessors every
113             C object will have. Below is a list of those specific to
114             this package.
115              
116             Note that these are mostly to ensure the inner workings of this
117             package.
118              
119             =back
120              
121             =head1 STATUS ACCESSORS
122              
123             All accessors can be accessed as follows:
124             $deb->status->ACCESSOR
125              
126             =over 4
127              
128             =item rules()
129              
130             The location of the C file.
131              
132             Will be removed after successful creation.
133              
134             =item compat()
135              
136             The location of the C file
137              
138             Will be removed after successful creation.
139              
140             =item changelog()
141              
142             The location of the C file
143              
144             Will be removed after successful creation.
145              
146             =item copyright()
147              
148             The location of the C file
149              
150             Will be removed after successful creation.
151              
152             =item control()
153              
154             The location of the C file
155              
156             Will be removed after successful creation.
157              
158             =item distdir()
159              
160             The directory where the C<.deb> file is placed.
161              
162             Will be removed after successful creation.
163              
164             =item package()
165              
166             The location of the C<.deb> file.
167              
168             Note this is equivalent to the C accessor already
169             standardly provided.
170              
171             =item files()
172              
173             List of all the generated files for this distribution.
174              
175             =back
176              
177             =cut
178              
179              
180             =head1 METHODS
181              
182             =head2 $bool = CPANPLUS::Dist::Deb->format_available();
183              
184             Returns a boolean indicating whether or not you can use this package
185             to create and install modules in your environment.
186              
187             It will verify if you have all the necessary components avialable to
188             build your own debian packages. You will need at least these
189             dependencies installed:
190              
191             =over 4
192              
193             =item debhelper
194            
195             =item dpkg
196              
197             =item dpkg-dev
198            
199             =item fakeroot
200              
201             =item gcc
202              
203             =item libc6-dev
204              
205             =item findutils
206              
207             =back
208              
209             =cut
210              
211             ### XXX check if we're on debian? or perhaps we can do this cross-platform
212             sub format_available {
213             my $flag;
214             for my $prog (qw[gencat dpkg dh_perl gcc cp dpkg-buildpackage
215             fakeroot xargs find]) {
216             unless( can_run($prog) ) {
217             error(loc("'%1' is a required program to build debian packages",
218             $prog));
219             $flag++;
220             }
221             }
222             return $flag ? 0 : 1;
223             }
224              
225             =head2 $bool = $deb->init
226              
227             Sets up the C object for use.
228             Effectively creates all the needed status accessors.
229              
230             Called automatically whenever you create a new C
231             object.
232              
233             =cut
234              
235             sub init {
236             my $self = shift;
237             my $status = $self->status;
238              
239             $status->mk_accessors(qw[rules compat changelog copyright control distdir
240             debiandir package package_name package_filename
241             readme prefix builddir _tmp_output_dir files
242             _prepare_args _create_args _install_args]);
243             ### XXX we might not be using _args properly!
244             return 1;
245             }
246              
247             =pod
248              
249             =head2 $loc = $dist->prepare([perl => '/path/to/perl', distdir => '/path/to/build/debs', copyright => 'copyright_text', prereq_target => TARGET, force => BOOL, verbose => BOOL, skiptest => BOOL, prefix => 'prefix-', distribution => 'disttype', deb_version => INT])
250              
251             C preps a distribution for creation. This means it will create
252             all meta data files required by C to build a C<.deb>
253             file of hte module you specified.
254             This will also satisfy any prerequisites the module may have.
255              
256             If you set C to true, it will skip the C stage.
257             If you set C to true, it will go over all the stages of the
258             creation process again, ignoring any previously cached results. It
259             will also ignore a bad return value from the C stage and still
260             allow the operation to return true.
261              
262             Returns true on success and false on failure.
263              
264             You may then call C<< $deb->create >> on the object to create the
265             C<.deb> from the metadata, and then C<< $deb->install >> on the object
266             to actually install it.
267              
268             Returns the location of the builddir on success, and false on failure.
269              
270             Note any extra options you pass along, will be passed to the underlying
271             installers verbatim. This enables you to, for example, specify extra
272             flags for the C stage.
273              
274             =cut
275              
276             sub prepare {
277             ### just in case you already did a create call for this module object
278             ### just via a different dist object
279             my $dist = shift;
280             my $self = $dist->parent;
281             my $dist_cpan = $self->status->dist_cpan;
282             $dist = $self->status->dist if $self->status->dist;
283             $self->status->dist( $dist ) unless $self->status->dist;
284              
285             my $cb = $self->parent;
286             my $conf = $cb->configure_object;
287             my %hash = @_;
288              
289             my $args;
290             my( $verbose,$force,$perl,$prereq_target,$distdir,$copyright,$prefix,
291             $keep_source,$distribution, $deb_version,$prereq_build);
292             { local $Params::Check::ALLOW_UNKNOWN = 1;
293             my $tmpl = {
294             verbose => { default => $conf->get_conf('verbose'),
295             store => \$verbose },
296             force => { default => $conf->get_conf('force'),
297             store => \$force },
298             perl => { default => ($conf->get_program('perl') || $^X),
299             store => \$perl },
300             ### XXX is this the right thing to do???
301             prereq_target => { default => 'install',
302             store => \$prereq_target },
303             copyright => { default => DEB_STANDARD_COPYRIGHT_PERL,
304             store => \$copyright },
305             distdir => { default => '', store => \$distdir },
306             prefix => { default => 'cpan-', store => \$prefix },
307             distribution => { default => DEB_DEFAULT_RELEASE,
308             store => \$distribution },
309             deb_version => { default => 1, store => \$deb_version },
310             #keep_source => { default => 0, store => \$keep_source },
311             prereq_build => { default => 0, store => \$prereq_build },
312             };
313              
314             $args = check( $tmpl, \%hash ) or return;
315             }
316              
317             ### store the prefix for later use
318             $dist->status->prefix( $prefix );
319             $dist->status->package_name( DEB_PACKAGE_NAME->($self, $prefix) );
320              
321             ### the directory we're going to put the files in, which has either
322             ### a custom root, or our standard base directory
323             my $basedir = File::Spec->catdir(
324             ( $distdir || DEB_BASE_DIR->( $conf, $perl ) ),
325             DEB_DISTDIR->( $dist, $prefix )
326             );
327            
328             ### did we already create the package? if so, don't bother to rebuild
329             ### unless we are forced to
330             { for my $has_xs (0,1) {
331             my $pkg = DEB_DEB_FILE_NAME->( $self, $basedir, $prefix, $has_xs);
332              
333             if( -e $pkg && -s _ and not $force) {
334             msg(loc("Already created package of '%1' at '%2' -- not doing"
335             ." so again unless you force", $self->module, $pkg ));
336              
337             $dist->status->prepared( 1 );
338             $dist->status->created( 1 );
339             $dist->status->package( $pkg );
340             return $dist->status->dist( $pkg );
341             }
342             }
343             }
344              
345             { ### we must install in site or vendor dirs..which means we *must*
346             ### tell this to the underlying make/build process!
347             MAKE: {
348             my $mmflags = $conf->get_conf('makemakerflags');
349             my $mmadd = DEB_MAKEMAKERFLAGS->( $dist->status->prefix );
350             $conf->set_conf( makemakerflags => $mmflags . ' ' . $mmadd )
351             unless $mmflags =~ /$mmadd/;
352            
353             my $buildflags = $conf->get_conf('buildflags');
354             my $buildadd = DEB_BUILDFLAGS->( $dist->status->prefix );
355             $conf->set_conf( buildflags => $buildflags . ' ' . $buildadd )
356             unless $buildflags =~ /$buildadd/;
357            
358             my $fail;
359             $fail++ unless $dist_cpan->prepare( %hash );
360            
361             ### restore the flags
362             $conf->set_conf( makemakerflags => $mmflags );
363             $conf->set_conf( buildflags => $buildflags );
364            
365             if( $fail ) {
366             $dist->status->prepared(0);
367             return;
368             }
369             }
370            
371            
372             unless ( $dist_cpan->create( %hash, prereq_format => __PACKAGE__ ) ) {
373             $dist->status->prepared(0);
374             return;
375             }
376            
377            
378            
379             my $debdir = DEB_DEBIAN_DIR->( $self->status->extract );
380             ### store the dirs we build debs in, and where we put the current
381             ### meta data files
382             $dist->status->distdir( $basedir ); # final destination
383             $dist->status->builddir( $self->status->extract ); # [EXTRACT]/
384             $dist->status->debiandir( $debdir ); # [EXTRACT]/debian
385             ### dir where the generated packages will end up after compiling them,
386             ### before moving them to their final destination
387             $dist->status->_tmp_output_dir(
388             File::Spec->catdir( $dist->status->builddir, '..' ) );
389            
390            
391             ### create final destination dir && debian subdir ###
392             for ( $debdir, $basedir ) {
393             unless( -d $_ ) {
394             unless( $cb->_mkdir( dir => $_ ) ) {
395             error( loc("Could not create directory '%1'", $_ ) );
396             $dist->status->prepared(0);
397             return;
398             }
399             }
400             }
401            
402             ### chdir to builddir ###
403             unless( $cb->_chdir( dir => $dist->status->builddir ) ) {
404             $dist->status->prepared(0);
405             return;
406             }
407             }
408              
409              
410             ### copy the original tarball over, in .orig format so it can
411             ### be diffed against by the dh- tools
412             { my $file = $self->status->fetch;
413             my $orig = File::Spec->catdir(
414             $dist->status->builddir,
415             '..', # be sure to updir, so the diff is included
416             DEB_ORIG_PACKAGE_NAME->( $self, $prefix ) );
417            
418             unless( $cb->_copy( file => $file, to => $orig ) ) {
419             error(loc("Couldn't copy original archive '%1' to '%2'",
420             $file, $orig ));
421             $dist->status->prepared(0);
422             return;
423             }
424             }
425              
426             ### let's figure out what this distribution will be called -- we'll need
427             ### that later to see if it was actually created
428             { my $has_xs = scalar GET_XS_FILES->( $self->status->extract ) ? 1 : 0;
429             my $debfile = DEB_DEB_FILE_NAME->( $self, '.', $prefix, $has_xs );
430            
431             $dist->status->package_filename( $debfile );
432             }
433              
434              
435             ### find where prereqs landed, etc.. add them to our dependency list ###
436             my @depends;
437             { my $prereqs = $self->status->prereqs;
438            
439             for my $prereq ( sort keys %$prereqs ) {
440             my $obj = $cb->module_tree($prereq);
441              
442             unless( $obj ) {
443             error( loc( "Couldn't find module object for prerequisite ".
444             "'%1' -- skipping", $prereq ) );
445             next;
446             }
447              
448             ### no point in listing prereqs that are IN the perl core
449             ### themselves
450             next if $obj->package_is_perl_core;
451              
452             ### if the prereq requires any specific version, we'll assume
453             ### the one we can provide, otherwise, we'll set it to undef,
454             ### marking 'any'
455             push @depends, [$obj,
456             ($prereqs->{$prereq} ? $obj->version : undef) ];
457             }
458             }
459              
460             ### write a standard debian readme file
461             { my $debreadme = DEB_README->( $dist->status->builddir );
462            
463             ### open the makefile for writing ###
464             my $fh;
465             unless( $fh = FileHandle->new( ">$debreadme" ) ) {
466             error( loc( "Could not open '%1' for writing: %2",
467             $debreadme, $! ) );
468             $dist->status->prepared(0);
469             return;
470             }
471              
472             print $fh DEB_README_CONTENTS;
473             close $fh;
474            
475             $dist->status->readme( $debreadme );
476             }
477              
478             ### get all the metadata to make the control file ###
479             { my $control = DEB_CONTROL->( $dist->status->builddir );
480              
481             ### open the makefile for writing ###
482             my $fh;
483             unless( $fh = FileHandle->new( ">$control" ) ) {
484             error( loc( "Could not open '%1' for writing: %2",
485             $control, $! ) );
486             $dist->status->prepared(0);
487             return;
488             }
489              
490             ### check if there are xs files in this distribution ###
491             my $has_xs = scalar GET_XS_FILES->( $self->status->extract ) ? 1 : 0;
492              
493             my $maintainer = $conf->get_conf('email');
494             my $desc = $self->description || $self->module;
495             my $arch = DEB_RULES_ARCH->($has_xs);
496              
497             my $pkg = DEB_PACKAGE_NAME->($self, $prefix);
498             my $std_version = DEB_STANDARDS_VERSION;
499             my $debhelper = DEB_DEBHELPER;
500             my $perl_depends = DEB_PERL_DEPENDS;
501              
502             ### prereqs will be 'libfoo-perl' if we don't have a prefix and
503             ### '${prefix}libfoo-perl' if we do have a prefix. We only add the
504             ### >= VERSION if the prereqs were stated with requiring a certain
505             ### version.. otherwise we leave it empty
506             my %seen;
507             my $prereqs = join ', ', map {
508             ### do we need a specific version?
509             my $ver = $_->[1]
510             ? ' (>= ' . $_->[1] . ')'
511             : '';
512            
513             ### standard lib
514             my $str = DEB_PACKAGE_NAME->($_->[0]) . $ver;
515              
516             ### our lib, if it has a prefix
517             if( $prefix ) {
518             $str .= ' | ' . DEB_PACKAGE_NAME->(
519             $_->[0], $prefix) . $ver;
520             }
521            
522             $str;
523             } grep {
524             ### shouldn't be a core module
525             ### and we shouldn't list the same
526             ### prereq twice. Note that 2 modules
527             ### may be in 1 package
528             !$_->[0]->package_is_perl_core and
529             !$seen{ DEB_PACKAGE_NAME->( $_->[0] ) }++
530             } @depends;
531              
532             ### always put debhelper in build-depends ###
533             my $build_depends = $debhelper;
534              
535             ### always add prereqs to depends ###
536             my $depends = join ', ', $perl_depends, $prereqs;
537              
538             ### empty by default, only used if this module has xs parts ###
539             my $build_indep; my $bdi_line = '';
540              
541             ### xs module, so all dependencies go in build-depend-indep
542             if( $has_xs ) {
543             $build_indep = $prereqs;
544              
545             ### the build-depends-indep line to add to the here-doc
546             ### since it's not allowed to be empty in the rules file
547             $bdi_line = "Build-Depends-Indep: $build_depends";
548              
549             ### no xs, so all dependencies get added to build-depend
550             } else {
551             $build_depends .= ', ' . $prereqs;
552             }
553              
554              
555             $fh->print(<< "EOF");
556             Source: $pkg
557             Section: perl
558             Priority: optional
559             Maintainer: $maintainer
560             Standards-Version: $std_version
561             Build-Depends: $build_depends
562             $bdi_line
563              
564             Architecture: $arch
565             Package: $pkg
566             EOF
567              
568             ### we might have to print some 'Replaces:' lines
569             ### - replace perl core if we were ever part of it
570             ### - replaces 'standard' debian module (that may or may not exist)
571             ### if we are built without a prefix
572             ### XXX OBSOLETE! since we install completely paralel to existing
573             ### moduels, and dont replace any files, Replaces: is no longer
574             ### required
575             # if ( $self->module_is_supplied_with_perl_core or not $prefix ) {
576             # my @printme;
577             #
578             # $fh->print('Replaces: ');
579             #
580             # ### so this module is also in perl core, add a rule telling the
581             # ### .deb that it's ok to replace stuff from those packages.
582             # push @printme, DEB_REPLACE_PERL_CORE
583             # if $self->module_is_supplied_with_perl_core;
584             #
585             # push @printme, DEB_PACKAGE_NAME->($self) if $prefix;
586             #
587             # $fh->print( join(', ', @printme), "\n" );
588             # }
589            
590             ### so we have a prefix? best explain what package we are /actually/
591             ### providing. Also note the Conflicts
592             $fh->print( "Provides: " . DEB_PACKAGE_NAME->($self) . "\n")
593             if $prefix;
594            
595             ### XXX remove 'Conflicts:' -- versioned provides don't work
596             ### with dpkg :( so if someone wants 'libfoo-perl > 2.0' it
597             ### will be seen as not provided by our libfoo-perl, and
598             ### will propbably uninstall these things... bad bad :(
599             # "Conflicts: ". DEB_PACKAGE_NAME->($self) . "\n")
600              
601             ### description should be mentioned twice: one long one, one
602             ### short one... format is as follows:
603             ### Description: short desc
604             ### long description
605            
606             $fh->print(<< "EOF");
607             Depends: $depends
608             Description: $desc
609             $desc
610              
611             EOF
612              
613             $fh->close;
614             $dist->status->control( $control );
615             }
616              
617              
618             ### get all the metadata for compat file and write it ###
619             { my $compat = DEB_COMPAT->( $dist->status->builddir );
620              
621             my $fh;
622             unless( $fh = FileHandle->new( ">$compat" ) ) {
623             error( loc( "Could not open '%1' for writing: %2",
624             $compat, $! ) );
625             $dist->status->prepared(0);
626             return;
627             }
628              
629             ### this is in the sample, but what the hell does it do?
630             ### -- it's just the version of the spec files we used
631             $fh->print("4\n");
632             $fh->close;
633              
634             $dist->status->compat( $compat );
635             }
636              
637             ### get all the metadata for changelog file and write it ###
638             { my $changelog = DEB_CHANGELOG->( $dist->status->builddir );
639              
640             my $fh;
641             unless( $fh = FileHandle->new( ">$changelog" ) ) {
642             error( loc( "Could not open '%1' for writing: %2",
643             $changelog, $! ) );
644             $dist->status->prepared(0);
645             return;
646             }
647              
648             ### XXX this will cause parse errors if the first line doesn't match
649             ### if (m/^(\w[-+0-9a-z.]*) \(([^\(\) \t]+)\)((\s+[-0-9a-z]+)+)\;/i) {
650             ### (taken from /usr/lib/dpkg/parsechangelog/debian ) which means that
651             ### we can not have _ in package names, but dots are fine.
652             my $pkg = DEB_PACKAGE_NAME->($self, $prefix);
653             my $version = DEB_VERSION->($self, $deb_version);
654             my $urgency = DEB_URGENCY;
655             my $email = $conf->get_conf('email');
656             my $who = __PACKAGE__;
657              
658             ### geez timestamps are a b*tch with debian changelogs..
659             ### this is the only correct format:
660             ### Sun, 3 Jun 2001 20:36:41 +0200
661             ### but scalar gmtime says:
662             ### Sat Jul 3 14:23:31 2004
663             my ($wday, $mon, $day, $time, $year) = split /\s+/, scalar gmtime;
664             my $when = sprintf "%s, %2d %s %s %s +0100",
665             $wday, $day, $mon, $year, $time; # crackfueled :(
666              
667             $fh->print(<< "EOF");
668             $pkg ($version) $distribution; $urgency
669              
670             * Initial Release.
671              
672             -- $who <$email> $when
673              
674             EOF
675              
676             $fh->close;
677              
678             $dist->status->changelog( $changelog );
679             }
680              
681             ### get all the metadata for changelog file and write it ###
682             { my $copyright_file = DEB_COPYRIGHT->( $dist->status->builddir );
683              
684             my $fh;
685             unless( $fh = FileHandle->new( ">$copyright_file" ) ) {
686             error( loc( "Could not open '%1' for writing: %2",
687             $copyright_file, $! ) );
688             $dist->status->prepared(0);
689             return;
690             }
691              
692             ### XXX probe for possible license here rather than assume the
693             ### default
694             my $pkg = $self->module;
695             my $who = $ENV{DEBFULLMAIL}
696             ? $ENV{DEBFULLNAME} . ' <' .
697             ($ENV{DEBEMAIL} || $conf->get_conf('email')) . '>'
698             : ($ENV{DEBEMAIL} || $conf->get_conf('email'));
699             my $when = 1900 + (localtime)[5];
700             my $license = DEB_STANDARD_COPYRIGHT_PERL;
701             my $author = $self->author->author;
702             my $email = $self->author->email;
703              
704             $fh->print(<< "EOF");
705             This is the debian package for the $pkg module.
706             It was created by $who.
707              
708             The upstream author is $author <$email>.
709              
710             Copyright (c) $when by $author
711              
712             $license
713              
714             EOF
715              
716             $fh->close;
717             $dist->status->copyright($copyright_file);
718             }
719              
720             { ### add the debian rules file, which is mostly static ###
721             my $rules_file = DEB_RULES->( $dist->status->builddir );
722             my $has_xs = scalar GET_XS_FILES->($self->status->extract)
723             ? 1 : 0;
724             my $content = DEB_GET_RULES_CONTENT->( $self, $prefix,
725             $has_xs, $verbose );
726              
727             my $fh;
728             unless( $fh = FileHandle->new( ">$rules_file" ) ) {
729             error( loc( "Could not open '%1' for writing: %2",
730             $rules_file, $! ) );
731             $dist->status->prepared(0);
732             return;
733             }
734              
735             $fh->print( $content );
736             $fh->close;
737              
738             ### make sure it's set as +x
739             chmod 0755, $rules_file;
740              
741             $dist->status->rules( $rules_file );
742             }
743              
744              
745             $dist->status->prepared(1);
746             return $dist->status->builddir;
747             }
748              
749             =pod
750              
751             =head2 $loc = $dist->create([force => BOOL, verbose => BOOL, keep_source => BOOL])
752              
753             C preps a distribution for installation. This means it will
754             build a C<.deb> file of the module object you've specified from the
755             meta data files that were generated during C.
756              
757             Returns true on success and false on failure.
758              
759             You may then call C<< $deb->install >> on the object to actually
760             install it.
761             Returns the location of the C<.deb> file on success, and false on failure.
762              
763             =cut
764              
765             sub create {
766             ### just in case you already did a create call for this module object
767             ### just via a different dist object
768             my $dist = shift;
769             my $self = $dist->parent;
770             $dist = $self->status->dist if $self->status->dist;
771             $self->status->dist( $dist ) unless $self->status->dist;
772              
773             my $cb = $self->parent;
774             my $conf = $cb->configure_object;
775             my %hash = @_;
776              
777             my $args;
778             my( $verbose,$force,$keep_source);
779             { local $Params::Check::ALLOW_UNKNOWN = 1;
780             my $tmpl = {
781             verbose => { default => $conf->get_conf('verbose'),
782             store => \$verbose },
783             force => { default => $conf->get_conf('force'),
784             store => \$force },
785             keep_source => { default => undef, store => \$keep_source },
786             };
787              
788             $args = check( $tmpl, \%hash ) or return;
789             }
790            
791             ### did you prepare it yet?
792             unless( $dist->status->prepared ) {
793             error( loc( "You have not successfully prepared a '%2' distribution ".
794             "yet -- cannot create yet", __PACKAGE__ ) );
795             return;
796             }
797            
798             ### already created?
799             if( $dist->status->created and not $force ) {
800             msg(loc("You have already created a '%2' distribution -- not doing ".
801             "so again unless you force", __PACKAGE__ ));
802             return 1;
803             }
804            
805             ### chdir to it ###
806             unless( $cb->_chdir( dir => $dist->status->builddir ) ) {
807             $dist->status->created(0);
808             return;
809             }
810              
811             { ### all rules files done, time to build the .deb ###
812             ### need to run: dpkg-buildpackage -rfakeroot -uc -us
813             my $prog;
814             unless( $prog = DEB_BIN_BUILDPACKAGE->() ) {
815             error(loc( "Cannot create debian package" ));
816             return $dist->status->created(0);
817             }
818              
819             my $buffer;
820             unless( scalar run(
821             command => [$prog, qw|-rfakeroot -uc -us -d|,
822             DEB_DPKG_SOURCE_IGNORE],
823             verbose => $verbose,
824             buffer => \$buffer )
825             ) {
826             error( loc( "Failed to create debian package for '%1': '%2'",
827             $self->module, $buffer ) );
828              
829             return $dist->status->created(0);
830             }
831              
832             ### ok, now we have a package created in:
833             ### ../$NAME_$VERSION_$ARCH.deb
834             ### and we can't tell dpkg-buildpackage to output it anywhere else :(
835             #my $has_xs = scalar GET_XS_FILES->($self->status->extract) ? 1 : 0;
836             #my $debfile = DEB_DEB_FILE_NAME->( $self, $dist->status->distdir,
837             # $prefix, $has_xs);
838             { my $tmpfile = File::Spec->catfile( $dist->status->_tmp_output_dir,
839             $dist->status->package_filename
840             );
841              
842             unless( -e $tmpfile && -s _ ) {
843             error( loc( "Debian package '%1' was supposed to be created ".
844             "but was not", $tmpfile ) );
845             return $dist->status->created(0);
846             }
847             }
848            
849             ### XXX moves stuff here
850             if( my @files = glob( File::Spec->catdir(
851             $dist->status->_tmp_output_dir,
852             $dist->status->package_name,
853             ) . '*' )
854             ) {
855             my @dest;
856             for my $file (@files) {
857             my $to = File::Spec->catdir(
858             $dist->status->distdir, basename( $file ) );
859            
860             unless( $cb->_move( file => $file, to => $to ) ) {
861             error(loc("Failed to move '%1' to its final ".
862             "destination '%2'", $file, $to ));
863             $dist->status->prepared(0);
864             return;
865             }
866             push @dest, $to;
867             }
868            
869             ### save what files we ended up moving
870             $dist->status->files( \@dest );
871            
872             } else {
873             error(loc("No files found matching pattern '%1' in temporary ".
874             "directory '%2'", $dist->status->package_name,
875             $dist->status->_tmp_output_dir ));
876             $dist->status->prepared(0);
877             return;
878             }
879              
880             ### final location
881             my $debfile = File::Spec->catfile( $dist->status->distdir,
882             $dist->status->package_filename );
883              
884              
885             ### store where we wrote the dist to
886             $dist->status->package( $debfile );
887             $dist->status->dist( $debfile );
888              
889             msg(loc("Wrote '%1' package for '%2' to '%3'",
890             'debian', $self->module, $debfile), $verbose);
891            
892             unless( $cb->_chdir( dir => $conf->_get_build('startdir') ) ) {
893             error(loc("Unable to '%1' back to startdir",'chdir'));
894             }
895             }
896              
897             $dist->status->created(1);
898             return $dist->status->dist;
899             }
900              
901             =pod
902              
903             =head2 $bool = $deb->install([verbose => BOOL, force => BOOL, dpkg => /path/to/dpkg, dpkg_flags => ["--extra", "--flags"]]);
904              
905             Installs the C<.deb> using C.
906              
907             Returns true on success and false on failure
908              
909             =cut
910              
911             sub install {
912             ### just in case you already did a create call for this module object
913             ### just via a different dist object
914             my $dist = shift;
915             my $self = $dist->parent;
916             $dist = $self->status->dist if $self->status->dist;
917             $self->status->dist( $dist ) unless $self->status->dist;
918              
919             my $cb = $self->parent;
920             my $conf = $cb->configure_object;
921             my %hash = @_;
922              
923             my ($dpkg,$verbose,$force,$flags);
924            
925             { local $Params::Check::ALLOW_UNKNOWN = 1;
926             my $tmpl = {
927             dpkg => { default => can_run('dpkg'), store => \$dpkg },
928             verbose => { default => $conf->get_conf('verbose'),
929             store => \$verbose },
930             force => { default => $conf->get_conf('force'),
931             store => \$force },
932             dpkg_flags => { default => [], strict_type => 1,
933             store => \$flags },
934             };
935            
936             check( $tmpl, \%hash ) or return;
937             }
938            
939             ### build the command ###
940             my $sudo = $conf->get_program('sudo');
941             my @cmd = ($dpkg, '-i', @$flags, $dist->status->package);
942             unshift @cmd, $sudo if $sudo;
943              
944             my $buffer;
945             unless( scalar run( command => \@cmd,
946             verbose => $verbose,
947             buffer => \$buffer )
948             ) {
949             error( loc( "Unable to install '%1': %2",
950             $dist->status->package, $buffer ) );
951             return $dist->status->installed(0);
952             }
953              
954             return $dist->status->installed(1);
955             };
956              
957             =pod
958              
959             =head2 $bool = $deb->uninstall([verbose => BOOL, force => BOOL, dpkg => /path/to/dpkg, dpkg_flags => ["--extra", "--flags"]]);
960              
961             Uninstalls the C<.deb> using C.
962              
963             Returns true on success and false on failure
964              
965             =cut
966              
967             sub uninstall {
968             ### just in case you already did a create call for this module object
969             ### just via a different dist object
970             my $dist = shift;
971             my $self = $dist->parent;
972             $dist = $self->status->dist if $self->status->dist;
973             $self->status->dist( $dist ) unless $self->status->dist;
974              
975             my $cb = $self->parent;
976             my $conf = $cb->configure_object;
977             my %hash = @_;
978              
979             my ($dpkg,$verbose,$force,$flags);
980            
981             { local $Params::Check::ALLOW_UNKNOWN = 1;
982             my $tmpl = {
983             dpkg => { default => can_run('dpkg'), store => \$dpkg },
984             verbose => { default => $conf->get_conf('verbose'),
985             store => \$verbose },
986             force => { default => $conf->get_conf('force'),
987             store => \$force },
988             dpkg_flags => { default => [], strict_type => 1,
989             store => \$flags },
990             };
991            
992             check( $tmpl, \%hash ) or return;
993             }
994            
995             ### build the command ###
996             my $sudo = $conf->get_program('sudo');
997             my @cmd = ($dpkg, '-r', @$flags, $dist->status->package_name);
998             unshift @cmd, $sudo if $sudo;
999              
1000             my $buffer;
1001             unless( scalar run( command => \@cmd,
1002             verbose => $verbose,
1003             buffer => \$buffer )
1004             ) {
1005             error( loc( "Unable to uninstall '%1': %2",
1006             $dist->status->package, $buffer ) );
1007             return $dist->status->uninstalled(0);
1008             }
1009              
1010             return $dist->status->uninstalled(1);
1011             };
1012              
1013             =head2 $loc = CPANPLUS::Dist::Deb->write_meta_files( type => sources|packages, [basedir => /path/to/base, perl => /path/to/perl, release => $releasename]);
1014              
1015             This writes the metafiles needed to use this archive as a debian mirror.
1016              
1017             It returns the location of the metafile on success, and false on failure.
1018              
1019             =cut
1020              
1021             { my $prog;
1022              
1023             sub write_meta_files {
1024             my $dist = shift;
1025             my %hash = @_;
1026            
1027             my($type, $basedir, $perl, $release);
1028             my $tmpl = {
1029             type => { required => 1, store => \$type,
1030             allow => [ DEB_METAFILE_SOURCES,
1031             DEB_METAFILE_PACKAGES] },
1032             basedir => { store => \$basedir },
1033             perl => { default => $^X, store => \$perl },
1034             release => { default => DEB_DEFAULT_RELEASE, store => \$release },
1035             };
1036            
1037             check( $tmpl, \%hash ) or return;
1038            
1039             ### check only once for it per running session if possible
1040             $prog ||= DEB_METAFILE_PROGRAM->();
1041            
1042             ### optional program, just can't run it.
1043             unless( $prog ) {
1044             error(loc("Could not find '%1' in your path -- please install it",
1045             $prog));
1046             return;
1047             }
1048              
1049             ### class or object method?
1050             my $conf = ref $dist
1051             ? $dist->parent->parent->configure_object
1052             : do { require CPANPLUS::Configure;
1053             CPANPLUS::Configure->new };
1054            
1055             ### store the old value if needed
1056             my $oldbase;
1057             if( $basedir ) {
1058             $oldbase = $conf->get_conf('base');
1059             $conf->set_conf( base => $basedir );
1060             };
1061            
1062             ### this is the base path under which we'll put the debian structure
1063             ### for source files
1064             my $path = DEB_BASE_DIR->( $conf, $perl );
1065            
1066             ### set back the old path
1067             $conf->set_conf( base => $oldbase ) if $oldbase;
1068            
1069             my $outputfile = DEB_OUTPUT_METAFILE->( $type, $path );
1070              
1071             ### check if we need to make the dir for this output file
1072             { my $dir = dirname( $outputfile );
1073             unless( -d $dir ) {
1074             CPANPLUS::Internals::Utils->_mkdir( dir => $dir ) or return;
1075             }
1076             }
1077              
1078             my $oldcwd = cwd();
1079             chdir $path or return error(loc( "Could not chdir to '%1': %2",
1080             $basedir, $! ));
1081              
1082             my $buffer;
1083             my $fail;
1084             my $command = "$prog $type . | gzip -9 > $outputfile";
1085            
1086             ### using IPC::Cmd here gives errors, probably due to pipes and >
1087             if( system($command) ) {
1088             error(loc("Could not run command '%1': %2", $command, $buffer ));
1089             $fail++;
1090             }
1091            
1092             chdir $oldcwd or error(loc("Could not chdir back to '%1': %2",
1093             $oldcwd, $! ));
1094            
1095             return if $fail;
1096            
1097             return $outputfile;
1098             }
1099             }
1100              
1101              
1102             1;
1103              
1104             =pod
1105              
1106             =head1 TODO
1107              
1108             There are no TODOs of a technical nature currently, merely of an
1109             administrative one;
1110              
1111             =over 4
1112              
1113             =item Scan for proper license
1114              
1115             Right now we assume that the license of every module is C
1116             as perl itself>. Although correct in almost all cases, it should
1117             really be probed rather than assumed.
1118             This forms a barrier before C<.debs> generated by this package can
1119             be used by C itself in it's own repositories.
1120              
1121             =item Long description
1122              
1123             Right now we provided the description as given by the module in it's
1124             meta data. However, not all modules provide this meta data and rather
1125             than scanning the files in the package for it, we simply default to the
1126             name of the module.
1127              
1128             =back
1129              
1130             =head1 AUTHOR
1131              
1132             This module by
1133             Jos Boumans Ekane@cpan.orgE.
1134              
1135             =head1 COPYRIGHT
1136              
1137             The CPAN++ interface (of which this module is a part of) is
1138             copyright (c) 2005, Jos Boumans Ekane@cpan.orgE.
1139             All rights reserved.
1140              
1141             This library is free software;
1142             you may redistribute and/or modify it under the same
1143             terms as Perl itself.
1144              
1145             =head1 SEE ALSO
1146              
1147             L, L, L,
1148             C, C, C
1149              
1150             =cut
1151              
1152              
1153              
1154             # Local variables:
1155             # c-indentation-style: bsd
1156             # c-basic-offset: 4
1157             # indent-tabs-mode: nil
1158             # End:
1159             # vim: expandtab shiftwidth=4:
1160              
1161              
1162             __END__