File Coverage

blib/lib/Pinto/Repository.pm
Criterion Covered Total %
statement 280 304 92.1
branch 67 100 67.0
condition 13 23 56.5
subroutine 53 56 94.6
pod 11 36 30.5
total 424 519 81.7


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