File Coverage

Build.PL
Criterion Covered Total %
statement 71 539 13.1
branch 9 256 3.5
condition 1 56 1.7
subroutine 14 64 21.8
pod n/a
total 95 915 10.3


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             # -*- perl -*-
3              
4             #
5             # Author: Slaven Rezic
6             #
7             # Copyright (C) 2017,2018,2019,2020,2021,2022,2023 Slaven Rezic. All rights reserved.
8             # This program is free software; you can redistribute it and/or
9             # modify it under the same terms as Perl itself.
10             #
11             # Mail: slaven@rezic.de
12             # WWW: http://www.rezic.de/eserte/
13             #
14              
15 1     1   5002 use strict;
  1         2  
  1         38  
16 1     1   679 use FindBin;
  1         1289  
  1         56  
17 1     1   626 use lib "$FindBin::RealBin/lib";
  1         626  
  1         16  
18              
19 1     1   141 use Config;
  1         1  
  1         30  
20 1     1   6 use Cwd qw(realpath getcwd);
  1         1  
  1         112  
21 1     1   6 use Digest::MD5 qw(md5_hex);
  1         2  
  1         52  
22 1     1   4 use File::Basename;
  1         1  
  1         50  
23 1     1   662 use Doit;
  1         6  
  1         9  
24 1     1   8 use Doit::Log;
  1         1  
  1         59  
25 1     1   4 use Doit::Util qw(in_directory get_os_release);
  1         1  
  1         645  
