line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ABSTRACT: Coordinates the database, files, and indexes |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package Pinto::Repository; |
4
|
|
|
|
|
|
|
|
5
|
51
|
|
|
51
|
|
327
|
use Moose; |
|
51
|
|
|
|
|
118
|
|
|
51
|
|
|
|
|
391
|
|
6
|
51
|
|
|
51
|
|
316705
|
use MooseX::StrictConstructor; |
|
51
|
|
|
|
|
173110
|
|
|
51
|
|
|
|
|
475
|
|
7
|
51
|
|
|
51
|
|
215921
|
use MooseX::MarkAsMethods ( autoclean => 1 ); |
|
51
|
|
|
|
|
129
|
|
|
51
|
|
|
|
|
414
|
|
8
|
|
|
|
|
|
|
|
9
|
51
|
|
|
51
|
|
222412
|
use Readonly; |
|
51
|
|
|
|
|
123
|
|
|
51
|
|
|
|
|
3048
|
|
10
|
51
|
|
|
51
|
|
295
|
use File::Find; |
|
51
|
|
|
|
|
121
|
|
|
51
|
|
|
|
|
2775
|
|
11
|
51
|
|
|
51
|
|
285
|
use Path::Class; |
|
51
|
|
|
|
|
115
|
|
|
51
|
|
|
|
|
2501
|
|
12
|
51
|
|
|
51
|
|
593
|
use List::Util qw(first); |
|
51
|
|
|
|
|
112
|
|
|
51
|
|
|
|
|
2737
|
|
13
|
|
|
|
|
|
|
|
14
|
51
|
|
|
51
|
|
17617
|
use Pinto::Store; |
|
51
|
|
|
|
|
195
|
|
|
51
|
|
|
|
|
2153
|
|
15
|
51
|
|
|
51
|
|
20626
|
use Pinto::Config; |
|
51
|
|
|
|
|
263
|
|
|
51
|
|
|
|
|
3414
|
|
16
|
51
|
|
|
51
|
|
23673
|
use Pinto::Locker; |
|
51
|
|
|
|
|
217
|
|
|
51
|
|
|
|
|
2333
|
|
17
|
51
|
|
|
51
|
|
21081
|
use Pinto::Database; |
|
51
|
|
|
|
|
273
|
|
|
51
|
|
|
|
|
3434
|
|
18
|
51
|
|
|
51
|
|
23220
|
use Pinto::PackageExtractor; |
|
51
|
|
|
|
|
215
|
|
|
51
|
|
|
|
|
2159
|
|
19
|
51
|
|
|
51
|
|
20464
|
use Pinto::Locator::Multiplex; |
|
51
|
|
|
|
|
213
|
|
|
51
|
|
|
|
|
2160
|
|
20
|
51
|
|
|
51
|
|
20206
|
use Pinto::PrerequisiteWalker; |
|
51
|
|
|
|
|
201
|
|
|
51
|
|
|
|
|
2333
|
|
21
|
51
|
|
|
51
|
|
407
|
use Pinto::Util qw(itis debug mksymlink throw); |
|
51
|
|
|
|
|
111
|
|
|
51
|
|
|
|
|
3887
|
|
22
|
51
|
|
|
51
|
|
311
|
use Pinto::Types qw(Dir); |
|
51
|
|
|
|
|
111
|
|
|
51
|
|
|
|
|
444
|
|
23
|
|
|
|
|
|
|
|
24
|
51
|
|
|
51
|
|
295726
|
use version; |
|
51
|
|
|
|
|
118
|
|
|
51
|
|
|
|
|
431
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
our $VERSION = '0.13'; # VERSION |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
Readonly our $REPOSITORY_VERSION => 1; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
with qw( Pinto::Role::UserAgent ); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
has root => ( |
42
|
|
|
|
|
|
|
is => 'ro', |
43
|
|
|
|
|
|
|
isa => Dir, |
44
|
|
|
|
|
|
|
required => 1, |
45
|
|
|
|
|
|
|
coerce => 1, |
46
|
|
|
|
|
|
|
); |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
has config => ( |
50
|
|
|
|
|
|
|
is => 'ro', |
51
|
|
|
|
|
|
|
isa => 'Pinto::Config', |
52
|
|
|
|
|
|
|
default => sub { Pinto::Config->new( root => $_[0]->root ) }, |
53
|
|
|
|
|
|
|
lazy => 1, |
54
|
|
|
|
|
|
|
); |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
has db => ( |
58
|
|
|
|
|
|
|
is => 'ro', |
59
|
|
|
|
|
|
|
isa => 'Pinto::Database', |
60
|
|
|
|
|
|
|
default => sub { Pinto::Database->new( repo => $_[0] ) }, |
61
|
|
|
|
|
|
|
lazy => 1, |
62
|
|
|
|
|
|
|
); |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
has store => ( |
66
|
|
|
|
|
|
|
is => 'ro', |
67
|
|
|
|
|
|
|
isa => 'Pinto::Store', |
68
|
|
|
|
|
|
|
default => sub { Pinto::Store->new( repo => $_[0] ) }, |
69
|
|
|
|
|
|
|
lazy => 1, |
70
|
|
|
|
|
|
|
); |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
has locator => ( |
74
|
|
|
|
|
|
|
is => 'ro', |
75
|
|
|
|
|
|
|
isa => 'Pinto::Locator', |
76
|
|
|
|
|
|
|
handles => [ qw(locate) ], |
77
|
|
|
|
|
|
|
default => sub { |
78
|
|
|
|
|
|
|
my $self = shift; |
79
|
|
|
|
|
|
|
my $cache_dir = $self->config->cache_dir; |
80
|
|
|
|
|
|
|
my $mux = Pinto::Locator::Multiplex->new(cache_dir => $cache_dir); |
81
|
|
|
|
|
|
|
return $mux->assemble($self->config->sources_list) |
82
|
|
|
|
|
|
|
}, |
83
|
|
|
|
|
|
|
lazy => 1, |
84
|
|
|
|
|
|
|
); |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
has locker => ( |
88
|
|
|
|
|
|
|
is => 'ro', |
89
|
|
|
|
|
|
|
isa => 'Pinto::Locker', |
90
|
|
|
|
|
|
|
handles => [qw(lock unlock)], |
91
|
|
|
|
|
|
|
default => sub { Pinto::Locker->new( repo => $_[0] ) }, |
92
|
|
|
|
|
|
|
lazy => 1, |
93
|
|
|
|
|
|
|
); |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub get_stack { |
99
|
410
|
|
|
410
|
1
|
83341
|
my ( $self, $stack ) = @_; |
100
|
|
|
|
|
|
|
|
101
|
410
|
100
|
|
|
|
2075
|
my $got = $self->get_stack_maybe($stack) |
102
|
|
|
|
|
|
|
or throw "Stack $stack does not exist"; |
103
|
|
|
|
|
|
|
|
104
|
403
|
|
|
|
|
17981
|
return $got; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub get_stack_maybe { |
111
|
579
|
|
|
579
|
1
|
2699
|
my ( $self, $stack ) = @_; |
112
|
|
|
|
|
|
|
|
113
|
579
|
50
|
|
|
|
3515
|
return $stack if itis( $stack, 'Pinto::Schema::Result::Stack' ); |
114
|
579
|
100
|
|
|
|
2834
|
return $self->get_default_stack if not $stack; |
115
|
|
|
|
|
|
|
|
116
|
372
|
|
|
|
|
1445
|
my $where = { name => $stack }; |
117
|
372
|
|
|
|
|
10313
|
return $self->db->schema->find_stack($where); |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
sub get_default_stack { |
124
|
207
|
|
|
207
|
1
|
630
|
my ($self) = @_; |
125
|
|
|
|
|
|
|
|
126
|
207
|
|
|
|
|
892
|
my $where = { is_default => 1 }; |
127
|
207
|
|
|
|
|
5759
|
my @stacks = $self->db->schema->search_stack($where)->all; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# Assert that there is no more than one default stack |
130
|
207
|
50
|
|
|
|
736783
|
throw "PANIC: There must be no more than one default stack" if @stacks > 1; |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# Error if the default stack has been set |
133
|
207
|
100
|
|
|
|
13810
|
throw "The default stack has not been set" if @stacks == 0; |
134
|
|
|
|
|
|
|
|
135
|
202
|
|
|
|
|
2811
|
return $stacks[0]; |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub get_all_stacks { |
142
|
5
|
|
|
5
|
1
|
29
|
my ($self) = @_; |
143
|
|
|
|
|
|
|
|
144
|
5
|
|
|
|
|
140
|
return $self->db->schema->stack_rs->all; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub get_revision { |
151
|
9
|
|
|
9
|
1
|
37
|
my ($self, $revision) = @_; |
152
|
|
|
|
|
|
|
|
153
|
9
|
50
|
|
|
|
63
|
my $rev = $self->get_revision_maybe($revision) |
154
|
|
|
|
|
|
|
or throw "No such revision $revision exists"; |
155
|
|
|
|
|
|
|
|
156
|
9
|
|
|
|
|
233
|
return $rev; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub get_revision_maybe { |
163
|
18
|
|
|
18
|
1
|
65
|
my ( $self, $revision ) = @_; |
164
|
|
|
|
|
|
|
|
165
|
18
|
50
|
|
|
|
119
|
return $revision if itis( $revision, 'Pinto::Schema::Result::Revision' ); |
166
|
|
|
|
|
|
|
|
167
|
18
|
|
|
|
|
138
|
my $where = { uuid => { like => lc "$revision%" } }; |
168
|
18
|
|
|
|
|
438
|
my @revs = $self->db->schema->search_revision($where); |
169
|
|
|
|
|
|
|
|
170
|
18
|
100
|
|
|
|
56460
|
if ( @revs > 1 ) { |
171
|
1
|
|
|
|
|
30
|
my $msg = "Revision ID $revision is ambiguous. Possible matches are:\n"; |
172
|
1
|
|
|
|
|
20
|
$msg .= $_->to_string("%i: %{48}T\n") for @revs; |
173
|
1
|
|
|
|
|
26
|
throw $msg; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
17
|
100
|
|
|
|
483
|
return @revs ? $revs[0] : (); |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub get_package { |
183
|
82
|
|
|
82
|
1
|
402
|
my ( $self, %args ) = @_; |
184
|
|
|
|
|
|
|
|
185
|
82
|
|
|
|
|
240
|
my $target = $args{target}; |
186
|
82
|
|
|
|
|
229
|
my $pkg_name = $args{name}; |
187
|
82
|
|
|
|
|
205
|
my $dist_path = $args{path}; |
188
|
82
|
|
|
|
|
2061
|
my $schema = $self->db->schema; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# Retrieve latest version of package that satisfies the target |
191
|
82
|
50
|
0
|
|
|
347
|
if ($target) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
192
|
82
|
|
|
|
|
1989
|
my $where = {name => $target->name}; |
193
|
82
|
100
|
|
|
|
1820
|
return unless my @pkgs = $schema->search_package( $where )->with_distribution; |
194
|
17
|
100
|
|
17
|
|
190567
|
return unless my $latest = first { $target->is_satisfied_by($_->version) } reverse sort { $a <=> $b } @pkgs; |
|
17
|
|
|
|
|
1002
|
|
|
3
|
|
|
|
|
481
|
|
195
|
15
|
|
|
|
|
1394
|
return $latest; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# Retrieve package from a specific distribution |
199
|
|
|
|
|
|
|
elsif ( $pkg_name && $dist_path ) { |
200
|
0
|
|
|
|
|
0
|
my ( $author, $archive ) = Pinto::Util::parse_dist_path($dist_path); |
201
|
0
|
|
|
|
|
0
|
my $where = {'me.name' => $pkg_name, 'distribution.author' => $author, 'distribution.archive' => $archive}; |
202
|
0
|
0
|
|
|
|
0
|
return unless my @pkgs = $schema->search_package($where)->with_distribution; |
203
|
0
|
|
|
|
|
0
|
return $pkgs[0]; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
# Retrieve latest version of package in the entire repository |
207
|
|
|
|
|
|
|
elsif ($pkg_name) { |
208
|
0
|
|
|
|
|
0
|
my $where = { name => $pkg_name }; |
209
|
0
|
0
|
|
|
|
0
|
return unless my @pkgs = $schema->search_package($where)->with_distribution; |
210
|
0
|
|
|
|
|
0
|
return (reverse sort { $a <=> $b } @pkgs)[0]; |
|
0
|
|
|
|
|
0
|
|
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
0
|
|
|
|
|
0
|
throw 'Invalid arguments'; |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub get_distribution { |
220
|
309
|
|
|
309
|
1
|
6494
|
my ( $self, %args ) = @_; |
221
|
|
|
|
|
|
|
|
222
|
309
|
|
|
|
|
9333
|
my $rs = $self->db->schema->distribution_rs->with_packages; |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# Retrieve a distribution by target |
225
|
309
|
100
|
|
|
|
100410
|
if ( my $target = $args{target} ) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
226
|
88
|
100
|
|
|
|
611
|
if ( itis( $target, 'Pinto::Target::Distribution' ) ) { |
|
|
50
|
|
|
|
|
|
227
|
6
|
|
|
|
|
164
|
return $rs->find_by_author_archive( $target->author, $target->archive ); |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
elsif ( itis( $target, 'Pinto::Target::Package' ) ) { |
230
|
82
|
100
|
|
|
|
465
|
return unless my $pkg = $self->get_package( target => $target ); |
231
|
15
|
|
|
|
|
1536
|
return $pkg->distribution; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
0
|
|
|
|
|
0
|
throw 'Invalid arguments'; |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# Retrieve a distribution by its path (e.g. AUTHOR/Dist-1.0.tar.gz) |
238
|
|
|
|
|
|
|
elsif ( my $path = $args{path} ) { |
239
|
53
|
|
|
|
|
2111
|
my ( $author, $archive ) = Pinto::Util::parse_dist_path($path); |
240
|
53
|
|
|
|
|
344
|
return $rs->find_by_author_archive( $author, $archive ); |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# Retrieve a distribution by author and archive |
244
|
|
|
|
|
|
|
elsif ( my $author = $args{author} ) { |
245
|
168
|
50
|
|
|
|
4670
|
my $archive = $args{archive} or throw "Must specify archive with author"; |
246
|
168
|
|
|
|
|
923
|
return $rs->find_by_author_archive( $author, $archive ); |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
0
|
|
|
|
|
0
|
throw 'Invalid arguments'; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub ups_distribution { |
256
|
65
|
|
|
65
|
1
|
406
|
my ( $self, %args ) = @_; |
257
|
|
|
|
|
|
|
|
258
|
65
|
100
|
|
|
|
706
|
return unless my $found = $self->locate( %args ); |
259
|
50
|
|
|
|
|
367
|
return $self->fetch_distribution( uri => $found->{uri} ); |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
sub add_distribution { |
266
|
163
|
|
|
163
|
0
|
889
|
my ( $self, %args ) = @_; |
267
|
|
|
|
|
|
|
|
268
|
163
|
|
|
|
|
683
|
my $archive = $args{archive}; |
269
|
163
|
|
|
|
|
607
|
my $author = uc $args{author}; |
270
|
163
|
|
100
|
|
|
1032
|
my $source = $args{source} || 'LOCAL'; |
271
|
|
|
|
|
|
|
|
272
|
163
|
|
|
|
|
1559
|
$self->assert_archive_not_duplicate( $author, $archive ); |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# Assemble the basic structure... |
275
|
161
|
|
|
|
|
1206
|
my $dist_struct = { |
276
|
|
|
|
|
|
|
author => $author, |
277
|
|
|
|
|
|
|
source => $source, |
278
|
|
|
|
|
|
|
archive => $archive->basename, |
279
|
|
|
|
|
|
|
mtime => Pinto::Util::mtime($archive), |
280
|
|
|
|
|
|
|
md5 => Pinto::Util::md5($archive), |
281
|
|
|
|
|
|
|
sha256 => Pinto::Util::sha256($archive) |
282
|
|
|
|
|
|
|
}; |
283
|
|
|
|
|
|
|
|
284
|
161
|
|
|
|
|
7757
|
my $extractor = Pinto::PackageExtractor->new( archive => $archive ); |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# Add provided packages... |
287
|
161
|
|
|
|
|
1138
|
my @provides = $extractor->provides; |
288
|
161
|
|
|
|
|
1154
|
$dist_struct->{packages} = \@provides; |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Add required packages... |
291
|
161
|
|
|
|
|
1519
|
my @requires = $extractor->requires; |
292
|
161
|
|
|
|
|
1407
|
$dist_struct->{prerequisites} = \@requires; |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
# Add metadata... |
295
|
161
|
|
|
|
|
1129
|
my $metadata = $extractor->metadata; |
296
|
161
|
|
|
|
|
842
|
$dist_struct->{metadata} = $metadata; |
297
|
|
|
|
|
|
|
|
298
|
161
|
|
|
|
|
654
|
my $p = scalar @provides; |
299
|
161
|
|
|
|
|
528
|
my $r = scalar @requires; |
300
|
161
|
|
|
|
|
1197
|
debug "Distribution $archive provides $p and requires $r packages"; |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# Update database *before* moving the archive into the |
303
|
|
|
|
|
|
|
# repository, so if there is an error in the DB, we can stop and |
304
|
|
|
|
|
|
|
# the repository will still be clean. |
305
|
|
|
|
|
|
|
|
306
|
161
|
|
|
|
|
6398
|
my $dist = $self->db->schema->create_distribution($dist_struct); |
307
|
161
|
|
|
|
|
1847111
|
$self->store->add_archive( $archive => $dist->native_path ); |
308
|
|
|
|
|
|
|
|
309
|
161
|
|
|
|
|
10147
|
return $dist; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
sub fetch_distribution { |
316
|
50
|
|
|
50
|
1
|
218
|
my ( $self, %args ) = @_; |
317
|
|
|
|
|
|
|
|
318
|
50
|
|
|
|
|
139
|
my $uri = $args{uri}; |
319
|
50
|
|
|
|
|
318
|
my $path = $uri->path; |
320
|
|
|
|
|
|
|
|
321
|
50
|
|
|
|
|
948
|
my $existing = $self->get_distribution( path => $path ); |
322
|
50
|
50
|
|
|
|
520977
|
throw "Distribution $existing already exists" if $existing; |
323
|
|
|
|
|
|
|
|
324
|
50
|
|
|
|
|
327
|
my ( $author, undef ) = Pinto::Util::parse_dist_path($path); |
325
|
50
|
|
|
|
|
476
|
my $archive = $self->mirror_temporary( $uri ); |
326
|
|
|
|
|
|
|
|
327
|
50
|
|
|
|
|
1454
|
my $dist = $self->add_distribution( |
328
|
|
|
|
|
|
|
archive => $archive, |
329
|
|
|
|
|
|
|
author => $author, |
330
|
|
|
|
|
|
|
source => $uri, |
331
|
|
|
|
|
|
|
); |
332
|
50
|
|
|
|
|
65282
|
return $dist; |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
sub delete_distribution { |
338
|
2
|
|
|
2
|
0
|
15
|
my ( $self, %args ) = @_; |
339
|
|
|
|
|
|
|
|
340
|
2
|
|
|
|
|
6
|
my $dist = $args{dist}; |
341
|
2
|
|
|
|
|
7
|
my $force = $args{force}; |
342
|
|
|
|
|
|
|
|
343
|
2
|
|
|
|
|
54
|
for my $reg ( $dist->registrations ) { |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
# TODO: say which stack it is pinned to |
346
|
7
|
100
|
100
|
|
|
10626
|
throw "$dist is pinned to a stack and cannot be deleted" |
347
|
|
|
|
|
|
|
if $reg->is_pinned and not $force; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
1
|
|
|
|
|
31
|
$dist->delete; |
351
|
1
|
|
|
|
|
3699
|
my $basedir = $self->config->authors_id_dir; |
352
|
1
|
|
|
|
|
25
|
$self->store->remove_archive( $dist->native_path($basedir) ); |
353
|
|
|
|
|
|
|
|
354
|
1
|
|
|
|
|
24
|
return $self; |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
sub package_count { |
360
|
5
|
|
|
5
|
0
|
23
|
my ($self) = @_; |
361
|
|
|
|
|
|
|
|
362
|
5
|
|
|
|
|
155
|
return $self->db->schema->package_rs->count; |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
sub distribution_count { |
368
|
5
|
|
|
5
|
0
|
21
|
my ($self) = @_; |
369
|
|
|
|
|
|
|
|
370
|
5
|
|
|
|
|
126
|
return $self->db->schema->distribution_rs->count; |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
sub stack_count { |
376
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
377
|
|
|
|
|
|
|
|
378
|
0
|
|
|
|
|
0
|
return $self->db->schema->stack_rs->count; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub revision_count { |
384
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
385
|
|
|
|
|
|
|
|
386
|
0
|
|
|
|
|
0
|
return $self->db->schema->revision_rs->count; |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
sub txn_begin { |
392
|
341
|
|
|
341
|
0
|
1010
|
my ($self) = @_; |
393
|
|
|
|
|
|
|
|
394
|
341
|
|
|
|
|
1532
|
debug 'Beginning db transaction'; |
395
|
341
|
|
|
|
|
8923
|
$self->db->schema->txn_begin; |
396
|
|
|
|
|
|
|
|
397
|
341
|
|
|
|
|
179277
|
return $self; |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
sub txn_rollback { |
403
|
44
|
|
|
44
|
0
|
162
|
my ($self) = @_; |
404
|
|
|
|
|
|
|
|
405
|
44
|
|
|
|
|
321
|
debug 'Rolling back db transaction'; |
406
|
44
|
|
|
|
|
1347
|
$self->db->schema->txn_rollback; |
407
|
|
|
|
|
|
|
|
408
|
44
|
|
|
|
|
20361
|
return $self; |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
sub txn_commit { |
414
|
297
|
|
|
297
|
0
|
1012
|
my ($self) = @_; |
415
|
|
|
|
|
|
|
|
416
|
297
|
|
|
|
|
1652
|
debug 'Committing db transaction'; |
417
|
297
|
|
|
|
|
7542
|
$self->db->schema->txn_commit; |
418
|
|
|
|
|
|
|
|
419
|
297
|
|
|
|
|
3666834
|
return $self; |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
sub svp_begin { |
425
|
162
|
|
|
162
|
0
|
613
|
my ( $self, $name ) = @_; |
426
|
|
|
|
|
|
|
|
427
|
162
|
|
|
|
|
1049
|
debug 'Beginning db savepoint'; |
428
|
162
|
|
|
|
|
4367
|
$self->db->schema->svp_begin($name); |
429
|
|
|
|
|
|
|
|
430
|
162
|
|
|
|
|
59565
|
return $self; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub svp_rollback { |
436
|
2
|
|
|
2
|
0
|
11
|
my ( $self, $name ) = @_; |
437
|
|
|
|
|
|
|
|
438
|
2
|
|
|
|
|
16
|
debug 'Rolling back db savepoint'; |
439
|
2
|
|
|
|
|
69
|
$self->db->schema->svp_rollback($name); |
440
|
|
|
|
|
|
|
|
441
|
2
|
|
|
|
|
2554
|
return $self; |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
sub svp_release { |
447
|
147
|
|
|
147
|
0
|
564
|
my ( $self, $name ) = @_; |
448
|
|
|
|
|
|
|
|
449
|
147
|
|
|
|
|
1585
|
debug 'Releasing db savepoint'; |
450
|
147
|
|
|
|
|
3882
|
$self->db->schema->svp_release($name); |
451
|
|
|
|
|
|
|
|
452
|
147
|
|
|
|
|
57158
|
return $self; |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
sub create_stack { |
459
|
129
|
|
|
129
|
0
|
639
|
my ( $self, %args ) = @_; |
460
|
|
|
|
|
|
|
|
461
|
129
|
|
|
|
|
436
|
my $stk_name = $args{name}; |
462
|
|
|
|
|
|
|
|
463
|
129
|
50
|
|
|
|
641
|
throw "Stack $stk_name already exists" |
464
|
|
|
|
|
|
|
if $self->get_stack_maybe( $stk_name ); |
465
|
|
|
|
|
|
|
|
466
|
129
|
|
|
|
|
914147
|
my $root = $self->db->get_root_revision; |
467
|
129
|
|
|
|
|
6832
|
my $stack = $self->db->schema->create_stack( { %args, head => $root } ); |
468
|
|
|
|
|
|
|
|
469
|
129
|
|
|
|
|
404882
|
$stack->make_filesystem; |
470
|
129
|
|
|
|
|
769
|
$stack->write_index; |
471
|
|
|
|
|
|
|
|
472
|
129
|
|
|
|
|
1181
|
return $stack; |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
sub copy_stack { |
478
|
10
|
|
|
10
|
0
|
63
|
my ( $self, %args ) = @_; |
479
|
|
|
|
|
|
|
|
480
|
10
|
|
|
|
|
39
|
my $copy_name = $args{name}; |
481
|
10
|
|
|
|
|
27
|
my $stack = delete $args{stack}; |
482
|
10
|
|
|
|
|
198
|
my $orig_name = $stack->name; |
483
|
|
|
|
|
|
|
|
484
|
10
|
100
|
|
|
|
170
|
if ( my $existing = $self->get_stack_maybe( $copy_name ) ) { |
485
|
2
|
|
|
|
|
119
|
throw "Stack $existing already exists"; |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
|
488
|
8
|
|
|
|
|
36059
|
my $dupe = $stack->duplicate(%args); |
489
|
|
|
|
|
|
|
|
490
|
8
|
|
|
|
|
22698
|
$dupe->make_filesystem; |
491
|
8
|
|
|
|
|
49
|
$dupe->write_index; |
492
|
|
|
|
|
|
|
|
493
|
8
|
|
|
|
|
62
|
return $dupe; |
494
|
|
|
|
|
|
|
} |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
sub rename_stack { |
499
|
4
|
|
|
4
|
0
|
23
|
my ( $self, %args ) = @_; |
500
|
|
|
|
|
|
|
|
501
|
4
|
|
|
|
|
12
|
my $new_name = $args{to}; |
502
|
4
|
|
|
|
|
10
|
my $stack = delete $args{stack}; |
503
|
4
|
|
|
|
|
72
|
my $old_name = $stack->name; |
504
|
|
|
|
|
|
|
|
505
|
4
|
100
|
|
|
|
61
|
if (my $existing_stack = $self->get_stack_maybe( $new_name )) { |
506
|
3
|
|
|
|
|
196
|
my $is_different_stack = lc $new_name ne lc $existing_stack->name; |
507
|
3
|
100
|
66
|
|
|
85
|
throw "Stack $new_name already exists" if $is_different_stack || $new_name eq $old_name; |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
3
|
|
|
|
|
4451
|
$stack->rename_filesystem( to => $new_name ); |
511
|
2
|
|
|
|
|
13
|
$stack->rename( to => $new_name ); |
512
|
|
|
|
|
|
|
|
513
|
2
|
|
|
|
|
13
|
return $stack; |
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
sub kill_stack { |
519
|
4
|
|
|
4
|
0
|
19
|
my ( $self, %args ) = @_; |
520
|
|
|
|
|
|
|
|
521
|
4
|
|
|
|
|
11
|
my $stack = $args{stack}; |
522
|
|
|
|
|
|
|
|
523
|
4
|
|
|
|
|
21
|
$stack->kill; |
524
|
2
|
|
|
|
|
12
|
$stack->kill_filesystem; |
525
|
|
|
|
|
|
|
|
526
|
2
|
|
|
|
|
7
|
return $stack; |
527
|
|
|
|
|
|
|
} |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
sub link_modules_dir { |
532
|
116
|
|
|
116
|
0
|
603
|
my ( $self, %args ) = @_; |
533
|
|
|
|
|
|
|
|
534
|
116
|
|
|
|
|
348
|
my $target_dir = $args{to}; |
535
|
116
|
|
|
|
|
2928
|
my $modules_dir = $self->config->modules_dir; |
536
|
116
|
|
|
|
|
2673
|
my $root_dir = $self->config->root_dir; |
537
|
|
|
|
|
|
|
|
538
|
116
|
100
|
100
|
|
|
849
|
if ( -e $modules_dir or -l $modules_dir ) { |
539
|
5
|
|
|
|
|
401
|
debug "Unlinking $modules_dir"; |
540
|
5
|
50
|
|
|
|
23
|
unlink $modules_dir or throw $!; |
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
|
543
|
116
|
|
|
|
|
11254
|
debug "Linking $modules_dir to $target_dir"; |
544
|
116
|
|
|
|
|
674
|
mksymlink( $modules_dir => $target_dir->relative($root_dir) ); |
545
|
|
|
|
|
|
|
|
546
|
116
|
|
|
|
|
717
|
return $self; |
547
|
|
|
|
|
|
|
} |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
sub unlink_modules_dir { |
552
|
2
|
|
|
2
|
0
|
6
|
my ($self) = @_; |
553
|
|
|
|
|
|
|
|
554
|
2
|
|
|
|
|
46
|
my $modules_dir = $self->config->modules_dir; |
555
|
|
|
|
|
|
|
|
556
|
2
|
50
|
33
|
|
|
14
|
if ( -e $modules_dir or -l $modules_dir ) { |
557
|
2
|
|
|
|
|
96
|
debug "Unlinking $modules_dir"; |
558
|
2
|
50
|
|
|
|
9
|
unlink $modules_dir or throw $!; |
559
|
|
|
|
|
|
|
} |
560
|
|
|
|
|
|
|
|
561
|
2
|
|
|
|
|
108
|
return $self; |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
sub clean_files { |
568
|
25
|
|
|
25
|
1
|
118
|
my ( $self, %args ) = @_; |
569
|
|
|
|
|
|
|
|
570
|
25
|
|
|
|
|
78
|
my $deleted = 0; |
571
|
25
|
|
|
|
|
638
|
my $dists_rs = $self->db->schema->distribution_rs->search( undef, { prefetch => {} } ); |
572
|
25
|
|
|
|
|
20251
|
my %known_dists = map { ( $_->to_string => 1 ) } $dists_rs->all; |
|
16
|
|
|
|
|
28449
|
|
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
my $callback = sub { |
575
|
203
|
100
|
|
203
|
|
12787
|
return if not -f $_; |
576
|
|
|
|
|
|
|
|
577
|
77
|
|
|
|
|
405
|
my $path = Path::Class::file($_); |
578
|
77
|
|
|
|
|
8526
|
my $author = $path->parent->basename; |
579
|
77
|
|
|
|
|
828
|
my $archive = $path->basename; |
580
|
|
|
|
|
|
|
|
581
|
77
|
100
|
|
|
|
562
|
return if $archive eq 'CHECKSUMS'; |
582
|
58
|
100
|
|
|
|
611
|
return if $archive eq '01mailrc.txt.gz'; |
583
|
33
|
100
|
|
|
|
359
|
return if exists $known_dists{"$author/$archive"}; |
584
|
|
|
|
|
|
|
|
585
|
17
|
|
|
|
|
588
|
debug "Removing orphaned archive at $path"; |
586
|
17
|
|
|
|
|
673
|
$self->store->remove_archive($path); |
587
|
17
|
|
|
|
|
420
|
$deleted++; |
588
|
25
|
|
|
|
|
36729
|
}; |
589
|
|
|
|
|
|
|
|
590
|
25
|
|
|
|
|
3136
|
my $authors_dir = $self->config->authors_dir; |
591
|
25
|
|
|
|
|
291
|
debug "Cleaning orphaned archives beneath $authors_dir"; |
592
|
25
|
|
|
|
|
1767
|
File::Find::find( { no_chdir => 1, wanted => $callback }, $authors_dir ); |
593
|
|
|
|
|
|
|
|
594
|
25
|
|
|
|
|
404
|
return $deleted; |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
sub optimize_database { |
600
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
601
|
|
|
|
|
|
|
|
602
|
0
|
|
|
|
|
0
|
debug 'Removing empty database pages'; |
603
|
0
|
|
|
|
|
0
|
$self->db->schema->storage->dbh->do('VACUUM;'); |
604
|
|
|
|
|
|
|
|
605
|
0
|
|
|
|
|
0
|
debug 'Updating database statistics'; |
606
|
0
|
|
|
|
|
0
|
$self->db->schema->storage->dbh->do('ANALYZE;'); |
607
|
|
|
|
|
|
|
|
608
|
0
|
|
|
|
|
0
|
return $self; |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
sub get_version { |
615
|
381
|
|
|
381
|
0
|
1093
|
my ($self) = @_; |
616
|
|
|
|
|
|
|
|
617
|
381
|
|
|
|
|
9989
|
my $version_file = $self->config->version_file; |
618
|
|
|
|
|
|
|
|
619
|
381
|
50
|
|
|
|
1790
|
return undef if not -e $version_file; # Old repos have no version file |
620
|
|
|
|
|
|
|
|
621
|
381
|
|
|
|
|
19780
|
my $version = $version_file->slurp( chomp => 1 ); |
622
|
|
|
|
|
|
|
|
623
|
381
|
|
|
|
|
106150
|
return $version; |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
sub set_version { |
629
|
113
|
|
|
113
|
0
|
359
|
my ( $self, $version ) = @_; |
630
|
|
|
|
|
|
|
|
631
|
113
|
|
33
|
|
|
1508
|
$version ||= $REPOSITORY_VERSION; |
632
|
|
|
|
|
|
|
|
633
|
113
|
|
|
|
|
3903
|
my $version_fh = $self->config->version_file->openw; |
634
|
113
|
|
|
|
|
23572
|
print {$version_fh} $version, "\n"; |
|
113
|
|
|
|
|
1103
|
|
635
|
113
|
|
|
|
|
3302
|
close $version_fh; |
636
|
|
|
|
|
|
|
|
637
|
113
|
|
|
|
|
719
|
return $self; |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
sub assert_archive_not_duplicate { |
643
|
163
|
|
|
163
|
0
|
541
|
my ( $self, $author, $archive ) = @_; |
644
|
|
|
|
|
|
|
|
645
|
163
|
50
|
|
|
|
1817
|
throw "Archive $archive does not exist" if not -e $archive; |
646
|
163
|
50
|
|
|
|
11399
|
throw "Archive $archive is not readable" if not -r $archive; |
647
|
|
|
|
|
|
|
|
648
|
163
|
|
|
|
|
6378
|
my $basename = $archive->basename; |
649
|
163
|
100
|
|
|
|
1355
|
if ( my $same_path = $self->get_distribution( author => $author, archive => $basename ) ) { |
650
|
2
|
|
|
|
|
115
|
throw "A distribution already exists as $same_path"; |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
|
653
|
161
|
|
|
|
|
1623545
|
my $sha256 = Pinto::Util::sha256($archive); |
654
|
161
|
|
|
|
|
6476
|
my $dupe = $self->db->schema->search_distribution( { sha256 => $sha256 } )->first; |
655
|
161
|
50
|
|
|
|
435287
|
throw "Archive $archive is identical to $dupe" if $dupe; |
656
|
|
|
|
|
|
|
|
657
|
161
|
|
|
|
|
19267
|
return $self; |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
sub assert_version_ok { |
663
|
380
|
|
|
380
|
0
|
1496
|
my ($self) = @_; |
664
|
|
|
|
|
|
|
|
665
|
380
|
|
|
|
|
2184
|
my $repo_version = $self->get_version; |
666
|
380
|
|
|
|
|
4591
|
my $code_version = $REPOSITORY_VERSION; |
667
|
|
|
|
|
|
|
|
668
|
51
|
|
|
51
|
|
143746
|
no warnings qw(uninitialized); |
|
51
|
|
|
|
|
120
|
|
|
51
|
|
|
|
|
13049
|
|
669
|
380
|
50
|
|
|
|
5081
|
if ( $repo_version != $code_version ) { |
670
|
0
|
|
|
|
|
0
|
my $msg = "Repository version ($repo_version) and Pinto version ($code_version) do not match.\n"; |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
# For really old repositories, the version is undefined and there is no automated |
673
|
|
|
|
|
|
|
# migration process. If the version is defined, then automatic migration should work. |
674
|
|
|
|
|
|
|
|
675
|
0
|
0
|
|
|
|
0
|
$msg .= |
676
|
|
|
|
|
|
|
defined $repo_version |
677
|
|
|
|
|
|
|
? "Use the 'migrate' command to bring the repo up to date" |
678
|
|
|
|
|
|
|
: "Contact thaljef\@cpan.org for migration instructions"; |
679
|
0
|
|
|
|
|
0
|
throw $msg; |
680
|
|
|
|
|
|
|
} |
681
|
|
|
|
|
|
|
|
682
|
380
|
|
|
|
|
1383
|
return $self; |
683
|
|
|
|
|
|
|
} |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
sub assert_sanity_ok { |
688
|
393
|
|
|
393
|
0
|
1451
|
my ($self) = @_; |
689
|
|
|
|
|
|
|
|
690
|
393
|
|
|
|
|
11265
|
my $root_dir = $self->config->root_dir; |
691
|
|
|
|
|
|
|
|
692
|
393
|
50
|
|
|
|
3725
|
throw "Directory $root_dir does not exist" |
693
|
|
|
|
|
|
|
unless -e $root_dir; |
694
|
|
|
|
|
|
|
|
695
|
393
|
50
|
|
|
|
23710
|
throw "$root_dir is not a directory" |
696
|
|
|
|
|
|
|
unless -d $root_dir; |
697
|
|
|
|
|
|
|
|
698
|
393
|
50
|
|
|
|
11310
|
throw "Directory $root_dir is not readable by you" |
699
|
|
|
|
|
|
|
unless -r $root_dir; |
700
|
|
|
|
|
|
|
|
701
|
393
|
50
|
|
|
|
10269
|
throw "Directory $root_dir is not writable by you" |
702
|
|
|
|
|
|
|
unless -w $root_dir; |
703
|
|
|
|
|
|
|
|
704
|
393
|
50
|
33
|
|
|
20069
|
throw "Directory $root_dir does not look like a Pinto repository" |
705
|
|
|
|
|
|
|
unless -e $self->config->db_file && -e $self->config->authors_dir; |
706
|
|
|
|
|
|
|
|
707
|
393
|
|
|
|
|
14556
|
return $self; |
708
|
|
|
|
|
|
|
} |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
sub clear_cache { |
713
|
2
|
|
|
2
|
0
|
13
|
my ($self) = @_; |
714
|
|
|
|
|
|
|
|
715
|
2
|
|
|
|
|
138
|
$self->locator->refresh; # Clears cache file from disk |
716
|
|
|
|
|
|
|
|
717
|
2
|
|
|
|
|
8
|
return $self; |
718
|
|
|
|
|
|
|
} |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
1; |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
__END__ |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
=pod |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
=encoding UTF-8 |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
=for :stopwords Jeffrey Ryan Thalhammer |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
=head1 NAME |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
Pinto::Repository - Coordinates the database, files, and indexes |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
=head1 VERSION |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
version 0.13 |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
=head2 root |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
=head2 config |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
=head2 db |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
=head2 store |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
=head2 locator |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
=head2 locker |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
=head1 METHODS |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
=head2 locate( target => ); |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
=head2 lock( $LOCK_TYPE ) |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
=head2 unlock |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
=head2 get_stack() |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
=head2 get_stack( $stack_name ) |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
=head2 get_stack( $stack_object ) |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
Returns the L<Pinto::Schema::Result::Stack> object with the given |
773
|
|
|
|
|
|
|
C<$stack_name>. If the argument is a L<Pinto::Schema::Result::Stack>, then it |
774
|
|
|
|
|
|
|
just returns that. If there is no stack with such a name in the repository, |
775
|
|
|
|
|
|
|
throws an exception. If you do not specify a stack name (or it is undefined) |
776
|
|
|
|
|
|
|
then you'll get whatever stack is currently marked as the default stack. |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
The stack object will not be open for revision, so you will not be able to |
779
|
|
|
|
|
|
|
change any of the registrations for that stack. To get a stack that you can |
780
|
|
|
|
|
|
|
modify, use C<open_stack>. |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
=head2 get_stack_maybe() |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
=head2 get_stack_maybe( $stack_name ) |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
=head2 get_stack_maybe( $stack_object ) |
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
Same as C<get_stack> but simply returns undef if the stack does not exist |
789
|
|
|
|
|
|
|
rather than throwing an exception. |
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
=head2 get_default_stack() |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
Returns the L<Pinto::Schema::Result::Stack> that is currently marked |
794
|
|
|
|
|
|
|
as the default stack in this repository. This is what you get when you |
795
|
|
|
|
|
|
|
call C<get_stack> without any arguments. |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
The stack object will not be open for revision, so you will not be |
798
|
|
|
|
|
|
|
able to change any of the registrations for that stack. To get a |
799
|
|
|
|
|
|
|
stack that you can modify, use C<open_stack>. |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
At any time, there must be exactly one default stack. This method will |
802
|
|
|
|
|
|
|
throw an exception if it discovers that condition is not true. |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
=head2 get_all_stacks() |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
Returns a list of all the L<Pinto::Schema::Result::Stack> objects in the |
807
|
|
|
|
|
|
|
repository. You can sort them as strings (by name) or numerically (by |
808
|
|
|
|
|
|
|
last modification time). |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
=head2 get_revision($commit) |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
=head2 get_revision_maybe($commit) |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
=head2 get_package( target => $pkg_spec ) |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
Returns a L<Pinto:Schema::Result::Package> representing the latest version of |
817
|
|
|
|
|
|
|
the package in the repository with the same name as the package target B<and |
818
|
|
|
|
|
|
|
the same or higher version> as the package spec. See |
819
|
|
|
|
|
|
|
L<Pinto::Target::Package> for the definition of a package target. |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
=head2 get_package( name => $pkg_name ) |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
Returns a L<Pinto:Schema::Result::Package> representing the latest version of |
824
|
|
|
|
|
|
|
the package in the repository with the given C<$pkg_name>. If there is no |
825
|
|
|
|
|
|
|
such package with that name in the repository, returns nothing. |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
=head2 get_package( name => $pkg_name, path => $dist_path ) |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
Returns the L<Pinto:Schema::Result::Package> with the given C<$pkg_name> that |
830
|
|
|
|
|
|
|
belongs to the distribution identified by C<$dist_path>. If there is no such |
831
|
|
|
|
|
|
|
package in the repository, returns nothing. |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
TODO: Consider making this a "maybe" function and the wrapping it with a |
834
|
|
|
|
|
|
|
version that throws exceptions if no match is found. See C<get_stack_maybe()> |
835
|
|
|
|
|
|
|
for an example. |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
=head2 get_distribution( target => $target ) |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
Given a L<Pinto::Target::Package>, returns the |
840
|
|
|
|
|
|
|
L<Pinto::Schema::Result::Distribution> that contains the B<latest version of |
841
|
|
|
|
|
|
|
the package> in this repository with the same name as the target B<and the |
842
|
|
|
|
|
|
|
same or higher version as the target>. Returns nothing if no such |
843
|
|
|
|
|
|
|
distribution is found. |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
Given a L<Pinto::Target::Distribution>, returns the |
846
|
|
|
|
|
|
|
L<Pinto::Schema::Result::Distribution> from this repository with the same |
847
|
|
|
|
|
|
|
author id and archive attributes as the target. Returns nothing if no such |
848
|
|
|
|
|
|
|
distribution is found. |
849
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
=head2 get_distribution( path => $dist_path ) |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
Given a distribution path, (for example C<AUTHOR/Dist-1.0.tar.gz> or |
853
|
|
|
|
|
|
|
C<A/AU/AUTHOR/Dist-1.0.tar.gz> returns the |
854
|
|
|
|
|
|
|
L<Pinto::Schema::Result::Distribution> from this repository that is |
855
|
|
|
|
|
|
|
identified by the author ID and archive file name in the path. Returns |
856
|
|
|
|
|
|
|
nothing if no such distribution is found. |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
=head2 get_distribution( author => $author, archive => $archive ) |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
Given an author id and a distribution archive file basename, returns the |
861
|
|
|
|
|
|
|
L<Pinto::Schema::Result::Distribution> from this repository with those |
862
|
|
|
|
|
|
|
attributes. Returns nothing if no such distribution exists. |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
TODO: Consider making this a "maybe" function and the wrapping it with a |
865
|
|
|
|
|
|
|
version that throws exceptions if no match is found. See C<get_stack_maybe()> |
866
|
|
|
|
|
|
|
for an example. |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
=head2 ups_distribution( target => target ) |
869
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
Given a L<Pinto::Target::Package>, locates the distribution that contains the |
871
|
|
|
|
|
|
|
latest version of the package across all upstream repositories with the same |
872
|
|
|
|
|
|
|
name as the target, and the same or higher version as the target. If such |
873
|
|
|
|
|
|
|
distribution is found, it is fetched and added to this repository. If it is |
874
|
|
|
|
|
|
|
not found, then an exception is thrown. |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
Given a L<Pinto::Target::Distribution>, locates the first distribution in any |
877
|
|
|
|
|
|
|
upstream repository with the same author and archive as the target. If such |
878
|
|
|
|
|
|
|
distribution is found, it is fetched and added to this repository. If it is |
879
|
|
|
|
|
|
|
not found, then an exception is thrown. |
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
TODO: Consider making this a "maybe" function and the wrapping it with a |
882
|
|
|
|
|
|
|
version that throws exceptions if no match is found. See C<get_stack_maybe()> |
883
|
|
|
|
|
|
|
for an example. |
884
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
=head2 add( archive => $path, author => $id ) |
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
=head2 add( archive => $path, author => $id, source => $uri ) |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
Adds the distribution archive located on the local filesystem at |
890
|
|
|
|
|
|
|
C<$path> to the repository in the author directory for the author with |
891
|
|
|
|
|
|
|
C<$id>. The packages provided by the distribution will be indexed, |
892
|
|
|
|
|
|
|
and the prerequisites will be recorded. If the C<source> is |
893
|
|
|
|
|
|
|
specified, it must be the URI to the root of the repository where the |
894
|
|
|
|
|
|
|
distribution came from. Otherwise, the C<source> defaults to |
895
|
|
|
|
|
|
|
C<LOCAL>. Returns a L<Pinto::Schema::Result::Distribution> object |
896
|
|
|
|
|
|
|
representing the newly added distribution. |
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
=head2 fetch_distribution( uri => $uri ) |
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
Fetches a distribution archive from a remote URI and adds it to this |
901
|
|
|
|
|
|
|
repository. The packages provided by the distribution will be indexed, and |
902
|
|
|
|
|
|
|
the prerequisites will be recorded. Returns a |
903
|
|
|
|
|
|
|
L<Pinto::Schema::Result::Distribution> object representing the fetched |
904
|
|
|
|
|
|
|
distribution. |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
=head2 clean_files() |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
Deletes all distribution archives that are on the filesystem but not |
909
|
|
|
|
|
|
|
in the database. This can happen when an Action fails or is aborted |
910
|
|
|
|
|
|
|
prematurely. |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
=head1 AUTHOR |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
Jeffrey Ryan Thalhammer <jeff@stratopan.com> |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
This software is copyright (c) 2015 by Jeffrey Ryan Thalhammer. |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
921
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
=cut |