File Coverage

Build
Criterion Covered Total %
statement 1 1 100.0
branch n/a
condition n/a
subroutine n/a
pod n/a
total 1 1 100.0


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