File Coverage

blib/lib/App/Pm2Port.pm
Criterion Covered Total %
statement 73 262 27.8
branch 2 76 2.6
condition 0 11 0.0
subroutine 19 32 59.3
pod 10 10 100.0
total 104 391 26.6


line stmt bran cond sub pod time code
1             package App::Pm2Port;
2              
3             #===============================================================================
4             #
5             # FILE: portupload.pl
6             #
7             # USAGE: ./portupload.pl
8             #
9             # DESCRIPTION: upload
10             #
11             # OPTIONS: ---
12             # REQUIREMENTS: ---
13             # BUGS: ---
14             # NOTES: ---
15             # AUTHOR: Andrey Kostenko (),
16             # COMPANY: Rambler Internet Holding
17             # VERSION: 1.0
18             # CREATED: 26.06.2009 02:13:30 MSD
19             # REVISION: ---
20             #===============================================================================
21              
22             $ENV{LC_ALL} = 'C';
23             our $VERSION=0.29;
24 1     1   22901 use 5.010;
  1         3  
  1         43  
25 1     1   6 use strict;
  1         2  
  1         56  
26 1     1   6 use warnings;
  1         11  
  1         28  
27 1     1   1655 use ExtUtils::MakeMaker();
  1         110945  
  1         31  
28 1     1   1299 use Net::FTP;
  1         69398  
  1         68  
29 1     1   1580 use Getopt::Long;
  1         16540  
  1         8  
30 1     1   1991 use File::Temp qw(tempdir);
  1         22498  
  1         101  
31 1     1   1216 use YAML qw(Dump LoadFile DumpFile);
  1         9676  
  1         92  
32 1     1   1460 use JSON::XS;
  1         8076  
  1         88  
33 1     1   909 use version;
  1         2799  
  1         8  
34 1     1   84 use File::Basename qw(dirname);
  1         3  
  1         66  
35 1     1   129190 use CPAN;
  1         249885  
  1         719  
36 1     1   1696 use CPANPLUS::Backend;
  1         549349  
  1         41  
37 1     1   33 use Config;
  1         3  
  1         55  
38 1     1   1133 use FreeBSD::Ports::INDEXhash qw/INDEXhash/;
  1         1199  
  1         14389  
