File Coverage

blib/lib/Distribution/Guess/BuildSystem.pm
Criterion Covered Total %
statement 138 140 98.5
branch 71 74 95.9
condition 15 15 100.0
subroutine 52 52 100.0
pod 37 37 100.0
total 313 318 98.4


line stmt bran cond sub pod time code
1 12     12   13049 use v5.10;
  12         42  
2              
3             package Distribution::Guess::BuildSystem;
4 12     12   64 use strict;
  12         23  
  12         260  
5              
6 12     12   70 use warnings;
  12         22  
  12         353  
7 12     12   67 no warnings;
  12         31  
  12         899  
8              
9 12     12   66 use Carp qw(carp);
  12         23  
  12         651  
10 12     12   72 use Config qw(%Config);
  12         34  
  12         534  
11 12     12   92 use Cwd qw(cwd);
  12         22  
  12         731  
12 12     12   4773 use File::Spec::Functions qw(catfile);
  12         8075  
  12         644  
13              
14 12     12   5181 use Module::Extract::VERSION;
  12         17871  
  12         23931  
15              
16             our $VERSION = '1.004';
17              
18             =encoding utf8
19              
20             =head1 NAME
21              
22             Distribution::Guess::BuildSystem - Guess what this distribution uses to build itself
23              
24             =head1 SYNOPSIS
25              
26             use Distribution::Guess::BuildSystem;
27              
28             chdir $dist_dir;
29              
30             my $guesser = Distribution::Guess::BuildSystem->new(
31             dist_dir => $dir
32             );
33              
34             my $build_files = $guesser->build_files; # Hash ref
35              
36             my $build_pl = $guesser->has_build_pl;
37             my $makefile_pl = $guesser->has_makefile_pl;
38              
39             my $both = $guesser->has_build_and_makefile;
40              
41             my $build_command = $guesser->build_commands; # Hash ref
42              
43             if( $guesser->uses_module_install ) {
44             my $version = $guesser->module_install_version;
45             my $pita = $guesser->uses_auto_install;
46             }
47              
48             if( $guesser->uses_makemaker ) {
49             my $version = $guesser->makemaker_version;
50             my $make = $guesser->make_command;
51             }
52              
53             =head1 DESCRIPTION
54              
55             There are three major build system for Perl distributions:
56              
57             =over 4
58              
59             =item * ExtUtils::MakeMaker
60              
61             Uses F and C.
62              
63             =item * Module::Build
64              
65             Uses F and C, although it might have a F that is
66             a wrapper.
67              
68             =item * Module::Install
69              
70             Uses F and calls to an embedded C. It might
71             use C to call C at build time.
72              
73             =back
74              
75             The trick is to figure out which one you are supposed to use. This module has
76             several methods to look at a distribution and guess what its build system is.
77             The main object is simply some settings. Every time you want to ask a
78             question about the distribution, the object looks at the distribution. That is,
79             it doesn't capture the information when you create the object.
80              
81             =head2 Methods
82              
83             =over 4
84              
85             =item new
86              
87             Creates a new guesser object. You can set:
88              
89             dist_dir - the distribution directory (where the build file is)
90             perl_binary - the path to the perl you want to use
91             prefer_module_build - some methods will return the preferred builder
92             prefer_makemaker - some methods will return the preferred builder
93              
94             If you prefer
95             The defaults are:
96              
97             dist_dir - current working directory
98             perl_binary - $^X (may be relative and no longer in path!)
99             prefer_module_build - true
100             prefer_makemaker - false
101              
102             =cut
103              
104             sub new {
105 17     17 1 72428 my %defaults = (
106             dist_dir => cwd(),
107             prefer_module_build => 1,
108             prefer_makemaker => 0,
109             perl_binary => $^X,
110             );
111              
112 17         411 my( $class, %args ) = @_;
113              
114 17         667 bless { %defaults, %args }, $class;
115             }
116              
117             =item dist_dir( [ DIR ] )
118              
119             Returns or sets the distribution directory.
120              
121             =cut
122              
123             sub dist_dir {
124 581     581 1 990 my( $self ) = shift;
125 581         1237 $self->_setting( 'dist_dir', @_ );
126             }
127              
128             =item perl_binary( [PERL] )
129              
130             Returns or sets the perl binary path. This is either the one that you set
131             or the value of C<$^X>. There's no check to verify that this is actually
132             a perl binary.
133              
134             =cut
135              
136             sub perl_binary {
137 4     4 1 10 my( $self ) = shift;
138 4         19 $self->_setting( 'perl_binary', @_ );
139             }
140              
141             =item prefer_makemaker( [TRUE|FALSE] )
142              
143             Returns or sets the Module::Build preference. If this is true, some of
144             the methods preferentially return answers for Module::Build over
145             MakeMaker when a distribution can use both systems. If both
146             C and C are true, then
147             MakeMaker wins.
148             =cut
149              
150             sub prefer_makemaker {
151 8     8 1 23 my( $self ) = shift;
152 8         21 $self->_setting( 'prefer_makemaker', @_ );
153             }
154              
155             =item prefer_module_build( [TRUE|FALSE] )
156              
157             Returns or sets the Module::Build preference. If this is true, some of
158             the methods preferentially return answers for Module::Build over
159             MakeMaker when a distribution can use both systems. If both
160             C and C are true, then
161             MakeMaker wins.
162              
163             =cut
164              
165             sub prefer_module_build {
166 17     17 1 42 my( $self ) = shift;
167 17         56 $self->_setting( 'prefer_module_build', @_ );
168             }
169              
170             sub _setting {
171 613     613   1213 my( $self, $key, $value ) = @_;
172              
173 613 100       1409 if( @_ == 3 ) {
174 3         8 $self->{$key} = $value;
175             }
176              
177 613         4974 return $self->{$key};
178             }
179              
180             =back
181              
182             =head2 Questions about the distribution
183              
184             =over 4
185              
186             =item build_files
187              
188             Returns an hash reference of build files found in the distribution. The
189             keys are the filenames of the build files. The values
190              
191             =cut
192              
193             {
194             my @files = (
195             [ qw( has_makefile_pl makefile_pl ) ],
196             [ qw( has_build_pl build_pl ) ],
197              
198             );
199              
200             sub build_files {
201 20     20 1 10555 my %found;
202              
203 20         107 foreach my $pairs ( @files ) {
204 40         166 my( $check, $file ) = @$pairs;
205 40 100       182 $found{ $_[0]->$file() } = $_[0]->$file() if $_[0]->$check()
206             }
207              
208 20         123 return \%found;
209             }
210             }
211              
212             =item preferred_build_file
213              
214             Returns the build file that you should use, even if there is more than
215             one. Right now this is simple:
216              
217             1. In the single build file distributions, return that build file
218              
219             2. If you've specified a preference with C or
220             C, use that.
221              
222             3. If there is no preference (both are false), prefer C.
223              
224             4. If no of those work, return nothing.
225              
226             =cut
227              
228             sub preferred_build_file {
229             # preference doesn't matter in single build system cases
230 32 100   32 1 6362 return $_[0]->makefile_pl if $_[0]->uses_makemaker_only;
231 19 100       85 return $_[0]->build_pl if $_[0]->uses_module_build_only;
232              
233             # preference now matter
234 13 100 100     40 return $_[0]->build_pl if(
235             $_[0]->prefer_module_build and $_[0]->uses_module_build );
236 8 100 100     122493 return $_[0]->makefile_pl if(
237             $_[0]->prefer_makemaker and $_[0]->uses_makemaker );
238              
239             # absence of preference
240 6 100       24 return $_[0]->build_pl if $_[0]->uses_module_build;
241 5 100       4264 return $_[0]->makefile_pl if $_[0]->uses_makemaker;
242              
243             # no build system?
244 2         9 return;
245             }
246              
247             =item preferred_build_command
248              
249             Returns the build command that you should use. This uses the logic of
250             C. It returns the result of either C
251             or C.
252              
253             =cut
254              
255             sub preferred_build_command {
256 17 100   17 1 68 return $_[0]->build_command if $_[0]->preferred_build_file eq $_[0]->build_pl;
257 8 100       25 return $_[0]->make_command if $_[0]->preferred_build_file eq $_[0]->makefile_pl;
258 1         12 return;
259             }
260              
261             =item build_file_paths
262              
263             Returns an anonymous hash to the paths to the build files, based on
264             the dist_dir argument to C and the return value of
265             C. The keys are the file names and the values are
266             the paths.
267              
268             =cut
269              
270             sub build_file_paths {
271 10     10 1 7838 my %paths;
272              
273 10         28 foreach my $file ( keys %{ $_[0]->build_files } ) {
  10         42  
274 12         54 $paths{$file} = File::Spec->catfile( $_[0]->dist_dir, $file );
275             }
276              
277 10         51 return \%paths;
278             }
279              
280             =item makefile_pl_path
281              
282             =cut
283              
284             sub makefile_pl_path {
285 59 100   59 1 49624 return unless $_[0]->has_makefile_pl;
286              
287 58         189 File::Spec->catfile( $_[0]->dist_dir, $_[0]->makefile_pl );
288             }
289              
290             =item build_pl_path
291              
292             =cut
293              
294             sub build_pl_path {
295 37 100   37 1 637 return unless $_[0]->has_build_pl;
296              
297 34         117 File::Spec->catfile( $_[0]->dist_dir, $_[0]->build_pl );
298             }
299              
300             =item has_build_pl
301              
302             Has the file name returned by C.
303              
304             =cut
305              
306             sub _has_file {
307 473     473   968 my( $self, $file ) = @_;
308              
309 473         1086 my $path = File::Spec->catfile(
310             $self->dist_dir, $file
311             );
312              
313 473 100       7274 $self->{has}{$file} = $path if -e $path;
314 473         4055 $self->{has}{$file};
315             }
316              
317 217     217 1 5467 sub has_build_pl { $_[0]->_has_file( $_[0]->build_pl ) }
318              
319             =item has_makefile_pl
320              
321             Has the file name returned by C.
322              
323             =cut
324              
325 256     256 1 5572 sub has_makefile_pl { $_[0]->_has_file( $_[0]->makefile_pl ) }
326              
327             =item has_build_and_makefile
328              
329             Has both the files returned by C and C.
330              
331             =cut
332              
333             sub has_build_and_makefile {
334 10 100   10 1 2789 $_[0]->has_build_pl
335             &&
336             $_[0]->has_makefile_pl
337             }
338              
339             =item make_command
340              
341             Looks in %Config to see what perl discovered when someone built it if you
342             can use a C variant to build the distribution.
343              
344             =cut
345              
346 29 100   29 1 1938 sub make_command { $_[0]->has_makefile_pl ? $Config{make} : () }
347              
348             =item build_command
349              
350             Returns C<./Build>, the script that F should have created, if
351             the distribution has a F. Otherwise it returns nothing.
352              
353             =cut
354              
355 18 50   18 1 54 sub build_command { $_[0]->has_build_pl ? './Build' : () }
356              
357             =item perl_command
358              
359             Returns the perl currently running. This is the perl that you would use
360             to run the F or F.
361              
362             =cut
363              
364 7 100   7 1 21 sub perl_command { $_[0]->has_build_pl ? $_[0]->perl_binary : () }
365              
366             =item build_commands
367              
368             Returns a hash reference of the commands you can use to build the
369             distribution. The keys are the commands, such as C or C.
370              
371             =cut
372              
373              
374             sub build_commands {
375 10     10 1 1159 my %commands;
376              
377 10 100       30 $commands{ $_[0]->make_command } = 1
378             if $_[0]->has_makefile_pl;
379              
380 10 100       43 $commands{ $_[0]->perl_command . " " . $_[0]->build_pl } = 1
381             if $_[0]->has_build_pl;
382              
383 10         76 return \%commands;
384             }
385              
386             =item uses_makemaker
387              
388             Returns true if the distro uses C.
389              
390             =cut
391              
392             sub _get_modules {
393 68     68   200 my( $self, $path ) = @_;
394 68         186 my $extractor = $self->module_extractor_class->new;
395 68         1329 $extractor->get_modules( $path );
396             }
397              
398             sub uses_makemaker {
399 30 100   30 1 42616 return unless $_[0]->has_makefile_pl;
400              
401 22         97 scalar grep { $_ eq $_[0]->makemaker_name }
  46         744617  
402             $_[0]->_get_modules( $_[0]->makefile_pl_path )
403             }
404              
405             =item uses_makemaker_only
406              
407             Returns true if MakeMaker is the only build system. Knowing that can cut
408             down on the logic quite a bit since you don't have to choose between
409             possibilities or preferences.
410              
411             =cut
412              
413             sub uses_makemaker_only {
414 36 100   36 1 645 return unless $_[0]->has_makefile_pl;
415 27 100       87 return if $_[0]->has_build_pl;
416              
417 15         62 return 1;
418             }
419              
420             =item makemaker_version
421              
422             Returns the version of Makemaker installed for the perl running this code.
423              
424             =cut
425              
426             sub makemaker_version {
427 5 100   5 1 580 return unless $_[0]->uses_makemaker;
428              
429 1         4 my $version = $_[0]->_get_version( $_[0]->makemaker_name );
430             }
431              
432             sub _get_version {
433 3     3   47 require Module::Extract::VERSION;
434              
435 3         16 my( $self, $module, @dirs ) = @_;
436              
437 3 100       56 @dirs = @INC unless @dirs;
438              
439 3         36 my $file = catfile( split /::/, $module ) . ".pm";
440              
441 3         11 my $found_module = 0;
442 3         14 foreach my $dir ( @dirs ) {
443 19         106 my $module = catfile( $dir, $file );
444 19 100       351 next unless -e $module;
445              
446 3         12 $found_module = 1;
447 3         42 return Module::Extract::VERSION->parse_version_safely( $module );
448             }
449              
450 0 0       0 return '$module not installed' unless $found_module;
451 0         0 return;
452             }
453              
454             =item uses_module_build
455              
456             Returns true if this distribution uses C. This means that it
457             has a F and that the F actually uses C.
458              
459             =cut
460              
461             sub uses_module_build {
462 37 100   37 1 1100 return unless $_[0]->has_build_pl;
463              
464 25         112 scalar grep { $_ eq $_[0]->module_build_name }
  18         522239  
465             $_[0]->_get_modules( $_[0]->build_pl_path );
466             }
467              
468             =item uses_module_build_only
469              
470             Returns true if C is the only build system. Knowing that can cut
471             down on the logic quite a bit since you don't have to choose between
472             possibilities or preferences.
473              
474             =cut
475              
476             sub uses_module_build_only {
477 25 100   25 1 47425 return unless $_[0]->has_build_pl;
478 22 100       77 return if $_[0]->has_makefile_pl;
479              
480 9         43 return 1;
481             }
482              
483             =item module_build_version
484              
485             Returns the version of C install for perl running this code.
486              
487             =cut
488              
489             sub module_build_version {
490 5 100   5 1 849 return unless $_[0]->uses_module_build;
491              
492 1         6 my $version = $_[0]->_get_version( $_[0]->module_build_name );
493             }
494              
495             =item uses_module_install
496              
497             Returns true if this distribution uses C.
498              
499             =cut
500              
501             sub uses_module_install {
502 24 100   24 1 3744 return unless $_[0]->has_makefile_pl;
503              
504 21         92 scalar grep { $_ eq $_[0]->module_install_name }
  57         880098  
505             $_[0]->_get_modules( $_[0]->makefile_pl_path )
506             }
507              
508             =item uses_auto_install
509              
510             Returns true if this distribution uses C and will
511             use the auto_install feature.
512              
513             This is a very simple test right now. If it finds the string
514             C in the build file, it returns true.
515              
516             =cut
517              
518             sub uses_auto_install {
519 10 100 100 10 1 2372 return unless $_[0]->has_makefile_pl && $_[0]->uses_module_install;
520              
521 2         15 $_[0]->_file_has_string( $_[0]->makefile_pl_path, 'auto_install' );
522             }
523              
524             =item module_install_version
525              
526             Returns the version of C.
527              
528             =cut
529              
530             sub module_install_version {
531 6 100   6 1 1041 return unless $_[0]->uses_module_install;
532              
533 1         4 my $version = $_[0]->_get_version(
534             $_[0]->module_install_name, $_[0]->module_install_dir
535             );
536             }
537              
538             =item uses_module_build_compat
539              
540             Returns true if this distribution uses C and will
541             use the C feature.
542              
543             This is a very simple test right now. If it finds the string
544             C in the build file, it returns true.
545              
546             =cut
547              
548             sub uses_module_build_compat {
549 10 100 100 10 1 3468 return unless $_[0]->has_build_pl && $_[0]->uses_module_build;
550              
551 3         18 $_[0]->_file_has_string( $_[0]->build_pl_path, 'create_makefile_pl' );
552             }
553              
554             =item build_pl_wraps_makefile_pl
555              
556             Returns true if C is a wrapper around C.
557              
558             =cut
559              
560             sub build_pl_wraps_makefile_pl {
561 5 100 100 5 1 599 return unless $_[0]->has_build_pl && $_[0]->has_makefile_pl;
562              
563 1         6 $_[0]->_file_has_string( $_[0]->build_pl_path,
564             "Makefile.PL" );
565             }
566              
567             sub _file_has_string {
568 13     13   15434 my $fh;
569 13 100       1432 unless( open $fh, "<", $_[1] ) {
570 1         235 carp "Could not open $_[1]: $!";
571 1         8 return;
572             }
573              
574 12 100       376 while( <$fh> ) { return 1 if /\Q$_[2]/ }
  128         761  
575              
576 6         104 return;
577             }
578              
579             =item just_give_me_a_hash
580              
581             =cut
582              
583             {
584             my @methods = qw(
585             dist_dir
586             build_files
587             build_file_paths
588             makefile_pl_path
589             build_pl_path
590             has_build_pl
591             has_makefile_pl
592             has_build_and_makefile
593             make_command
594             perl_command
595             build_commands
596             uses_makemaker
597             makemaker_version
598             uses_module_build
599             module_build_version
600             uses_module_install
601             uses_auto_install
602             module_install_version
603             uses_module_build_compat
604             build_pl_wraps_makefile_pl
605             );
606              
607             sub just_give_me_a_hash {
608 3     3 1 3906 my %hash = ();
609              
610 3         16 foreach my $method ( @methods ) {
611 60         252 $hash{ $method } = $_[0]->$method();
612             }
613              
614 3         15 return \%hash;
615             }
616             }
617              
618             =back
619              
620             =head2 Methods for strings
621              
622             You may want to override or extend these, so they are methods.
623              
624             =over 4
625              
626             =item makefile_pl
627              
628             Returns the string used for the Makefile.PL filename. Seems stupid
629             until you want to change it in a subclass, which you can do now
630             that it's a method. :)
631              
632             =cut
633              
634 385     385 1 5733 sub makefile_pl { 'Makefile.PL' }
635              
636             =item build_pl
637              
638             Returns the string used for the Build.PL filename. Seems stupid
639             until you want to change it in a subclass, which you can do now
640             that it's a method. :)
641              
642             =cut
643              
644 308     308 1 2938 sub build_pl { 'Build.PL' }
645              
646             =item makemaker_name
647              
648             Returns the module name of Makemaker, which is C.
649              
650             =cut
651              
652 47     47 1 286 sub makemaker_name { 'ExtUtils::MakeMaker' }
653              
654             =item module_build_name
655              
656             Return the string representing the name for Module::Build.
657              
658             =cut
659              
660 19     19 1 221 sub module_build_name { 'Module::Build' }
661              
662             =item module_install_name
663              
664             Return the string representing the name for Module::Install. By default
665             this is C.
666              
667             =cut
668              
669 58     58 1 256 sub module_install_name { 'inc::Module::Install' }
670              
671             =item module_install_dir
672              
673             Returns the directory that contains Module::Install. This is the distribution
674             directory because the module name is actually C.
675              
676             =cut
677              
678 1     1 1 3 sub module_install_dir { $_[0]->dist_dir }
679              
680             =item module_extractor_class
681              
682             The name of the module that can get a list of used modules from a Perl file.
683             By default this is Module::Extract::Use.
684              
685             =cut
686              
687 68     68 1 522 sub module_extractor_class { 'Module::Extract::Use' }
688 12     12   5146 BEGIN { require Module::Extract::Use }
689              
690             =back
691              
692             =head1 TO DO
693              
694              
695             =head1 SEE ALSO
696              
697              
698             =head1 SOURCE AVAILABILITY
699              
700             This source is in Github:
701              
702             https://github.com/briandfoy/distribution-guess-buildsystem.git
703              
704             =head1 AUTHOR
705              
706             brian d foy, C<< >>
707              
708             =head1 COPYRIGHT AND LICENSE
709              
710             Copyright © 2008-2022, brian d foy . All rights reserved.
711              
712             You may redistribute this under the terms of the Artistic License 2.0.
713              
714             =cut
715              
716             1;