26              
27 1         8 my $doit = Doit->init;
28              
29 1         2 my $Build_PL_file_contents = do {
30 1 50       43 open my $fh, '<', 'Build.PL'
31             or error "Error opening Build.PL: $!";
32 1         5 local $/ = undef;
33 1         58 <$fh>;
34             };
35 1         117 my $Build_PL_md5hex = md5_hex $Build_PL_file_contents;
36              
37 1         3 for (@ARGV) {
38 3 50       10 if (/^[^-].*=.*/) { # looks like oldfashioned option without leading dash (e.g. "installdirs=vendor")
39 0         0 s/^/--/;
40             }
41             }
42              
43 1 50       50 if (basename($0) eq 'Build.PL') {
44 0         0 _Build_PL_mode();
45             }
46              
47             # Check if Build is up-to-date (md5 check, no timestamp check)
48             {
49 1 50       2 open my $fh, '<', $0
  1         29  
50             or error "Can't open $0: $!";
51 1         17 my $shebang = <$fh>;
52 1         3 my $md5_line = <$fh>;
53 1 50       7 if (my($old_md5hex) = $md5_line =~ m{^# MD5: (\S+)}) {
54 1 50       12 if ($old_md5hex ne $Build_PL_md5hex) {
55 0         0 my $perl;
56 0 0       0 if (($perl) = $shebang =~ m{^#!\s*(.*)}) {
57             # parsed it
58             } else {
59 0         0 warning "Cannot parse perl interpreter path out of '$shebang', fallback to 'perl'";
60 0         0 $perl = "perl";
61             }
62 0         0 error "Build.PL changed, please run '$perl Build.PL' again";
63             }
64             } else {
65 0         0 error "Unexpected: no MD5 found in '$md5_line'";
66             }
67             }
68              
69 1         8 require Getopt::Long;
70 1         7 my %opt = (verbose => 0, uninst => 0, destdir => '', create_packlist => 1);
71 1         1 $Build_PL::ARGV=$Build_PL::ARGV if 0; # cease -w
72 1         3 @ARGV = (@$Build_PL::ARGV, @ARGV);
73 1 50       5 if ($ENV{PERL_MB_OPT}) {
74 0         0 require Text::ParseWords;
75 0         0 push @ARGV, Text::ParseWords::shellwords($ENV{PERL_MB_OPT});
76             }
77             Getopt::Long::GetOptions(
78 1 50       3 \%opt,
79             'allow_mb_mismatch=i',
80             'config=s%',
81             'create_packlist=i',
82             'destdir=s',
83             'installdirs=s',
84             'install_base=s',
85             'install_path=s%',
86             'prefix=s',
87             'uninst:1',
88             'verbose:1',
89             'versionlib=s',
90             'version=s',
91             # The following are just ignored, but currently set by cover
92             'extra_compiler_flags=s',
93             'extra_linker_flags=s',
94             )
95             or error "usage: $0 [options]";
96              
97 1   50     1370 my $action = shift || 'build';
98 1         5 $action =~ s/-/_/g;
99 1 50       4 if (@ARGV) {
100 0         0 error "No arguments allowed";
101             }
102             {
103 1     1   2 no strict 'refs';
  1         8  
  1         2  
  1         154  
104 1         7 &$action;
105             }
106              
107             sub build {
108 0     0   0 build_libs();
109 0         0 manifypods();
110             }
111              
112             sub build_libs {
113 0     0   0 $doit->make_path('blib/lib');
114 0         0 $doit->make_path('blib/arch'); # not used, but keep ExtUtils::Install quiet
115 0         0 require File::Find;
116 0         0 my @pm_files;
117 1 0 0 1   7 File::Find::find(sub { no warnings 'once'; push @pm_files, $File::Find::name if /\.(pm|pod)$/ && -f $_ }, "lib");
  1     0   2  
  1         368  
  0         0  
  0         0  
118 0         0 for my $file (@pm_files) {
119 0         0 my $dest = 'blib/'.$file;
120 0 0 0     0 if (!-e $dest || -M $dest > -M $file) {
121 0         0 $doit->make_path(dirname($dest));
122 0         0 $doit->copy($file, $dest);
123             }
124             }
125             }
126              
127             sub manifypods {
128             # Handles only Pods in .pod files (which is the case in the Doit distribution)
129 0     0   0 require File::Find;
130 0         0 require Pod::Man;
131 0 0       0 my $mansep = $^O =~ m{^(MSWin32|cygwin)$} ? '.' : '::';
132             File::Find::find
133             ({
134             wanted => sub {
135 0 0 0 0   0 if (-f $_ && /\.pod$/) {
136 1     1   7 no warnings 'once';
  1         1  
  1         7762  
137 0         0 my $pod = $File::Find::name;
138 0         0 my $section = 3; # no scripts yet, so we can hardcode here
139 0         0 my %options = (section => $section);
140 0         0 (my $man = $pod) =~ s{^lib.}{};
141 0         0 $man =~ s{/+}{$mansep}g;
142 0         0 $man =~ s{\.pod$}{.$Config{"man${section}ext"}};
143 0         0 $man = "blib/man$section/$man";
144 0 0 0     0 if (!-e $man || -M $man > -M $pod || -M $man > -M "Build") {
      0        
145 0         0 $doit->make_path(dirname($man));
146 0         0 my $parser = Pod::Man->new(%options);
147 0 0       0 if ($doit->is_dry_run) {
148 0         0 info "$pod -> $man (dry-run)";
149             } else {
150 0         0 info "$pod -> $man";
151 0 0       0 $parser->parse_from_file($pod, $man)
152             or error "Could not install $man";
153             }
154 0         0 $doit->chmod(0644, $man); # XXX should this be changeable? like $PERM_RW in Makefile.PL?
155             }
156             }
157             },
158 0         0 no_chdir => 1,
159             },
160             "lib");
161             }
162              
163             sub clean {
164 0     0   0 $doit->remove_tree('blib');
165             }
166              
167 0     0   0 sub realclean { &clean }
168              
169             sub test {
170 1     1   13 local $ENV{PERL_DL_NONLAZY} = 1;
171 1         7 require File::Glob;
172 1         6 require File::Spec;
173 1         722 $doit->system($^X, "-MExtUtils::Command::MM", "-MTest::Harness", "-e", 'undef *Test::Harness::Switches; test_harness(0, "blib/lib", "blib/arch")', File::Glob::bsd_glob(File::Spec->catfile("t", "*.t")));
174             # $doit->system(_prove_path(), '-b', 't'); # use right perl?
175             }
176              
177             sub test_xt {
178 0     0     $doit->system(_prove_path(), '-b', 'xt'); # use right perl?
179             }
180              
181             sub test_installed {
182 0     0     my $t_dir = "$FindBin::RealBin/t";
183 0 0         chdir "/"
184             or error "Cannot chdir to /: $!";
185 0           $doit->system(_prove_path(), $t_dir);
186             }
187              
188             sub test_in_docker {
189 0     0     my $distro_spec = $ENV{DISTRO_SPEC}; # XXX this should be a proper option!
190 0 0 0       if (!$distro_spec || $distro_spec !~ m{^.*:.*$}) {
191 0           error "Please set DISTRO_SPEC environment variable to something like 'debian:jessie'";
192             }
193 0           my $more_testing = $ENV{XXX_MORE_TESTING}; # XXX this will be a proper option in future!
194 0 0         Doit::Log::set_label("[$distro_spec" . ($more_testing ? " (more)" : "") . "]");
195 0           for my $tool (qw(docker)) {
196 0 0         $doit->which($tool) or error "$tool is missing";
197             }
198 0           require File::Temp;
199 0           my $dir = File::Temp::tempdir("Doit_test_in_docker_XXXXXXXX", TMPDIR => 1, CLEANUP => 1);
200 0           my $dockerfile = <<"EOF";
201             FROM $distro_spec
202              
203             EOF
204 0 0         if ($ENV{XXX_INVALIDATE_CACHE}) { # XXX this will be a proper option in future!
205 0           _add_Dockerfile_invalidate_cmd(\$dockerfile);
206             }
207              
208 0           my $add_opts = {};
209 0           $dockerfile .= _fix_Dockerfile_for_dist($distro_spec, $add_opts);
210 0           _docker_add_distro_specific_files(dir => $dir, distro_spec => $distro_spec);
211 0 0         if (-e "$dir/.distro_support") {
212 0           $dockerfile .= <<'EOF';
213             COPY .distro_support .distro_support
214             RUN .distro_support/run.sh
215             EOF
216             }
217              
218 0 0         if ($distro_spec =~ m{^(centos|rockylinux|fedora):}) {
    0          
219             ######################################################################
220             # CentOS
221             # From https://fedoraproject.org/wiki/EPEL/FAQ#How_can_I_install_the_packages_from_the_EPEL_software_repository.3F
222 0 0 0       if ($distro_spec eq 'centos:6') {
    0          
223 0           $dockerfile .= <<"EOF";
224             RUN rpm -Uvh https://dl.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm
225             EOF
226             } elsif ($distro_spec eq 'centos:7' || $distro_spec eq 'rockylinux:8') {
227 0           $dockerfile .= <<"EOF";
228             RUN yum -y install epel-release
229             EOF
230             } else {
231 0           info "No EPEL support for $distro_spec";
232             }
233 0           $dockerfile .= <<"EOF";
234             RUN yum -y install \\
235             sudo \\
236             rsync \\
237             "perl(Digest::MD5)" \\
238             "perl(ExtUtils::MakeMaker)" \\
239             "perl(FindBin)" \\
240             "perl(Hash::Util)" \\
241             "perl(Sys::Hostname)" \\
242             "perl(Test::More)" \\
243             "perl(Tie::File)" \\
244             make \\
245             git
246              
247             EOF
248 0 0         if ($distro_spec eq 'centos:8') {
    0          
    0          
249             # Requires also PowerTools repo additionally to EPEL
250 0           $dockerfile .= <<"EOF";
251             RUN dnf -y install 'dnf-command(config-manager)'
252             RUN yum config-manager --set-enabled PowerTools
253             EOF
254             } elsif ($distro_spec eq 'rockylinux:8') {
255 0           $dockerfile .= <<"EOF";
256             RUN dnf -y --enablerepo=powertools install perl-IPC-Run
257             EOF
258             } elsif ($distro_spec eq 'rockylinux:9') {
259 0           $dockerfile .= <<"EOF";
260             RUN dnf -y --enablerepo=crb install perl-IPC-Run
261             EOF
262             }
263 0           $dockerfile .= <<"EOF";
264             RUN yum -y install \\
265             "perl(IPC::Run)"
266             EOF
267 0 0 0       if ($distro_spec ne 'centos:8' && $distro_spec ne 'rockylinux:8' && $distro_spec ne 'rockylinux:9') {
      0        
268             # Currently not available in CentOS8 and Rocky
269 0           $dockerfile .= <<"EOF";
270             RUN yum -y install \\
271             "perl(Net::OpenSSH)"
272             EOF
273             }
274 0 0         if ($distro_spec eq 'centos:6') {
275 0           $dockerfile .= <<"EOF";
276             RUN curl -L https://cpanmin.us | perl - App::cpanminus
277              
278             # Not available as an RPM
279             RUN cpanm --quiet --notest CPAN::Meta
280             EOF
281             } else {
282 0           $dockerfile .= <<"EOF";
283             RUN yum -y install \\
284             "perl(CPAN::Meta)"
285             EOF
286             }
287 0 0         if ($more_testing) {
288 0           $dockerfile .= <<"EOF";
289             RUN yum -y install \\
290             "perl(Capture::Tiny)" \\
291             "perl(Term::ANSIColor)" \\
292             "perl(BSD::Resource)" \\
293             "perl(CPAN::Meta::Validator)" \\
294             "perl(LWP::UserAgent)" \\
295             "perl(Config::IniFiles)" \\
296             file
297              
298             ENV GITHUB_ACTIONS 1
299             ENV DOIT_TEST_WITH_SUDO 1
300              
301             EOF
302 0 0         if ($distro_spec eq 'centos:6') {
303 0           $dockerfile .= <<"EOF";
304             # Term::ANSIColor exists, but is too old (no colorstrip function)
305             RUN cpanm --quiet --notest "Term::ANSIColor~>=2.01"
306              
307             RUN yum -y install python34-pip
308              
309             EOF
310             } else {
311 0           $dockerfile .= <<"EOF";
312             RUN yum -y install python3-pip
313             EOF
314             }
315             }
316             } elsif ($distro_spec =~ m{^alpine(:|$)}) {
317 0           $dockerfile .= <<"EOF";
318             RUN apk update
319             # perl-utils for prove
320             # shadow for useradd
321             RUN apk add sudo rsync git perl perl-utils make shadow
322             EOF
323 0 0         if ($more_testing) {
324 0           $dockerfile .= <<"EOF";
325             RUN apk add py3-pip
326              
327             #ENV GITHUB_ACTIONS 1
328             ENV DOIT_TEST_WITH_SUDO 1
329              
330             EOF
331             }
332              
333             } else {
334             ######################################################################
335             # Debian-like (Debian, Ubuntu, LinuxMint ...)
336 0           my $packages_spec;
337             {
338 0           my @packages;
  0            
339             {
340 0 0         push @packages, (
  0            
341             'libipc-run-perl',
342             ($distro_spec eq 'ubuntu:precise' ? () : 'libnet-openssh-perl'),
343             'sudo',
344             'rsync',
345             'git',
346             );
347             }
348 0 0         if ($more_testing) {
349 0 0         push @packages, (
350             'libbsd-resource-perl',
351             'libcapture-tiny-perl',
352             'libconfig-inifiles-perl',
353             'libcpan-meta-perl',
354             'libdevel-hide-perl',
355             'libwww-perl',
356             'perl-modules',
357             'locales',
358             'file',
359             ($distro_spec eq 'ubuntu:precise' ? () : 'python3-pip'),
360             );
361             }
362 0           $packages_spec = join(" \\\n", map { " $_" } @packages);
  0            
363             }
364              
365 0 0         if ($distro_spec =~ m{^(ubuntu:precise)$}) {
366             # See https://gist.github.com/dergachev/f5da514802fcbbb441a1
367 0           $dockerfile .= <<'EOF'
368             RUN sed -i.bak -r 's/(archive|security).ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list
369             EOF
370             }
371 0           $dockerfile .= <<"EOF";
372             ENV DEBIAN_FRONTEND noninteractive
373              
374             RUN apt-get$add_opts->{apt_get_update_opts} update && apt-get install -y --no-install-recommends$add_opts->{apt_get_install_opts} \\
375             $packages_spec
376              
377             EOF
378 0 0         if ($more_testing) {
379 0           $dockerfile .= <<"EOF";
380             ENV GITHUB_ACTIONS 1
381             ENV DOIT_TEST_WITH_SUDO 1
382              
383             EOF
384             }
385             }
386              
387 0           for my $env_key (qw(HARNESS_OPTIONS)) {
388 0 0         if (defined $ENV{$env_key}) {
389 0           $dockerfile .= <<"EOF";
390             ENV $env_key "$ENV{$env_key}"
391             EOF
392             }
393             }
394              
395 0           $doit->write_binary("$dir/Dockerfile", $dockerfile);
396             in_directory {
397 0     0     (my $tag = $distro_spec) =~ s{:}{-}g;
398 0           $tag = 'doit-test-' . $tag;
399 0           $doit->system(qw(docker build -t), $tag, qw(.));
400 0           $doit->system(
401             qw(docker run), '-v', "$FindBin::RealBin:/data:ro", $tag,
402             'sh', '-c', 'rsync -a --no-owner --no-group --exclude=blib "--exclude=Doit-*.tar.gz" /data/ /tmp/Doit/ && cd /tmp/Doit && perl Build.PL && ./Build && ./Build generate_META_json && ./Build test && ./Build test_xt && ./Build dist_install_and_test'
403             );
404 0           } $dir;
405              
406 0           Doit::Log::set_label(undef);
407             }
408              
409             # Run docker-based tests on a number of Linux distributions:
410             # the stable ones of Debian, Ubuntu and CentOS, and some
411             # older versions of these distributions.
412             sub test_standard {
413 0     0     Doit::Log::set_label("[local]");
414 0           $doit->system($^X, 'Build.PL');
415 0           $doit->system('./Build');
416 0           $doit->system('./Build', 'test');
417 0           Doit::Log::set_label(undef);
418 0           my @results;
419 0           for my $distro_spec ('debian:bookworm', 'ubuntu:jammy', 'debian:bullseye', 'ubuntu:focal', 'debian:buster', 'ubuntu:bionic', 'centos:7', 'debian:stretch', 'debian:jessie', 'ubuntu:xenial', 'ubuntu:precise', 'centos:6', 'alpine:latest') {
420 0           local $ENV{DISTRO_SPEC} = $distro_spec;
421 0           for my $more_testing (0, 1) {
422 0           local $ENV{XXX_MORE_TESTING} = $more_testing;
423 0           my $t0 = time; # currently not hires, should be fine for now
424 0           $doit->system('./Build', 'test_in_docker');
425 0           my $t1 = time;
426 0           push @results, { distro => $distro_spec, more_testing => $more_testing, result => 'pass', time => ($t1-$t0)."s" };
427             }
428             }
429              
430 0           my $report = "test_standard results\n";
431 0           my @cols = qw(distro more_testing result time);
432 0           my @col_widths;
433 0           for my $col (@cols) {
434 0           my $max_width;
435 0           for my $result (@results) {
436 0           my $width = length $result->{$col};
437 0 0 0       $max_width = $width if !defined $max_width || $max_width < $width;
438             }
439 0           push @col_widths, $max_width;
440             }
441 0           for my $result (@results) {
442 0           for my $col_i (0 .. $#cols) {
443 0           $report .= sprintf "%-${col_widths[$col_i]}s ", $result->{$cols[$col_i]};
444             }
445 0           $report .= "\n";
446             }
447 0           info $report;
448             }
449              
450             sub test_kwalitee (;$) {
451 0     0     my($distdir) = @_;
452             # If cwd is used then more tests fail,
453             # because META files are not available here.
454 0 0         $distdir = $FindBin::RealBin if !defined $distdir;
455              
456 0 0         if (eval { require Test::Kwalitee; 1 }) {
  0            
  0            
457             in_directory {
458 0     0     local $ENV{RELEASE_TESTING} = 1;
459 0           eval { $doit->system($^X, '-MTest::More', '-MTest::Kwalitee=kwalitee_ok', '-e', 'kwalitee_ok(qw(-has_manifest -has_meta_yml)); done_testing') };
  0            
460 0           } $distdir;
461             } else {
462 0           warning "Test::Kwalitee is not installed";
463             }
464             }
465              
466             sub test_pod (;$) {
467 0     0     my($distdir) = @_;
468 0 0         $distdir = $FindBin::RealBin if !defined $distdir;
469              
470 0 0         if (eval { require Test::Pod; 1 }) {
  0            
  0            
471             in_directory {
472 0     0     eval { $doit->system($^X, '-MTest::Pod', '-e', 'all_pod_files_ok()') };
  0            
473 0           } $distdir;
474             } else {
475 0           warning "Test::Pod is not installed";
476             }
477             }
478              
479             sub test_cpan_versions {
480 0     0     my($distdir) = @_;
481              
482 0 0         if ($doit->which("cpan_check_versions")) {
483             in_directory {
484 0     0     $doit->system('cpan_check_versions', '-remote');
485 0           } $distdir;
486             } else {
487 0           warning <
488             No cpan_check_versions found in PATH, cannot check for properly
489             incremented VERSIONs. Please check git://github.com/eserte/srezic-misc.git
490             EOF
491             }
492             }
493              
494             sub git_checks {
495 0     0     _check_clean_git();
496              
497 0           my $Doit_VERSION = _get_Doit_VERSION();
498              
499 0           my $out = $doit->info_qx(qw(git tag -l), $Doit_VERSION);
500 0 0 0       if (defined $out && $out ne '') {
501 0           error "A git tag $Doit_VERSION already exists";
502             }
503             }
504              
505             sub distdir {
506 0     0     my(%options) = @_;
507 0           my $temporary = delete $options{temporary};
508 0 0         error "Unhandled options: " . join(" ", %options) if %options;
509              
510 0           require File::Temp;
511 0           my $tempdir = File::Temp::tempdir("Doit_distdir_XXXXXXXX", TMPDIR => 1, CLEANUP => $temporary);
512 0           my $Doit_VERSION = _get_Doit_VERSION();
513 0           my $distdir = "$tempdir/Doit-$Doit_VERSION";
514 0           $doit->mkdir($distdir);
515 0           for my $line (split /\0/, $doit->info_qx({quiet=>1}, 'git', 'ls-files', '-z')) {
516 0 0         next if ($line =~ m{^( \.travis\.yml
517             | \.?appveyor\.yml
518             | \.github/.*
519             | \.gitignore
520             )$}x);
521             # XXX maybe implement also MANIFEST.SKIP?
522 0           my $dirname = dirname $line;
523 0 0         if ($dirname ne '.') {
524 0           $doit->make_path("$distdir/$dirname");
525             }
526 0           $doit->copy($line, "$distdir/$dirname/");
527             }
528              
529 0           generate_META_json("$distdir/META.json");
530 0           generate_META_yml("$distdir/META.yml" );
531              
532 0           test_kwalitee($distdir);
533 0           test_pod($distdir);
534              
535             # If not temporary, then it is assumed that the
536             # interactive distdir action is called, and
537             # provide information to the user.
538 0 0         if (!$temporary) {
539 0           info "Distribution directory is $distdir";
540             }
541              
542 0           $distdir;
543             }
544              
545             sub dist {
546 0 0   0     if (!$ENV{DOIT_TEST_SKIP_SOME_CHECKS}) {
547 0           git_checks();
548             }
549             # else skip because Doit version is usually not incremented in
550             # this phase and the git tag already exists
551              
552              
553 0           my $tarfile = _get_tarfilename();
554 0 0         if (-e $tarfile) {
555 0           error "$tarfile already exists";
556             }
557 0           my $distdir = distdir(temporary => 1);
558              
559 0 0         if (!$ENV{DOIT_TEST_SKIP_SOME_CHECKS}) {
560 0           test_cpan_versions($distdir);
561             }
562             # else because versions of all Doit modules are usually not
563             # incremented in this phase
564              
565             in_directory {
566             # Note: tar cfvz C:/... ... does not seem to work on Windows
567             # (for all or some tar versions?). Error message is:
568             # tar (child): Cannot connect to C: resolve failed
569             # So create in cwd first, and move to final location.
570 0     0     $doit->system('tar', 'cfvz', basename($tarfile), basename($distdir));
571 0           $doit->move(basename($tarfile), $tarfile);
572 0           } "$distdir/..";
573             }
574              
575             sub dist_install_and_test {
576 0     0     local $ENV{DOIT_TEST_SKIP_SOME_CHECKS} = 1; # XXX is there a better interface?
577 0           my $tarfile = _get_tarfilename();
578 0 0         if (!-e $tarfile) {
579 0           dist();
580             }
581 0           require File::Temp;
582 0           my $dir = File::Temp::tempdir("Doit_dist_install_and_test_XXXXXXXX", TMPDIR => 1, CLEANUP => 1);
583 0           my $Doit_VERSION = _get_Doit_VERSION();
584             in_directory {
585             # Note: see above for tar under Windows problems
586 0     0     $doit->move($tarfile, basename($tarfile));
587 0           $doit->system('tar', 'xfz', basename($tarfile));
588             in_directory {
589 0           $doit->system($^X, 'Build.PL');
590 0 0         my @Build = $^O eq 'MSWin32' ? ($^X, 'Build') : ('./Build');
591 0 0         my @sudo = $^O eq 'MSWin32' ? () : ('sudo');
592 0           $doit->system(@Build);
593 0           $doit->system(@Build, 'test');
594 0           $doit->system(@sudo, @Build, 'install');
595 0           $doit->system(@Build, 'test-installed');
596 0           } "Doit-$Doit_VERSION";
597 0           } $dir;
598             }
599              
600             sub dist_install_with_cpanm {
601 0     0     my $tarfile = _get_tarfilename();
602 0 0         if (!-e $tarfile) {
603 0           dist();
604             }
605 0           $doit->system('cpanm', $tarfile);
606 0           test_installed();
607             }
608              
609             sub look {
610 0     0     my $distdir = distdir(temporary => 1);
611             in_directory {
612 0     0     info "Spawning $ENV{SHELL} in $distdir...";
613 0           local $ENV{DOIT_BUILD_SHELL_LEVEL} = $ENV{DOIT_BUILD_SHELL_LEVEL};
614 0           $ENV{DOIT_BUILD_SHELL_LEVEL}++;
615 0           $doit->system($ENV{SHELL});
616 0           } $distdir;
617             }
618              
619             sub cover {
620 0     0     $doit->system(_cover_path(), '--test');
621             }
622              
623             sub show_cover {
624 0     0     cover();
625 0 0         my $browser = $^O eq 'darwin' ? 'open' : $doit->which('xdg-open') ? 'xdg-open' : 'firefox';
    0          
626 0           $doit->system($browser, "$FindBin::RealBin/cover_db/coverage.html");
627             }
628              
629             sub install {
630 0     0     build();
631             # XXX check if test suite was run?
632              
633             # MOD_INSTALL = $(ABSPERLRUN) -MExtUtils::Install -e 'install([ from_to => {@ARGV}, verbose => '\''$(VERBINST)'\'', uninstall_shadows => '\''$(UNINST)'\'', dir_mode => '\''$(PERM_DIR)'\'' ]);' --
634             # $(MOD_INSTALL) \
635              
636             # for a perl install:
637             # read "$(PERL_ARCHLIB)/auto/$(FULLEXT)/.packlist" \
638             # write "$(DESTINSTALLARCHLIB)/auto/$(FULLEXT)/.packlist" \
639             # "$(INST_LIB)" "$(DESTINSTALLPRIVLIB)" \
640             # "$(INST_ARCHLIB)" "$(DESTINSTALLARCHLIB)" \
641             # "$(INST_BIN)" "$(DESTINSTALLBIN)" \
642             # "$(INST_SCRIPT)" "$(DESTINSTALLSCRIPT)" \
643             # "$(INST_MAN1DIR)" "$(DESTINSTALLMAN1DIR)" \
644             # "$(INST_MAN3DIR)" "$(DESTINSTALLMAN3DIR)"
645              
646             # for a site install:
647             # read "$(SITEARCHEXP)/auto/$(FULLEXT)/.packlist" \
648             # write "$(DESTINSTALLSITEARCH)/auto/$(FULLEXT)/.packlist" \
649             # "$(INST_LIB)" "$(DESTINSTALLSITELIB)" \
650             # "$(INST_ARCHLIB)" "$(DESTINSTALLSITEARCH)" \
651             # "$(INST_BIN)" "$(DESTINSTALLSITEBIN)" \
652             # "$(INST_SCRIPT)" "$(DESTINSTALLSITESCRIPT)" \
653             # "$(INST_MAN1DIR)" "$(DESTINSTALLSITEMAN1DIR)" \
654             # "$(INST_MAN3DIR)" "$(DESTINSTALLSITEMAN3DIR)"
655            
656 0           require Data::Dumper;
657 0           require ExtUtils::Install;
658 0           my $FULLEXT = 'Doit';
659 0           my $INST_LIB = 'blib/lib';
660 0           my $INST_ARCHLIB = 'blib/arch';
661 0           my $INST_BIN = 'blib/bin';
662 0           my $INST_SCRIPT = 'blib/script';
663 0           my $INST_MAN1DIR = 'blib/man1';
664 0           my $INST_MAN3DIR = 'blib/man3';
665 0           my $PERM_DIR = '755';
666             my @euii_args = (
667             from_to => {
668             (
669             $opt{install_base}
670             ?
671             (
672             read => "$Config{sitearchexp}/auto/$FULLEXT/.packlist",
673             ($opt{create_packlist} ? (write => "$opt{install_base}/lib/perl5/$Config{archname}/auto/$FULLEXT/.packlist") : ()),
674             $INST_LIB => "$opt{install_base}/lib/perl5",
675             $INST_ARCHLIB => "$opt{install_base}/lib/perl5",
676             $INST_BIN => "$opt{install_base}/bin",
677             $INST_SCRIPT => "$opt{install_base}/bin",
678             $INST_MAN1DIR => "$opt{install_base}/man/man1",
679             $INST_MAN3DIR => "$opt{install_base}/man/man3",
680             )
681             :
682             ($opt{installdirs}||'') eq 'core'
683             ?
684             (
685             read => "$Config{archlib}/auto/$FULLEXT/.packlist",
686             ($opt{create_packlist} ? (write => "$opt{destdir}$Config{installarchlib}/auto/$FULLEXT/.packlist") : ()),
687             $INST_LIB => "$opt{destdir}$Config{installprivlib}",
688             $INST_ARCHLIB => "$opt{destdir}$Config{installarchlib}",
689             $INST_BIN => "$opt{destdir}$Config{installbin}",
690             $INST_SCRIPT => "$opt{destdir}$Config{installscript}",
691             ($Config{installman1dir} ? ($INST_MAN1DIR => "$opt{destdir}$Config{installman1dir}") : ()),
692             ($Config{installman3dir} ? ($INST_MAN3DIR => "$opt{destdir}$Config{installman3dir}") : ()),
693             )
694             :
695             ($opt{installdirs}||'') eq 'vendor'
696             ?
697             (
698             read => "$Config{vendorlib}/auto/$FULLEXT/.packlist",
699             ($opt{create_packlist} ? (write => "$opt{destdir}$Config{installvendorarch}/auto/$FULLEXT/.packlist") : ()),
700             $INST_LIB => "$opt{destdir}$Config{installvendorlib}",
701             $INST_ARCHLIB => "$opt{destdir}$Config{installvendorarch}",
702             $INST_BIN => "$opt{destdir}$Config{installvendorbin}",
703             $INST_SCRIPT => "$opt{destdir}$Config{installvendorscript}",
704             ($Config{installvendorman1dir} ? ($INST_MAN1DIR => "$opt{destdir}$Config{installvendorman1dir}") : ()),
705             ($Config{installvendorman3dir} ? ($INST_MAN3DIR => "$opt{destdir}$Config{installvendorman3dir}") : ()),
706             )
707             : # default is site
708             (
709             read => "$Config{sitearchexp}/auto/$FULLEXT/.packlist",
710             ($opt{create_packlist} ? (write => "$opt{destdir}$Config{installsitearch}/auto/$FULLEXT/.packlist") : ()),
711             $INST_LIB => "$opt{destdir}$Config{installsitelib}",
712             $INST_ARCHLIB => "$opt{destdir}$Config{installsitearch}",
713             $INST_BIN => "$opt{destdir}$Config{installsitebin}",
714             $INST_SCRIPT => "$opt{destdir}$Config{installsitescript}",
715             ($Config{installsiteman1dir} ? ($INST_MAN1DIR => "$opt{destdir}$Config{installsiteman1dir}") : ()),
716             ($Config{installsiteman3dir} ? ($INST_MAN3DIR => "$opt{destdir}$Config{installsiteman3dir}") : ()),
717             )
718             )
719             },
720             verbose => $opt{verbose},
721             uninstall_shadows => $opt{uninst},
722 0 0 0       dir_mode => $PERM_DIR,
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
723             dry_run => $doit->is_dry_run,
724             );
725 0           my $euii_args_dump = Data::Dumper->new([{ @euii_args }],[qw()])->Indent(1)->Useqq(1)->Sortkeys(1)->Terse(1)->Dump;
726 0           info "Run ExtUtils::Install::install with parameters\n" . $euii_args_dump;
727 0           ExtUtils::Install::install([@euii_args]);
728 0 0         if ($doit->is_dry_run) {
729 0           info "(this was dry-run mode)";
730             }
731             }
732              
733             {
734 1         0 my $Doit_VERSION;
  0         0  
735              
736             sub _get_Doit_VERSION () {
737 0 0   0     return $Doit_VERSION if defined $Doit_VERSION;
738              
739             {
740 0           my $Doit_pm = $INC{"Doit.pm"};
  0            
741 0 0         open my $fh, $Doit_pm or die "Cannot open $Doit_pm: $!";
742 0           while(<$fh>) {
743 0 0         if (/\$VERSION\s*=\s*'(.*)'/) {
744 0           $Doit_VERSION = $1;
745 0           last;
746             }
747             }
748 0 0         if (!defined $Doit_VERSION) {
749 0           error "Fatal: Cannot find \$VERSION in $Doit_pm";
750             }
751             }
752 0 0         if ($Doit_VERSION !~ m{^\d+\.[\d_]+$}) {
753 0           error "Doit.pm VERSION $Doit_VERSION does not look as expected";
754             }
755             # Check also for numerical value of version
756 0 0         if (!defined $Doit::VERSION) {
757 0           error "Unexpected: cannot find \$VERSION in loaded Doit.pm";
758             }
759             {
760 0           (my $Doit_numerical_version = $Doit_VERSION) =~ s{_}{}g;
  0            
761 0 0         if ($Doit_numerical_version != $Doit::VERSION) {
762 0           error "Unexpected: parsed version $Doit_VERSION is not numerically equal to loaded version $Doit::VERSION";
763             }
764             }
765 0           $Doit_VERSION;
766             }
767             }
768              
769 1         345 sub _get_tarfilename () {
770 0     0     my $Doit_VERSION = _get_Doit_VERSION();
771 0           getcwd . "/Doit-" . $Doit_VERSION . ".tar.gz";
772             }
773              
774             sub _generate_META ($;$) {
775 0     0     my($destfile, $meta_version) = @_;
776              
777 0           require CPAN::Meta;
778 0           require ExtUtils::MakeMaker;
779 0           my $meta = CPAN::Meta->new({
780             name => 'Doit',
781             author => 'Slaven Rezic ',
782             abstract => 'a scripting framework',
783             license => 'perl',
784             version => MM->parse_version("$FindBin::RealBin/lib/Doit.pm"),
785             dynamic_config => 0,
786             prereqs => {
787             configure => {
788             requires => {
789             'Digest::MD5' => 0,
790             'Exporter' => 5.57, # use Exporter "import"
791             'File::Path' => 2.0, # make_path
792             },
793             },
794             runtime => {
795             recommends => {
796             'IPC::Run' => 0,
797             'Net::OpenSSH' => 0,
798             },
799             requires => {
800             'perl' => 5.006,
801             'Exporter' => 5.57, # use Exporter "import"
802             'File::Path' => 2.07, # make_path
803             },
804             },
805             test => {
806             requires => {
807             'Test::More' => 0,
808             },
809             },
810             },
811             resources => {
812             repository => { url => 'git://github.com/eserte/Doit' },
813             },
814             generated_by => "Doit version " . _get_Doit_VERSION(),
815             });
816 0 0         if ($doit->is_dry_run) {
817 0 0         info "Would create $destfile" . (defined $meta_version ? " (version $meta_version)" : "") . " (dry-run)";
818             } else {
819 0 0         $meta->save($destfile, (defined $meta_version ? { version => $meta_version } : ()));
820             }
821             }
822              
823             sub generate_META_json (;$) {
824 0   0 0     my $destfile = shift || 'META.json';
825 0           _generate_META $destfile;
826             }
827              
828             sub generate_META_yml (;$) {
829 0   0 0     my $destfile = shift || 'META.yml';
830 0           _generate_META $destfile, 1.4;
831             }
832              
833             # XXX the debian package build functionality should go into
834             # a separate Doit component
835              
836             sub debian_package {
837 0     0     _debian_package('--depends' => 'perl, libnet-openssh-perl, libipc-run-perl', '--add-distro-version' => '1');
838             }
839              
840             sub _debian_package {
841 0     0     my(%opts) = @_;
842              
843 0           for my $tool (qw(dh-make-perl)) { # git is checked if needed
844 0 0         $doit->which($tool) or error "$tool is missing";
845             }
846              
847 0           my $distdir = distdir(temporary => 1);
848              
849 0           my $version = delete $opts{'--version'};
850 0           my $add_distro_version = delete $opts{'--add-distro-version'};
851 0 0         if (!defined $version) {
852 0 0         $doit->which('git') or error 'git is missing --- please install it or alternatively specify --version manually';
853 0           chomp(my $git_describe = eval { $doit->info_qx('git', 'describe') }); # XXX what if this fails? Optionally made fatal?
  0            
854 0 0         if (defined $git_describe) {
855 0 0         if ($git_describe =~ m{^([0-9\._]+)$}) {
    0          
856 0           $version = $1;
857             } elsif ($git_describe =~ m{^([0-9\._]+)-(\d+)-g(.*)}) {
858 0           $version = $1."+git".$2."+".$3."-1"; # XXX make "1" configurable?
859             } else {
860 0           error "Cannot parse output from git describe: '$git_describe'";
861             }
862 0           $version =~ s{_}{-}; # replace "devel" version specifier
863 0 0         if ($add_distro_version) {
864 0           my $osr = get_os_release();
865 0 0         if (!$osr) {
866 0           error 'Cannot read /etc/os-release --- please specify --version manually';
867             }
868 0           my $dist_id = $osr->{ID};
869 0           my $rel = $osr->{VERSION_ID};
870 0 0         if ($dist_id eq 'debian') {
    0          
    0          
871 0           $rel =~ s{^(\d+).*}{$1};
872 0           $version .= "+deb${rel}u${add_distro_version}";
873             } elsif ($dist_id eq 'linuxmint') {
874 0           $version .= "+linuxmint${rel}u${add_distro_version}";
875             } elsif ($dist_id eq 'ubuntu') {
876 0           $version .= "~ubuntu${rel}.${add_distro_version}";
877             } else {
878 0           error "No distro version support for '$dist_id'";
879             }
880             }
881             } else {
882 0           warning "No information using git-describe available --- use automatic version detection";
883             }
884             }
885              
886 0           my $deb;
887             in_directory {
888 0 0   0     $doit->system(qw(dh-make-perl --build --vcs none), (defined $version ? ('--version', $version) : ()), %opts);
889 0           require File::Glob;
890 0           my(@debs) = File::Glob::bsd_glob("$distdir/../*.deb");
891 0 0         if (@debs != 1) {
892 0           error "Expecting exactly one generated .deb, but got: <@debs>\n";
893             }
894 0           $deb = $debs[0];
895 0           } $distdir;
896 0           $doit->copy($deb, basename($deb));
897 0           print basename($deb), "\n";
898             }
899              
900             sub debian_package_with_docker {
901 0     0     my $distro_spec = $ENV{DISTRO_SPEC}; # XXX this should be a proper option!
902 0 0 0       if (!$distro_spec || $distro_spec !~ m{^.*:.*$}) {
903 0           error "Please set DISTRO_SPEC environment variable to something like 'debian:jessie'";
904             }
905 0           for my $tool (qw(docker)) {
906 0 0         $doit->which($tool) or error "$tool is missing";
907             }
908              
909             # Cannot access directories outside of /Users when working
910             # with docker-machine @ Mac, see for an explanation:
911             # https://stackoverflow.com/questions/37673140/docker-volume-located-in-tmp-on-osx-empty
912 0           my $limited_volume_availability = $^O eq 'darwin';
913              
914 0           require File::Temp;
915 0           my $dir = File::Temp::tempdir("Doit_debian_package_docker_XXXXXXXX", TMPDIR => !$limited_volume_availability, CLEANUP => 1);
916 0           $dir = realpath $dir; # docker volumes have to be specified with absolute paths
917              
918 0 0         my $pkgdir = $limited_volume_availability ? "$FindBin::RealBin/pkg" : "/tmp";
919 0 0         if (!-d $pkgdir) {
920 0           $doit->mkdir($pkgdir);
921             }
922              
923 0           my $use_workdir = $ENV{USE_WORKDIR}; # XXX this should be a proper option
924 0 0         if ($use_workdir) {
925             # no --cvs-exclude --- git-describe has to work
926 0           $doit->system('rsync', '-a', '--exclude=blib', '.', $dir);
927             } else {
928 0           $doit->add_component('git');
929 0           $doit->git_repo_update(
930             repository => $FindBin::RealBin,
931             directory => $dir,
932             # no: we need the full history for correct git version calculation: clone_opts => [qw(--depth=1)],
933             );
934             }
935             in_directory {
936 0     0     my $dockerfile = <<"EOF";
937             FROM $distro_spec
938             EOF
939 0           my $add_opts = {};
940 0           $dockerfile .= _fix_Dockerfile_for_dist($distro_spec, $add_opts);
941 0           $dockerfile .= <<"EOF";
942              
943             ENV DEBIAN_FRONTEND noninteractive
944              
945             RUN apt-get$add_opts->{apt_get_update_opts} update && apt-get$add_opts->{apt_get_install_opts} install -y --no-install-recommends \\
946             dh-make-perl \\
947             git
948              
949             # XXX This is depending on the current perl module and should be configurable
950             RUN apt-get$add_opts->{apt_get_install_opts} install -y --no-install-recommends \\
951             libipc-run-perl \\
952             libnet-openssh-perl
953              
954             EOF
955 0           for my $env_key (qw(DEBFULLNAME DEBEMAIL EMAIL)) {
956 0 0         if ($ENV{$env_key}) {
957 0           $dockerfile .= <<"EOF";
958             ENV $env_key "$ENV{$env_key}"
959             EOF
960             }
961             }
962 0           $doit->write_binary("Dockerfile", $dockerfile);
963              
964 0           (my $label = $distro_spec) =~ s{:}{-}g;
965 0           $label = "doit-deb-$label";
966 0           $doit->system(qw(docker build -t), $label, qw(.));
967 0           $doit->system(
968             qw(docker run), '-v', "$dir:/data", '-v', "$pkgdir:/pkg", $label,
969             'sh', '-c', 'git config --global --add safe.directory /data && cd /data && perl Build.PL && ./Build debian_package && cp *.deb /pkg'
970             );
971 0           } $dir;
972 0           info "Package is available in $pkgdir";
973             }
974              
975             sub release {
976 0     0     my $Doit_VERSION = _get_Doit_VERSION();
977 0           for my $existing_tag (split /\n/, $doit->info_qx({quiet=>1}, 'git', 'tag')) {
978 0 0         if ($Doit_VERSION eq $existing_tag) {
979 0           error "The version $Doit_VERSION is already tagged --- probably the release was already done";
980             }
981             }
982              
983             FIND_VERSION: {
984 0 0         open my $cfh, '<', 'Changes'
  0            
985             or error "Can't open Changes: $!";
986 0           while(<$cfh>) {
987 0 0         if (/^\Q$Doit_VERSION\E\s/) {
988 0           last FIND_VERSION;
989             }
990             }
991 0           error "Cannot find version $Doit_VERSION in Changes";
992             }
993              
994 0           $doit->system('git', 'fetch');
995              
996 0           $doit->add_component('git');
997 0           my $git_status = $doit->git_short_status;
998 0 0 0       if ($git_status ne '' && $git_status ne '<') {
999 0           error "Please check the git status";
1000             }
1001              
1002             # XXX TODO: check first if the current version already exists at CPAN
1003 0           my $tarfile = _get_tarfilename();
1004 0 0         if (!-e $tarfile) {
1005 0           dist();
1006             } else {
1007 0           info "Use existing tarball $tarfile";
1008             }
1009              
1010 0           print STDERR "Upload $tarfile? (y/n) ";
1011 0 0         if (!y_or_n()) {
1012 0           error "exiting release process";
1013             }
1014              
1015 0           $doit->system('cpan-upload', basename($tarfile));
1016              
1017 0           $doit->system('git', 'tag', '-a', '-m', "* $Doit_VERSION", $Doit_VERSION);
1018 0           $doit->system('git', 'push', 'origin', 'master', $Doit_VERSION);
1019             }
1020              
1021             sub ci_precheck {
1022 0     0     my @ci_systems = ('github-actions', 'appveyor');
1023              
1024 0           _check_clean_git();
1025              
1026 0           for my $ci_system (@ci_systems) {
1027 0           $doit->system('git', 'push', 'origin', "+HEAD:XXX-${ci_system}");
1028             }
1029              
1030             # check-ci is available here: https://github.com/eserte/srezic-misc/blob/master/scripts/check-ci
1031 0           $doit->system('check-ci', (map { "--$_" } @ci_systems));
  0            
1032             }
1033              
1034             sub _prove_path {
1035 0     0     my @directory_candidates = ($Config{bin}, dirname(realpath $^X));
1036 0           my @basename_candidates = ('prove', "prove$Config{version}");
1037             my @candidates = map {
1038 0           my $basename = $_;
  0            
1039             map {
1040 0           "$_/$basename";
  0            
1041             } @directory_candidates;
1042             } @basename_candidates;
1043 0 0         if ($^O eq 'MSWin32') {
1044 0           unshift @candidates, map { "$_.bat"} @candidates;
  0            
1045             }
1046 0           for my $candidate (@candidates) {
1047 0 0         if (-x $candidate) {
1048 0           return $candidate;
1049             }
1050             }
1051 0           error "No 'prove' for the current perl found";
1052             }
1053              
1054             sub _cover_path {
1055 0     0     my @candidates = ("$Config{bin}/cover");
1056 0 0         if ($^O eq 'MSWin32') {
1057 0           unshift @candidates, map { "$_.bat"} @candidates;
  0            
1058             }
1059 0           for my $candidate (@candidates) {
1060 0 0         if (-x $candidate) {
1061 0           return $candidate;
1062             }
1063             }
1064 0           error "No 'cover' for the current perl found";
1065             }
1066              
1067             sub _Build_PL_mode {
1068 0     0     require Data::Dumper;
1069 0           my $argv_serialized = "\n" . '$Build_PL::ARGV = ' . Data::Dumper->new([\@ARGV], [])->Indent(1)->Useqq(1)->Sortkeys(1)->Terse(1)->Dump . ";\n\n";
1070             {
1071 0 0         if (-l "Build") { # formerly this used to be a symlink
  0            
1072 0           $doit->unlink("Build");
1073             }
1074 0           my $preamble = <<"EOF";
1075             #! $Config{perlpath}
1076             # MD5: $Build_PL_md5hex
1077             EOF
1078 0           $preamble .= $argv_serialized;
1079 0           $doit->write_binary({quiet=>1}, 'Build', $preamble . qq{# line 1 "Build.PL"\n} . $Build_PL_file_contents);
1080 0           $doit->chmod(0755, 'Build');
1081              
1082 0           eval {
1083 0           generate_META_json("MYMETA.json");
1084 0           generate_META_yml("MYMETA.yml" );
1085             };
1086 0 0         warning "Failure while generating MYMETA.* files, continue without.\nError was:\n$@" if $@;
1087             }
1088 0           exit;
1089             }
1090              
1091             # Return a string for adding to Dockerfile after the FROM line. Also
1092             # the 2nd parameter (which has to be an empty hashref) is filled with
1093             # further instructions to amend the Dockerfile (currently only
1094             # apt_get_update_opts).
1095             sub _fix_Dockerfile_for_dist {
1096 0     0     my($distro_spec, $add_opts_ref) = @_;
1097 0 0         if ($distro_spec =~ m{^debian:(wheezy|jessie|stretch|7|8|9)$}) {
    0          
1098 0           my $codename = $1;
1099 0 0         if ($codename eq '7') { $codename = 'wheezy' }
  0 0          
    0          
1100 0           elsif ($codename eq '8') { $codename = 'jessie' }
1101 0           elsif ($codename eq '9') { $codename = 'stretch' }
1102             # https://unix.stackexchange.com/questions/508724/failed-to-fetch-jessie-backports-repository
1103 0           $add_opts_ref->{apt_get_update_opts} = ' -o Acquire::Check-Valid-Until=false';
1104             # https://askubuntu.com/questions/74345/how-do-i-bypass-ignore-the-gpg-signature-checks-of-apt
1105 0           $add_opts_ref->{apt_get_install_opts} = ' -o APT::Get::AllowUnauthenticated=true';
1106 0           <
1107             RUN echo 'deb [check-valid-until=no] http://archive.debian.org/debian $codename main' > /etc/apt/sources.list
1108             RUN echo 'deb [check-valid-until=no] http://archive.debian.org/debian-security/ $codename/updates main' >> /etc/apt/sources.list
1109             EOF
1110             } elsif ($distro_spec =~ m{^perl:(5\.18\.\d+|.*stretch)$}) { # XXX add more perl versions based on jessie/stretch/... containers
1111             # docker perl images are based on debian base images; older
1112             # ones need patching
1113 0           $add_opts_ref->{apt_get_install_opts} = ' -o APT::Get::AllowUnauthenticated=true';
1114 0           <<'EOF';
1115             RUN perl -i -pe \
1116             's{deb http://(?:http.debian.net|deb.debian.org)/debian (\S+) main}{deb [check-valid-until=no] http://archive.debian.org/debian $1 main}; \
1117             s{deb http://security.debian.org.* ([^/]+)/updates main}{deb [check-valid-until=no] http://archive.debian.org/debian-security/ $1/updates main}; \
1118             $_ = "" if m{^deb .*-updates main}; \
1119             ' /etc/apt/sources.list
1120             EOF
1121             } else {
1122 0           $add_opts_ref->{apt_get_update_opts} = '';
1123 0           $add_opts_ref->{apt_get_install_opts} = '';
1124 0           '';
1125             }
1126             }
1127              
1128             sub _add_Dockerfile_invalidate_cmd {
1129 0     0     my $dockerfile_ref = shift;
1130 0           require POSIX;
1131 0           $$dockerfile_ref .= <<"EOF";
1132             # Just a hack to make sure that the following lines
1133             # are executed at least once a day
1134 0           RUN echo @{[ POSIX::strftime("%F", localtime) ]}
1135             EOF
1136             }
1137              
1138             sub _docker_add_distro_specific_files {
1139 0     0     my %opts = @_;
1140 0   0       my $dir = delete $opts{dir} || die 'Please specify dir';
1141 0   0       my $distro_spec = delete $opts{distro_spec} || die 'Please specify distro_spec';
1142 0 0         die 'Unhandled options: ' . join(' ', %opts) if %opts;
1143              
1144 0 0         if ($distro_spec eq 'centos:6') {
1145 0           $doit->mkdir("$dir/.distro_support");
1146             # Instructions from https://gcore.de/de/hilfe/linux/centos6-repo-nach-eol-anpassen.php
1147 0           $doit->write_binary("$dir/.distro_support/CentOS.repo", <<'EOF');
1148             [base]
1149             name=CentOS-6.10 - Base
1150             baseurl=http://vault.centos.org/6.10/os/$basearch/
1151             gpgcheck=1
1152             gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
1153             enabled=1
1154             metadata_expire=never
1155              
1156             #released updates
1157             [updates]
1158             name=CentOS-6.10 - Updates
1159             baseurl=http://vault.centos.org/6.10/updates/$basearch/
1160             gpgcheck=1
1161             gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
1162             enabled=1
1163             metadata_expire=never
1164              
1165             # additional packages that may be useful
1166             [extras]
1167             name=CentOS-6.10 - Extras
1168             baseurl=http://vault.centos.org/6.10/extras/$basearch/
1169             gpgcheck=1
1170             gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
1171             enabled=1
1172             metadata_expire=never
1173              
1174             # additional packages that extend functionality of existing packages
1175             [centosplus]
1176             name=CentOS-6.10 - CentOSPlus
1177             baseurl=http://vault.centos.org/6.10/centosplus/$basearch/
1178             gpgcheck=1
1179             gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
1180             enabled=0
1181             metadata_expire=never
1182              
1183             #contrib - packages by Centos Users
1184             [contrib]
1185             name=CentOS-6.10 - Contrib
1186             baseurl=http://vault.centos.org/6.10/contrib/$basearch/
1187             gpgcheck=1
1188             gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
1189             enabled=0
1190             metadata_expire=never
1191             EOF
1192 0           $doit->write_binary("$dir/.distro_support/epel.repo", <<'EOF');
1193             [epel]
1194             name=Extra Packages for Enterprise Linux 6 - $basearch
1195             baseurl=https://archives.fedoraproject.org/pub/archive/epel/6/$basearch
1196             enabled=1
1197             gpgcheck=1
1198             gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
1199             metadata_expire=never
1200              
1201             [epel-debuginfo]
1202             name=Extra Packages for Enterprise Linux 6 - $basearch - Debug
1203             baseurl=https://archives.fedoraproject.org/pub/archive/epel/6/$basearch/debug
1204             enabled=0
1205             gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
1206             gpgcheck=1
1207             metadata_expire=never
1208              
1209             [epel-source]
1210             name=Extra Packages for Enterprise Linux 6 - $basearch - Source
1211             baseurl=https://archives.fedoraproject.org/pub/archive/epel/6/SRPMS
1212             enabled=0
1213             gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
1214             gpgcheck=1
1215             metadata_expire=never
1216             EOF
1217 0           $doit->write_binary("$dir/.distro_support/run.sh", <<'EOF');
1218             #! /bin/sh
1219             set -ex
1220             rm -f /etc/yum.repos.d/CentOS*.repo
1221             rm -f /etc/yum.repos.d/epel.repo
1222             cp .distro_support/CentOS.repo /etc/yum.repos.d/
1223             cp .distro_support/epel.repo /etc/yum.repos.d/
1224             yum clean all
1225             EOF
1226 0           $doit->chmod(0755, "$dir/.distro_support/run.sh");
1227             }
1228             }
1229              
1230             sub _check_clean_git {
1231 0     0     $doit->add_component('git');
1232              
1233 0           my $status = $doit->git_short_status;
1234 0 0         if ($status eq '<<') {
1235 0           error 'Working directory has uncomitted changes: ' . `git status`;
1236             }
1237 0 0         if ($status eq '*') {
1238 0           error 'Working directory has files not under git control (and not in .gitignore or .git/info/exclude): ' . `git status`;
1239             }
1240             }
1241              
1242             # REPO BEGIN
1243             # REPO NAME y_or_n /home/eserte/src/srezic-repository
1244             # REPO MD5 146cfcf8f954555fe0117a55b0ddc9b1
1245              
1246             #=head2 y_or_n
1247             #
1248             #Accept user input. Return true on 'y', return false on 'n', otherwise
1249             #ask again.
1250             #
1251             #A default may be supplied as an optional argument:
1252             #
1253             # y_or_n 'y';
1254             # y_or_n 'n';
1255             #
1256             #=cut
1257              
1258             sub y_or_n (;$) {
1259 0     0     my $default = shift;
1260 0           while () {
1261 0           chomp(my $yn = );
1262 0 0 0       if ($yn eq '' && defined $default) {
1263 0           $yn = $default;
1264             }
1265 0 0         if (lc $yn eq 'y') {
    0          
1266 0           return 1;
1267             } elsif (lc $yn eq 'n') {
1268 0           return 0;
1269             } else {
1270 0           print STDERR "Please answer y or n: ";
1271             }
1272             }
1273             }
1274             # REPO END
1275              
1276             __END__