39              
40             =head2 new
41              
42             =cut
43              
44             sub new {
45 1     1 1 15 my $class = shift;
46 1         3 my %params = @_;
47 1         8 $params{INDEX} = { INDEXhash() };
48 1         17193 $params{cpan} = CPANPLUS::Backend->new;
49 1         101868 bless {%params}, $class;
50             }
51              
52             =head2 prompt
53              
54             Asks something
55              
56             =cut
57              
58             sub prompt {
59 0     0 1 0 my ( $text, $default ) = @_;
60 0         0 require Term::ReadLine;
61 0         0 state $term = Term::ReadLine->new('perl2port');
62 0         0 $term->readline( $text, $default );
63             }
64              
65             =head2 perl_version_parse
66              
67             Args: $version
68              
69             Converts perl version number to something understandable by FreeBSD
70              
71             =cut
72              
73             sub perl_version_parse {
74 5     5 1 27 my ( $self, $version ) = @_;
75 5         8 my $b = 0;
76 14         64 return join '.', map { int $_ }
  20         37  
77 5         41 grep { defined }
78             ( $version =~ /^(\d+)\.(\d{1,3})(?:\.(\d{1,3})|(\d{3}))?$/ );
79             }
80              
81             =head2 get_dependencies
82              
83             Returns FreeBSD-style list of dependencies.
84              
85             =cut
86              
87             sub get_dependencies {
88 0     0 1 0 my $self = shift;
89 0         0 my $requires = shift;
90 0         0 my $ports = shift;
91 0 0       0 return '' unless $requires;
92 0         0 my @deps;
93             my %deps;
94 0         0 foreach ( keys %$requires ) {
95 0         0 my $module = $_;
96 0 0       0 next if $module eq 'perl';
97 0         0 my $distribution;
98 0 0       0 unless ($ports) {
99 0         0 my $cpan_module = CPAN::Shell->expand( "Module", $module );
100 0 0       0 if ($cpan_module) {
101 0         0 $distribution = $cpan_module->distribution()->base_id;
102             }
103             else {
104 0         0 ( $distribution = $module ) =~ s/::/-/g;
105             }
106 0 0       0 next if $distribution =~ /^perl-/;
107 0         0 $distribution = "p5-$distribution";
108 0         0 $distribution =~ s/-v?[\d\.]+$//;
109 0         0 $distribution =~ s/^p5-(ANSIColor)$/p5-Term-$1/;
110 0         0 $distribution =~ s/libwww-perl/libwww/;
111             }
112             else {
113 0         0 $distribution = $module;
114             }
115 0 0       0 next if $deps{$distribution};
116 0         0 $deps{$distribution} = 1;
117 0         0 my ($package_name) = grep /^\Q$distribution-\E[\d.]+/, keys %{ $self->{INDEX} };
  0         0  
118 0         0 my $location = $self->{INDEX}{$package_name}{path};
119 0 0       0 unless ($location) {
120 0         0 print "Creating dependency for $distribution";
121              
122             #die "Missing dependency for $distribution";
123 0 0       0 unless (fork) {
124 0         0 my $a = App::Pm2Port->new( module => $module );
125 0         0 $a->run;
126 0         0 exit;
127             }
128 0         0 wait;
129 0         0 $location =
130             '/usr/ports/'
131             . LoadFile( glob "~/.portupload/$module.yml" )->{category}
132             . "/$distribution";
133             }
134 0         0 $location =~ s!/usr/ports!\${PORTSDIR}!;
135 0         0 push @deps, "$distribution>=$requires->{$module}:$location";
136             }
137 0 0       0 unshift @deps, '' if $ports;
138 0         0 @deps = sort @deps;
139 0         0 join " \\\n\t\t", @deps;
140             }
141              
142             =head2 create_makefile
143              
144             Args: $metafile, $portupload_file, $man1, $man3
145              
146             =cut
147              
148             sub create_makefile {
149 0     0 1 0 my $self = shift;
150 0         0 my $file = shift;
151 0         0 my $portupload_file = shift;
152 0         0 my $man1 = shift;
153 0         0 my $man3 = shift;
154 0         0 my $module = shift;
155 0         0 open +( my $makefile ), '>', 'Makefile';
156 0         0 ( my $comment = $file->{abstract} ) =~ s/\.$//;
157 0         0 $comment = ucfirst $comment;
158 0         0 print $makefile "# New ports collection makefile for: $file->{name}\n";
159 0         0 print $makefile "# Date created: " . `date "+\%d \%B \%Y"`;
160 0         0 print $makefile "# Whom: $portupload_file->{maintainer}\n";
161 0         0 print $makefile "#\n";
162 0         0 print $makefile "# \$FreeBSD\$\n\n";
163 0         0 print $makefile "PORTNAME= $file->{name}\n";
164 0         0 print $makefile "PORTVERSION= $file->{version}\n";
165 0         0 print $makefile "CATEGORIES= $portupload_file->{category} perl5\n";
166 0   0     0 print $makefile "MASTER_SITES= "
167             . ( $portupload_file->{master_sites} || 'CPAN' ) . "\n";
168 0         0 print $makefile "PKGNAMEPREFIX= p5-\n";
169 0         0 print $makefile "\n";
170 0         0 print $makefile "MAINTAINER= $portupload_file->{maintainer}\n";
171 0         0 print $makefile "COMMENT= $comment\n";
172 0         0 print $makefile "\n";
173 0         0 print $makefile "BUILD_DEPENDS= "
174             . $self->get_dependencies( $file->{requires} )
175             . $self->get_dependencies( $portupload_file->{requires}, 1 ) . "\n";
176 0         0 print $makefile "RUN_DEPENDS=\t\${BUILD_DEPENDS}\n";
177 0         0 print $makefile "\n";
178 0 0       0 print $makefile "USE_APACHE=" . $portupload_file->{apache} . "\n"
179             if $portupload_file->{apache};
180 0 0       0 print $makefile "PERL_MODBUILD= YES\n" if $module->get_installer_type =~ /build/i;
181 0 0       0 print $makefile "PERL_CONFIGURE= "
182             . (
183             $file->{requires}{perl}
184             ? $self->perl_version_parse( $file->{requires}{perl} ) . "+"
185             : 'YES'
186             ) . "\n";
187 0 0       0 print $makefile "MAN1= " . $man1 . "\n" if $man1;
188 0 0       0 print $makefile "MAN3= " . $man3 . "\n" if $man3;
189 0         0 print $makefile "\n";
190              
191 0 0       0 if ( $portupload_file->{additional} ) {
192 0         0 print $makefile ".include \n";
193 0         0 $portupload_file->{additional} =~ s/ {4}/\t/g;
194 0         0 print $makefile $portupload_file->{additional};
195 0         0 print $makefile ".include \n";
196             }
197             else {
198 0         0 print $makefile ".include \n";
199             }
200 0         0 close $makefile;
201             }
202              
203             =head2 create_config
204              
205             Creates config file for module
206              
207             =cut
208              
209             sub create_config {
210 0     0 1 0 my ( $self, $name ) = @_;
211 0         0 mkdir glob "~/.portupload";
212 0         0 my ($package_name) = grep /^\Qp5-$name-\E[\d.]+/, keys %{ $self->{INDEX} };
  0         0  
213 0         0 my $pkg_info = $self->{INDEX}{$package_name};
214 0         0 my $config = {};
215 0         0 my $suggested_category;
216 0         0 ( $config->{category}, $suggested_category ) =
217             $self->suggest_category( $name, $pkg_info->{categories} );
218 0   0     0 $config->{category} ||= prompt( "Port category:", $suggested_category );
219 0         0 my $maintainer_email = $pkg_info->{maintainer};
220              
221 0 0       0 if ( -e glob '~/.porttools' ) {
222 0   0     0 $maintainer_email ||= `. ~/.porttools;echo \$EMAIL`;
223 0         0 chomp $maintainer_email;
224             }
225 0   0     0 $config->{maintainer} = $maintainer_email
226             || prompt( "Maintainer email:", "$ENV{USER}\@rambler-co.ru" );
227 0         0 DumpFile( glob("~/.portupload/$self->{module}.yml"), $config );
228             }
229              
230             =head2 run
231              
232             Makes actually all work
233              
234             =cut
235              
236             sub run {
237 0     0 1 0 my ($self) = @_;
238 0         0 my ( $post_on_cpan, $submit_to_freebsd );
239              
240             GetOptions(
241             'h|help' => sub {
242 0     0   0 print
243             qq{Usage: $0 [ --info ] [ --no-tests ] [ --no-upload ] [ --no-commit ] [ --cpan ]\n};
244 0         0 exit 0;
245             },
246             'info' => sub {
247 0     0   0 $ENV{INFO_ONLY} = 1;
248             },
249             'no-tests' => sub {
250 0     0   0 $ENV{NOTEST} = 1;
251             },
252             'no-upload' => sub {
253 0     0   0 $ENV{NO_UPLOAD} = 1;
254             },
255             'no-commit' => sub {
256 0     0   0 $ENV{NO_COMMIT} = 1;
257             },
258             'freebsd' => sub {
259 0     0   0 $submit_to_freebsd = 1;
260             }
261 0         0 );
262              
263 0         0 my $module = $self->{cpan}->parse_module( module => $self->{module} );
264 0         0 $module->fetch;
265 0         0 chdir $module->extract;
266              
267 0         0 $module->prepare;
268             #$module->test or die unless $ENV{NOTEST};
269 0         0 $module->install;
270 0         0 my $file = $self->load_meta;
271 0         0 my $version = $file->{version};
272 0 0       0 $self->create_config( $file->{name} )
273             unless -f glob "~/.portupload/$self->{module}.yml";
274 0         0 my $portupload_file = LoadFile( glob "~/.portupload/$self->{module}.yml" );
275 0         0 my $ftp;
276 0 0       0 printf qq{
    0          
277             Tests: %s
278             },
279             $ENV{NOTEST} ? 'no' : 'yes',
280             $ENV{NO_UPLOAD} ? 'no' : $portupload_file->{master_sites},
281             ;
282 0 0       0 exit if $ENV{INFO_ONLY};
283 0         0 print ">>> PList\n";
284 0         0 my ( $man1, $man3, @pkg_plist ) = $self->generate_plist( $module->packlist );
285 0         0 system("make -s clean");
286 0         0 chdir tempdir();
287              
288 0 0       0 if (
289             system(
290             "cvs -d :pserver:anoncvs\@anoncvs.tw.FreeBSD.org/home/ncvs co ports/$portupload_file->{category}/p5-$file->{name}"
291             ) == 0
292             )
293             {
294 0 0       0 chdir "ports/$portupload_file->{category}/p5-$file->{name}" or do {
295 0         0 mkdir "ports";
296 0 0       0 mkdir "ports/p5-$file->{name}" or die;
297 0 0       0 chdir "ports/p5-$file->{name}" or die;
298             }
299             }
300              
301 0         0 $self->create_makefile( $file, $portupload_file, $man1, $man3, $module );
302 0         0 open PLIST, '>', 'pkg-plist';
303 0 0       0 if ( !$portupload_file->{distfiles} ) {
304 0         0 print PLIST @pkg_plist;
305             }
306             else {
307 0         0 print PLIST "\n";
308             }
309 0         0 close PLIST;
310 0         0 open PDESCR, '>', 'pkg-descr';
311 0         0 print PDESCR $file->{abstract};
312 0         0 print PDESCR "\n\nWWW: http://search.cpan.org/dist/$file->{name}\n";
313 0 0       0 if ( !system("$ENV{EDITOR} Makefile") ) {
314 0         0 print ">>> Enter your root password:\n";
315 0         0 system("sudo port fetch");
316 0 0       0 if ( system("port test") ) {
317 0         0 warn "test failed\n";
318 0 0       0 unless ( $ENV{NOTEST} ) {
319 0         0 exit;
320             }
321             }
322 0 0       0 if ( -d 'CVS' ) {
323 0         0 system("port submit -c -m update");
324             }
325             else {
326 0         0 system("port submit -m new");
327             }
328             }
329              
330             }
331              
332             =head2 generate_plist
333              
334             created list of manpages and pg-plist
335              
336             =cut
337              
338             sub generate_plist {
339 0     0 1 0 my ($self, $packlist, $module ) = @_;
340 0         0 my @files = sort keys %$packlist;
341 0         0 my (@man1, @man3, @plist, @dlist);
342 0         0 foreach ( @files ) {
343 0 0       0 if (m{^$Config{man1dir}/(.+)$}) {
344 0         0 push @man1, $1;
345 0         0 next;
346             }
347 0 0       0 if (m{^$Config{man3dir}/(.+)$}) {
348 0         0 push @man3, $1;
349 0         0 next;
350             }
351 0 0       0 if (m{^$Config{installsitelib}/(.+)}) {
352 0         0 push @plist, '%%SITE_PERL%%/' . $1 . "\n";
353 0         0 push @dlist, $self->_get_dlist( $plist[-1] , '%%SITE_PERL%%' );
354 0         0 next;
355             }
356 0 0       0 if (m{^$Config{installsitebin}/(.+)}) {
357 0         0 push @plist, 'bin/' . $1 . "\n";
358 0         0 next;
359             }
360 0         0 die $_;
361             }
362 0 0       0 unless ($module->get_installer_type =~ /build/i) {
363 0         0 my $packlist_file = $packlist->packlist_file();
364 0         0 $packlist_file =~ s/$Config{installsitelib}/\%\%SITE_PERL\%\%\/\%\%PERL_ARCH\%\%/;
365 0         0 push @dlist, $self->_get_dlist( $packlist_file , '%%SITE_PERL%%/%%PERL_ARCH%%/auto' );
366 0         0 push @plist, $packlist_file . "\n";
367             }
368 0         0 my $man1 = join "\\\n\t\t", @man1;
369 0         0 my $man3 = join "\\\n\t\t", @man3;
370 0         0 my %dlist = map { $_ => 1 } @dlist;
  0         0  
371 0         0 return $man1, $man3, @plist, reverse sort keys %dlist;
372             }
373              
374             sub _get_dlist {
375 1     1   2 my $self = shift;
376 1         5 my $file = shift;
377 1         1 my $root = shift;
378 1         6 my @dlist;
379 1         2 do {
380 5         174 $file = dirname($file);
381 5 50       12 die "Can't get directory list for $file from $root" if $file eq '.';
382 5         16 push @dlist, '@dirrmtry ' . $file . "\n";
383             } while ( $file ne $root );
384 1         5 pop @dlist;
385 1         15 return @dlist;
386             }
387              
388             =head2 suggest_category
389              
390             Tries to find category for module name.
391              
392             =cut
393              
394             sub suggest_category {
395 2     2 1 6 my $self = shift;
396 2         8 my $module = shift;
397 2         12 my ($root) = split /-/, $module;
398 2         4 my $categories = shift;
399 2 50       6 if ($categories) {
400 0         0 return grep !/^perl$/, @$categories;
401             }
402 2         3 given ($root) {
403 2         12 when (/^DBI(x)?|DBD$/) {
404 2         68 return 'databases';
405             }
406 0           when (/^Catalyst|HTML|WWW$/) {
407 0           return 'www';
408             }
409 0           when (/^Net$/) {
410 0           return 'net';
411             }
412 0           when (/^CSS$/) {
413 0           return 'textproc';
414             }
415             }
416 0           return undef, 'devel';
417             }
418              
419             =head2 load_meta
420              
421             Loads META.yml or META.json
422              
423             =cut
424              
425             sub load_meta {
426 0     0 1   my $self = shift;
427 0 0         if ( -e 'META.json' ) {
428 0 0         open +( my $f ), '<', 'META.json' or die $!;
429 0           local $/ = undef;
430 0           local $\ = undef;
431 0           return JSON::XS::decode_json(<$f>);
432             }
433             else {
434 0           return LoadFile('META.yml');
435             }
436             }
437             1;
438              
439             __END__