File Coverage

blib/lib/App/GhaInstall.pm
Criterion Covered Total %
statement 17 156 10.9
branch 0 98 0.0
condition 0 12 0.0
subroutine 6 21 28.5
pod 0 15 0.0
total 23 302 7.6


line stmt bran cond sub pod time code
1 1     1   726 use 5.006;
  1         3  
2 1     1   5 use strict;
  1         2  
  1         21  
3 1     1   4 use warnings;
  1         2  
  1         180  
4              
5             package App::GhaInstall;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.002';
9              
10             our $ALLOW_FAIL = 0;
11             our $DRY_RUN = 0;
12              
13             sub maybe_die {
14 0     0 0   my $exit = shift;
15 0 0         if ( $exit ) {
16 0 0         if ( $ALLOW_FAIL ) {
17 0           warn "Failed, but continuing anyway...\n";
18             }
19             else {
20 0           die "Failed; stopping!\n";
21             }
22             }
23 0           return;
24             }
25              
26             sub CPAN_CONFIG_FILENAME () {
27 0     0 0   $ENV{HOME} . '/' . 'GhaInstallConfig.pm'
28             }
29              
30             sub SHOULD_INSTALL_OPTIONAL_DEPS () {
31 1     1   7 no warnings;
  1         2  
  1         130  
32             $ENV{GHA_TESTING_COVER} =~ /^(true|1)$/i
33 0 0   0 0   or $ENV{GHA_INSTALL_OPTIONAL} =~ /^(true|1)$/i
34             }
35              
36             sub SHOULD_INSTALL_COVERAGE_DEPS () {
37 1     1   7 no warnings;
  1         1  
  1         112  
38 0     0 0   $ENV{GHA_TESTING_COVER} =~ /^(true|1)$/i
39             }
40              
41             sub SHOULD_INSTALL_GITHUB_DEPS () {
42 1     1   7 no warnings;
  1         2  
  1         1597  
43             !! $ENV{CI}
44 0     0 0   }
45              
46             sub go {
47 0     0 0   shift;
48            
49 0           my @modules;
50            
51 0           foreach ( @_ ) {
52 0 0         if ( /--allow-fail/ ) {
    0          
    0          
    0          
53 0           $ALLOW_FAIL = 1;
54             }
55             elsif ( /--dry-run/ ) {
56 0           $DRY_RUN = 1;
57             }
58             elsif ( /--configure/ ) {
59 0           install_configure_dependencies();
60             }
61             elsif ( /--auto/ ) {
62 0           install_dependencies();
63             }
64             else {
65 0           push @modules, $_;
66             }
67             }
68            
69 0 0         if ( @modules ) {
70 0           install_modules( @modules );
71             }
72            
73 0           return 0;
74             }
75              
76             sub slurp {
77 0     0 0   my $file = shift;
78 0 0         open my $fh, '<', $file
79             or die "$file exists but cannot be read\n";
80 0           local $/;
81 0           return <$fh>;
82             }
83              
84             sub read_json {
85 0     0 0   my $file = shift;
86 0 0         return unless -f $file;
87            
88 0           my $hash;
89            
90 0 0         if ( eval { require JSON::MaybeXS; 1 } ) {
  0 0          
  0            
91 0           my $json = 'JSON::MaybeXS'->new;
92 0           $hash = $json->decode( slurp($file) );
93             }
94 0           elsif ( eval { require JSON::PP; 1 } ) {
  0            
95 0           my $json = 'JSON::PP'->new;
96 0           $hash = $json->decode( slurp($file) );
97             }
98             else {
99             # Bundled version of JSON::Tiny
100 0           require App::GhaInstall::JSON;
101 0           $hash = JSON::Tiny::decode_json( slurp($file) );
102             }
103            
104 0 0         return unless ref($hash) eq 'HASH';
105            
106 0           $hash->{metatype} = 'JSON';
107 0           return $hash;
108             }
109              
110             sub read_yaml {
111 0     0 0   my $file = shift;
112 0 0         return unless -f $file;
113            
114 0           my $hash;
115            
116 0 0         if ( eval { require JSON::XS; 1 } ) {
  0            
  0            
117 0           $hash = YAML::XS::Load( slurp($file) );
118             }
119             else {
120             # Bundled version of YAML::Tiny
121 0           require App::GhaInstall::YAML;
122 0           $hash = YAML::Tiny::Load( slurp($file) );
123             }
124            
125 0 0         return unless ref($hash) eq 'HASH';
126            
127 0           $hash->{metatype} = 'YAML';
128 0           return $hash;
129             }
130              
131             sub install_configure_dependencies {
132 0 0 0 0 0   my $meta =
133             read_json('META.json') || read_yaml('META.yml')
134             or die("Cannot read META.json or META.yml");
135            
136 0           my ( @need, @want );
137            
138 0 0         if ( $meta->{metatype} eq 'JSON' ) {
139 0           for my $phase ( qw( configure build ) ) {
140 0 0         push @need, keys %{ $meta->{prereqs}{$phase}{requires} or {} };
  0            
141 0 0         push @want, keys %{ $meta->{prereqs}{$phase}{recommends} or {} };
  0            
142 0 0         push @want, keys %{ $meta->{prereqs}{$phase}{suggests} or {} };
  0            
143             }
144             }
145             else {
146 0 0         push @need, keys %{ $meta->{configure_requires} or {} };
  0            
147 0 0         push @need, keys %{ $meta->{build_requires} or {} };
  0            
148             }
149            
150 0 0         if ( @need ) {
151 0           install_modules( @need );
152             }
153            
154 0 0 0       if ( @want and SHOULD_INSTALL_OPTIONAL_DEPS ) {
155 0           local $ALLOW_FAIL = 1;
156 0           install_modules( @want );
157             }
158            
159 0           return;
160             }
161              
162             sub install_dependencies {
163 0 0 0 0 0   my $meta =
164             read_json('MYMETA.json') || read_yaml('MYMETA.yml') || read_json('META.json') || read_yaml('META.yml')
165             or die("Cannot read MYMETA.json or MYMETA.yml");
166            
167 0           my ( @need, @want );
168            
169 0 0         if ( $meta->{metatype} eq 'JSON' ) {
170 0           for my $phase ( qw( configure build runtime test ) ) {
171 0 0         push @need, keys %{ $meta->{prereqs}{$phase}{requires} or {} };
  0            
172 0 0         push @want, keys %{ $meta->{prereqs}{$phase}{recommends} or {} };
  0            
173 0 0         push @want, keys %{ $meta->{prereqs}{$phase}{suggests} or {} };
  0            
174             }
175             }
176             else {
177 0 0         push @need, keys %{ $meta->{configure_requires} or {} };
  0            
178 0 0         push @need, keys %{ $meta->{build_requires} or {} };
  0            
179 0 0         push @need, keys %{ $meta->{requires} or {} };
  0            
180 0 0         push @need, keys %{ $meta->{test_requires} or {} };
  0            
181 0 0         push @want, keys %{ $meta->{recommends} or {} };
  0            
182             }
183            
184 0 0         if ( SHOULD_INSTALL_GITHUB_DEPS ) {
185 0           push @need, 'App::GhaProve';
186             }
187            
188 0 0         if ( SHOULD_INSTALL_COVERAGE_DEPS ) {
189 0           push @need, 'Devel::Cover';
190 0           push @need, 'Devel::Cover::Report::Coveralls';
191 0           push @need, 'Devel::Cover::Report::Codecov';
192             }
193            
194 0 0         if ( @need ) {
195 0           install_modules( @need );
196             }
197            
198 0 0 0       if ( @want and SHOULD_INSTALL_OPTIONAL_DEPS ) {
199 0           local $ALLOW_FAIL = 1;
200 0           install_modules( @want );
201             }
202            
203 0           return;
204             }
205              
206             my $installer;
207             sub INSTALLER () {
208 0 0   0 0   return $installer if defined $installer;
209 0           my $output = `cpanm --version`;
210 0 0         if ( $output =~ /cpanminus/ ) {
211 0           $installer = 'cpanm';
212             }
213             else {
214 0           $output = `cpm --help`;
215 0 0         if ( $output =~ /install/ ) {
216 0           $installer = 'cpm';
217             }
218             else {
219 0           ensure_configured_cpan();
220 0           $installer = 'cpan';
221             }
222             }
223 0           return $installer;
224             }
225              
226             sub install_modules {
227 0     0 0   my @modules = grep $_ ne 'perl', @_;
228            
229 0 0         if ( $DRY_RUN ) {
230 0           warn "install: $_\n" for @modules;
231 0           return;
232             }
233              
234 0 0         if ( INSTALLER eq 'cpanm' ) {
235 0           return maybe_die system 'cpanm', '-n', @modules;
236             }
237            
238 0 0         if ( INSTALLER eq 'cpm' ) {
239 0           return maybe_die system 'cpm', 'install', '-g', @modules;
240             }
241              
242 0           install_module $_ for @_;
243             }
244              
245             sub install_module {
246 0     0 0   my $module = shift;
247            
248 0 0         if ( $DRY_RUN ) {
249 0           warn "install: $module\n";
250 0           return;
251             }
252            
253 0 0         if ( INSTALLER eq 'cpanm' ) {
254 0           return maybe_die system 'cpanm', '-n', $module;
255             }
256            
257 0 0         if ( INSTALLER eq 'cpm' ) {
258 0           return maybe_die system 'cpm', 'install', '-g', $module;
259             }
260            
261 0           return maybe_die system 'cpan', '-J', CPAN_CONFIG_FILENAME, '-T', $module;
262             }
263              
264             sub ensure_configured_cpan {
265 0 0   0 0   return if -f CPAN_CONFIG_FILENAME;
266 0           open my $fh, '>', CPAN_CONFIG_FILENAME; print { $fh } <<'CONFIG';
  0            
  0            
267             use Cwd ();
268              
269             my $home = $ENV{HOME};
270             my $cwd = Cwd::cwd;
271              
272             $CPAN::Config = {
273             'applypatch' => q[],
274             'auto_commit' => q[0],
275             'build_cache' => q[100],
276             'build_dir' => qq[$home/.cpan/build],
277             'build_dir_reuse' => q[0],
278             'build_requires_install_policy' => q[yes],
279             'bzip2' => q[/bin/bzip2],
280             'cache_metadata' => q[1],
281             'check_sigs' => q[0],
282             'colorize_output' => q[0],
283             'commandnumber_in_prompt' => q[1],
284             'connect_to_internet_ok' => q[1],
285             'cpan_home' => qq[$home/.cpan],
286             'ftp_passive' => q[1],
287             'ftp_proxy' => q[],
288             'getcwd' => q[cwd],
289             'gpg' => q[/usr/bin/gpg],
290             'gzip' => q[/bin/gzip],
291             'halt_on_failure' => q[0],
292             'histfile' => qq[$home/.cpan/histfile],
293             'histsize' => q[100],
294             'http_proxy' => q[],
295             'inactivity_timeout' => q[0],
296             'index_expire' => q[1],
297             'inhibit_startup_message' => q[0],
298             'keep_source_where' => qq[$home/.cpan/sources],
299             'load_module_verbosity' => q[none],
300             'make' => q[/usr/bin/make],
301             'make_arg' => q[],
302             'make_install_arg' => q[],
303             'make_install_make_command' => q[/usr/bin/make],
304             'makepl_arg' => q[INSTALLDIRS=site],
305             'mbuild_arg' => q[],
306             'mbuild_install_arg' => q[],
307             'mbuild_install_build_command' => q[./Build],
308             'mbuildpl_arg' => q[--installdirs site],
309             'no_proxy' => q[],
310             'pager' => q[/usr/bin/less],
311             'patch' => q[/usr/bin/patch],
312             'perl5lib_verbosity' => q[none],
313             'prefer_external_tar' => q[1],
314             'prefer_installer' => q[MB],
315             'prefs_dir' => qq[$home/.cpan/prefs],
316             'prerequisites_policy' => q[follow],
317             'scan_cache' => q[atstart],
318             'shell' => q[/bin/sh],
319             'show_unparsable_versions' => q[0],
320             'show_upload_date' => q[0],
321             'show_zero_versions' => q[0],
322             'tar' => q[/bin/tar],
323             'tar_verbosity' => q[none],
324             'term_is_latin' => q[1],
325             'term_ornaments' => q[1],
326             'test_report' => q[0],
327             'trust_test_report_history' => q[0],
328             'unzip' => q[/usr/bin/unzip],
329             'urllist' => [q[http://cpan.mirrors.uk2.net/], q[http://cpan.singletasker.co.uk/], q[http://cpan.cpantesters.org/]],
330             'use_sqlite' => q[0],
331             'version_timeout' => q[15],
332             'wget' => q[/usr/bin/wget],
333             'yaml_load_code' => q[0],
334             'yaml_module' => q[YAML],
335             };
336             1;
337             CONFIG
338             }
339              
340             1;
341              
342             __END__