-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathx-perl-create-cpanfile-snapshot
executable file
·163 lines (128 loc) · 3.99 KB
/
x-perl-create-cpanfile-snapshot
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/perl
use strict;
use warnings;
use Cwd;
use Getopt::Long;
sub usage {
print "Error: $@\n" if $@;
print <<EOU;
Usage: x-perl-create-cpanfile-snapshot <options> [<deps>...]
Use the current folder cpanfile to generate a fresh cpanfile.snapshot.
Uses a volume to cache the installed modules, the follow-up runs will be much faster.
If you need extra packages to install, just pass them along like this:
x-perl-create-cpanfile-snapshot libidn-dev file-dev
Options:
--dryrun Do everything except run Docker
--verbose Show what is going on
--volume Define the name of the persistent volume to use.
If none is used, we will construct a new name based
on the current work directory
--reset Remove volume before starting, forces full rebuild
--shell After the install is configured, start a shell
--all Install all deps, including non-prod
--official Use official Perl image
--alpine Use Alpine Perl image
--target=label Use local Dockerfile with a specific target label
EOU
exit(1);
}
GetOptions(
\my %cfg, 'help|?', 'volume', 'reset', 'shell', 'all',
'next', 'verbose', 'official', 'alpine', 'dryrun', 'target=s'
) or usage();
usage() if $cfg{help};
$cfg{verbose} = 1 if $cfg{dryrun};
my $target = $cfg{target} || _fetch_target_label();
l("target for image to use as dep: $target");
my $single = 0;
$single++ if $cfg{official};
$single++ if $cfg{alpine};
$single++ if $target;
usage("Cannot use --official, --alpine, and --target=<target> together") if $single > 1;
my $vrs = "perl";
$vrs = "alpine" if $cfg{alpine};
## use the project dir as volume name as a fallback
my $cwd = getcwd();
my $vol = $cfg{volume};
unless ($vol) {
$vol = $cwd;
$vol =~ s/^$ENV{HOME}//;
$vol =~ s{^/}{}g;
$vol =~ s{/}{-}g;
$vol .= "-cpan-deps-for-$vrs";
}
l("use '$vol' as volume name");
if ($cfg{reset}) {
l("remove volume '$vol', forcing full rebuild");
system('docker', 'volume', 'rm', $vol) and die "Error: failed to remove volume '$vol', exit code $!";
}
my $label = 'latest-build';
$label = 'next-build' if $cfg{next};
$label = "$vrs-$label";
my $shell = $cfg{shell} || '';
my $deps = join(' ', @ARGV);
l("install deps: $deps");
my $all = $cfg{all} ? ' --all ' : '';
$deps .= _fetch_deps_from_cpanfile($vrs);
my $script = "
set -xe
if [ -n '$deps' ] ; then
if [ '$vrs' = 'perl' ] ; then
apt update
apt install -y $deps
else
apk --no-cache add $deps
fi
fi
rm -rf /deps/local
ln -s /cache-deps /deps/local
cd /src
pdi-build-deps --skip-snapshot --verbose $all
cp /deps/cpanfile.snapshot /src
if [ -n \"$shell\" ] ; then
exec /bin/sh
fi
";
l("Prepare script to run: $script");
my $docker_tag = "melopt/perl-alt:$label";
l(".... initial tag $docker_tag (target is $target)");
if ($target) {
$docker_tag = lc($vol);
l(".... found target $target, new docker tag is $docker_tag");
system('docker', 'build', '--tag', $docker_tag, '--target', $target, '.');
}
l(".... final tag $docker_tag");
exec('docker', 'run', '-it', '--rm', '-v', "$vol:/cache-deps", '-v', "$cwd:/src", $docker_tag, '/bin/sh', '-c', $script)
unless $cfg{dryrun};
sub l {
return unless $cfg{verbose};
print "* @_\n";
}
sub _fetch_deps_from_cpanfile {
my ($vrs) = @_;
my $fn = 'cpanfile.cfg';
$fn = 'cpanfile' unless -r $fn;
l("Scan '$fn' for $vrs deps");
open(my $fh, $fn) or return '';
my @deps;
while (<$fh>) {
push @deps, $1 if m/^#+\s+requires_package_$vrs\s+(.+)$/i;
push @deps, $1 if m/^#+\s+requires_package\s+(.+)$/i;
}
return '' unless @deps;
l('Found dependencies: ', @deps);
return join(' ', @deps);
}
sub _fetch_target_label {
my $fn = 'cpanfile.cfg';
$fn = 'cpanfile' unless -r $fn;
l("Scan '$fn' for Dockerfile target label");
open(my $fh, $fn) or return '';
my $target;
while (<$fh>) {
$target = $1 if m/^\s*#*\s*target_label\s+(.+)$/i;
}
return '' unless $target;
l("Found target lavel: $target");
return $target;
}