line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!perl |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package App::opan; |
4
|
|
|
|
|
|
|
|
5
|
3
|
|
|
3
|
|
4544
|
use strictures 2; |
|
3
|
|
|
|
|
1687
|
|
|
3
|
|
|
|
|
139
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.003004'; |
8
|
|
|
|
|
|
|
|
9
|
3
|
|
|
3
|
|
2327
|
use Dist::Metadata; |
|
3
|
|
|
|
|
106482
|
|
|
3
|
|
|
|
|
117
|
|
10
|
3
|
|
|
3
|
|
1822
|
use File::Open qw(fopen); |
|
3
|
|
|
|
|
4924
|
|
|
3
|
|
|
|
|
215
|
|
11
|
3
|
|
|
3
|
|
1867
|
use List::UtilsBy qw(sort_by); |
|
3
|
|
|
|
|
5986
|
|
|
3
|
|
|
|
|
231
|
|
12
|
3
|
|
|
3
|
|
1341
|
use IPC::System::Simple qw(capture); |
|
3
|
|
|
|
|
20259
|
|
|
3
|
|
|
|
|
247
|
|
13
|
3
|
|
|
3
|
|
859
|
use Mojo::Util qw(monkey_patch); |
|
3
|
|
|
|
|
207776
|
|
|
3
|
|
|
|
|
281
|
|
14
|
3
|
|
|
3
|
|
657
|
use Mojo::File qw(path); |
|
3
|
|
|
|
|
29867
|
|
|
3
|
|
|
|
|
164
|
|
15
|
3
|
|
|
3
|
|
1085
|
use Import::Into; |
|
3
|
|
|
|
|
5604
|
|
|
3
|
|
|
|
|
8686
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our %TOKENS = map { $_=>1 } split/:/, $ENV{OPAN_AUTH_TOKENS} || ''; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub cpan_fetch { |
20
|
5
|
|
|
5
|
|
208
|
my $app = shift; |
21
|
5
|
|
|
|
|
96
|
my $url = Mojo::URL->new(shift)->to_abs($app->cpan_url); |
22
|
5
|
|
|
|
|
5917
|
my $tx = $app->ua->get($url); |
23
|
5
|
100
|
|
|
|
766458
|
return $tx->res unless my $err = $tx->error; |
24
|
1
|
|
|
|
|
29
|
die sprintf "%s %s: %s\n", $tx->req->method, $url, $err->{message}; |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub packages_header { |
28
|
18
|
|
|
18
|
|
142
|
my ($count) = @_; |
29
|
18
|
|
|
|
|
223
|
(my $str = <<" HEADER") =~ s/^ //mg; |
30
|
|
|
|
|
|
|
File: 02packages.details.txt |
31
|
|
|
|
|
|
|
Description: Package names found in directory \$CPAN/authors/id/ |
32
|
|
|
|
|
|
|
Columns: package name, version, path |
33
|
|
|
|
|
|
|
Intended-For: Automated fetch routines, namespace documentation. |
34
|
|
|
|
|
|
|
Written-By: App::opan |
35
|
|
|
|
|
|
|
Line-Count: ${count} |
36
|
18
|
|
|
|
|
432
|
Last-Updated: ${\scalar gmtime} GMT |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
HEADER |
39
|
18
|
|
|
|
|
534
|
return $str; |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub extract_provides_from_tarball { |
43
|
5
|
|
|
5
|
|
18
|
my ($tarball) = @_; |
44
|
5
|
|
|
|
|
197
|
Dist::Metadata->new(file => $tarball)->package_versions; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub pod_section { |
48
|
36
|
|
|
36
|
|
75
|
my ($cmd, $for_description) = @_; |
49
|
36
|
|
|
|
|
87
|
my $fh = fopen __FILE__; |
50
|
|
|
|
|
|
|
|
51
|
36
|
|
|
|
|
2620
|
my $pod = ''; |
52
|
36
|
100
|
|
|
|
693
|
while (<$fh>) { /^=head3 $cmd\s*$/ && last } |
|
18972
|
|
|
|
|
54827
|
|
53
|
36
|
50
|
100
|
|
|
122
|
while (<$fh>) { /^=head/ && last || ($pod .= $_) } |
|
318
|
|
|
|
|
787
|
|
54
|
|
|
|
|
|
|
|
55
|
36
|
100
|
|
|
|
62
|
if ($for_description) { |
56
|
24
|
50
|
|
|
|
225
|
$pod = $pod =~ m!\n(\S+.*?\.)(?:\s|$)!s ? $1 : "$0 $cmd --help for more info"; |
57
|
24
|
|
|
|
|
81
|
$pod =~ s![\n\r]+! !g; |
58
|
24
|
|
|
|
|
160
|
$pod =~ s![\s\.]+$!!; |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
36
|
|
|
|
|
252
|
$pod =~ s!\b[CIL]<\/?([^>]+)\>!$1!g; # Remove C<...> pod notation |
62
|
36
|
|
|
|
|
1263
|
return $pod; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub provides_to_packages_entries { |
66
|
5
|
|
|
5
|
|
283124
|
my ($path, $provides) = @_; |
67
|
|
|
|
|
|
|
# <@mst> ok, I officially have no idea what order 02packages is actually in |
68
|
|
|
|
|
|
|
# <@rjbs> $list .= join "", sort {lc $a cmp lc $b} @listing02; |
69
|
|
|
|
|
|
|
[ |
70
|
|
|
|
|
|
|
map +[ |
71
|
|
|
|
|
|
|
$_, defined($provides->{$_}) ? $provides->{$_} : 'undef', $path |
72
|
5
|
50
|
|
4
|
|
159
|
], sort_by { lc } keys %$provides |
|
4
|
|
|
|
|
59
|
|
73
|
|
|
|
|
|
|
] |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub entries_from_packages_file { |
77
|
36
|
|
|
36
|
|
57078
|
my ($file) = @_; |
78
|
36
|
|
|
|
|
430
|
my $fh = fopen $file; |
79
|
36
|
|
|
|
|
5027
|
while (my $header = <$fh>) { |
80
|
295
|
100
|
|
|
|
1076
|
last if $header =~ /^$/; |
81
|
|
|
|
|
|
|
} |
82
|
36
|
|
|
|
|
90
|
my @entries; |
83
|
36
|
|
|
|
|
287
|
while (my $line = <$fh>) { |
84
|
502592
|
|
|
|
|
752165
|
chomp($line); |
85
|
502592
|
|
|
|
|
2666199
|
push @entries, [ split /\s+/, $line ]; |
86
|
|
|
|
|
|
|
} |
87
|
36
|
|
|
|
|
1324
|
return \@entries; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub merge_packages_entries { |
91
|
17
|
|
|
17
|
|
198
|
my ($base, $merge_these) = @_; |
92
|
17
|
50
|
|
|
|
84
|
return $base unless $merge_these; |
93
|
17
|
|
|
|
|
41
|
my @merged; |
94
|
17
|
|
|
|
|
45
|
my @to_merge = @$merge_these; |
95
|
17
|
|
|
|
|
165
|
foreach my $idx (0..$#$base) { |
96
|
1004822
|
|
66
|
|
|
1620905
|
while (@to_merge and lc($to_merge[0][0]) lt lc($base->[$idx][0])) { |
97
|
0
|
|
|
|
|
0
|
push @merged, shift @to_merge; |
98
|
|
|
|
|
|
|
} |
99
|
1004822
|
100
|
100
|
|
|
2135439
|
push @merged, ( |
100
|
|
|
|
|
|
|
(@to_merge and $to_merge[0][0] eq $base->[$idx][0]) |
101
|
|
|
|
|
|
|
? shift @to_merge |
102
|
|
|
|
|
|
|
: $base->[$idx] |
103
|
|
|
|
|
|
|
); |
104
|
|
|
|
|
|
|
} |
105
|
17
|
|
|
|
|
78
|
push @merged, @to_merge; |
106
|
17
|
|
|
|
|
138
|
return \@merged; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub write_packages_file { |
110
|
18
|
|
|
18
|
|
14646
|
my ($file, $entries) = @_; |
111
|
18
|
|
|
|
|
281
|
my $fh = fopen $file, 'w'; |
112
|
18
|
|
|
|
|
13545
|
print $fh packages_header(scalar @$entries); |
113
|
|
|
|
|
|
|
local *_ = sub { |
114
|
|
|
|
|
|
|
# mirroring 'sub rewrite02 {' in lib/PAUSE/mldistwatch.pm |
115
|
|
|
|
|
|
|
# see http://github.com/andk/pause for the whole thing |
116
|
1004826
|
|
|
1004826
|
|
1636373
|
my ($one, $two) = (30, 8); |
117
|
1004826
|
100
|
|
|
|
1538087
|
if (length($_[0]) > $one) { |
118
|
498040
|
|
|
|
|
588447
|
$one += 8 - length($_[1]); |
119
|
498040
|
|
|
|
|
570290
|
$two = length($_[1]); |
120
|
|
|
|
|
|
|
} |
121
|
1004826
|
|
|
|
|
3832330
|
sprintf "%-${one}s %${two}s %s\n", @_; |
122
|
18
|
|
|
|
|
371
|
}; |
123
|
18
|
|
|
|
|
176
|
print $fh _(@$_) for @$entries; |
124
|
18
|
|
|
|
|
9099
|
close $fh; |
125
|
18
|
|
|
|
|
374
|
path("${file}.gz")->spurt(scalar capture(gzip => -c => $file)); |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub add_dist_to_index { |
129
|
5
|
|
|
5
|
|
581
|
my ($index, $dist) = @_; |
130
|
5
|
|
|
|
|
37
|
my $existing = entries_from_packages_file($index); |
131
|
5
|
|
|
|
|
42
|
my ($path) = $dist =~ m{pans/[a-z]+/dists/(.*)}; |
132
|
5
|
|
|
|
|
177
|
write_packages_file( |
133
|
|
|
|
|
|
|
$index, |
134
|
|
|
|
|
|
|
merge_packages_entries( |
135
|
|
|
|
|
|
|
$existing, |
136
|
|
|
|
|
|
|
provides_to_packages_entries( |
137
|
|
|
|
|
|
|
$path, |
138
|
|
|
|
|
|
|
extract_provides_from_tarball($dist) |
139
|
|
|
|
|
|
|
), |
140
|
|
|
|
|
|
|
) |
141
|
|
|
|
|
|
|
); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
sub remove_dist_from_index { |
145
|
1
|
|
|
1
|
|
58
|
my ($index, $dist) = @_; |
146
|
1
|
|
|
|
|
16
|
my $existing = entries_from_packages_file($index); |
147
|
1
|
|
|
|
|
41
|
my $exclude = qr/\Q${dist}\E$/; |
148
|
1
|
|
|
|
|
57
|
write_packages_file( |
149
|
|
|
|
|
|
|
$index, |
150
|
|
|
|
|
|
|
[ grep $_->[2] !~ $exclude, @$existing ], |
151
|
|
|
|
|
|
|
); |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
my @pan_names = qw(upstream custom pinset combined nopin); |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
sub do_init { |
157
|
2
|
|
|
2
|
|
14
|
my ($app) = @_; |
158
|
2
|
|
|
|
|
15
|
path("pans/$_/dists")->make_path for @pan_names; |
159
|
2
|
|
|
|
|
2531
|
write_packages_file("pans/$_/index", []) for qw(custom pinset); |
160
|
2
|
|
|
|
|
13693
|
do_pull($app); |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
sub do_fetch { |
164
|
2
|
|
|
2
|
|
19
|
my ($app) = @_; |
165
|
2
|
|
|
|
|
103
|
path('pans/upstream/index.gz')->spurt( |
166
|
|
|
|
|
|
|
cpan_fetch($app, 'modules/02packages.details.txt.gz')->body |
167
|
|
|
|
|
|
|
); |
168
|
2
|
|
|
|
|
13350
|
path('pans/upstream/index')->spurt( |
169
|
|
|
|
|
|
|
scalar capture qw(gzip -dc), 'pans/upstream/index.gz' |
170
|
|
|
|
|
|
|
); |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub do_merge { |
174
|
4
|
|
|
4
|
|
83
|
my ($app) = @_; |
175
|
4
|
|
|
|
|
68
|
my $upstream = entries_from_packages_file('pans/upstream/index'); |
176
|
4
|
|
|
|
|
54
|
my $pinset = entries_from_packages_file('pans/pinset/index'); |
177
|
4
|
|
|
|
|
42
|
my $custom = entries_from_packages_file('pans/custom/index'); |
178
|
|
|
|
|
|
|
|
179
|
4
|
|
|
|
|
50
|
my $nopin = merge_packages_entries($upstream, $custom); |
180
|
4
|
|
|
|
|
43
|
write_packages_file('pans/nopin/index', $nopin); |
181
|
|
|
|
|
|
|
|
182
|
4
|
|
|
|
|
1305705
|
my $combined = merge_packages_entries( |
183
|
|
|
|
|
|
|
$upstream, merge_packages_entries($pinset, $custom) |
184
|
|
|
|
|
|
|
); |
185
|
4
|
|
|
|
|
99
|
write_packages_file('pans/combined/index', $combined); |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub do_pull { |
189
|
2
|
|
|
2
|
|
35
|
my ($app) = @_; |
190
|
2
|
|
|
|
|
104
|
do_fetch($app); |
191
|
2
|
|
|
|
|
382172
|
do_merge($app); |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub do_add { |
195
|
2
|
|
|
2
|
|
25
|
my ($app, $path_arg) = @_; |
196
|
2
|
|
|
|
|
30
|
my $path = path($path_arg); |
197
|
2
|
|
|
|
|
53
|
my $pan_dir = path('pans/custom/dists/M/MY/MY')->make_path; |
198
|
2
|
50
|
|
|
|
818
|
$path->copy_to(my $pan_path = $pan_dir->child($path->basename)) |
199
|
|
|
|
|
|
|
or die "Failed to copy ${path} into custom pan: $!"; |
200
|
2
|
|
|
|
|
2001
|
add_dist_to_index('pans/custom/index', $pan_path); |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub do_unadd { |
204
|
0
|
|
|
0
|
|
0
|
my ($app, $dist) = @_; |
205
|
0
|
|
|
|
|
0
|
remove_dist_from_index('pans/custom/index', $dist); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub do_pin { |
209
|
3
|
|
|
3
|
|
40
|
my ($app, $path_arg) = @_; |
210
|
3
|
100
|
|
|
|
38
|
$path_arg =~ /^(([A-Z])[A-Z])[A-Z]/ and $path_arg = join('/', $2, $1, $path_arg); |
211
|
3
|
|
|
|
|
14
|
my $path = path($path_arg); |
212
|
3
|
|
|
|
|
62
|
my $res = cpan_fetch($app, "authors/id/$path"); |
213
|
2
|
|
|
|
|
61
|
path("pans/pinset/dists/")->child($path->dirname)->make_path; |
214
|
2
|
|
|
|
|
933
|
add_dist_to_index('pans/pinset/index', path("pans/pinset/dists/$path")->spurt($res->body)); |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub do_unpin { |
218
|
1
|
|
|
1
|
|
24
|
my ($app, $dist) = @_; |
219
|
1
|
|
|
|
|
19
|
remove_dist_from_index('pans/pinset/index', $dist); |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
sub generate_purgelist { |
223
|
2
|
|
|
2
|
|
125
|
my @list; |
224
|
2
|
|
|
|
|
14
|
foreach my $pan (qw(pinset custom)) { |
225
|
|
|
|
|
|
|
my %indexed = map +("pans/${pan}/dists/".$_->[2] => 1), |
226
|
4
|
|
|
|
|
9
|
@{entries_from_packages_file("pans/${pan}/index")}; |
|
4
|
|
|
|
|
27
|
|
227
|
4
|
|
|
|
|
838
|
foreach my $file (sort glob "pans/${pan}/dists/*/*/*/*") { |
228
|
6
|
100
|
|
|
|
55
|
push @list, $file unless $indexed{$file}; |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
} |
231
|
2
|
|
|
|
|
308
|
return @list; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
sub do_purgelist { |
235
|
1
|
|
|
1
|
|
33
|
print "$_\n" for &generate_purgelist; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
sub do_purge { |
239
|
1
|
|
|
1
|
|
19
|
unlink($_) for &generate_purgelist; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub run_with_server { |
243
|
0
|
|
|
0
|
|
0
|
my ($app, $run, $pan, @args) = @_; |
244
|
0
|
0
|
0
|
|
|
0
|
unless ( |
245
|
|
|
|
|
|
|
defined($pan) and $pan =~ /^--(combined|nopin|autopin)$/ |
246
|
|
|
|
|
|
|
) { |
247
|
0
|
|
|
|
|
0
|
unshift @args, grep defined, $pan; |
248
|
0
|
|
|
|
|
0
|
$pan = '--combined'; |
249
|
|
|
|
|
|
|
} |
250
|
0
|
|
|
|
|
0
|
$pan =~ s/^--//; |
251
|
0
|
|
|
|
|
0
|
require Mojo::IOLoop::Server; |
252
|
0
|
|
|
|
|
0
|
my $port = Mojo::IOLoop::Server->generate_port; |
253
|
0
|
|
|
|
|
0
|
my $url = "http://localhost:${port}/"; |
254
|
0
|
|
|
|
|
0
|
my $pid = fork(); |
255
|
0
|
0
|
|
|
|
0
|
die "fork() fork()ed up: $!" unless defined $pid; |
256
|
0
|
0
|
|
|
|
0
|
unless ($pid) { |
257
|
0
|
0
|
|
|
|
0
|
$ENV{OPAN_AUTOPIN} = 1 if $pan eq 'autopin'; |
258
|
0
|
|
|
|
|
0
|
$app->start(daemon => -l => $url); |
259
|
0
|
|
|
|
|
0
|
exit(0); |
260
|
|
|
|
|
|
|
} |
261
|
0
|
|
|
|
|
0
|
eval { $run->("${url}${pan}", @args) }; |
|
0
|
|
|
|
|
0
|
|
262
|
0
|
|
|
|
|
0
|
my $err = $@; |
263
|
0
|
|
|
|
|
0
|
kill TERM => $pid; |
264
|
0
|
0
|
|
|
|
0
|
warn "Run block failed: $err" if $err; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
sub do_cpanm { |
268
|
0
|
|
|
0
|
|
0
|
my ($app, @args) = @_; |
269
|
|
|
|
|
|
|
run_with_server($app, sub { |
270
|
0
|
|
|
0
|
|
0
|
my ($mirror, @args) = @_; |
271
|
0
|
|
|
|
|
0
|
system(cpanm => '--mirror', $mirror, '--mirror-only', @args); |
272
|
0
|
|
|
|
|
0
|
}, @args); |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub do_carton { |
276
|
0
|
|
|
0
|
|
0
|
my ($app, @args) = @_; |
277
|
|
|
|
|
|
|
run_with_server($app, sub { |
278
|
0
|
|
|
0
|
|
0
|
my ($mirror, @args) = @_; |
279
|
0
|
|
|
|
|
0
|
local $ENV{PERL_CARTON_MIRROR} = $mirror; |
280
|
0
|
|
|
|
|
0
|
system(carton => @args); |
281
|
0
|
|
|
|
|
0
|
}, @args); |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
foreach my $cmd ( |
285
|
|
|
|
|
|
|
qw(init fetch add unadd pin unpin merge pull purgelist purge cpanm carton) |
286
|
|
|
|
|
|
|
) { |
287
|
|
|
|
|
|
|
my $pkg = "App::opan::Command::${cmd}"; |
288
|
|
|
|
|
|
|
my $code = __PACKAGE__->can("do_${cmd}"); |
289
|
|
|
|
|
|
|
Mojo::Base->import::into($pkg, 'Mojolicious::Command'); |
290
|
24
|
|
|
24
|
|
597
|
monkey_patch $pkg, description => sub { pod_section($cmd, 1) }; |
|
|
|
|
24
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
24
|
|
|
|
291
|
12
|
|
|
12
|
|
7252
|
monkey_patch $pkg, usage => sub { pod_section($cmd, 0) }; |
|
|
|
|
12
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
12
|
|
|
|
292
|
|
|
|
|
|
|
monkey_patch $pkg, |
293
|
10
|
|
|
10
|
|
77192
|
run => sub { my $self = shift; $code->($self->app, @_) }; |
|
10
|
|
|
10
|
|
74
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
10
|
|
|
|
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
|
296
|
3
|
|
|
3
|
|
1602
|
use Mojolicious::Lite; |
|
3
|
|
|
|
|
674326
|
|
|
3
|
|
|
|
|
23
|
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
Mojo::IOLoop->recurring(600 => sub { do_pull(app); }) if $ENV{OPAN_RECURRING_PULL}; |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
post "/upload" => sub { |
301
|
|
|
|
|
|
|
my $c = shift; |
302
|
|
|
|
|
|
|
unless ($TOKENS{$c->req->url->to_abs->password || ""}) { |
303
|
|
|
|
|
|
|
$c->res->headers->www_authenticate("Basic realm=opan"); |
304
|
|
|
|
|
|
|
return $c->render(status => 401, text => "Token missing or not found\n"); |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
my $upload = $c->req->upload('dist') || $c->req->upload('pause99_add_uri_httpupload') |
307
|
|
|
|
|
|
|
or return $c->render(status => 400, text => "dist file missing\n"); |
308
|
|
|
|
|
|
|
my $pan_dir = path('pans/custom/dists/M/MY/MY')->make_path; |
309
|
|
|
|
|
|
|
$upload->move_to(my $pan_path = $pan_dir->child($upload->filename)) |
310
|
|
|
|
|
|
|
or $c->render( |
311
|
|
|
|
|
|
|
status => 500, |
312
|
|
|
|
|
|
|
text => "Failed to move ${upload} into custom pan: $!\n" |
313
|
|
|
|
|
|
|
); |
314
|
|
|
|
|
|
|
add_dist_to_index('pans/custom/index', $pan_path); |
315
|
|
|
|
|
|
|
do_merge(app); |
316
|
|
|
|
|
|
|
$c->render(text => "$pan_path Added to opan\n"); |
317
|
|
|
|
|
|
|
}; |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
push(@{app->commands->namespaces}, 'App::opan::Command'); |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
helper cpan_url => sub { Mojo::URL->new($ENV{OPAN_MIRROR} || 'https://www.cpan.org/') }; |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
my $nopin_static = Mojolicious::Static->new( |
324
|
|
|
|
|
|
|
paths => [ 'pans/custom/dists' ] |
325
|
|
|
|
|
|
|
); |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
my $pinset_static = Mojolicious::Static->new( |
328
|
|
|
|
|
|
|
paths => [ 'pans/pinset/dists' ] |
329
|
|
|
|
|
|
|
); |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
my $combined_static = Mojolicious::Static->new( |
332
|
|
|
|
|
|
|
paths => [ 'pans/custom/dists', 'pans/pinset/dists' ] |
333
|
|
|
|
|
|
|
); |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
my $base_static = Mojolicious::Static->new( |
336
|
|
|
|
|
|
|
paths => [ 'pans' ] |
337
|
|
|
|
|
|
|
); |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
foreach my $pan (qw(upstream nopin combined pinset custom)) { |
340
|
|
|
|
|
|
|
get "/${pan}/modules/02packages.details.txt" => sub { |
341
|
|
|
|
|
|
|
$base_static->dispatch($_[0]->stash(path => "${pan}/index")); |
342
|
|
|
|
|
|
|
}; |
343
|
|
|
|
|
|
|
get "/${pan}/modules/02packages.details.txt.gz" => sub { |
344
|
|
|
|
|
|
|
$base_static->dispatch($_[0]->stash(path => "${pan}/index.gz")); |
345
|
|
|
|
|
|
|
}; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
my $serve_upstream = sub { |
349
|
|
|
|
|
|
|
my ($c) = @_; |
350
|
|
|
|
|
|
|
$c->render_later; |
351
|
|
|
|
|
|
|
$c->ua->get( |
352
|
|
|
|
|
|
|
$c->cpan_url.'authors/id/'.$c->stash->{dist_path}, |
353
|
|
|
|
|
|
|
sub { |
354
|
|
|
|
|
|
|
my (undef, $tx) = @_; |
355
|
|
|
|
|
|
|
$c->tx->res($tx->res); |
356
|
|
|
|
|
|
|
$c->rendered; |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
); |
359
|
|
|
|
|
|
|
return; |
360
|
|
|
|
|
|
|
}; |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
get '/upstream/authors/id/*dist_path' => $serve_upstream; |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
get '/combined/authors/id/*dist_path' => sub { |
365
|
|
|
|
|
|
|
$_[0]->stash(path => $_[0]->stash->{dist_path}); |
366
|
|
|
|
|
|
|
$combined_static->dispatch($_[0]) or $serve_upstream->($_[0]); |
367
|
|
|
|
|
|
|
}; |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
get '/nopin/authors/id/*dist_path' => sub { |
370
|
|
|
|
|
|
|
$_[0]->stash(path => $_[0]->stash->{dist_path}); |
371
|
|
|
|
|
|
|
$nopin_static->dispatch($_[0]) or $serve_upstream->($_[0]); |
372
|
|
|
|
|
|
|
}; |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
get "/autopin/modules/02packages.details.txt" => sub { |
375
|
|
|
|
|
|
|
return $_[0]->render(text => 'Autopin off', status => 404) |
376
|
|
|
|
|
|
|
unless $ENV{OPAN_AUTOPIN}; |
377
|
|
|
|
|
|
|
$base_static->dispatch($_[0]->stash(path => "nopin/index")); |
378
|
|
|
|
|
|
|
}; |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
get "/autopin/modules/02packages.details.txt.gz" => sub { |
381
|
|
|
|
|
|
|
return $_[0]->render(text => 'Autopin off', status => 404) |
382
|
|
|
|
|
|
|
unless $ENV{OPAN_AUTOPIN}; |
383
|
|
|
|
|
|
|
$base_static->dispatch($_[0]->stash(path => "nopin/index.gz")); |
384
|
|
|
|
|
|
|
}; |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
get '/autopin/authors/id/*dist_path' => sub { |
387
|
|
|
|
|
|
|
return $_[0]->render(text => 'Autopin off', status => 404) |
388
|
|
|
|
|
|
|
unless $ENV{OPAN_AUTOPIN}; |
389
|
|
|
|
|
|
|
return if $nopin_static->dispatch($_[0]->stash(path => $_[0]->stash->{dist_path})); |
390
|
|
|
|
|
|
|
return if eval { |
391
|
|
|
|
|
|
|
do_pin(app, $_[0]->stash->{path}); |
392
|
|
|
|
|
|
|
$pinset_static->dispatch($_[0]); |
393
|
|
|
|
|
|
|
}; |
394
|
|
|
|
|
|
|
return $_[0]->render(text => 'Not found', status => 404); |
395
|
|
|
|
|
|
|
}; |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
caller() ? app : app->tap(sub { shift->log->level('fatal') })->start; |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
=head1 NAME |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
App::opan - A CPAN overlay for darkpan and pinning purposes |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=head1 SYNOPSIS |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
Set up an opan (creates a directory tree in C): |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
$ opan init |
408
|
|
|
|
|
|
|
$ opan pin MSTROUT/M-1.tar.gz |
409
|
|
|
|
|
|
|
$ opan add ./My-Dist-1.23.tar.gz |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
Now, you can start the server: |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
$ opan daemon -l http://localhost:8030/ |
414
|
|
|
|
|
|
|
Server available at http://localhost:8030/ |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
Then in another terminal, run one of: |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
$ cpanm --mirror http://localhost:8030/combined/ --mirror-only --installdeps . |
419
|
|
|
|
|
|
|
$ PERL_CARTON_MIRROR=http://localhost:8030/combined/ carton install |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
Or, to let opan do that part for you, skip starting the server and run one of: |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
$ opan cpanm --installdeps . |
424
|
|
|
|
|
|
|
$ opan carton install |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
=head1 DESCRIPTION |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
Two basic approaches to using this thing. First, if you're using carton, you |
429
|
|
|
|
|
|
|
can probably completely ignore the pinning system, so just do: |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
$ opan init |
432
|
|
|
|
|
|
|
$ opan add ./My-DarkPan-Dist-1.23.tar.gz |
433
|
|
|
|
|
|
|
$ git add pans/; git commit -m 'fresh opan' |
434
|
|
|
|
|
|
|
$ opan carton install |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
You can reproduce this install with simply: |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
$ opan carton install --deployment |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
When you want to update to a new version of the cpan index (assuming you |
441
|
|
|
|
|
|
|
already have an additional requirement that's too old in your current |
442
|
|
|
|
|
|
|
snapshot): |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
$ opan pull |
445
|
|
|
|
|
|
|
$ git add pans/; git commit -m 'update pans' |
446
|
|
|
|
|
|
|
$ opan carton install |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
Second, if you're not using carton, but you want reproducible installs, you |
449
|
|
|
|
|
|
|
can still mostly ignore the pinning system by doing: |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
$ opan init |
452
|
|
|
|
|
|
|
$ opan add ./My-DarkPan-Dist-1.23.tar.gz |
453
|
|
|
|
|
|
|
$ opan cpanm --autopin --installdeps . |
454
|
|
|
|
|
|
|
$ git add pans/; git commit -m 'opan with current version pinning' |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
Your reproducible install is now: |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
$ opan cpanm --installdeps . |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
When you want to update to a new version of the cpan index (assuming you |
461
|
|
|
|
|
|
|
already have an additional requirement that's too old in your current |
462
|
|
|
|
|
|
|
snapshot): |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
$ opan pull |
465
|
|
|
|
|
|
|
$ opan cpanm --autopin --installdeps . |
466
|
|
|
|
|
|
|
$ git add pans/; git commit -m 'update pans' |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
To update a single dist in this system, the easy route is: |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
$ opan unpin Thingy-1.23.tar.gz |
471
|
|
|
|
|
|
|
$ opan cpanm Thingy |
472
|
|
|
|
|
|
|
Fetching http://www.cpan.org/authors/id/S/SO/SOMEONE/Thingy-1.25.tar.gz |
473
|
|
|
|
|
|
|
... |
474
|
|
|
|
|
|
|
$ opan pin SOMEONE/Thing-1.25.tar.gz |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
This will probably make more sense if you read the L and L |
477
|
|
|
|
|
|
|
documentation following before trying to set things up. |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
=head2 Commands |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=head3 init |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
opan init |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
Creates a C directory with empty indexes for L and L |
486
|
|
|
|
|
|
|
and a fresh index for L (i.e. runs L for you at the end |
487
|
|
|
|
|
|
|
of initialisation). |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
=head3 fetch |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
opan fetch |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
Fetches 02packages from www.cpan.org into the L PAN. |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
=head3 add |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
opan add Dist-Name-1.23.tar.gz |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
Imports a distribution file into the L PAN under author C. Any |
500
|
|
|
|
|
|
|
path parts provided before the filename will be stripped. |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
Support for other authors is pending somebody explaining why that would have |
503
|
|
|
|
|
|
|
a point. See L for the command you probably wanted instead. |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
=head3 unadd |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
opan unadd Dist-Name-1.23.tar.gz |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
Looks for a C path in the L PAN index |
510
|
|
|
|
|
|
|
and removes the entries. |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
Does not remove the dist file, see L. |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=head3 pin |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
opan pin AUTHOR/Dist-Name-1.23.tar.gz |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
Fetches the file from the L PAN and adds it to L. |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=head3 unpin |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
opan unpin Dist-Name-1.23.tar.gz |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
Looks for a C path in the L PAN index |
525
|
|
|
|
|
|
|
and removes the entries. |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
Does not remove the dist file, see L. |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=head3 merge |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
opan merge |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
Rebuilds the L and L PANs' index files. |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
=head3 pull |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
opan pull |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
Does a L and then a L. There's no equivalent for others, |
540
|
|
|
|
|
|
|
on the assumption what you'll do is roughly L, L, L, |
541
|
|
|
|
|
|
|
L, ... repeat ..., L. |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=head3 purgelist |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
opan purgelist |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
Outputs a list of all non-indexed dists in L and L. |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
=head3 purge |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
opan purge |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
Deletes all files that would have been listed by L. |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
=head3 daemon |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
opan daemon |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
Starts a single process server using L. |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
=head3 prefork |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
opan prefork |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
Starts a multi-process preforking server using |
566
|
|
|
|
|
|
|
L. |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
=head3 get |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
opan get /upstream/modules/02packages.details.txt.gz |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
Runs a request against the opan URL space using L. |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
=head3 cpanm |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
opan cpanm --installdeps . |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
Starts a temporary server process and runs cpanm. |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
cpanm --mirror http://localhost:/combined/ --mirror-only |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
Can also be run with one of: |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
opan cpanm --nopin |
585
|
|
|
|
|
|
|
opan cpanm --autopin |
586
|
|
|
|
|
|
|
opan cpanm --combined |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
to request a specific PAN. |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
=head3 carton |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
opan carton install |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
Starts a temporary server process and runs carton. |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
PERL_CARTON_MIRROR=http://localhost:/combined/ carton |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
Can also be run with one of: |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
opan carton --nopin |
601
|
|
|
|
|
|
|
opan carton --autopin |
602
|
|
|
|
|
|
|
opan carton --combined |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
to request a specific PAN. |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
=head2 PANs |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
=head3 upstream |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
02packages: Fetched from www.cpan.org by the L command. |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
Dist files: Fetched from www.cpan.org on-demand. |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
=head3 pinset |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
02packages: Managed by L and L commands. |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
Dist files: Fetched from www.cpan.org by L command. |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
=head3 custom |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
02packages: Managed by L and L commands. |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
Dist files: Imported from local disk by L command. |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
=head3 combined |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
02packages: Merged from upstream, pinset and custom PANs by L command. |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
Dist files: Fetched from custom, pinset and upstream in that order. |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
=head3 nopin |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
02packages: Merged from upstream and custom PANs by L command. |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
Dist files: Fetched from custom, pinset and upstream in that order. |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
=head3 autopin |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
Virtual PAN with no presence on disk. |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
Identical to nopin, but fetching a dist from upstream does an implict L. |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
Since this can modify your opan config, it's only enabled if the environment |
645
|
|
|
|
|
|
|
variable C is set to a true value (calling the L or |
646
|
|
|
|
|
|
|
L commands with C<--autopin> sets this for you, because you already |
647
|
|
|
|
|
|
|
specified you wanted that). |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=head2 uploads |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
To enable the /upload endpoint, set the ENV var OPAN_AUTH_TOKENS to a colon |
652
|
|
|
|
|
|
|
separated list of accepted tokens for uploads. This will allow a post with a |
653
|
|
|
|
|
|
|
'file' upload argument, checking http basic auth password against the provided |
654
|
|
|
|
|
|
|
auth tokens. |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
=head2 recurring pull |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
Set ENV OPAN_RECURRING_PULL to a true value to make opan automatically pull |
659
|
|
|
|
|
|
|
from upstream every 600 seconds |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
=head2 custom upstream |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
Set the ENV var OPAN_MIRROR to specify a cpan mirror - the default is |
664
|
|
|
|
|
|
|
www.cpan.org. Remember that if you need to temporarily overlay your overlay |
665
|
|
|
|
|
|
|
but only for one user, there's nothing stopping you setting OPAN_MIRROR to |
666
|
|
|
|
|
|
|
another opan. |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
=head1 AUTHOR |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
Matt S. Trout (mst) |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
=head1 CONTRIBUTORS |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
Aaron Crane (arc) |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
Marcus Ramburg (marcus) |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=head1 COPYRIGHT |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
Copyright (c) 2016-2018 the L L and L |
681
|
|
|
|
|
|
|
as listed above. |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
=head1 LICENSE |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
This library is free software and may be distributed under the same terms |
686
|
|
|
|
|
|
|
as perl itself. |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
=cut |