line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Minilla::Project; |
2
|
1
|
|
|
1
|
|
1057
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
30
|
|
3
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
22
|
|
4
|
1
|
|
|
1
|
|
20
|
use utf8; |
|
1
|
|
|
|
|
27
|
|
|
1
|
|
|
|
|
7
|
|
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
502
|
use TOML 0.92 qw(from_toml); |
|
1
|
|
|
|
|
26174
|
|
|
1
|
|
|
|
|
57
|
|
7
|
1
|
|
|
1
|
|
8
|
use File::Basename qw(basename dirname); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
62
|
|
8
|
1
|
|
|
1
|
|
460
|
use File::Spec::Functions qw(catdir catfile); |
|
1
|
|
|
|
|
781
|
|
|
1
|
|
|
|
|
68
|
|
9
|
1
|
|
|
1
|
|
481
|
use DirHandle; |
|
1
|
|
|
|
|
1799
|
|
|
1
|
|
|
|
|
32
|
|
10
|
1
|
|
|
1
|
|
452
|
use File::pushd; |
|
1
|
|
|
|
|
16570
|
|
|
1
|
|
|
|
|
58
|
|
11
|
1
|
|
|
1
|
|
537
|
use CPAN::Meta; |
|
1
|
|
|
|
|
29240
|
|
|
1
|
|
|
|
|
36
|
|
12
|
1
|
|
|
1
|
|
503
|
use Module::CPANfile; |
|
1
|
|
|
|
|
5988
|
|
|
1
|
|
|
|
|
37
|
|
13
|
1
|
|
|
1
|
|
7
|
use Module::Runtime qw(require_module); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
11
|
|
14
|
|
|
|
|
|
|
|
15
|
1
|
|
|
1
|
|
50
|
use Minilla; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
22
|
|
16
|
1
|
|
|
1
|
|
6
|
use Minilla::Git qw(git_show_toplevel); |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
81
|
|
17
|
1
|
|
|
1
|
|
7
|
use Minilla::Logger; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
56
|
|
18
|
1
|
|
|
1
|
|
488
|
use Minilla::Metadata; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
34
|
|
19
|
1
|
|
|
1
|
|
482
|
use Minilla::WorkDir; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
36
|
|
20
|
1
|
|
|
1
|
|
7
|
use Minilla::ReleaseTest; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
19
|
|
21
|
1
|
|
|
1
|
|
6
|
use Minilla::Unsupported; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
23
|
|
22
|
1
|
|
|
1
|
|
465
|
use Minilla::ModuleMaker::ModuleBuild; |
|
1
|
|
|
|
|
45
|
|
|
1
|
|
|
|
|
38
|
|
23
|
1
|
|
|
1
|
|
487
|
use Minilla::ModuleMaker::ModuleBuildTiny; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
24
|
1
|
|
|
1
|
|
438
|
use Minilla::ModuleMaker::ExtUtilsMakeMaker; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
39
|
|
25
|
1
|
|
|
1
|
|
7
|
use Minilla::Util qw(slurp_utf8 find_dir cmd spew_raw slurp_raw spew_utf8); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
62
|
|
26
|
1
|
|
|
1
|
|
7
|
use Encode qw(decode_utf8); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
73
|
|
27
|
1
|
|
|
1
|
|
557
|
use URI; |
|
1
|
|
|
|
|
4686
|
|
|
1
|
|
|
|
|
32
|
|
28
|
|
|
|
|
|
|
|
29
|
1
|
|
|
1
|
|
6
|
use Moo; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
5
|
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
has dir => ( |
32
|
|
|
|
|
|
|
is => 'rw', |
33
|
|
|
|
|
|
|
builder => 1, |
34
|
|
|
|
|
|
|
trigger => 1, |
35
|
|
|
|
|
|
|
required => 1, |
36
|
|
|
|
|
|
|
); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
has module_maker => ( |
39
|
|
|
|
|
|
|
is => 'ro', |
40
|
|
|
|
|
|
|
default => sub { |
41
|
|
|
|
|
|
|
my $self = shift; |
42
|
|
|
|
|
|
|
if ($self->config && defined($self->config->{module_maker})) { |
43
|
|
|
|
|
|
|
# Automatic require. |
44
|
|
|
|
|
|
|
my $klass = $self->config->{module_maker}; |
45
|
|
|
|
|
|
|
$klass = $klass =~ s/^\+// ? $klass : "Minilla::ModuleMaker::$klass"; |
46
|
|
|
|
|
|
|
return $klass->new(); |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
Minilla::ModuleMaker::ModuleBuildTiny->new() |
49
|
|
|
|
|
|
|
}, |
50
|
|
|
|
|
|
|
lazy => 1, |
51
|
|
|
|
|
|
|
); |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
has dist_name => ( |
54
|
|
|
|
|
|
|
is => 'lazy', |
55
|
|
|
|
|
|
|
); |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
has build_class => ( |
58
|
|
|
|
|
|
|
is => 'lazy', |
59
|
|
|
|
|
|
|
); |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
has main_module_path => ( |
62
|
|
|
|
|
|
|
is => 'lazy', |
63
|
|
|
|
|
|
|
); |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
has metadata => ( |
66
|
|
|
|
|
|
|
is => 'lazy', |
67
|
|
|
|
|
|
|
required => 1, |
68
|
|
|
|
|
|
|
handles => [qw(name perl_version license)], |
69
|
|
|
|
|
|
|
clearer => 1, |
70
|
|
|
|
|
|
|
); |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
has contributors => ( |
73
|
|
|
|
|
|
|
is => 'lazy', |
74
|
|
|
|
|
|
|
); |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
has work_dir => ( |
77
|
|
|
|
|
|
|
is => 'lazy', |
78
|
|
|
|
|
|
|
); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
has files => ( |
81
|
|
|
|
|
|
|
is => 'lazy', |
82
|
|
|
|
|
|
|
); |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
has release_branch => ( |
85
|
|
|
|
|
|
|
is => 'lazy', |
86
|
|
|
|
|
|
|
clearer => 1, |
87
|
|
|
|
|
|
|
); |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
has no_index => ( |
90
|
|
|
|
|
|
|
is => 'ro', |
91
|
|
|
|
|
|
|
default => sub { |
92
|
|
|
|
|
|
|
my $self = shift; |
93
|
|
|
|
|
|
|
exists $self->config->{no_index} ? |
94
|
|
|
|
|
|
|
$self->config->{no_index} : |
95
|
|
|
|
|
|
|
{ |
96
|
|
|
|
|
|
|
directory => [qw( |
97
|
|
|
|
|
|
|
t xt inc share eg examples author builder |
98
|
|
|
|
|
|
|
) ] |
99
|
|
|
|
|
|
|
}; |
100
|
|
|
|
|
|
|
}, |
101
|
|
|
|
|
|
|
); |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
has script_files => ( |
104
|
|
|
|
|
|
|
is => 'ro', |
105
|
|
|
|
|
|
|
default => sub { |
106
|
|
|
|
|
|
|
my $self = shift; |
107
|
|
|
|
|
|
|
my $script_files = exists $self->config->{script_files} ? |
108
|
|
|
|
|
|
|
$self->config->{script_files} : |
109
|
|
|
|
|
|
|
['script/*', 'bin/*']; |
110
|
|
|
|
|
|
|
join ', ', map { "glob('$_')" } @$script_files; |
111
|
|
|
|
|
|
|
}, |
112
|
|
|
|
|
|
|
); |
113
|
|
|
|
|
|
|
|
114
|
1
|
|
|
1
|
|
727
|
no Moo; |
|
1
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
6
|
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub allow_pureperl { |
117
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
118
|
0
|
0
|
|
|
|
|
$self->config->{allow_pureperl} ? 1 : 0; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub version { |
122
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
123
|
0
|
|
0
|
|
|
|
my $version = $self->config->{version} || $self->metadata->version; |
124
|
0
|
0
|
|
|
|
|
unless (defined $version) { |
125
|
0
|
|
|
|
|
|
errorf("Minilla can't aggregate version number from '" . $self->main_module_path . '"'); |
126
|
|
|
|
|
|
|
} |
127
|
0
|
|
|
|
|
|
return $version; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub static_install { |
131
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
132
|
0
|
0
|
|
|
|
|
my $v = exists $self->config->{static_install} ? $self->config->{static_install} : 'auto'; |
133
|
0
|
0
|
|
|
|
|
return 0+$v if $v =~ /^\d+$/; |
134
|
0
|
0
|
|
|
|
|
errorf "Found unsupported value '%s' for static_install in minil.toml", $v if $v ne 'auto'; |
135
|
|
|
|
|
|
|
|
136
|
0
|
0
|
|
|
|
|
return 0 if $self->build_class ne 'Module::Build'; |
137
|
0
|
0
|
|
|
|
|
return 0 if $self->requires_external_bin; |
138
|
0
|
|
|
|
|
|
my @script_files = eval $self->script_files; # XXX |
139
|
0
|
0
|
|
|
|
|
return 0 if grep { !/^script\b/ } @script_files; |
|
0
|
|
|
|
|
|
|
140
|
0
|
0
|
0
|
|
|
|
return 0 if %{$self->PL_files} or grep { /^lib\b.*\.PL$/ } @{$self->files}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
141
|
0
|
0
|
|
|
|
|
return 0 if grep { /\.xs$/ } @{$self->files}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
142
|
0
|
0
|
|
|
|
|
return 0 if @{$self->unsupported->os}; |
|
0
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
|
return 1; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub authors { |
148
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
149
|
0
|
0
|
|
|
|
|
if (my $authors_from = $self->config->{authors_from}) { |
150
|
0
|
|
|
|
|
|
my $meta = Minilla::Metadata->new( |
151
|
|
|
|
|
|
|
source => $authors_from |
152
|
|
|
|
|
|
|
); |
153
|
0
|
|
|
|
|
|
return $meta->authors; |
154
|
|
|
|
|
|
|
} |
155
|
0
|
0
|
|
|
|
|
$self->config->{authors} || $self->metadata->authors; |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
sub unsupported { |
159
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
160
|
0
|
|
0
|
|
|
|
my $unsupported = $self->config->{unsupported} || {}; |
161
|
0
|
|
|
|
|
|
return Minilla::Unsupported->new(%$unsupported); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub abstract { |
165
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
166
|
0
|
0
|
|
|
|
|
if (my $abstract_from = $self->config->{abstract_from}) { |
167
|
0
|
|
|
|
|
|
my $meta = Minilla::Metadata->new( |
168
|
|
|
|
|
|
|
source => $abstract_from |
169
|
|
|
|
|
|
|
); |
170
|
0
|
|
|
|
|
|
return $meta->abstract; |
171
|
|
|
|
|
|
|
} |
172
|
0
|
0
|
|
|
|
|
$self->config->{abstract} || $self->metadata->abstract; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub badges { |
176
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
177
|
0
|
0
|
|
|
|
|
$self->config->{badges} || []; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub tap_harness_args { |
181
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
182
|
0
|
|
|
|
|
|
$self->config->{tap_harness_args}; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub use_xsutil { |
186
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
187
|
0
|
0
|
|
|
|
|
return defined $self->config->{XSUtil} ? 1 : 0; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub needs_compiler_c99 { |
191
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
192
|
0
|
0
|
|
|
|
|
if( my $xsutil = $self->config->{XSUtil} ){ |
193
|
0
|
0
|
|
|
|
|
return $xsutil->{needs_compiler_c99} ? 1 : 0; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
sub needs_compiler_cpp { |
198
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
199
|
0
|
0
|
|
|
|
|
if( my $xsutil = $self->config->{XSUtil} ){ |
200
|
0
|
0
|
|
|
|
|
return $xsutil->{needs_compiler_cpp} ? 1 : 0; |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
sub generate_ppport_h { |
205
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
206
|
0
|
0
|
|
|
|
|
if( my $xsutil = $self->config->{XSUtil} ){ |
207
|
0
|
|
0
|
|
|
|
return $xsutil->{generate_ppport_h} || 0; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub generate_xshelper_h { |
212
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
213
|
0
|
0
|
|
|
|
|
if( my $xsutil = $self->config->{XSUtil} ){ |
214
|
0
|
|
0
|
|
|
|
return $xsutil->{generate_xshelper_h} || 0; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub cc_warnings{ |
219
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
220
|
0
|
0
|
|
|
|
|
if( my $xsutil = $self->config->{XSUtil} ){ |
221
|
0
|
0
|
|
|
|
|
return $xsutil->{cc_warnings} ? 1 : 0; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub _build_dir { |
226
|
0
|
|
|
0
|
|
|
my $self = shift; |
227
|
0
|
|
|
|
|
|
return git_show_toplevel(); |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub _trigger_dir { |
231
|
0
|
|
|
0
|
|
|
my ($self, $dir) = @_; |
232
|
0
|
0
|
|
|
|
|
unless (File::Spec->file_name_is_absolute($dir)) { |
233
|
0
|
|
|
|
|
|
$self->dir(File::Spec->rel2abs($dir)); |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
sub config { |
238
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
239
|
|
|
|
|
|
|
|
240
|
0
|
|
|
|
|
|
my $toml_path = File::Spec->catfile($self->dir, 'minil.toml'); |
241
|
0
|
0
|
|
|
|
|
if (-f $toml_path) { |
242
|
0
|
|
|
|
|
|
my ($conf, $err) = from_toml(slurp_utf8($toml_path)); |
243
|
0
|
0
|
|
|
|
|
if ($err) { |
244
|
0
|
|
|
|
|
|
errorf("TOML error in %s: %s\n", $toml_path, $err); |
245
|
|
|
|
|
|
|
} |
246
|
0
|
0
|
|
|
|
|
$self->_patch_config_for_mb($conf) unless $conf->{module_maker}; |
247
|
0
|
|
|
|
|
|
$conf; |
248
|
|
|
|
|
|
|
} else { |
249
|
0
|
|
|
|
|
|
+{}; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
sub _patch_config_for_mb { |
254
|
0
|
|
|
0
|
|
|
my($self, $conf) = @_; |
255
|
|
|
|
|
|
|
|
256
|
0
|
0
|
0
|
|
|
|
if (exists $conf->{build} or exists $conf->{XSUtil}) { |
257
|
0
|
0
|
|
|
|
|
warn <{__already_warned}++; |
258
|
|
|
|
|
|
|
! |
259
|
|
|
|
|
|
|
! WARNING: |
260
|
|
|
|
|
|
|
! module_maker is not set in your Minilla config (minil.toml), but found [build] or [XSUtil] section in it. |
261
|
|
|
|
|
|
|
! Defaulting to Module::Build, but you're suggested to add the following to your minil.toml: |
262
|
|
|
|
|
|
|
! |
263
|
|
|
|
|
|
|
! module_maker="ModuleBuild" |
264
|
|
|
|
|
|
|
! |
265
|
|
|
|
|
|
|
! This friendly warning will go away in the next major release, and Minilla will default to ModuleBuildTiny |
266
|
|
|
|
|
|
|
! when module_maker is not explicitly set in minil.toml. |
267
|
|
|
|
|
|
|
! |
268
|
|
|
|
|
|
|
WARN |
269
|
0
|
|
|
|
|
|
$conf->{module_maker} = "ModuleBuild"; |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
0
|
|
|
|
|
|
return; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub c_source { |
276
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
277
|
0
|
0
|
|
|
|
|
$self->config->{c_source} ? join(' ', @{$self->config->{c_source}}) : ''; |
|
0
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
sub _build_dist_name { |
281
|
0
|
|
|
0
|
|
|
my $self = shift; |
282
|
|
|
|
|
|
|
|
283
|
0
|
|
|
|
|
|
my $dist_name; |
284
|
0
|
0
|
0
|
|
|
|
if ($self->config && defined($self->config->{name})) { |
285
|
0
|
|
|
|
|
|
my $conf = $self->config; |
286
|
0
|
0
|
|
|
|
|
if ($conf->{name} =~ /::/) { |
287
|
0
|
|
|
|
|
|
(my $better_name = $conf->{name}) =~ s/::/-/g; |
288
|
0
|
|
|
|
|
|
Carp::croak(qq(You shouldn't set 'name="$conf->{name}"' in minil.toml. You need to set the value as 'name="$better_name"'.)); |
289
|
|
|
|
|
|
|
} |
290
|
0
|
|
|
|
|
|
$dist_name = $conf->{name}; |
291
|
|
|
|
|
|
|
} |
292
|
0
|
0
|
|
|
|
|
unless (defined $dist_name) { |
293
|
0
|
|
|
|
|
|
infof("Detecting project name from directory name.\n"); |
294
|
0
|
|
|
|
|
|
$dist_name = $self->_detect_project_name_from_dir; |
295
|
|
|
|
|
|
|
} |
296
|
0
|
0
|
|
|
|
|
if ($dist_name eq '.') { Carp::confess("Heh? " . $self->dir); } |
|
0
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
|
298
|
0
|
0
|
|
|
|
|
unless ($dist_name) { |
299
|
0
|
|
|
|
|
|
errorf("Cannot detect distribution name from minil.toml or directory name(cwd: %s, dir:%s)\n", Cwd::getcwd(), $self->dir); |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
|
302
|
0
|
|
|
|
|
|
return $dist_name; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub _detect_project_name_from_dir { |
306
|
0
|
|
|
0
|
|
|
my $self = shift; |
307
|
|
|
|
|
|
|
|
308
|
0
|
|
|
|
|
|
local $_ = basename($self->dir); |
309
|
0
|
|
|
|
|
|
$_ =~ s!--!-!g; |
310
|
0
|
|
|
|
|
|
$_ =~ s!\Ap5-!!; |
311
|
0
|
|
|
|
|
|
return $_; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
sub _build_build_class { |
315
|
0
|
|
|
0
|
|
|
my $self = shift; |
316
|
|
|
|
|
|
|
|
317
|
0
|
|
|
|
|
|
my $build_class; |
318
|
0
|
0
|
|
|
|
|
if (my $conf = $self->config) { |
319
|
0
|
|
|
|
|
|
$build_class = $conf->{build}{build_class}; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
0
|
0
|
|
|
|
|
return $build_class if $build_class; |
323
|
|
|
|
|
|
|
|
324
|
0
|
0
|
|
|
|
|
return $self->use_xsutil ? 'Module::Build::XSUtil' : 'Module::Build'; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
sub _build_main_module_path { |
328
|
0
|
|
|
0
|
|
|
my $self = shift; |
329
|
|
|
|
|
|
|
|
330
|
0
|
|
|
|
|
|
my $dist_name = $self->dist_name; |
331
|
0
|
|
|
|
|
|
my $source_path = $self->_detect_source_path($dist_name); |
332
|
0
|
0
|
0
|
|
|
|
unless (defined($source_path) && -e $source_path) { |
333
|
0
|
|
0
|
|
|
|
errorf("%s not found.\n", $source_path || "main module($dist_name)"); |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
|
336
|
0
|
|
|
|
|
|
infof("Retrieving meta data from %s.\n", $source_path); |
337
|
0
|
|
|
|
|
|
return $source_path; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub _build_metadata { |
341
|
0
|
|
|
0
|
|
|
my $self = shift; |
342
|
|
|
|
|
|
|
|
343
|
0
|
|
|
|
|
|
my $config = +{%{$self->config}}; |
|
0
|
|
|
|
|
|
|
344
|
0
|
0
|
|
|
|
|
if (my $license = delete $config->{license}) { |
345
|
0
|
|
|
|
|
|
$config->{_license_name} = $license; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
# fill from main_module |
349
|
0
|
|
|
|
|
|
my $metadata = Minilla::Metadata->new( |
350
|
|
|
|
|
|
|
source => $self->main_module_path, |
351
|
|
|
|
|
|
|
%$config, |
352
|
|
|
|
|
|
|
); |
353
|
0
|
|
|
|
|
|
infof("Name: %s\n", $metadata->name); |
354
|
0
|
|
|
|
|
|
infof("Abstract: %s\n", $metadata->abstract); |
355
|
0
|
|
|
|
|
|
infof("Version: %s\n", $metadata->version); |
356
|
|
|
|
|
|
|
|
357
|
0
|
|
|
|
|
|
return $metadata; |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
sub _case_insensitive_match { |
361
|
0
|
|
|
0
|
|
|
my $path = shift; |
362
|
0
|
|
|
|
|
|
my @path = File::Spec->splitdir($path); |
363
|
0
|
|
|
|
|
|
my $realpath = '.'; |
364
|
0
|
|
|
|
|
|
LOOP: for my $part (@path) { |
365
|
|
|
|
|
|
|
my $d = DirHandle->new($realpath) |
366
|
0
|
0
|
|
|
|
|
or do { |
367
|
|
|
|
|
|
|
# warn "Cannot open dirhandle"; |
368
|
0
|
|
|
|
|
|
return; |
369
|
|
|
|
|
|
|
}; |
370
|
0
|
|
|
|
|
|
while (defined($_ = $d->read)) { |
371
|
0
|
0
|
|
|
|
|
if (uc($_) eq uc($part)) { |
372
|
0
|
|
|
|
|
|
$realpath = catfile($realpath, $_); |
373
|
0
|
|
|
|
|
|
next LOOP; |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
# does not match |
378
|
|
|
|
|
|
|
# warn "Does not match: $part in $realpath"; |
379
|
0
|
|
|
|
|
|
return undef; |
380
|
|
|
|
|
|
|
} |
381
|
0
|
|
|
|
|
|
return $realpath; |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
sub format_tag { |
385
|
0
|
|
|
0
|
0
|
|
my ($self, $version) = @_; |
386
|
0
|
0
|
|
|
|
|
if (defined(my $format = $self->config->{tag_format})) { |
387
|
0
|
|
|
|
|
|
(my $tag = $format) =~ s/%v/$version/; |
388
|
0
|
|
|
|
|
|
$tag; |
389
|
|
|
|
|
|
|
} else { |
390
|
0
|
|
|
|
|
|
$version; |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
sub _detect_source_path { |
395
|
0
|
|
|
0
|
|
|
my ($self, $dir) = @_; |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# like cpan-outdated => lib/App/cpanminus.pm |
398
|
0
|
|
|
|
|
|
my $pat2 = "App-" . do { |
399
|
0
|
|
|
|
|
|
local $_ = $dir; |
400
|
0
|
|
|
|
|
|
s!-!!; |
401
|
0
|
|
|
|
|
|
$_; |
402
|
|
|
|
|
|
|
}; |
403
|
0
|
|
|
|
|
|
for my $path ("App-$dir", $pat2, $dir) { |
404
|
0
|
|
|
|
|
|
$path =~ s!::!/!g; |
405
|
0
|
|
|
|
|
|
$path =~ s!-!/!g; |
406
|
0
|
|
|
|
|
|
$path = "lib/${path}.pm"; |
407
|
|
|
|
|
|
|
|
408
|
0
|
0
|
|
|
|
|
return $path if -f $path; |
409
|
|
|
|
|
|
|
|
410
|
0
|
|
|
|
|
|
$path = _case_insensitive_match($path); |
411
|
0
|
0
|
|
|
|
|
return $path if defined($path); |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
|
414
|
0
|
|
|
|
|
|
return undef; |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
sub load_cpanfile { |
418
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
419
|
0
|
|
|
|
|
|
Module::CPANfile->load(catfile($self->dir, 'cpanfile')); |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
sub cpan_meta { |
423
|
0
|
|
|
0
|
0
|
|
my ($self, $release_status) = @_; |
424
|
0
|
0
|
0
|
|
|
|
$release_status ||= ($self->version =~ /_/ ? 'unstable' : 'stable'); |
425
|
|
|
|
|
|
|
|
426
|
0
|
|
|
|
|
|
my $cpanfile = $self->load_cpanfile; |
427
|
0
|
|
|
|
|
|
my $merged_prereqs = $cpanfile->prereqs->with_merged_prereqs( |
428
|
|
|
|
|
|
|
CPAN::Meta::Prereqs->new($self->module_maker->prereqs($self)) |
429
|
|
|
|
|
|
|
); |
430
|
0
|
|
|
|
|
|
$merged_prereqs = $merged_prereqs->with_merged_prereqs( |
431
|
|
|
|
|
|
|
CPAN::Meta::Prereqs->new(Minilla::ReleaseTest->prereqs) |
432
|
|
|
|
|
|
|
); |
433
|
0
|
0
|
|
|
|
|
if ($self->metadata->perl_version) { |
434
|
0
|
|
|
|
|
|
$merged_prereqs = $merged_prereqs->with_merged_prereqs( |
435
|
|
|
|
|
|
|
CPAN::Meta::Prereqs->new(+{ |
436
|
|
|
|
|
|
|
runtime => { |
437
|
|
|
|
|
|
|
requires => { |
438
|
|
|
|
|
|
|
perl => $self->metadata->perl_version, |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
}) |
442
|
|
|
|
|
|
|
); |
443
|
|
|
|
|
|
|
} |
444
|
0
|
|
|
|
|
|
$merged_prereqs = $merged_prereqs->as_string_hash; |
445
|
|
|
|
|
|
|
|
446
|
0
|
|
0
|
|
|
|
my $dat = { |
447
|
|
|
|
|
|
|
"meta-spec" => { |
448
|
|
|
|
|
|
|
"version" => "2", |
449
|
|
|
|
|
|
|
"url" => "http://search.cpan.org/perldoc?CPAN::Meta::Spec" |
450
|
|
|
|
|
|
|
}, |
451
|
|
|
|
|
|
|
license => [ $self->license->meta2_name ], |
452
|
|
|
|
|
|
|
abstract => $self->abstract, |
453
|
|
|
|
|
|
|
dynamic_config => 0, |
454
|
|
|
|
|
|
|
version => $self->version, |
455
|
|
|
|
|
|
|
name => $self->dist_name, |
456
|
|
|
|
|
|
|
prereqs => $merged_prereqs, |
457
|
|
|
|
|
|
|
generated_by => "Minilla/$Minilla::VERSION", |
458
|
|
|
|
|
|
|
release_status => $release_status || 'stable', |
459
|
|
|
|
|
|
|
no_index => $self->no_index, |
460
|
|
|
|
|
|
|
x_static_install => $self->static_install, |
461
|
|
|
|
|
|
|
}; |
462
|
0
|
0
|
|
|
|
|
unless ($dat->{abstract}) { |
463
|
0
|
|
|
|
|
|
errorf("Cannot retrieve 'abstract' from %s. You need to write POD in your main module.\n", $self->dir); |
464
|
|
|
|
|
|
|
} |
465
|
0
|
0
|
|
|
|
|
if ($self->authors) { |
466
|
0
|
|
|
|
|
|
$dat->{author} = $self->authors; |
467
|
|
|
|
|
|
|
} else { |
468
|
0
|
|
|
|
|
|
errorf("Cannot determine 'author' from %s\n", $self->dir); |
469
|
|
|
|
|
|
|
} |
470
|
0
|
0
|
0
|
|
|
|
if ($self->contributors && @{$self->contributors} > 0) { |
|
0
|
|
|
|
|
|
|
471
|
0
|
|
|
|
|
|
$dat->{x_contributors} = $self->contributors; |
472
|
|
|
|
|
|
|
} |
473
|
0
|
0
|
|
|
|
|
if (my $authority = $self->config->{authority}) { |
474
|
0
|
|
|
|
|
|
$dat->{x_authority} = $authority; |
475
|
|
|
|
|
|
|
} |
476
|
0
|
0
|
|
|
|
|
if (my $metadata = $self->config->{Metadata}) { |
477
|
0
|
|
|
|
|
|
$dat->{$_} = $metadata->{$_} for keys %$metadata; |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
# fill 'provides' section |
481
|
0
|
0
|
|
|
|
|
if ($release_status ne 'unstable') { |
482
|
0
|
|
|
|
|
|
my $provides = Module::Metadata->provides( |
483
|
|
|
|
|
|
|
dir => File::Spec->catdir($self->dir, 'lib'), |
484
|
|
|
|
|
|
|
version => 2 |
485
|
|
|
|
|
|
|
); |
486
|
0
|
0
|
|
|
|
|
unless (%$provides) { |
487
|
0
|
|
|
|
|
|
errorf("%s does not provides any package. Abort.\n", $self->dir); |
488
|
|
|
|
|
|
|
} |
489
|
0
|
|
|
|
|
|
$dat->{provides} = $provides; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
# fill repository information |
493
|
0
|
|
|
|
|
|
my $git_info = $self->extract_git_info; |
494
|
0
|
0
|
|
|
|
|
if ($git_info->{bugtracker}) { |
495
|
0
|
|
|
|
|
|
$dat->{resources}->{bugtracker} = $git_info->{bugtracker}; |
496
|
|
|
|
|
|
|
} |
497
|
0
|
0
|
|
|
|
|
if ($git_info->{repository}) { |
498
|
0
|
|
|
|
|
|
$dat->{resources}->{repository} = $git_info->{repository}; |
499
|
|
|
|
|
|
|
} |
500
|
0
|
0
|
|
|
|
|
if ($git_info->{homepage}) { |
501
|
0
|
|
|
|
|
|
$dat->{resources}->{homepage} = $git_info->{homepage}; |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
# optional features |
505
|
0
|
0
|
|
|
|
|
if ($cpanfile->features) { |
506
|
0
|
|
|
|
|
|
my $optional_features = {}; |
507
|
0
|
|
|
|
|
|
foreach my $feature ($cpanfile->features) { |
508
|
0
|
|
|
|
|
|
$optional_features->{$feature->identifier} = { |
509
|
|
|
|
|
|
|
description => $feature->description, |
510
|
|
|
|
|
|
|
prereqs => $feature->prereqs->as_string_hash, |
511
|
|
|
|
|
|
|
} |
512
|
|
|
|
|
|
|
} |
513
|
0
|
|
|
|
|
|
$dat->{optional_features} = $optional_features; |
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
|
516
|
0
|
|
|
|
|
|
my $meta = CPAN::Meta->new($dat); |
517
|
0
|
|
|
|
|
|
return $meta; |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
sub extract_git_info { |
521
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
522
|
|
|
|
|
|
|
|
523
|
0
|
|
|
|
|
|
my $guard = pushd($self->dir); |
524
|
|
|
|
|
|
|
|
525
|
0
|
|
|
|
|
|
my $bugtracker; |
526
|
|
|
|
|
|
|
my $repository; |
527
|
0
|
|
|
|
|
|
my $homepage; |
528
|
0
|
0
|
|
|
|
|
if ( my $registered_url = `git config --get remote.origin.url` ) { |
529
|
0
|
|
|
|
|
|
$registered_url =~ s/\n//g; |
530
|
|
|
|
|
|
|
# XXX Make it public clone URL, but this only works with github |
531
|
0
|
0
|
0
|
|
|
|
if ($registered_url !~ m{^file://} && $registered_url =~ /(?:github|gitlab)\.com/) { |
532
|
0
|
|
|
|
|
|
my ($git_service, $user, $repo) = $registered_url =~ m{ |
533
|
|
|
|
|
|
|
(github\.com|gitlab\.com) |
534
|
|
|
|
|
|
|
(?:(?::[0-9]+)?/|:)([^/]+) |
535
|
|
|
|
|
|
|
/ |
536
|
|
|
|
|
|
|
(.+?)(?:\.git)? |
537
|
|
|
|
|
|
|
$ |
538
|
|
|
|
|
|
|
}ix; |
539
|
0
|
|
|
|
|
|
my $git_url = "https://$git_service/$user/$repo.git"; |
540
|
0
|
|
|
|
|
|
my $http_url = "https://$git_service/$user/$repo"; |
541
|
0
|
0
|
|
|
|
|
unless ($self->config->{no_github_issues}) { |
542
|
0
|
|
|
|
|
|
$bugtracker = +{ |
543
|
|
|
|
|
|
|
web => "$http_url/issues", |
544
|
|
|
|
|
|
|
}; |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
$repository = +{ |
547
|
0
|
|
|
|
|
|
type => "git", |
548
|
|
|
|
|
|
|
url => $git_url, |
549
|
|
|
|
|
|
|
web => $http_url, |
550
|
|
|
|
|
|
|
}; |
551
|
0
|
|
0
|
|
|
|
$homepage = $self->config->{homepage} || $http_url; |
552
|
|
|
|
|
|
|
} else { |
553
|
0
|
0
|
|
|
|
|
if ($registered_url !~ m{^(?:https?|ssh|git)://}) { |
554
|
|
|
|
|
|
|
# We can't do much more than this, but we need to fix |
555
|
|
|
|
|
|
|
# user@host:path/to/repo.git to git://$host/path/to/repo.git in |
556
|
|
|
|
|
|
|
# order to work with CPAN::Meta |
557
|
0
|
|
|
|
|
|
$registered_url =~ s{ |
558
|
|
|
|
|
|
|
\A |
559
|
|
|
|
|
|
|
[^@]+ # user name, which we toss away |
560
|
|
|
|
|
|
|
@ |
561
|
|
|
|
|
|
|
([^:]+) # anything other than a ":" |
562
|
|
|
|
|
|
|
: |
563
|
|
|
|
|
|
|
(.+) # anything, which is the repository |
564
|
|
|
|
|
|
|
\Z |
565
|
|
|
|
|
|
|
}{git://$1/$2}gx; |
566
|
|
|
|
|
|
|
} |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
# normal repository |
569
|
0
|
0
|
|
|
|
|
if ($registered_url !~ m{^file://}) { |
570
|
0
|
|
|
|
|
|
$repository = +{ |
571
|
|
|
|
|
|
|
type => "git", |
572
|
|
|
|
|
|
|
url => $registered_url, |
573
|
|
|
|
|
|
|
}; |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
} |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
return +{ |
579
|
0
|
|
|
|
|
|
bugtracker => $bugtracker, |
580
|
|
|
|
|
|
|
repository => $repository, |
581
|
|
|
|
|
|
|
homepage => $homepage, |
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
sub readme_from { |
586
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
587
|
0
|
0
|
|
|
|
|
$self->config->{readme_from} || $self->main_module_path; |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
sub regenerate_files { |
591
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
592
|
|
|
|
|
|
|
|
593
|
0
|
|
|
|
|
|
$self->regenerate_meta_json(); |
594
|
0
|
|
|
|
|
|
$self->regenerate_readme_md(); |
595
|
0
|
|
|
|
|
|
$self->module_maker->generate($self); |
596
|
0
|
0
|
|
|
|
|
if (Cwd::getcwd() ne $self->dir) { |
597
|
0
|
|
|
|
|
|
my $guard = pushd($self->dir); |
598
|
0
|
|
|
|
|
|
$self->module_maker->generate($self); |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
sub regenerate_meta_json { |
603
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
604
|
|
|
|
|
|
|
|
605
|
0
|
|
|
|
|
|
my $meta = $self->cpan_meta('unstable'); |
606
|
0
|
|
|
|
|
|
$meta->save(File::Spec->catfile($self->dir, 'META.json'), { |
607
|
|
|
|
|
|
|
version => '2.0' |
608
|
|
|
|
|
|
|
}); |
609
|
|
|
|
|
|
|
} |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
sub generate_minil_toml { |
612
|
0
|
|
|
0
|
0
|
|
my ($self, $profile) = @_; |
613
|
|
|
|
|
|
|
|
614
|
0
|
|
|
|
|
|
my $fname = File::Spec->catfile($self->dir, 'minil.toml'); |
615
|
0
|
|
|
|
|
|
my $project_name = $self->_detect_project_name_from_dir; |
616
|
0
|
|
|
|
|
|
my $content = join("\n", |
617
|
|
|
|
|
|
|
qq{name = "$project_name"}, |
618
|
|
|
|
|
|
|
qq{badges = ["github-actions/test.yml"]}, |
619
|
|
|
|
|
|
|
); |
620
|
|
|
|
|
|
|
|
621
|
0
|
0
|
|
|
|
|
if ($profile eq 'ModuleBuild') { |
|
|
0
|
|
|
|
|
|
622
|
0
|
|
|
|
|
|
$content .= qq{\nmodule_maker="ModuleBuild"\n}; |
623
|
|
|
|
|
|
|
} elsif ($profile eq 'ExtUtilsMakeMaker') { |
624
|
0
|
|
|
|
|
|
$content .= qq{\nmodule_maker="ExtUtilsMakeMaker"\n}; |
625
|
|
|
|
|
|
|
} else { |
626
|
0
|
|
|
|
|
|
$content .= qq{\nmodule_maker="ModuleBuildTiny"\n}; |
627
|
|
|
|
|
|
|
} |
628
|
0
|
|
|
|
|
|
$content .= qq{static_install = "auto"\n}; |
629
|
|
|
|
|
|
|
|
630
|
0
|
|
|
|
|
|
spew_raw($fname, $content . "\n"); |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
sub regenerate_readme_md { |
634
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
635
|
|
|
|
|
|
|
|
636
|
0
|
|
0
|
|
|
|
my $markdown_maker = $self->config->{markdown_maker} || 'Pod::Markdown'; |
637
|
0
|
|
|
|
|
|
require_module($markdown_maker); |
638
|
0
|
0
|
|
|
|
|
if ($markdown_maker eq 'Pod::Markdown') { |
639
|
0
|
|
|
|
|
|
$markdown_maker->VERSION('1.322'); |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
|
642
|
0
|
|
|
|
|
|
my $parser = $markdown_maker->new; |
643
|
0
|
0
|
|
|
|
|
if (not $parser->isa('Pod::Markdown')) { |
644
|
0
|
|
|
|
|
|
errorf("'markdown_maker' config key must be a subclass of Pod::Markdown\n"); |
645
|
|
|
|
|
|
|
} |
646
|
0
|
|
|
|
|
|
$parser->parse_from_file($self->readme_from); |
647
|
|
|
|
|
|
|
|
648
|
0
|
|
|
|
|
|
my $fname = File::Spec->catfile($self->dir, 'README.md'); |
649
|
0
|
|
|
|
|
|
my $markdown = $parser->as_markdown; |
650
|
|
|
|
|
|
|
|
651
|
0
|
0
|
0
|
|
|
|
if (ref $self->badges eq 'ARRAY' && scalar @{$self->badges} > 0) { |
|
0
|
|
|
|
|
|
|
652
|
0
|
|
|
|
|
|
my $user_name; |
653
|
|
|
|
|
|
|
my $repository_name; |
654
|
|
|
|
|
|
|
|
655
|
0
|
|
|
|
|
|
my $git_info = $self->extract_git_info; |
656
|
0
|
0
|
|
|
|
|
if (my $web_url = $git_info->{repository}->{web}) { |
657
|
0
|
|
|
|
|
|
($user_name, $repository_name) = $web_url =~ m!https://.+/(.+)/(.+)!; |
658
|
|
|
|
|
|
|
} |
659
|
0
|
|
|
|
|
|
my $branch = $self->release_branch; |
660
|
0
|
|
|
|
|
|
my @badges; |
661
|
0
|
0
|
0
|
|
|
|
if ($user_name && $repository_name) { |
662
|
0
|
|
|
|
|
|
for my $badge (@{$self->badges}) { |
|
0
|
|
|
|
|
|
|
663
|
0
|
|
|
|
|
|
my $uri = URI->new( $badge ); |
664
|
0
|
|
|
|
|
|
my $service_name = $uri->path; |
665
|
0
|
0
|
|
|
|
|
if ($service_name =~ /^travis(?:-ci\.(?:org|com))?$/) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
666
|
0
|
|
|
|
|
|
my $build_uri = $uri->clone; |
667
|
0
|
|
|
|
|
|
$build_uri->scheme('https'); |
668
|
0
|
|
|
|
|
|
$build_uri->path("$user_name/$repository_name"); |
669
|
0
|
|
|
|
|
|
$build_uri->query_form({}); |
670
|
0
|
|
|
|
|
|
my $image_uri = $uri->clone; |
671
|
0
|
|
|
|
|
|
$image_uri->scheme('https'); |
672
|
0
|
|
|
|
|
|
$image_uri->path("$user_name/$repository_name.svg"); |
673
|
0
|
|
|
|
|
|
my %image_uri_qs = $image_uri->query_form; |
674
|
0
|
0
|
|
|
|
|
$image_uri_qs{branch} = $branch if !defined($image_uri_qs{branch}); |
675
|
0
|
0
|
|
|
|
|
if ($service_name =~ /^travis(?:-ci\.(?:org|com))$/) { |
|
|
0
|
|
|
|
|
|
676
|
0
|
|
|
|
|
|
$_->host($service_name) foreach ($build_uri, $image_uri); |
677
|
|
|
|
|
|
|
} elsif (!defined($image_uri_qs{token})) { |
678
|
0
|
|
|
|
|
|
$_->host("travis-ci.org") foreach ($build_uri, $image_uri); |
679
|
|
|
|
|
|
|
} else { |
680
|
0
|
|
|
|
|
|
$_->host("travis-ci.com") foreach ($build_uri, $image_uri); |
681
|
|
|
|
|
|
|
} |
682
|
|
|
|
|
|
|
# Sort the query params so that the end URL is |
683
|
|
|
|
|
|
|
# deterministic and easier to test. |
684
|
0
|
|
|
|
|
|
$image_uri->query_form( map { ( $_, $image_uri_qs{$_} ) } sort keys %image_uri_qs ); |
|
0
|
|
|
|
|
|
|
685
|
0
|
|
|
|
|
|
push @badges, "[![Build Status]($image_uri)]($build_uri)"; |
686
|
|
|
|
|
|
|
} elsif ($service_name eq 'appveyor') { |
687
|
0
|
|
|
|
|
|
( my $appveyor_repository_name = $repository_name ) =~ s/\./-/g; |
688
|
0
|
|
|
|
|
|
push @badges, "[![Build Status](https://img.shields.io/appveyor/ci/$user_name/$appveyor_repository_name/$branch.svg?logo=appveyor)](https://ci.appveyor.com/project/$user_name/$appveyor_repository_name/branch/$branch)"; |
689
|
|
|
|
|
|
|
} elsif ($service_name eq 'coveralls') { |
690
|
0
|
|
|
|
|
|
push @badges, "[![Coverage Status](https://img.shields.io/coveralls/$user_name/$repository_name/$branch.svg?style=flat)](https://coveralls.io/r/$user_name/$repository_name?branch=$branch)" |
691
|
|
|
|
|
|
|
} elsif ($service_name eq 'codecov') { |
692
|
0
|
|
|
|
|
|
push @badges, "[![Coverage Status](http://codecov.io/github/$user_name/$repository_name/coverage.svg?branch=$branch)](https://codecov.io/github/$user_name/$repository_name?branch=$branch)"; |
693
|
|
|
|
|
|
|
} elsif ($service_name eq 'gitter') { |
694
|
0
|
|
|
|
|
|
push @badges, "[![Gitter chat](https://badges.gitter.im/$user_name/$repository_name.png)](https://gitter.im/$user_name/$repository_name)"; |
695
|
|
|
|
|
|
|
} elsif ($service_name eq 'circleci') { |
696
|
0
|
|
|
|
|
|
push @badges, "[![Build Status](https://circleci.com/gh/$user_name/$repository_name.svg)](https://circleci.com/gh/$user_name/$repository_name)"; |
697
|
|
|
|
|
|
|
} elsif ($service_name eq 'metacpan') { |
698
|
0
|
|
0
|
|
|
|
my $module_name = $self->config->{name} || $repository_name; |
699
|
0
|
|
|
|
|
|
push @badges, "[![MetaCPAN Release](https://badge.fury.io/pl/$module_name.svg)](https://metacpan.org/release/$module_name)"; |
700
|
|
|
|
|
|
|
} elsif ($service_name eq 'kritika') { |
701
|
0
|
|
|
|
|
|
my $build_uri = $uri->clone; |
702
|
0
|
|
|
|
|
|
$build_uri->scheme('https'); |
703
|
0
|
|
|
|
|
|
$build_uri->host('kritika.io'); |
704
|
0
|
|
|
|
|
|
$build_uri->path("/users/$user_name/repos/$user_name+$repository_name"); |
705
|
0
|
|
|
|
|
|
$build_uri->query_form({}); |
706
|
0
|
|
|
|
|
|
my $image_uri = $uri->clone; |
707
|
0
|
|
|
|
|
|
$image_uri->scheme('https'); |
708
|
0
|
|
|
|
|
|
$image_uri->host('kritika.io'); |
709
|
0
|
|
|
|
|
|
$image_uri->path("/users/$user_name/repos/$user_name+$repository_name/heads/$branch/status.svg"); |
710
|
0
|
|
|
|
|
|
push @badges, "[![Kritika Status]($image_uri)]($build_uri)"; |
711
|
|
|
|
|
|
|
} elsif ($service_name =~ m!^github-actions(?:/(.+))?$!) { |
712
|
0
|
|
0
|
|
|
|
my $workflow_file = $1 || 'test'; |
713
|
0
|
0
|
|
|
|
|
if ($workflow_file =~ /\.(?:yml|yaml)$/) { |
714
|
0
|
|
|
|
|
|
push @badges, "[![Actions Status](https://github.com/$user_name/$repository_name/actions/workflows/$workflow_file/badge.svg)](https://github.com/$user_name/$repository_name/actions)"; |
715
|
|
|
|
|
|
|
} else { |
716
|
0
|
|
|
|
|
|
push @badges, "[![Actions Status](https://github.com/$user_name/$repository_name/workflows/$workflow_file/badge.svg)](https://github.com/$user_name/$repository_name/actions)"; |
717
|
|
|
|
|
|
|
} |
718
|
|
|
|
|
|
|
} elsif ($service_name eq 'gitlab-pipeline') { |
719
|
0
|
|
|
|
|
|
push @badges, "[![Gitlab pipeline](https://gitlab.com/$user_name/$repository_name/badges/$branch/pipeline.svg)](https://gitlab.com/$user_name/$repository_name/-/commits/$branch)"; |
720
|
|
|
|
|
|
|
} elsif ($service_name eq 'gitlab-coverage') { |
721
|
0
|
|
|
|
|
|
push @badges, "[![Gitlab coverage](https://gitlab.com/$user_name/$repository_name/badges/$branch/coverage.svg)](https://gitlab.com/$user_name/$repository_name/-/commits/$branch)"; |
722
|
|
|
|
|
|
|
} |
723
|
|
|
|
|
|
|
} |
724
|
|
|
|
|
|
|
} |
725
|
|
|
|
|
|
|
|
726
|
0
|
|
|
|
|
|
$markdown = "\n" . $markdown; |
727
|
0
|
|
|
|
|
|
$markdown = join(' ', @badges) . $markdown |
728
|
|
|
|
|
|
|
} |
729
|
|
|
|
|
|
|
|
730
|
0
|
|
|
|
|
|
spew_utf8($fname, $markdown); |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
sub verify_prereqs { |
734
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
735
|
|
|
|
|
|
|
|
736
|
0
|
0
|
|
|
|
|
if ($Minilla::AUTO_INSTALL) { |
737
|
0
|
|
|
|
|
|
system('cpanm', '--quiet', '--installdeps', '--with-develop', '.'); |
738
|
|
|
|
|
|
|
} |
739
|
|
|
|
|
|
|
} |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
sub _build_contributors { |
742
|
0
|
|
|
0
|
|
|
my $self = shift; |
743
|
|
|
|
|
|
|
|
744
|
0
|
0
|
|
|
|
|
return [] unless (`git show-ref --head`); |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
my $normalize = sub { |
747
|
0
|
|
|
0
|
|
|
local $_ = shift; |
748
|
0
|
0
|
|
|
|
|
if (/<([^>]+)>/) { |
749
|
0
|
|
|
|
|
|
$1; |
750
|
|
|
|
|
|
|
} else { |
751
|
0
|
|
|
|
|
|
$_; |
752
|
|
|
|
|
|
|
} |
753
|
0
|
|
|
|
|
|
}; |
754
|
0
|
|
|
|
|
|
my @lines = do { |
755
|
0
|
|
|
|
|
|
my %uniq; |
756
|
0
|
|
|
|
|
|
reverse grep { !$uniq{$normalize->($_)}++ } split /\n/, `git log --format="%aN <%aE>"` |
|
0
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
}; |
758
|
0
|
|
|
|
|
|
my %is_author = map { $normalize->($_) => 1 } @{$self->authors}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
759
|
0
|
|
|
|
|
|
@lines = map { decode_utf8($_) } @lines; |
|
0
|
|
|
|
|
|
|
760
|
0
|
|
|
|
|
|
@lines = grep { !$is_author{$normalize->($_)} } @lines; |
|
0
|
|
|
|
|
|
|
761
|
0
|
|
|
|
|
|
@lines = grep { $_ ne 'Your Name ' } @lines; |
|
0
|
|
|
|
|
|
|
762
|
0
|
|
|
|
|
|
@lines = grep { ! /^\(no author\) <\(no author\)\@[\d\w\-]+>$/ } @lines; |
|
0
|
|
|
|
|
|
|
763
|
0
|
|
|
|
|
|
[sort @lines]; |
764
|
|
|
|
|
|
|
} |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
sub _build_work_dir { |
767
|
0
|
|
|
0
|
|
|
my $self = shift; |
768
|
0
|
|
|
|
|
|
Minilla::WorkDir->new( |
769
|
|
|
|
|
|
|
project => $self, |
770
|
|
|
|
|
|
|
); |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
sub _build_files { |
774
|
0
|
|
|
0
|
|
|
my $self = shift; |
775
|
0
|
|
|
|
|
|
my $conf = $self->config->{'FileGatherer'}; |
776
|
|
|
|
|
|
|
my @files = Minilla::FileGatherer->new( |
777
|
|
|
|
|
|
|
exclude_match => $conf->{exclude_match}, |
778
|
0
|
0
|
|
|
|
|
exists $conf->{include_dotfiles} ? (include_dotfiles => $conf->{include_dotfiles}) : (), |
779
|
|
|
|
|
|
|
)->gather_files( |
780
|
|
|
|
|
|
|
$self->dir |
781
|
|
|
|
|
|
|
); |
782
|
0
|
|
|
|
|
|
\@files; |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
sub _build_release_branch { |
786
|
0
|
|
|
0
|
|
|
my $self = shift; |
787
|
0
|
0
|
|
|
|
|
if (my $br = $self->config->{release}->{branch}) { |
788
|
0
|
|
|
|
|
|
return $br; |
789
|
|
|
|
|
|
|
} |
790
|
0
|
|
|
|
|
|
my $show = `git remote show origin`; |
791
|
0
|
|
|
|
|
|
my ($br) = $show =~ /^\s*HEAD branch:\s(\S+)$/m; |
792
|
|
|
|
|
|
|
# For backward compatibility, fallback to 'master' just in case, |
793
|
|
|
|
|
|
|
# but it's unlikely to be used in practice. |
794
|
0
|
|
0
|
|
|
|
return $br || 'master'; |
795
|
|
|
|
|
|
|
} |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
sub perl_files { |
798
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
799
|
0
|
|
|
|
|
|
my @files = @{$self->files}; |
|
0
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
grep { |
801
|
0
|
0
|
|
|
|
|
$_ =~ /\.(?:pm|pl|t)$/i || slurp_raw($_) =~ m{ ^ \#\! .* perl }ix |
|
0
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
} @files; |
803
|
|
|
|
|
|
|
} |
804
|
|
|
|
|
|
|
|
805
|
0
|
0
|
|
0
|
0
|
|
sub PL_files { shift->config->{PL_files} || +{} } |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
sub requires_external_bin { |
808
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
809
|
0
|
|
|
|
|
|
return $self->config->{requires_external_bin}; |
810
|
|
|
|
|
|
|
} |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
# @return true if the project is valid, false otherwise. |
813
|
|
|
|
|
|
|
sub validate { |
814
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
815
|
0
|
|
|
|
|
|
my $module_maker = $self->module_maker; |
816
|
0
|
0
|
|
|
|
|
if ($module_maker->can('validate')) { |
817
|
0
|
|
|
|
|
|
return $module_maker->validate(); |
818
|
|
|
|
|
|
|
} else { |
819
|
0
|
|
|
|
|
|
return 1; |
820
|
|
|
|
|
|
|
} |
821
|
|
|
|
|
|
|
} |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
1; |