Build perls in parallel.
Paul Johnson
8 years ago
12 | 12 | use lib "utils"; |
13 | 13 | |
14 | 14 | use Getopt::Long; |
15 | use Parallel::Iterator "iterate_as_array"; | |
15 | 16 | |
16 | use Devel::Cover::BuildUtils qw( prove_command cpus ); | |
17 | use Devel::Cover::BuildUtils qw( prove_command cpus nice_cpus ); | |
17 | 18 | |
18 | 19 | my $Options = { |
20 | build => 0, | |
19 | 21 | dry_run => 0, |
22 | force => 0, | |
20 | 23 | ignore_failure => 0, |
21 | 24 | silent => 1, |
22 | 25 | version => [], |
24 | 27 | |
25 | 28 | my $Silent = ""; |
26 | 29 | |
30 | sub _exists { | |
31 | my ($v) = @_; | |
32 | eval { !system "dc-$v -v$Silent" } | |
33 | } | |
34 | ||
27 | 35 | sub get_options { |
28 | 36 | die "Bad option" unless |
29 | 37 | GetOptions($Options, qw( |
30 | 38 | build! |
31 | 39 | dry_run! |
40 | force! | |
32 | 41 | ignore_failure! |
33 | 42 | list! |
34 | 43 | silent! |
35 | 44 | version=s |
36 | 45 | )); |
37 | $Options->{version} = [ | |
38 | map { ($_, "$_-thr") } | |
39 | qw( 5.6.1 5.6.2 | |
40 | 5.8.0 5.8.1 5.8.2 5.8.3 5.8.4 5.8.5 5.8.6 5.8.7 5.8.8 5.8.9 | |
41 | 5.10.0 5.10.1 | |
42 | 5.12.0 5.12.1 5.12.2 5.12.3 5.12.4 5.12.5 | |
43 | 5.14.0 5.14.1 5.14.2 5.14.3 5.14.4 | |
44 | 5.16.0 5.16.1 5.16.2 5.16.3 | |
45 | 5.18.0 5.18.1 5.18.2 | |
46 | 5.20.0 5.20.1 5.20.2 5.20.3 | |
47 | 5.22.0 5.22.1 | |
48 | 5.23.0 5.23.1 5.23.2 5.23.3 5.23.4 5.23.5 5.23.6 | |
49 | 5.23.7 | |
50 | ) | |
51 | ] unless @{$Options->{version}}; | |
46 | $Options->{version} = [ map { ($_, "$_-thr") } qw( | |
47 | 5.6.1 5.6.2 | |
48 | 5.8.0 5.8.1 5.8.2 5.8.3 5.8.4 5.8.5 5.8.6 5.8.7 5.8.8 5.8.9 | |
49 | 5.10.0 5.10.1 | |
50 | 5.12.0 5.12.1 5.12.2 5.12.3 5.12.4 5.12.5 | |
51 | 5.14.0 5.14.1 5.14.2 5.14.3 5.14.4 | |
52 | 5.16.0 5.16.1 5.16.2 5.16.3 | |
53 | 5.18.0 5.18.1 5.18.2 5.18.3 5.18.4 | |
54 | 5.20.0 5.20.1 5.20.2 5.20.3 | |
55 | 5.22.0 5.22.1 | |
56 | 5.23.0 5.23.1 5.23.2 5.23.3 5.23.4 5.23.5 5.23.6 5.23.7 5.23.8 5.23.9 | |
57 | ) ] unless @{$Options->{version}}; | |
52 | 58 | $Silent = " >/dev/null 2>&1" if $Options->{silent}; |
53 | 59 | $Options->{version} = |
54 | [ grep eval { !system "perl$_ -v$Silent" }, @{$Options->{version}} ] | |
55 | unless $Options->{build}; | |
60 | [ grep { | |
61 | my $exists = eval { !system "dc-$_ -v$Silent" }; | |
62 | $exists ^ $Options->{build} | |
63 | } @{$Options->{version}} ]; | |
56 | 64 | } |
57 | 65 | |
58 | 66 | sub sys { |
61 | 69 | return if $Options->{dry_run}; |
62 | 70 | $command .= $Silent if $Options->{silent} && !$user; |
63 | 71 | my $ret = system $command; |
64 | die "command failed: $?" if $ret && !$Options->{ignore_failure}; | |
72 | warn "command failed: $?" if $ret && !$Options->{ignore_failure}; | |
73 | !$ret | |
74 | } | |
75 | ||
76 | sub _build_version { | |
77 | my ($v) = @_; | |
78 | my $opts = ""; | |
79 | my ($n) = $v =~ /(\d+\.\d+\.\d+)/ or die "Can't parse [$v}"; | |
80 | $opts .= " --thread" if $v =~ /thr/; | |
81 | $opts .= " --force" if $n =~ /^5\.6\./; | |
82 | my $j = cpus + 1; | |
83 | sys "perlbrew -v install $n --as dc-$v -j $j $opts --notest --noman" or do { | |
84 | warn "perlbrew $v failed"; | |
85 | return; | |
86 | }; | |
87 | my $dir = ($ENV{PERLBREW_ROOT} || die 'No $PERLBREW_ROOT') . | |
88 | "/perls/dc-$v/bin"; | |
89 | unless (-d $dir) { | |
90 | warn "$dir does not exist"; | |
91 | return; | |
92 | } | |
93 | $ENV{PATH} = "$dir:$ENV{PATH}"; | |
94 | sys "curl -L http://cpanmin.us | perl - App::cpanminus" or do { | |
95 | warn "cpanm installation for $v failed"; | |
96 | return; | |
97 | }; | |
98 | my @mods = qw( Storable Digest::MD5 Test::More ); | |
99 | my ($s) = $n =~ /(\d+)$/; | |
100 | if (($v !~ /thr/ || $s == 1) && $n !~ /^5\.6\./) { | |
101 | push @mods, qw( | |
102 | Template | |
103 | PPI::HTML | |
104 | Perl::Tidy | |
105 | Pod::Coverage | |
106 | Pod::Coverage::CountParents | |
107 | Test::Differences | |
108 | Parallel::Iterator | |
109 | JSON::PP | |
110 | ); | |
111 | push @mods, "Perl::Tidy" if !$s || $s % 2; | |
112 | push @mods, "PPI::HTML" if !$s || !($s % 2); | |
113 | } | |
114 | sys "cpanm @mods" or do { | |
115 | warn "module installation for $v failed"; | |
116 | return; | |
117 | }; | |
118 | my $ln = "/usr/local/bin/dc-$v"; | |
119 | unlink $ln; | |
120 | my ($perl) = "$dir/perl"; | |
121 | print "$perl => $ln\n"; | |
122 | sys "sudo ln -s $perl $ln" or warn "Can't ln $perl => $ln: $!"; | |
65 | 123 | } |
66 | 124 | |
67 | 125 | sub build { |
68 | for my $v (@{$Options->{version}}) { | |
69 | my $opts = ""; | |
70 | my ($n) = $v =~ /(\d+\.\d+\.\d+)/ or die "Can't parse [$v}"; | |
71 | $opts .= " -D usethreads" if $v =~ /thr/; | |
72 | $opts .= " --force" if $n =~ /^5\.6\./; | |
73 | my $j = cpus + 1; | |
74 | sys "perlbrew -v install $n --as dc-$v -j $j $opts"; | |
75 | sys "perlbrew use $v && " . | |
76 | "curl -L http://cpanmin.us | perl - App::cpanminus"; | |
77 | my @mods = qw( Storable Digest::MD5 Test::More ); | |
78 | my ($s) = $n =~ /(\d+)$/; | |
79 | if (($v !~ /thr/ || $s == 1) && $n !~ /^5\.6\./) { | |
80 | push @mods, qw( | |
81 | Template | |
82 | PPI::HTML | |
83 | Perl::Tidy | |
84 | Pod::Coverage | |
85 | Pod::Coverage::CountParents | |
86 | Test::Differences | |
87 | Parallel::Iterator | |
88 | JSON::PP | |
89 | ); | |
90 | push @mods, "Perl::Tidy" if !$s || $s % 2; | |
91 | push @mods, "PPI::HTML" if !$s || !($s % 2); | |
92 | } | |
93 | sys "perlbrew use $v && cpanm @mods"; | |
94 | } | |
126 | print "Building: @{$Options->{version}}\n"; | |
127 | my @res = iterate_as_array( | |
128 | { workers => nice_cpus * 2 }, | |
129 | sub { | |
130 | my (undef, $v) = @_; | |
131 | _build_version($v); | |
132 | }, | |
133 | $Options->{version} | |
134 | ); | |
95 | 135 | exit |
96 | 136 | } |
97 | ||
98 | $ENV{PATH} = join ":", grep !/perlbrew/, split ":", $ENV{PATH}; | |
99 | 137 | |
100 | 138 | get_options; |
101 | 139 | build if $Options->{build}; |
104 | 142 | |
105 | 143 | print "Testing against: @{$Options->{version}}\n"; |
106 | 144 | for my $v (@{$Options->{version}}) { |
107 | my $perl = "perl$v"; | |
145 | my $perl = "dc-$v"; | |
108 | 146 | (my $c = $command) =~ s/=perl/$perl/g; |
147 | # print "Running [$c] from $v\n"; | |
109 | 148 | # $c =~ s/=v/$v/g; |
110 | 149 | if ($c =~ /^make /) { |
111 | 150 | sys "rm -rf t/e2e"; |