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