File Coverage

blib/lib/PPM/Make.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package PPM::Make;
2 4     4   72574 use strict;
  4         14  
  4         228  
3 4     4   26 use warnings;
  4         10  
  4         174  
4 4     4   2865 use PPM::Make::Config qw(:all);
  4         54  
  4         1932  
5 4     4   3372 use PPM::Make::Util qw(:all);
  0            
  0            
6             use PPM::Make::Meta;
7             use PPM::Make::Search;
8             use Cwd;
9             use Pod::Find qw(pod_find contains_pod);
10             use File::Basename;
11             use File::Path;
12             use File::Find;
13             use File::Copy;
14             use File::Spec;
15             use Net::FTP;
16             use Pod::Html;
17             use XML::Writer;
18             use version;
19              
20             our $VERSION = '0.9902';
21              
22             my $protocol = $PPM::Make::Util::protocol;
23             my $ext = $PPM::Make::Util::ext;
24             my $no_case = 0;
25             my $html = 'blib/html';
26              
27             sub new {
28             my ($class, %opts) = @_;
29              
30             die "\nInvalid option specification" unless check_opts(%opts);
31            
32             $opts{zip_archive} = 1 if ($opts{binary} and $opts{binary} =~ /\.zip$/);
33              
34             my ($arch, $os) = arch_and_os($opts{arch}, $opts{os}, $opts{noas});
35             my $has = what_have_you($opts{program}, $arch, $os);
36              
37             my %cfg;
38             # $opts{no_cfg} = 1 if $opts{install};
39             unless ($opts{no_cfg}) {
40             if (my $file = get_cfg_file()) {
41             %cfg = read_cfg($file, $arch) or die "\nError reading config file";
42             }
43             }
44             my $opts = %cfg ? merge_opts(\%cfg, \%opts) : \%opts;
45              
46             $no_case = 1 if defined $opts->{no_case};
47             my $search = PPM::Make::Search->new(
48             no_remote_lookup => $opts->{no_remote_lookup},
49             );
50             my $self = {
51             opts => $opts || {},
52             cwd => '',
53             has => $has,
54             args => {},
55             ppd => '',
56             archive => '',
57             zip => '',
58             prereq_pm => {},
59             file => '',
60             version => '',
61             use_mb => '',
62             ARCHITECTURE => $arch,
63             OS => $os,
64             cpan_meta => $opts->{cpan_meta},
65             search => $search,
66             fetch_error => '',
67             };
68             bless $self, $class;
69             }
70              
71             sub make_ppm {
72             my $self = shift;
73             die 'No software available to make a zip archive'
74             if ( ($self->{opts}->{zip_archive} or $self->{opts}->{zipdist})
75             and not $self->{has}->{zip});
76             my $dist = $self->{opts}->{dist};
77             $self->{org_dir} = my $org_dir = cwd;
78             if ($dist) {
79             my $build_dir = File::Spec->tmpdir;
80             chdir $build_dir or die "Cannot chdir to $build_dir: $!";
81             print "Working directory: $build_dir\n";
82              
83             my $local_dist = File::Spec->file_name_is_absolute($dist)
84             ? $dist
85             : File::Spec->catfile($org_dir, $dist);
86             if (-f $local_dist) {
87             print "Found a local distribution: $local_dist\n";
88             my $basename = basename($local_dist);
89             copy($local_dist, File::Spec->catfile($build_dir, $basename));
90             $self->{search}->{no_remote_lookup} = 0;
91             }
92              
93             die $self->{fetch_error}
94             unless ($dist = $self->fetch_file($dist, no_case => $no_case));
95             # if ($dist =~ m!$protocol!
96             # or $dist =~ m!^\w/\w\w/! or $dist !~ m!$ext!);
97             print "Extracting files from $dist ....\n";
98             my $name = $self->extract_dist($dist, $build_dir);
99             chdir $name or die "Cannot chdir to $name: $!";
100             $self->{file} = $dist;
101             }
102             die "Need a Makefile.PL or Build.PL to build"
103             unless (-f 'Makefile.PL' or -f 'Build.PL');
104             my $force = $self->{opts}->{force};
105             $self->{cwd} = cwd;
106             print "Working directory: $self->{cwd}\n";
107             my $mb = -e 'Build.PL';
108             $self->{mb} = $mb;
109             die "This distribution requires Module::Build to build"
110             if ($mb and not HAS_MB);
111             $self->check_script() if $self->{opts}->{script};
112             $self->check_files() if $self->{opts}->{add};
113             $self->adjust_binary() if $self->{opts}->{arch_sub};
114             $self->build_dist()
115             unless (-d 'blib' and
116             (-f 'Makefile' or ($mb and -f 'Build' and -d '_build'))
117             and not $force);
118              
119             my $meta = PPM::Make::Meta->new(dir => $self->{cwd},
120             search => $self->{search},
121             );
122             die qq{Creating PPM::Make::Meta object failed}
123             unless ($meta and (ref($meta) eq 'PPM::Make::Meta'));
124             $meta->meta();
125             foreach my $key( keys %{$meta->{info}}) {
126             next unless defined $meta->{info}->{$key};
127             $self->{args}->{$key} ||= $meta->{info}->{$key};
128             }
129              
130             if ($self->{version} = $self->{args}->{VERSION}) {
131             my $version = version->new($self->{version});
132             $self->{version} = $version;
133             $self->{version} =~ s/^v//x;
134             }
135             else {
136             warn "Could not extract version information";
137             }
138             unless ($self->{opts}->{no_html}) {
139             $self->make_html() unless (-d 'blib/html' and not $force);
140             }
141             $dist = $self->make_dist();
142             $self->make_ppd($dist);
143             # if ($self->{opts}->{install}) {
144             # die 'Must have the ppm utility to install' unless HAS_PPM;
145             # $self->ppm_install();
146             # }
147             $self->make_cpan() if $self->{opts}->{cpan};
148             $self->make_zipdist($dist)
149             if ($self->{opts}->{zipdist} and not $self->{opts}->{no_upload});
150             if (defined $self->{opts}->{upload} and not $self->{opts}->{no_upload}) {
151             die 'Please specify the location to place the ppd file'
152             unless $self->{opts}->{upload}->{ppd};
153             $self->upload_ppm();
154             }
155              
156             if ($org_dir ne $self->{cwd}) {
157             for (qw/archive ppd zip/) {
158             copy(File::Spec->catfile($self->{cwd}, $self->{$_}), $org_dir) if $self->{$_};
159             }
160             }
161              
162             return 1;
163             }
164              
165             sub check_script {
166             my $self = shift;
167             my $script = $self->{opts}->{script};
168             return if ($script =~ m!$protocol!);
169             my ($name, $path, $suffix) = fileparse($script, '\..*');
170             my $file = $name . $suffix;
171             $self->{opts}->{script} = $file;
172             return if (-e $file);
173             copy($script, $file) or die "Copying $script to $self->{cwd} failed: $!";
174             }
175              
176             sub check_files {
177             my $self = shift;
178             my @entries = ();
179             foreach my $file (@{$self->{opts}->{add}}) {
180             my ($name, $path, $suffix) = fileparse($file, '\..*');
181             my $entry = $name . $suffix;
182             push @entries, $entry;
183             next if (-e $entry);
184             copy($file, $entry) or die "Copying $file to $self->{cwd} failed: $!";
185             }
186             $self->{opts}->{add} = \@entries if @entries;
187             }
188              
189             sub extract_dist {
190             my ($self, $file, $build_dir) = @_;
191              
192             my $has = $self->{has};
193             my ($tar, $gzip, $unzip) = @$has{qw(tar gzip unzip)};
194              
195             my ($name, $path, $suffix) = fileparse($file, $ext);
196             if (-d "$build_dir/$name") {
197             rmtree("$build_dir/$name", 1, 0)
198             or die "rmtree of $name failed: $!";
199             }
200             EXTRACT: {
201             if ($suffix eq '.zip') {
202             ($unzip eq 'Archive::Zip') && do {
203             my $arc = Archive::Zip->new();
204             die "Read of $file failed"
205             unless $arc->read($file) == Archive::Zip::AZ_OK();
206             $arc->extractTree();
207             last EXTRACT;
208             };
209             ($unzip) && do {
210             my @args = ($unzip, $file);
211             print "@args\n";
212             system(@args) == 0 or die "@args failed: $?";
213             last EXTRACT;
214             };
215              
216             }
217             else {
218             ($tar eq 'Archive::Tar') && do {
219             my $arc = Archive::Tar->new($file, 1);
220             $arc->extract($arc->list_files);
221             last EXTRACT;
222             };
223             ($tar and $gzip) && do {
224             my @args = ($gzip, '-dc', $file, '|', $tar, 'xvf', '-');
225             print "@args\n";
226             system(@args) == 0 or die "@args failed: $?";
227             last EXTRACT;
228             };
229             }
230             die "Cannot extract $file";
231             }
232             return $name;
233             }
234              
235             sub adjust_binary {
236             my $self = shift;
237             my $binary = $self->{opts}->{binary};
238             my $archname = $self->{ARCHITECTURE};
239             return unless $archname;
240             if ($binary) {
241             if ($binary =~ m!$ext!) {
242             if ($binary =~ m!/!) {
243             $binary =~ s!(.*?)([\w\-]+)$ext!$1$archname/$2$3!;
244             }
245             else {
246             $binary = $archname . '/' . $binary;
247             }
248             }
249             else {
250             $binary =~ s!/$!!;
251             $binary .= '/' . $archname . '/';
252             }
253             }
254             else {
255             $binary = $archname . '/';
256             }
257             $self->{opts}->{binary} = $binary;
258             }
259              
260             sub build_dist {
261             my $self = shift;
262             my $binary = $self->{opts}->{binary};
263             my $script = $self->{opts}->{script};
264             my $exec = $self->{opts}->{exec};
265              
266             my $has = $self->{has};
267             my ($make, $perl) = @$has{qw(make perl)};
268             my $mb = $self->{mb};
269              
270             my $makepl = $mb ? 'Build.PL' : 'Makefile.PL';
271             my @args = ($perl, $makepl);
272             if (not $mb and my $makepl_arg = $CPAN::Config->{makepl_arg}) {
273             push @args, (split ' ', $makepl_arg);
274             }
275             print "@args\n";
276             system(@args) == 0 or die qq{@args failed: $?};
277              
278             # if ($mb) {
279             # my $file = 'Build.PL';
280             # unless (my $r = do $file) {
281             # die "Can't parse $file: $@" if $@;
282             # die "Can't do $file: $!" unless defined $r;
283             # die "Can't run $file" unless $r;
284             # }
285             # }
286             # else {
287             # $self->write_makefile();
288             # }
289              
290             my $build = 'Build';
291             @args = $mb ? ($perl, $build) : ($make);
292             if (not $mb and my $make_arg = $CPAN::Config->{make_arg}) {
293             push @args, (split ' ', $make_arg);
294             }
295             print "@args\n";
296             system(@args) == 0 or die "@args failed: $?";
297              
298             unless ($self->{opts}->{skip}) {
299             @args = $mb ? ($perl, $build, 'test') : ($make, 'test');
300             print "@args\n";
301             unless (system(@args) == 0) {
302             die "@args failed: $?" unless $self->{opts}->{ignore};
303             warn "@args failed: $?";
304             }
305             }
306             return 1;
307             }
308              
309             sub make_html {
310             my $self = shift;
311             my $args = $self->{args};
312             my $cwd = $self->{cwd};
313             unless (-d $html) {
314             mkpath($html, 1, 0755) or die "Couldn't mkdir $html: $!";
315             }
316             my %pods = pod_find({-verbose => 1}, "$cwd/blib/");
317             if (-d "$cwd/blib/script/") {
318             finddepth( sub {
319             $pods{$File::Find::name} =
320             "script::" . basename($File::Find::name)
321             if (-f $_ and not /\.bat$/ and contains_pod($_));
322             }, "$cwd/blib/script");
323             }
324              
325             foreach my $pod (keys %pods){
326             my @dirs = split /::/, $pods{$pod};
327             my $isbin = shift @dirs eq 'script';
328              
329             (my $infile = File::Spec->abs2rel($pod)) =~ s!^\w+:!!;
330             $infile =~ s!\\!/!g;
331             my $outfile = (pop @dirs) . '.html';
332              
333             my @rootdirs = $isbin? ('bin') : ('site', 'lib');
334             (my $path2root = "../" x (@rootdirs+@dirs)) =~ s|/$||;
335            
336             (my $fulldir = File::Spec->catfile($html, @rootdirs, @dirs)) =~ s!\\!/!g;
337             unless (-d $fulldir){
338             mkpath($fulldir, 1, 0755)
339             or die "Couldn't mkdir $fulldir: $!";
340             }
341             ($outfile = File::Spec->catfile($fulldir, $outfile)) =~ s!\\!/!g;
342              
343             my $htmlroot = "$path2root/site/lib";
344             my $podroot = "$cwd/blib";
345             my $podpath = join ":" => map { $podroot . '/' . $_ }
346             ($isbin ? qw(bin lib) : qw(lib));
347             (my $package = $pods{$pod}) =~ s!^(lib|script)::!!;
348             my $abstract = parse_abstract($package, $infile);
349             my $title = $abstract ? "$package - $abstract" : $package;
350             my @opts = (
351             '--header',
352             "--title=$title",
353             "--infile=$infile",
354             "--outfile=$outfile",
355             "--podroot=$podroot",
356             "--htmlroot=$htmlroot",
357             "--css=$path2root/Active.css",
358             );
359             print "pod2html @opts\n";
360             pod2html(@opts);# or warn "pod2html @opts failed: $!";
361             }
362             ###################################
363             }
364              
365             sub make_dist {
366             my $self = shift;
367             my $args = $self->{args};
368             my $has = $self->{has};
369             my ($tar, $gzip, $zip) = @$has{qw(tar gzip zip)};
370             my $force_zip = $self->{opts}->{zip_archive};
371             my $binary = $self->{opts}->{binary};
372             my $name;
373             if ($binary and $binary =~ /$ext/) {
374             ($name = $binary) =~ s!.*/(.*)$ext!$1!;
375             }
376             else {
377             $name = $args->{DISTNAME} || $args->{NAME};
378             $name =~ s!::!-!g;
379             }
380              
381             $name .= "-$self->{version}"
382             if ( ($self->{opts}->{vs} or $self->{opts}->{vsr}) and $self->{version});
383              
384             my $is_Win32 = (not $self->{OS} or $self->{OS} =~ /Win32/i
385             or not $self->{ARCHITECTURE} or
386             $self->{ARCHITECTURE} =~ /Win32/i);
387              
388             my $script = $self->{opts}->{script};
389             my $script_is_external = $script ? ($script =~ /$protocol/) : '';
390             my @files;
391             if ($self->{opts}->{add}) {
392             @files = @{$self->{opts}->{add}};
393             }
394              
395             my $arc = $force_zip ? ($name . '.zip') : ($name . '.tar.gz');
396             # unless ($self->{opts}->{force}) {
397             # return $arc if (-f $arc);
398             # }
399             unlink $arc if (-e $arc);
400              
401             DIST: {
402             ($tar eq 'Archive::Tar' and not $force_zip) && do {
403             $name .= '.tar.gz';
404             my @f;
405             my $arc = Archive::Tar->new();
406             if ($is_Win32) {
407             finddepth(sub { push @f, $File::Find::name
408             unless $File::Find::name =~ m!blib/man\d!;
409             print $File::Find::name,"\n"}, 'blib');
410             }
411             else {
412             finddepth(sub { push @f, $File::Find::name;
413             print $File::Find::name,"\n"}, 'blib');
414             }
415             if ($script and not $script_is_external) {
416             push @f, $script;
417             print "$script\n";
418             }
419             if (@files) {
420             push @f, @files;
421             print join "\n", @files;
422             }
423             $arc->add_files(@f);
424             $arc->write($name, 1);
425             last DIST;
426             };
427             ($tar and $gzip and not $force_zip) && do {
428             $name .= '.tar';
429             my @args = ($tar, 'cvf', $name);
430              
431             if ($is_Win32) {
432             my @f;
433             finddepth(sub {
434             push @f, $File::Find::name
435             if $File::Find::name =~ m!blib/man\d!;},
436             'blib');
437             for (@f) {
438             push @args, "--exclude", $_;
439             }
440             }
441              
442             push @args, 'blib';
443              
444             if ($script and not $script_is_external) {
445             push @args, $script;
446             }
447             if (@files) {
448             push @args, @files;
449             }
450             print "@args\n";
451             system(@args) == 0 or die "@args failed: $?";
452             @args = ($gzip, $name);
453             print "@args\n";
454             system(@args) == 0 or die "@args failed: $?";
455             $name .= '.gz';
456             last DIST;
457             };
458             ($zip eq 'Archive::Zip') && do {
459             $name .= '.zip';
460             my $arc = Archive::Zip->new();
461             if ($is_Win32) {
462             die "zip of blib failed" unless $arc->addTree('blib', 'blib',
463             sub{$_ !~ m!blib/man\d/!
464             && print "$_\n";}) == Archive::Zip::AZ_OK();
465             }
466             else {
467             die "zip of blib failed" unless $arc->addTree('blib', 'blib',
468             sub{print "$_\n";}) == Archive::Zip::AZ_OK();
469             }
470             if ($script and not $script_is_external) {
471             die "zip of $script failed"
472             unless $arc->addFile($script, $script);
473             print "$script\n";
474             }
475             if (@files) {
476             for (@files) {
477             die "zip of $_ failed" unless $arc->addFile($_, $_);
478             print "$_\n";
479             }
480             }
481             die "Writing to $name failed"
482             unless $arc->writeToFileNamed($name) == Archive::Zip::AZ_OK();
483             last DIST;
484             };
485             ($zip) && do {
486             $name .= '.zip';
487             my @args = ($zip, '-r', $name, 'blib');
488             if ($script and not $script_is_external) {
489             push @args, $script;
490             print "$script\n";
491             }
492             if (@files) {
493             push @args, @files;
494             print join "\n", @files;
495             }
496             if ($is_Win32) {
497             my @f;
498             finddepth(sub {
499             push @f, $File::Find::name
500             unless $File::Find::name =~ m!blib/man\d!;},
501             'blib');
502             for (@f) {
503             push @args, "-x", $_;
504             }
505             }
506              
507             print "@args\n";
508             system(@args) == 0 or die "@args failed: $?";
509             last DIST;
510             };
511             die "Cannot make archive for $name";
512             }
513             return $name;
514             }
515              
516             sub make_ppd {
517             my ($self, $dist) = @_;
518             my $has = $self->{has};
519             my ($make, $perl) = @$has{qw(make perl)};
520             my $binary = $self->{opts}->{binary};
521             if ($binary) {
522             unless ($binary =~ /$ext/) {
523             $binary =~ s!/$!!;
524             $binary .= '/' . $dist;
525             }
526             }
527              
528             (my $name = $dist) =~ s!$ext!!;
529             if ($self->{opts}->{vsr} and not $self->{opts}->{vsp}) {
530             $name =~ s/-$self->{version}// if $self->{version};
531             }
532             if ($self->{opts}->{vsp} and $name !~ m/-$self->{version}/) {
533             $name .= "-$self->{version}";
534             }
535             my $ppd = $name . '.ppd';
536             my $args = $self->{args};
537             my $os = $self->{OS};
538             my $arch = $self->{ARCHITECTURE};
539             my $d;
540              
541             $d->{SOFTPKG}->{NAME} = $d->{TITLE} = $name;
542             $d->{SOFTPKG}->{VERSION} = cpan2ppd_version($self->{version} || 0);
543             $d->{OS}->{NAME} = $os if $os;
544             $d->{ARCHITECTURE}->{NAME} = $arch if $arch;
545             $d->{ABSTRACT} = $args->{ABSTRACT};
546             $d->{AUTHOR} = (ref($args->{AUTHOR}) eq 'ARRAY') ?
547             (join ', ', @{$args->{AUTHOR}}) : $args->{AUTHOR};
548             $d->{CODEBASE}->{HREF} = $self->{opts}->{no_upload} ? $dist :
549             ($binary || $dist);
550             ($self->{archive} = $d->{CODEBASE}->{HREF}) =~ s!.*/(.*)!$1!;
551              
552             if ( my $script = $self->{opts}->{script}) {
553             if (my $exec = $self->{opts}->{exec}) {
554             $d->{INSTALL}->{EXEC} = $exec;
555             }
556             if ($script =~ m!$protocol!) {
557             $d->{INSTALL}->{HREF} = $script;
558             (my $name = $script) =~ s!.*/(.*)!$1!;
559             $d->{INSTALL}->{SCRIPT} = $name;
560             }
561             else {
562             $d->{INSTALL}->{SCRIPT} = $script;
563             }
564             }
565              
566             my $search = $self->{search};
567             {
568             if ($search->search($name, mode => 'dist')) {
569             my $mods = $search->{dist_results}->{$name}->{mods};
570             if ($mods and (ref($mods) eq 'ARRAY')) {
571             foreach my $mod (@$mods) {
572             my $mod_name = $mod->{mod_name};
573             next unless $mod_name;
574             my $mod_vers = $mod->{mod_vers};
575             if ($] < 5.10) {
576             $mod_name .= '::' unless ($mod_name =~ /::/);
577             }
578             push @{$d->{PROVIDE}}, {NAME => $mod_name, VERSION => $mod_vers};
579             }
580             }
581             }
582             else {
583             $search->search_error(qq{Cannot obtain the modules that '$name' provides});
584             }
585             }
586             my $mod_ref;
587             foreach my $dp (keys %{$args->{PREREQ_PM}}) {
588             next if ($dp eq 'perl' or is_core($dp));
589             $dp =~ s{-}{::}g;
590             $d->{REQUIRE}->{$dp} = $args->{PREREQ_PM}->{$dp} || 0;
591             push @$mod_ref, $dp;
592             }
593             my %deps = map {$_ => 1} @$mod_ref;
594             {
595             if ($mod_ref and ref($mod_ref) eq 'ARRAY') {
596             if ($search->search($mod_ref, mode => 'mod')) {
597             my $matches = $search->{mod_results};
598             if ($matches and ref($matches) eq 'HASH') {
599             foreach my $dp(keys %$matches) {
600             next unless $deps{$dp};
601             my $results = $matches->{$dp};
602             next unless (defined $results and defined $results->{mod_name});
603             my $dist = $results->{dist_name};
604             next if (not $dist or $dist =~ m!^perl$!
605             or $dist =~ m!^Test! or is_ap_core($dist));
606             $self->{prereq_pm}->{$dist} =
607             $d->{DEPENDENCY}->{$dist} =
608             cpan2ppd_version($args->{PREREQ_PM}->{$dp} || 0);
609             }
610             }
611             else {
612             $search->search_error(qq{Cannot find information on prerequisites for '$name'});
613             }
614             }
615             }
616             }
617             foreach (qw(OS ARCHITECTURE)) {
618             delete $d->{$_}->{NAME} unless $self->{$_};
619             }
620             $self->print_ppd($d, $ppd);
621             $self->{ppd} = $ppd;
622             }
623              
624             sub print_ppd {
625             my ($self, $d, $fn) = @_;
626             open (my $fh, '>', $fn) or die "Couldn't write to $fn: $!";
627             my $writer = XML::Writer->new(OUTPUT => $fh, DATA_INDENT => 2);
628             $writer->xmlDecl('UTF-8');
629             # weird hack to eliminate an empty line after the XML declaration
630             $writer->startTag('SOFTPKG', NAME => $d->{SOFTPKG}->{NAME}, VERSION => $d->{SOFTPKG}->{VERSION});
631             $writer->setDataMode(1);
632             $writer->dataElement(TITLE => $d->{TITLE});
633             $writer->dataElement(ABSTRACT => $d->{ABSTRACT});
634             $writer->dataElement(AUTHOR => $d->{AUTHOR});
635             $writer->startTag('IMPLEMENTATION');
636              
637             foreach (sort keys %{$d->{DEPENDENCY}}) {
638             $writer->emptyTag('DEPENDENCY' => NAME => $_, VERSION => $d->{DEPENDENCY}->{$_});
639             }
640             if ($] > 5.008) {
641             foreach (sort keys %{$d->{REQUIRE}}) {
642             $writer->emptyTag('REQUIRE' => NAME => $_, VERSION => $d->{REQUIRE}->{$_});
643             }
644             }
645             foreach (qw(OS ARCHITECTURE)) {
646             next unless $d->{$_}->{NAME};
647             $writer->emptyTag($_ => NAME => $d->{$_}->{NAME});
648             }
649              
650             if (my $script = $d->{INSTALL}->{SCRIPT}) {
651             my %attr;
652             for (qw/EXEC HREF/) {
653             next unless $d->{INSTALL}->{$_};
654             $attr{$_} = $d->{INSTALL}->{$_};
655             }
656             $writer->dataElement('INSTALL', $script, %attr);
657             }
658              
659             $writer->emptyTag('CODEBASE' => HREF => $d->{CODEBASE}->{HREF});
660              
661             my $provide = $d->{PROVIDE};
662             unless ($self->{opts}->{no_ppm4}) {
663             if ($provide and (ref($provide) eq 'ARRAY')) {
664             foreach my $mod(@$provide) {
665             my %attr;
666             if ($mod->{VERSION}) {
667             $attr{VERSION} = $mod->{VERSION};
668             }
669             $writer->emptyTag('PROVIDE' => NAME => $mod->{NAME}, %attr);
670             }
671             }
672             }
673             $writer->endTag('IMPLEMENTATION');
674             $writer->endTag('SOFTPKG');
675             $writer->end;
676             $fh->close;
677             $self->{codebase} = $d->{CODEBASE}->{HREF};
678             }
679              
680             sub make_zipdist {
681             my ($self, $dist) = @_;
682             my $ppd = $self->{ppd};
683             (my $zipdist = $ppd) =~ s!\.ppd$!.zip!;
684             if (-f $zipdist) {
685             unlink $zipdist or warn "Could not unlink $zipdist: $!";
686             }
687             my $cb = $self->{codebase};
688             my ($path, $archive, $local);
689             if ($cb =~ m!/!) {
690             ($path, $archive) = $cb =~ m!(.*)/(.*)!;
691             $local = ($path !~ m!(http|ftp)://!
692             and not File::Spec->file_name_is_absolute($path) ) ? 1 : 0;
693             }
694             else {
695             $archive = $cb;
696             }
697             my $readme = 'README.ppm';
698             open(my $fh, '>', $readme) or die "Cannot open $readme: $!";
699             print $fh <<"END";
700             To install this ppm package, run the following command
701             in the current directory:
702              
703             ppm install $ppd
704              
705             END
706             close $fh;
707              
708             my $ppd_zip = $ppd . '.copy';
709             open(my $rfh, '<', $ppd) or die "Cannot open $ppd: $!";
710             open(my $wfh, '>', $ppd_zip) or die "Cannot open $ppd_zip: $!";
711             while (my $line = <$rfh>) {
712             $line =~ s{HREF=\"(http|ftp)://.*/([^/]+)\"}{HREF="$2"};
713             print $wfh $line;
714             }
715             close($rfh);
716             close($wfh);
717              
718             my $zip = $self->{has}->{zip};
719             my $copy = $local ? File::Spec::Unix->catfile($path, $archive) : $archive;
720             print qq{\nCreating $zipdist ...\n};
721             if ($zip eq 'Archive::Zip') {
722             my %contents = ($ppd_zip => $ppd,
723             $archive => $copy,
724             $readme => 'README');
725             my $arc = Archive::Zip->new();
726             foreach (keys %contents) {
727             print "Adding $_ as $contents{$_}\n";
728             unless ($arc->addFile($_, $contents{$_})) {
729             die "Failed to add $_";
730             }
731             }
732             die "Writing to $zipdist failed"
733             unless $arc->writeToFileNamed($zipdist) == Archive::Zip::AZ_OK();
734             }
735             else {
736             if ($path and $local) {
737             unless (-d $path) {
738             mkpath($path, 1, 0777) or die "Cannot mkpath $path: $!";
739             }
740             copy($archive, $copy) or die "Cannot cp $archive to $copy: $!";
741             }
742             rename($ppd, "$ppd.tmp") or die "Cannnot rename $ppd to $ppd.tmp: $!";
743             rename($ppd_zip, $ppd) or die "Cannnot rename $ppd_zip to $ppd: $!";
744              
745             my @args = ($zip, $zipdist, $ppd, $copy, $readme);
746             print "@args\n";
747             system(@args) == 0 or die "@args failed: $?";
748             rename($ppd, $ppd_zip) or die "Cannnot rename $ppd to $ppd_zip: $!";
749             rename("$ppd.tmp", $ppd) or die "Cannnot rename $ppd.tmp to $ppd: $!";
750             if ($path and $local and -d $path) {
751             rmtree($path, 1, 1) or warn "Cannot rmtree $path: $!";
752             }
753             }
754             $self->{zip} = $zipdist;
755             unlink $readme;
756             unlink $ppd_zip;
757             }
758              
759             sub make_cpan {
760             my $self = shift;
761             my ($ppd, $archive) = ($self->{ppd}, $self->{archive});
762             my %seen;
763             my $man = 'MANIFEST';
764             my $copy = $man . '.orig';
765             unless (-e $copy) {
766             rename($man, $copy) or die "Cannot rename $man: $!";
767             }
768             open(my $orig, '<', $copy) or die "Cannot read $copy: $!";
769             open(my $new, '>', $man) or die "Cannot open $man for writing: $!";
770             while (<$orig>) {
771             $seen{ppd}++ if $_ =~ /$ppd/;
772             $seen{archive}++ if $_ =~ /$archive/;
773             print $new $_;
774             }
775             close $orig;
776             print $new "\n$ppd\n" unless $seen{ppd};
777             print $new "$archive\n" unless $seen{archive};
778             close $new;
779             my @args = ($self->{has}->{make}, 'dist');
780             print "@args\n";
781             system(@args) == 0 or die qq{system @args failed: $?};
782             return;
783             }
784              
785             sub upload_ppm {
786             my $self = shift;
787             my ($ppd, $archive, $zip) = ($self->{ppd}, $self->{archive}, $self->{zip});
788             my $upload = $self->{opts}->{upload};
789             my $ppd_loc = $upload->{ppd};
790             my $zip_loc = $upload->{zip};
791             my $ar_loc = $self->{opts}->{arch_sub} ?
792             $self->{ARCHITECTURE} : $upload->{ar} || $ppd_loc;
793             if (defined $ar_loc) {
794             if (not File::Spec->file_name_is_absolute($ar_loc)) {
795             ($ar_loc = File::Spec->catdir($ppd_loc, $ar_loc)) =~ s!\\!/!g;
796             }
797             }
798             if (defined $zip_loc) {
799             if (not File::Spec->file_name_is_absolute($zip_loc)) {
800             ($zip_loc = File::Spec->catdir($ppd_loc, $zip_loc)) =~ s!\\!/!g;
801             }
802             }
803              
804             if (my $host = $upload->{host}) {
805             print qq{\nUploading files to $host ...\n};
806             my ($user, $passwd) = ($upload->{user}, $upload->{passwd});
807             die "Must specify a username and password to log into $host"
808             unless ($user and $passwd);
809             my $ftp = Net::FTP->new($host)
810             or die "Cannot connect to $host: $@";
811             $ftp->login($user, $passwd)
812             or die "Login for user $user failed: ", $ftp->message;
813             $ftp->cwd($ppd_loc) or die
814             "cwd to $ppd_loc failed: ", $ftp->message;
815             if ($Net::FTP::VERSION eq '2.77') {
816             $ftp->binary;
817             }
818             else {
819             $ftp->ascii;
820             }
821             $ftp->put($ppd)
822             or die "Cannot upload $ppd: ", $ftp->message;
823             $ftp->cwd($ar_loc)
824             or die "cwd to $ar_loc failed: ", $ftp->message;
825             $ftp->binary;
826             $ftp->put($archive)
827             or die "Cannot upload $archive: ", $ftp->message;
828             if ($self->{opts}->{zipdist} and -f $zip) {
829             $ftp->cwd($zip_loc)
830             or die "cwd to $zip_loc failed: ", $ftp->message;
831             $ftp->put($zip)
832             or die "Cannot upload $zip: ", $ftp->message;
833             }
834             $ftp->quit;
835             print qq{Done!\n};
836             }
837             else {
838             print qq{\nCopying files ....\n};
839             copy($ppd, "$ppd_loc/$ppd")
840             or die "Cannot copy $ppd to $ppd_loc: $!";
841             unless (-d $ar_loc) {
842             mkdir $ar_loc or die "Cannot mkdir $ar_loc: $!";
843             }
844             copy($archive, "$ar_loc/$archive")
845             or die "Cannot copy $archive to $ar_loc: $!";
846             if ($self->{opts}->{zipdist} and -f $zip) {
847             unless (-d $zip_loc) {
848             mkdir $zip_loc or die "Cannot mkdir $zip_loc: $!";
849             }
850             copy($zip, "$zip_loc/$zip")
851             or die "Cannot copy $zip to $zip_loc: $!";
852             }
853             print qq{Done!\n};
854             }
855             }
856              
857             sub fetch_file {
858             my ($self, $dist, %args) = @_;
859             my $no_case = $args{no_case};
860             my $to;
861             if (-f $dist) {
862             $to = basename($dist, $ext);
863             unless ($dist eq $to) {
864             copy($dist, $to) or die "Cannot cp $dist to $to: $!";
865             }
866             return $to;
867             }
868             if ($dist =~ m!$protocol!) {
869             ($to = $dist) =~ s!.*/(.*)!$1!;
870             print "Fetching $dist ....\n";
871             my $rc = mirror($dist, $to);
872             unless ($rc) {
873             $self->{fetch_error} = qq{Fetch of $dist failed.};
874             return;
875             }
876             return $to;
877             }
878             my $search = $self->{search};
879             my $results;
880             unless ($dist =~ /$ext$/) {
881             my $mod = $dist;
882             $mod =~ s!-!::!g;
883             if ($search->search($mod, mode => 'mod')) {
884             $results = $search->{mod_results}->{$mod};
885             }
886             unless ($results) {
887             $mod =~ s!::!-!g;
888             if ($search->search($mod, mode => 'dist')) {
889             $results = $search->{dist_results}->{$mod};
890             }
891             }
892             unless ($results->{cpanid} and $results->{dist_file}) {
893             $self->{fetch_error} = qq{Cannot get distribution name of '$mod'};
894             return;
895             }
896             $dist = cpan_file($results->{cpanid}, $results->{dist_file});
897             }
898             my $id = dirname($dist);
899             $to = basename($dist, $ext);
900             my $src = HAS_CPAN ?
901             File::Spec->catdir($src_dir, 'authors/id', $id) :
902             $src_dir;
903             my $CS = 'CHECKSUMS';
904             my $get_cs = 0;
905             for my $file( ($to, $CS)) {
906             my $local = File::Spec->catfile($src, $file);
907             if (-e $local and $src_dir ne $build_dir and not $get_cs) {
908             copy($local, '.') or do {
909             $self->{fetch_error} = "Cannot copy $local: $!";
910             return;
911             };
912             next;
913             }
914             else {
915             my $from;
916             $get_cs = 1;
917             foreach my $url(@url_list) {
918             $url =~ s!/$!!;
919             $from = $url . '/authors/id/' . $id . '/' . $file;
920             print "Fetching $from ...\n";
921             last if mirror($from, $file);
922             }
923             unless (-e $file) {
924             $self->{fetch_error} = "Fetch of $file from $from failed";
925             return;
926             }
927             if ($src_dir ne $build_dir) {
928             unless (-d $src) {
929             mkpath($src) or do {
930             $self->{fetch_error} = "Cannot mkdir $src: $!";
931             return;
932             };
933             }
934             copy($file, $src) or warn "Cannot copy $to to $src: $!";
935             }
936             }
937             }
938             return $to unless $to =~ /$ext$/;
939             my $cksum;
940             unless ($cksum = load_cs($CS)) {
941             $self->{fetch_error} = qq{Checksums check disabled - cannot load $CS file.};
942             return;
943             }
944             unless (verifyMD5($cksum, $to)) {
945             $self->{fetch_error} = qq{Checksums check for "$to" failed.};
946             return;
947             }
948             unlink $CS or warn qq{Cannot unlink "$CS": $!\n};
949             return $to;
950             }
951              
952             1;
953              
954             __END__