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