line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Generate a distribution tarball for a package. |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# This is the implementation of the docknot dist command, which determines and |
4
|
|
|
|
|
|
|
# runs the commands necessary to build a distribution tarball for a given |
5
|
|
|
|
|
|
|
# package. |
6
|
|
|
|
|
|
|
# |
7
|
|
|
|
|
|
|
# SPDX-License-Identifier: MIT |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
############################################################################## |
10
|
|
|
|
|
|
|
# Modules and declarations |
11
|
|
|
|
|
|
|
############################################################################## |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
package App::DocKnot::Dist 3.02; |
14
|
|
|
|
|
|
|
|
15
|
4
|
|
|
4
|
|
138499
|
use 5.024; |
|
4
|
|
|
|
|
29
|
|
16
|
4
|
|
|
4
|
|
24
|
use autodie; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
43
|
|
17
|
4
|
|
|
4
|
|
18288
|
use warnings; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
136
|
|
18
|
|
|
|
|
|
|
|
19
|
4
|
|
|
4
|
|
1851
|
use App::DocKnot::Config; |
|
4
|
|
|
|
|
11
|
|
|
4
|
|
|
|
|
118
|
|
20
|
4
|
|
|
4
|
|
2407
|
use Archive::Tar (); |
|
4
|
|
|
|
|
302510
|
|
|
4
|
|
|
|
|
137
|
|
21
|
4
|
|
|
4
|
|
32
|
use Carp qw(croak); |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
182
|
|
22
|
4
|
|
|
4
|
|
21
|
use Cwd qw(getcwd); |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
138
|
|
23
|
4
|
|
|
4
|
|
1347
|
use File::Copy qw(move); |
|
4
|
|
|
|
|
5693
|
|
|
4
|
|
|
|
|
221
|
|
24
|
4
|
|
|
4
|
|
26
|
use File::Find qw(find); |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
243
|
|
25
|
4
|
|
|
4
|
|
24
|
use File::Path qw(remove_tree); |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
179
|
|
26
|
4
|
|
|
4
|
|
2555
|
use IPC::Run qw(run); |
|
4
|
|
|
|
|
79190
|
|
|
4
|
|
|
|
|
201
|
|
27
|
4
|
|
|
4
|
|
1405
|
use IPC::System::Simple qw(systemx); |
|
4
|
|
|
|
|
14874
|
|
|
4
|
|
|
|
|
229
|
|
28
|
4
|
|
|
4
|
|
25
|
use List::MoreUtils qw(any lastval); |
|
4
|
|
|
|
|
18
|
|
|
4
|
|
|
|
|
43
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# Base commands to run for various types of distributions. Additional |
31
|
|
|
|
|
|
|
# variations may be added depending on additional configuration parameters. |
32
|
|
|
|
|
|
|
#<<< |
33
|
|
|
|
|
|
|
our %COMMANDS = ( |
34
|
|
|
|
|
|
|
'Autoconf' => [ |
35
|
|
|
|
|
|
|
['./bootstrap'], |
36
|
|
|
|
|
|
|
['./configure', 'CC=clang'], |
37
|
|
|
|
|
|
|
['make', 'warnings'], |
38
|
|
|
|
|
|
|
['make', 'check'], |
39
|
|
|
|
|
|
|
['make', 'clean'], |
40
|
|
|
|
|
|
|
['./configure', 'CC=gcc'], |
41
|
|
|
|
|
|
|
['make', 'warnings'], |
42
|
|
|
|
|
|
|
['make', 'check'], |
43
|
|
|
|
|
|
|
['make', 'clean'], |
44
|
|
|
|
|
|
|
['make', 'check-cppcheck'], |
45
|
|
|
|
|
|
|
['make', 'distcheck'], |
46
|
|
|
|
|
|
|
], |
47
|
|
|
|
|
|
|
'ExtUtils::MakeMaker' => [ |
48
|
|
|
|
|
|
|
['perl', 'Makefile.PL'], |
49
|
|
|
|
|
|
|
['make', 'disttest'], |
50
|
|
|
|
|
|
|
['make', 'dist'], |
51
|
|
|
|
|
|
|
], |
52
|
|
|
|
|
|
|
'Module::Build' => [ |
53
|
|
|
|
|
|
|
['perl', 'Build.PL'], |
54
|
|
|
|
|
|
|
['./Build', 'disttest'], |
55
|
|
|
|
|
|
|
['./Build', 'dist'], |
56
|
|
|
|
|
|
|
], |
57
|
|
|
|
|
|
|
'make' => [ |
58
|
|
|
|
|
|
|
['make', 'dist'], |
59
|
|
|
|
|
|
|
], |
60
|
|
|
|
|
|
|
); |
61
|
|
|
|
|
|
|
#>>> |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# Regexes matching files or directories in the source tree to ignore when |
64
|
|
|
|
|
|
|
# comparing it against the generated distribution (in other words, we don't |
65
|
|
|
|
|
|
|
# care whether these files or any files in these directories are included in |
66
|
|
|
|
|
|
|
# the distribution). These should match the full file path relative to the |
67
|
|
|
|
|
|
|
# top directory. |
68
|
|
|
|
|
|
|
# |
69
|
|
|
|
|
|
|
# Include all of the build-generated files for docknot itself so that we can |
70
|
|
|
|
|
|
|
# use the new version to release the new version. |
71
|
|
|
|
|
|
|
## no critic (RegularExpressions::ProhibitFixedStringMatches) |
72
|
|
|
|
|
|
|
our @DIST_IGNORE = ( |
73
|
|
|
|
|
|
|
qr{ \A [.]git \z }xms, |
74
|
|
|
|
|
|
|
qr{ \A autom4te[.]cache \z }xms, |
75
|
|
|
|
|
|
|
qr{ \A Build \z }xms, |
76
|
|
|
|
|
|
|
qr{ \A MANIFEST[.]bak \z }xms, |
77
|
|
|
|
|
|
|
qr{ \A MYMETA [.] (?:json (?:[.]lock)? | yml) \z }xms, |
78
|
|
|
|
|
|
|
qr{ \A _build \z }xms, |
79
|
|
|
|
|
|
|
qr{ \A blib \z }xms, |
80
|
|
|
|
|
|
|
qr{ \A config[.]h[.]in~ \z }xms, |
81
|
|
|
|
|
|
|
qr{ \A cover_db \z }xms, |
82
|
|
|
|
|
|
|
qr{ \A tests/config \z }xms, |
83
|
|
|
|
|
|
|
qr{ [.]tar[.][gx]z \z }xms, |
84
|
|
|
|
|
|
|
); |
85
|
|
|
|
|
|
|
## use critic |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
############################################################################## |
88
|
|
|
|
|
|
|
# Helper methods |
89
|
|
|
|
|
|
|
############################################################################## |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# Given the path to the source tree, generate a list of files that we expect |
92
|
|
|
|
|
|
|
# to find in the distribution tarball. |
93
|
|
|
|
|
|
|
# |
94
|
|
|
|
|
|
|
# $self - The App::DocKnot::Dist object |
95
|
|
|
|
|
|
|
# $path - The directory path |
96
|
|
|
|
|
|
|
# |
97
|
|
|
|
|
|
|
# Returns: A list of files (no directories) that the distribution tarball |
98
|
|
|
|
|
|
|
# should contain. |
99
|
|
|
|
|
|
|
sub _expected_dist_files { |
100
|
5
|
|
|
5
|
|
20
|
my ($self, $path) = @_; |
101
|
5
|
|
|
|
|
12
|
my @files; |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# Find all files in the source directory, stripping its path from the file |
104
|
|
|
|
|
|
|
# name and excluding (and pruning) anything matching @DIST_IGNORE. |
105
|
|
|
|
|
|
|
my $wanted = sub { |
106
|
86
|
|
|
86
|
|
185
|
my $name = $File::Find::name; |
107
|
86
|
|
|
|
|
380
|
$name =~ s{ \A \Q$path\E / }{}xms; |
108
|
86
|
50
|
|
|
|
172
|
return if !$name; |
109
|
86
|
100
|
|
|
|
408
|
if (any { $name =~ $_ } @DIST_IGNORE) { |
|
896
|
|
|
|
|
1526
|
|
110
|
5
|
|
|
|
|
9
|
$File::Find::prune = 1; |
111
|
5
|
|
|
|
|
100
|
return; |
112
|
|
|
|
|
|
|
} |
113
|
81
|
100
|
|
|
|
2682
|
return if -d; |
114
|
51
|
|
|
|
|
1029
|
push(@files, $name); |
115
|
5
|
|
|
|
|
50
|
}; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# Generate and return the list of files. |
118
|
5
|
|
|
|
|
560
|
find($wanted, $path); |
119
|
5
|
|
|
|
|
40
|
return @files; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# Find the tarball compressed with gzip given a directory and a prefix. |
123
|
|
|
|
|
|
|
# |
124
|
|
|
|
|
|
|
# $self - The App::DocKnot::Dist object |
125
|
|
|
|
|
|
|
# $path - The directory path |
126
|
|
|
|
|
|
|
# $prefix - The tarball file prefix |
127
|
|
|
|
|
|
|
# |
128
|
|
|
|
|
|
|
# Returns: The full path to the gzip tarball |
129
|
|
|
|
|
|
|
# Throws: Text exception if no gzip tarball was found |
130
|
|
|
|
|
|
|
sub _find_gzip_tarball { |
131
|
3
|
|
|
3
|
|
14
|
my ($self, $path, $prefix) = @_; |
132
|
3
|
|
|
|
|
19
|
my @files = $self->_find_matching_tarballs($path, $prefix); |
133
|
3
|
|
|
3
|
|
55
|
my $gzip_file = lastval { m{ [.]tar [.]gz \z }xms } @files; |
|
3
|
|
|
|
|
37
|
|
134
|
3
|
50
|
|
|
|
25
|
if (!defined($gzip_file)) { |
135
|
0
|
|
|
|
|
0
|
die "cannot find gzip tarball for $prefix in $path\n"; |
136
|
|
|
|
|
|
|
} |
137
|
3
|
|
|
|
|
57
|
return File::Spec->catfile($path, $gzip_file); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# Find matching tarballs given a directory and a prefix. |
141
|
|
|
|
|
|
|
# |
142
|
|
|
|
|
|
|
# $self - The App::DocKnot::Dist object |
143
|
|
|
|
|
|
|
# $path - The directory path |
144
|
|
|
|
|
|
|
# $prefix - The tarball file prefix |
145
|
|
|
|
|
|
|
# |
146
|
|
|
|
|
|
|
# Returns: All matching files, without the directory name, as a list |
147
|
|
|
|
|
|
|
sub _find_matching_tarballs { |
148
|
9
|
|
|
9
|
|
36
|
my ($self, $path, $prefix) = @_; |
149
|
9
|
|
|
|
|
229
|
my $pattern = qr{ \A \Q$prefix\E - \d.* [.]tar [.][xg]z \z }xms; |
150
|
9
|
|
|
|
|
94
|
opendir(my $source, $path); |
151
|
9
|
|
|
|
|
2561
|
my @files = grep { $_ =~ $pattern } readdir($source); |
|
68
|
|
|
|
|
255
|
|
152
|
9
|
|
|
|
|
50
|
closedir($source); |
153
|
9
|
|
|
|
|
997
|
return @files; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# Given a directory and a prefix for tarballs in that directory, ensure that |
157
|
|
|
|
|
|
|
# all the desired compression formats exist. Currently this only handles |
158
|
|
|
|
|
|
|
# generating the xz version of a gzip tarball. |
159
|
|
|
|
|
|
|
# |
160
|
|
|
|
|
|
|
# $self - The App::DocKnot::Dist object |
161
|
|
|
|
|
|
|
# $path - The directory path |
162
|
|
|
|
|
|
|
# $prefix - The tarball file prefix |
163
|
|
|
|
|
|
|
sub _generate_compression_formats { |
164
|
3
|
|
|
3
|
|
12
|
my ($self, $path, $prefix) = @_; |
165
|
3
|
|
|
|
|
14
|
my @files = $self->_find_matching_tarballs($path, $prefix); |
166
|
3
|
100
|
|
3
|
|
49
|
if (!any { m{ [.]tar [.]xz \z }xms } @files) { |
|
3
|
|
|
|
|
36
|
|
167
|
1
|
|
|
1
|
|
11
|
my $gzip_file = lastval { m{ [.]tar [.]gz \z }xms } @files; |
|
1
|
|
|
|
|
7
|
|
168
|
1
|
|
|
|
|
28
|
systemx('gzip', '-dk', File::Spec->catfile($path, $gzip_file)); |
169
|
1
|
|
|
|
|
3783
|
my $tar_file = $gzip_file; |
170
|
1
|
|
|
|
|
23
|
$tar_file =~ s{ [.]gz \z }{}xms; |
171
|
1
|
|
|
|
|
28
|
systemx('xz', File::Spec->catfile($path, $tar_file)); |
172
|
|
|
|
|
|
|
} |
173
|
3
|
|
|
|
|
31783
|
return; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# Given a source directory, a prefix for tarballs and related files (such as |
177
|
|
|
|
|
|
|
# signatures), and a destination directory, move all matching files from the |
178
|
|
|
|
|
|
|
# source directory to the destination directory. |
179
|
|
|
|
|
|
|
# |
180
|
|
|
|
|
|
|
# $self - The App::DocKnot::Dist object |
181
|
|
|
|
|
|
|
# $source_path - The source directory path |
182
|
|
|
|
|
|
|
# $prefix - The tarball file prefix |
183
|
|
|
|
|
|
|
# $dest_path - The destination directory path |
184
|
|
|
|
|
|
|
# |
185
|
|
|
|
|
|
|
# Throws: Text exception if no files are found |
186
|
|
|
|
|
|
|
# Text exception on failure to move a file |
187
|
|
|
|
|
|
|
sub _move_tarballs { |
188
|
3
|
|
|
3
|
|
38
|
my ($self, $source_path, $prefix, $dest_path) = @_; |
189
|
3
|
|
|
|
|
41
|
my @files = $self->_find_matching_tarballs($source_path, $prefix); |
190
|
3
|
|
|
|
|
62
|
for my $file (@files) { |
191
|
3
|
|
|
|
|
69
|
my $source_file = File::Spec->catfile($source_path, $file); |
192
|
3
|
50
|
|
|
|
53
|
move($source_file, $dest_path) |
193
|
|
|
|
|
|
|
or die "cannot move $source_file to $dest_path: $!\n"; |
194
|
|
|
|
|
|
|
} |
195
|
3
|
|
|
|
|
1058
|
return; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# Given a command with arguments, replace a command of "perl" with the |
199
|
|
|
|
|
|
|
# configured path to Perl, if any. Assumes that the perl configuration |
200
|
|
|
|
|
|
|
# parameter is set in the object and should not be called if this is not true. |
201
|
|
|
|
|
|
|
# |
202
|
|
|
|
|
|
|
# $self - The App::DocKnot::Dist object |
203
|
|
|
|
|
|
|
# $command_ref - Reference to an array representing a command with arguments |
204
|
|
|
|
|
|
|
# |
205
|
|
|
|
|
|
|
# Returns: Reference to an array representing a command with arguments, with |
206
|
|
|
|
|
|
|
# the command replaced with the configured path to Perl if it was |
207
|
|
|
|
|
|
|
# "perl" |
208
|
|
|
|
|
|
|
sub _replace_perl_path { |
209
|
12
|
|
|
12
|
|
55
|
my ($self, $command_ref) = @_; |
210
|
12
|
100
|
|
|
|
39
|
if ($command_ref->[0] ne 'perl') { |
211
|
8
|
|
|
|
|
24
|
return $command_ref; |
212
|
|
|
|
|
|
|
} |
213
|
4
|
|
|
|
|
16
|
my @command = $command_ref->@*; |
214
|
4
|
|
|
|
|
23
|
$command[0] = $self->{perl}; |
215
|
4
|
|
|
|
|
20
|
return [@command]; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
############################################################################## |
219
|
|
|
|
|
|
|
# Public interface |
220
|
|
|
|
|
|
|
############################################################################## |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# Create a new App::DocKnot::Dist object, which will be used for subsequent |
223
|
|
|
|
|
|
|
# calls. |
224
|
|
|
|
|
|
|
# |
225
|
|
|
|
|
|
|
# $class - Class of object ot create |
226
|
|
|
|
|
|
|
# $args - Anonymous hash of arguments with the following keys: |
227
|
|
|
|
|
|
|
# distdir - Path to the directory for distribution tarball |
228
|
|
|
|
|
|
|
# metadata - Path to the directory containing package metadata |
229
|
|
|
|
|
|
|
# perl - Path to Perl to use (default: search the user's PATH) |
230
|
|
|
|
|
|
|
# |
231
|
|
|
|
|
|
|
# Returns: Newly created object |
232
|
|
|
|
|
|
|
# Throws: Text exceptions on invalid metadata directory path |
233
|
|
|
|
|
|
|
# Text exception on missing or invalid distdir argument |
234
|
|
|
|
|
|
|
sub new { |
235
|
7
|
|
|
7
|
1
|
12214
|
my ($class, $args_ref) = @_; |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# Create the config reader. |
238
|
7
|
|
|
|
|
14
|
my %config_args; |
239
|
7
|
100
|
|
|
|
21
|
if ($args_ref->{metadata}) { |
240
|
4
|
|
|
|
|
9
|
$config_args{metadata} = $args_ref->{metadata}; |
241
|
|
|
|
|
|
|
} |
242
|
7
|
|
|
|
|
37
|
my $config = App::DocKnot::Config->new(\%config_args); |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# Ensure we were given a valid distdir argument. |
245
|
7
|
|
|
|
|
14
|
my $distdir = $args_ref->{distdir}; |
246
|
7
|
50
|
|
|
|
74
|
if (!defined($distdir)) { |
|
|
50
|
|
|
|
|
|
247
|
0
|
|
|
|
|
0
|
croak('distdir path not given'); |
248
|
|
|
|
|
|
|
} elsif (!-d $distdir) { |
249
|
0
|
|
|
|
|
0
|
croak("distdir path $distdir does not exist or is not a directory"); |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# Create and return the object. |
253
|
|
|
|
|
|
|
my $self = { |
254
|
|
|
|
|
|
|
config => $config->config(), |
255
|
|
|
|
|
|
|
distdir => $distdir, |
256
|
|
|
|
|
|
|
perl => $args_ref->{perl}, |
257
|
7
|
|
|
|
|
31
|
}; |
258
|
7
|
|
|
|
|
26
|
bless($self, $class); |
259
|
7
|
|
|
|
|
90
|
return $self; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# Given a distribution tarball compressed with gzip, ensure that every file |
263
|
|
|
|
|
|
|
# from the source directory that is expected to be there is in the |
264
|
|
|
|
|
|
|
# distribution tarball. Assumes that it is run from the root of the source |
265
|
|
|
|
|
|
|
# directory. |
266
|
|
|
|
|
|
|
# |
267
|
|
|
|
|
|
|
# $self - The App::DocKnot::Dist object |
268
|
|
|
|
|
|
|
# $source - Path to the source directory |
269
|
|
|
|
|
|
|
# $tarball - Path to a gzip-compressed distribution tarball |
270
|
|
|
|
|
|
|
# |
271
|
|
|
|
|
|
|
# Returns: A list of files missing from the distribution (so an empty list |
272
|
|
|
|
|
|
|
# means all expected files were found) |
273
|
|
|
|
|
|
|
sub check_dist { |
274
|
5
|
|
|
5
|
1
|
5426
|
my ($self, $source, $tarball) = @_; |
275
|
5
|
|
|
|
|
57
|
my @expected = $self->_expected_dist_files(getcwd()); |
276
|
5
|
|
|
|
|
13
|
my %expected = map { $_ => 1 } @expected; |
|
51
|
|
|
|
|
154
|
|
277
|
5
|
|
|
|
|
103
|
my $archive = Archive::Tar->new($tarball); |
278
|
5
|
|
|
|
|
61114
|
for my $file ($archive->list_files()) { |
279
|
85
|
|
|
|
|
1922
|
$file =~ s{ \A [^/]* / }{}xms; |
280
|
85
|
|
|
|
|
136
|
delete $expected{$file}; |
281
|
|
|
|
|
|
|
} |
282
|
5
|
|
|
|
|
36
|
my @missing = sort(keys(%expected)); |
283
|
5
|
|
|
|
|
157
|
return @missing; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# Analyze a source directory and return the list of commands to run to |
287
|
|
|
|
|
|
|
# generate a distribution tarball. |
288
|
|
|
|
|
|
|
# |
289
|
|
|
|
|
|
|
# $self - The App::DocKnot::Dist object |
290
|
|
|
|
|
|
|
# |
291
|
|
|
|
|
|
|
# Returns: List of commands, each of which is a list of strings representing |
292
|
|
|
|
|
|
|
# a command and its arguments |
293
|
|
|
|
|
|
|
sub commands { |
294
|
9
|
|
|
9
|
1
|
100
|
my ($self) = @_; |
295
|
9
|
|
|
|
|
47
|
my $type = $self->{config}{build}{type}; |
296
|
9
|
|
|
|
|
40
|
my @commands = map { [@$_] } $COMMANDS{$type}->@*; |
|
41
|
|
|
|
|
108
|
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# Special-case: If a specific path to Perl was configured, use that path |
299
|
|
|
|
|
|
|
# rather than searching for perl in the user's PATH. This is used |
300
|
|
|
|
|
|
|
# primarily by the test suite, which wants to run a Module::Build Build.PL |
301
|
|
|
|
|
|
|
# and thus has to use the same perl binary as the one running the tests. |
302
|
9
|
100
|
|
|
|
38
|
if (defined($self->{perl})) { |
303
|
4
|
|
|
|
|
11
|
@commands = map { $self->_replace_perl_path($_) } @commands; |
|
12
|
|
|
|
|
60
|
|
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
# Special-case: Autoconf packages with C++ support should also attempt a |
307
|
|
|
|
|
|
|
# build with a C++ compiler. |
308
|
9
|
100
|
100
|
|
|
31
|
if ($type eq 'Autoconf' && $self->{config}{build}{cplusplus}) { |
309
|
|
|
|
|
|
|
#<<< |
310
|
1
|
|
|
|
|
14
|
my @extra = ( |
311
|
|
|
|
|
|
|
['./configure', 'CC=g++'], |
312
|
|
|
|
|
|
|
['make', 'check'], |
313
|
|
|
|
|
|
|
['make', 'clean'], |
314
|
|
|
|
|
|
|
); |
315
|
|
|
|
|
|
|
#>>> |
316
|
1
|
|
|
|
|
3
|
splice(@commands, 1, 0, @extra); |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
# Special-case: Autoconf packages with Valgrind support should also run |
320
|
|
|
|
|
|
|
# make check-valgrind. |
321
|
9
|
100
|
100
|
|
|
30
|
if ($type eq 'Autoconf' && $self->{config}{build}{valgrind}) { |
322
|
1
|
|
|
|
|
11
|
splice(@commands, -3, 0, ['make', 'check-valgrind']); |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
|
325
|
9
|
|
|
|
|
41
|
return @commands; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
# Generate a distribution tarball. This assumes it is run from the root |
329
|
|
|
|
|
|
|
# directory of the package to release and that it is a Git repository. It |
330
|
|
|
|
|
|
|
# exports the Git repository, runs the commands to generate the tarball, and |
331
|
|
|
|
|
|
|
# then removes the working tree. |
332
|
|
|
|
|
|
|
# |
333
|
|
|
|
|
|
|
# $self - The App::DocKnot::Dist object |
334
|
|
|
|
|
|
|
# |
335
|
|
|
|
|
|
|
# Throws: Text exception if any of the commands fail |
336
|
|
|
|
|
|
|
# Text exception if the distribution is missing files |
337
|
|
|
|
|
|
|
sub make_distribution { |
338
|
3
|
|
|
3
|
1
|
6969
|
my ($self) = @_; |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# Determine the source directory and the distribution directory name. |
341
|
3
|
50
|
|
|
|
33
|
my $source = getcwd() or die "cannot get current directory: $!\n"; |
342
|
3
|
|
|
|
|
96
|
my $prefix = $self->{config}{distribution}{tarname}; |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
# If the distribution directory name already exists, remove it. Automake |
345
|
|
|
|
|
|
|
# may have made parts of it read-only, so be forceful in the removal. |
346
|
|
|
|
|
|
|
# Note that this does not pass the safe parameter and therefore should not |
347
|
|
|
|
|
|
|
# be called on attacker-controlled directories. |
348
|
3
|
|
|
|
|
17
|
chdir($self->{distdir}); |
349
|
3
|
100
|
|
|
|
203
|
if (-d $prefix) { |
350
|
1
|
|
|
|
|
422
|
remove_tree($prefix); |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# Export the Git repository into a new directory. |
354
|
3
|
|
|
|
|
47
|
my @git = ('git', 'archive', "--remote=$source", "--prefix=${prefix}/", |
355
|
|
|
|
|
|
|
'master',); |
356
|
3
|
|
|
|
|
10
|
my @tar = qw(tar xf -); |
357
|
3
|
50
|
|
|
|
37
|
run(\@git, q{|}, \@tar) or die "@git | @tar failed with status $?\n"; |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
# Change to that directory and run the configured commands. |
360
|
3
|
|
|
|
|
75895
|
chdir($prefix); |
361
|
3
|
|
|
|
|
618
|
for my $command_ref ($self->commands()) { |
362
|
9
|
|
|
|
|
3985504
|
systemx($command_ref->@*); |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
# Move the generated tarball to the parent directory. |
366
|
3
|
|
|
|
|
802047
|
$self->_move_tarballs(File::Spec->curdir(), $prefix, File::Spec->updir()); |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
# Remove the working tree. |
369
|
3
|
|
|
|
|
31
|
chdir(File::Spec->updir()); |
370
|
3
|
|
|
|
|
8070
|
remove_tree($prefix, { safe => 1 }); |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
# Generate additional compression formats if needed. |
373
|
3
|
|
|
|
|
58
|
$self->_generate_compression_formats(getcwd(), $prefix); |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
# Check the distribution for any missing files. If there are any, report |
376
|
|
|
|
|
|
|
# them and then fail with an error. |
377
|
3
|
|
|
|
|
62
|
my $tarball = $self->_find_gzip_tarball(getcwd(), $prefix); |
378
|
3
|
|
|
|
|
17
|
chdir($source); |
379
|
3
|
|
|
|
|
207
|
my @missing = $self->check_dist($source, $tarball); |
380
|
3
|
100
|
|
|
|
32
|
if (@missing) { |
381
|
2
|
50
|
|
|
|
76
|
print "Files found in local tree but not in distribution:\n" |
382
|
|
|
|
|
|
|
or die "cannot print to stdout: $!\n"; |
383
|
2
|
50
|
|
|
|
34
|
print q{ } . join(qq{\n }, @missing) . "\n" |
384
|
|
|
|
|
|
|
or die "cannot print to stdout: $!\n"; |
385
|
2
|
|
|
|
|
12
|
my $count = scalar(@missing); |
386
|
2
|
100
|
|
|
|
19
|
my $files = ($count == 1) ? '1 file' : "$count files"; |
387
|
2
|
|
|
|
|
52
|
die "$files missing from distribution\n"; |
388
|
|
|
|
|
|
|
} |
389
|
1
|
|
|
|
|
24
|
return; |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
############################################################################## |
393
|
|
|
|
|
|
|
# Module return value and documentation |
394
|
|
|
|
|
|
|
############################################################################## |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
1; |
397
|
|
|
|
|
|
|
__END__ |