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   365 use Moose;
  51         125  
  51         454  
6 51     51   352144 use MooseX::StrictConstructor;
  51         209573  
  51         499  
7 51     51   247267 use MooseX::MarkAsMethods ( autoclean => 1 );
  51         128  
  51         458  
8              
9 51     51   240502 use Readonly;
  51         117  
  51         3246  
10 51     51   326 use File::Find;
  51         116  
  51         2784  
11 51     51   314 use Path::Class;
  51         103  
  51         2644  
12 51     51   293 use List::Util qw(first);
  51         116  
  51         2962  
13              
14 51     51   20460 use Pinto::Store;
  51         567  
  51         2303  
15 51     51   21229 use Pinto::Config;
  51         297  
  51         3695  
16 51     51   24317 use Pinto::Locker;
  51         241  
  51         2853  
17 51     51   24527 use Pinto::Database;
  51         259  
  51         3462  
18 51     51   22905 use Pinto::PackageExtractor;
  51         227  
  51         2309  
19 51     51   21310 use Pinto::Locator::Multiplex;
  51         290  
  51         2263  
20 51     51   21325 use Pinto::PrerequisiteWalker;
  51         209  
  51         2488  
21 51     51   434 use Pinto::Util qw(itis debug mksymlink throw);
  51         100  
  51         4257  
22 51     51   332 use Pinto::Types qw(Dir);
  51         107  
  51         470  
23              
24 51     51   304315 use version;
  51         134  
  51         461  
25              
26             #-------------------------------------------------------------------------------
27              
28             our $VERSION = '0.14'; # 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 78134 my ( $self, $stack ) = @_;
100              
101 410 100       1851 my $got = $self->get_stack_maybe($stack)
102             or throw "Stack $stack does not exist";
103              
104 403         17234 return $got;
105             }
106              
107             #-------------------------------------------------------------------------------
108              
109              
110             sub get_stack_maybe {
111 579     579 1 2519 my ( $self, $stack ) = @_;
112              
113 579 50       3173 return $stack if itis( $stack, 'Pinto::Schema::Result::Stack' );
114 579 100       2587 return $self->get_default_stack if not $stack;
115              
116 372         1282 my $where = { name => $stack };
117 372         9420 return $self->db->schema->find_stack($where);
118             }
119              
120             #-------------------------------------------------------------------------------
121              
122              
123             sub get_default_stack {
124 207     207 1 575 my ($self) = @_;
125              
126 207         831 my $where = { is_default => 1 };
127 207         5431 my @stacks = $self->db->schema->search_stack($where)->all;
128              
129             # Assert that there is no more than one default stack
130 207 50       674758 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       12848 throw "The default stack has not been set" if @stacks == 0;
134              
135 202         2648 return $stacks[0];
136             }
137              
138             #-------------------------------------------------------------------------------
139              
140              
141             sub get_all_stacks {
142 5     5 1 22 my ($self) = @_;
143              
144 5         112 return $self->db->schema->stack_rs->all;
145             }
146              
147             #-------------------------------------------------------------------------------
148              
149              
150             sub get_revision {
151 9     9 1 33 my ($self, $revision) = @_;
152              
153 9 50       40 my $rev = $self->get_revision_maybe($revision)
154             or throw "No such revision $revision exists";
155              
156 9         224 return $rev;
157             }
158              
159             #-------------------------------------------------------------------------------
160              
161              
162             sub get_revision_maybe {
163 18     18 1 53 my ( $self, $revision ) = @_;
164              
165 18 50       93 return $revision if itis( $revision, 'Pinto::Schema::Result::Revision' );
166              
167 18         122 my $where = { uuid => { like => lc "$revision%" } };
168 18         456 my @revs = $self->db->schema->search_revision($where);
169              
170 18 100       50804 if ( @revs > 1 ) {
171 1         17 my $msg = "Revision ID $revision is ambiguous. Possible matches are:\n";
172 1         9 $msg .= $_->to_string("%i: %{48}T\n") for @revs;
173 1         26 throw $msg;
174             }
175              
176 17 100       400 return @revs ? $revs[0] : ();
177             }
178              
179             #-------------------------------------------------------------------------------
180              
181              
182             sub get_package {
183 82     82 1 368 my ( $self, %args ) = @_;
184              
185 82         251 my $target = $args{target};
186 82         230 my $pkg_name = $args{name};
187 82         204 my $dist_path = $args{path};
188 82         1988 my $schema = $self->db->schema;
189              
190             # Retrieve latest version of package that satisfies the target
191 82 50 0     328 if ($target) {
    0          
    0          
192 82         1856 my $where = {name => $target->name};
193 82 100       1809 return unless my @pkgs = $schema->search_package( $where )->with_distribution;
194 17 100   17   175007 return unless my $latest = first { $target->is_satisfied_by($_->version) } reverse sort { $a <=> $b } @pkgs;
  17         852  
  3         330  
195 15         1320 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 5061 my ( $self, %args ) = @_;
221              
222 309         8722 my $rs = $self->db->schema->distribution_rs->with_packages;
223              
224             # Retrieve a distribution by target
225 309 100       94644 if ( my $target = $args{target} ) {
    100          
    50          
226 88 100       597 if ( itis( $target, 'Pinto::Target::Distribution' ) ) {
    50          
227 6         173 return $rs->find_by_author_archive( $target->author, $target->archive );
228             }
229             elsif ( itis( $target, 'Pinto::Target::Package' ) ) {
230 82 100       437 return unless my $pkg = $self->get_package( target => $target );
231 15         1496 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         1788 my ( $author, $archive ) = Pinto::Util::parse_dist_path($path);
240 53         324 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       4268 my $archive = $args{archive} or throw "Must specify archive with author";
246 168         817 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 344 my ( $self, %args ) = @_;
257              
258 65 100       647 return unless my $found = $self->locate( %args );
259 50         391 return $self->fetch_distribution( uri => $found->{uri} );
260             }
261              
262             #-------------------------------------------------------------------------------
263              
264              
265             sub add_distribution {
266 163     163 0 773 my ( $self, %args ) = @_;
267              
268 163         492 my $archive = $args{archive};
269 163         550 my $author = uc $args{author};
270 163   100     932 my $source = $args{source} || 'LOCAL';
271              
272 163         1286 $self->assert_archive_not_duplicate( $author, $archive );
273              
274             # Assemble the basic structure...
275 161         1008 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         6851 my $extractor = Pinto::PackageExtractor->new( archive => $archive );
285              
286             # Add provided packages...
287 161         1044 my @provides = $extractor->provides;
288 161         1074 $dist_struct->{packages} = \@provides;
289              
290             # Add required packages...
291 161         1395 my @requires = $extractor->requires;
292 161         1344 $dist_struct->{prerequisites} = \@requires;
293              
294             # Add metadata...
295 161         988 my $metadata = $extractor->metadata;
296 161         1128 $dist_struct->{metadata} = $metadata;
297              
298 161         574 my $p = scalar @provides;
299 161         519 my $r = scalar @requires;
300 161         1027 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         5957 my $dist = $self->db->schema->create_distribution($dist_struct);
307 161         1672145 $self->store->add_archive( $archive => $dist->native_path );
308              
309 161         9446 return $dist;
310             }
311              
312             #------------------------------------------------------------------------------
313              
314              
315             sub fetch_distribution {
316 50     50 1 214 my ( $self, %args ) = @_;
317              
318 50         137 my $uri = $args{uri};
319 50         313 my $path = $uri->path;
320              
321 50         993 my $existing = $self->get_distribution( path => $path );
322 50 50       486464 throw "Distribution $existing already exists" if $existing;
323              
324 50         348 my ( $author, undef ) = Pinto::Util::parse_dist_path($path);
325 50         421 my $archive = $self->mirror_temporary( $uri );
326              
327 50         1364 my $dist = $self->add_distribution(
328             archive => $archive,
329             author => $author,
330             source => $uri,
331             );
332 50         58601 return $dist;
333             }
334              
335             #------------------------------------------------------------------------------
336              
337             sub delete_distribution {
338 2     2 0 16 my ( $self, %args ) = @_;
339              
340 2         8 my $dist = $args{dist};
341 2         7 my $force = $args{force};
342              
343 2         40 for my $reg ( $dist->registrations ) {
344              
345             # TODO: say which stack it is pinned to
346 7 100 100     7912 throw "$dist is pinned to a stack and cannot be deleted"
347             if $reg->is_pinned and not $force;
348             }
349              
350 1         26 $dist->delete;
351 1         4677 my $basedir = $self->config->authors_id_dir;
352 1         42 $self->store->remove_archive( $dist->native_path($basedir) );
353              
354 1         27 return $self;
355             }
356              
357             #------------------------------------------------------------------------------
358              
359             sub package_count {
360 5     5 0 15 my ($self) = @_;
361              
362 5         119 return $self->db->schema->package_rs->count;
363             }
364              
365             #-------------------------------------------------------------------------------
366              
367             sub distribution_count {
368 5     5 0 17 my ($self) = @_;
369              
370 5         124 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 954 my ($self) = @_;
393              
394 341         1415 debug 'Beginning db transaction';
395 341         8291 $self->db->schema->txn_begin;
396              
397 341         157742 return $self;
398             }
399              
400             #-------------------------------------------------------------------------------
401              
402             sub txn_rollback {
403 44     44 0 138 my ($self) = @_;
404              
405 44         270 debug 'Rolling back db transaction';
406 44         1055 $self->db->schema->txn_rollback;
407              
408 44         17876 return $self;
409             }
410              
411             #-------------------------------------------------------------------------------
412              
413             sub txn_commit {
414 297     297 0 912 my ($self) = @_;
415              
416 297         1656 debug 'Committing db transaction';
417 297         7189 $self->db->schema->txn_commit;
418              
419 297         5289999 return $self;
420             }
421              
422             #-------------------------------------------------------------------------------
423              
424             sub svp_begin {
425 162     162 0 500 my ( $self, $name ) = @_;
426              
427 162         908 debug 'Beginning db savepoint';
428 162         4054 $self->db->schema->svp_begin($name);
429              
430 162         55539 return $self;
431             }
432              
433             #-------------------------------------------------------------------------------
434              
435             sub svp_rollback {
436 2     2 0 9 my ( $self, $name ) = @_;
437              
438 2         14 debug 'Rolling back db savepoint';
439 2         50 $self->db->schema->svp_rollback($name);
440              
441 2         1778 return $self;
442             }
443              
444             #-------------------------------------------------------------------------------
445              
446             sub svp_release {
447 147     147 0 528 my ( $self, $name ) = @_;
448              
449 147         1468 debug 'Releasing db savepoint';
450 147         3777 $self->db->schema->svp_release($name);
451              
452 147         55496 return $self;
453              
454             }
455              
456             #-------------------------------------------------------------------------------
457              
458             sub create_stack {
459 129     129 0 614 my ( $self, %args ) = @_;
460              
461 129         381 my $stk_name = $args{name};
462              
463 129 50       634 throw "Stack $stk_name already exists"
464             if $self->get_stack_maybe( $stk_name );
465              
466 129         862572 my $root = $self->db->get_root_revision;
467 129         6382 my $stack = $self->db->schema->create_stack( { %args, head => $root } );
468              
469 129         385137 $stack->make_filesystem;
470 129         735 $stack->write_index;
471              
472 129         1140 return $stack;
473             }
474              
475             #-------------------------------------------------------------------------------
476              
477             sub copy_stack {
478 10     10 0 65 my ( $self, %args ) = @_;
479              
480 10         38 my $copy_name = $args{name};
481 10         30 my $stack = delete $args{stack};
482 10         211 my $orig_name = $stack->name;
483              
484 10 100       160 if ( my $existing = $self->get_stack_maybe( $copy_name ) ) {
485 2         68 throw "Stack $existing already exists";
486             }
487              
488 8         36076 my $dupe = $stack->duplicate(%args);
489              
490 8         24208 $dupe->make_filesystem;
491 8         44 $dupe->write_index;
492              
493 8         52 return $dupe;
494             }
495              
496             #-------------------------------------------------------------------------------
497              
498             sub rename_stack {
499 4     4 0 21 my ( $self, %args ) = @_;
500              
501 4         9 my $new_name = $args{to};
502 4         11 my $stack = delete $args{stack};
503 4         65 my $old_name = $stack->name;
504              
505 4 100       51 if (my $existing_stack = $self->get_stack_maybe( $new_name )) {
506 3         150 my $is_different_stack = lc $new_name ne lc $existing_stack->name;
507 3 100 66     64 throw "Stack $new_name already exists" if $is_different_stack || $new_name eq $old_name;
508             }
509              
510 3         4425 $stack->rename_filesystem( to => $new_name );
511 2         11 $stack->rename( to => $new_name );
512              
513 2         10 return $stack;
514             }
515              
516             #-------------------------------------------------------------------------------
517              
518             sub kill_stack {
519 4     4 0 15 my ( $self, %args ) = @_;
520              
521 4         11 my $stack = $args{stack};
522              
523 4         21 $stack->kill;
524 2         11 $stack->kill_filesystem;
525              
526 2         8 return $stack;
527             }
528              
529             #-------------------------------------------------------------------------------
530              
531             sub link_modules_dir {
532 116     116 0 590 my ( $self, %args ) = @_;
533              
534 116         388 my $target_dir = $args{to};
535 116         2924 my $modules_dir = $self->config->modules_dir;
536 116         2615 my $root_dir = $self->config->root_dir;
537              
538 116 100 100     813 if ( -e $modules_dir or -l $modules_dir ) {
539 5         403 debug "Unlinking $modules_dir";
540 5 50       21 unlink $modules_dir or throw $!;
541             }
542              
543 116         10691 debug "Linking $modules_dir to $target_dir";
544 116         687 mksymlink( $modules_dir => $target_dir->relative($root_dir) );
545              
546 116         648 return $self;
547             }
548              
549             #-------------------------------------------------------------------------------
550              
551             sub unlink_modules_dir {
552 2     2 0 6 my ($self) = @_;
553              
554 2         44 my $modules_dir = $self->config->modules_dir;
555              
556 2 50 33     13 if ( -e $modules_dir or -l $modules_dir ) {
557 2         96 debug "Unlinking $modules_dir";
558 2 50       8 unlink $modules_dir or throw $!;
559             }
560              
561 2         101 return $self;
562             }
563              
564             #-------------------------------------------------------------------------------
565              
566              
567             sub clean_files {
568 25     25 1 93 my ( $self, %args ) = @_;
569              
570 25         74 my $deleted = 0;
571 25         533 my $dists_rs = $self->db->schema->distribution_rs->search( undef, { prefetch => {} } );
572 25         16782 my %known_dists = map { ( $_->to_string => 1 ) } $dists_rs->all;
  16         25021  
573              
574             my $callback = sub {
575 203 100   203   11795 return if not -f $_;
576              
577 77         336 my $path = Path::Class::file($_);
578 77         7696 my $author = $path->parent->basename;
579 77         767 my $archive = $path->basename;
580              
581 77 100       534 return if $archive eq 'CHECKSUMS';
582 58 100       562 return if $archive eq '01mailrc.txt.gz';
583 33 100       346 return if exists $known_dists{"$author/$archive"};
584              
585 17         567 debug "Removing orphaned archive at $path";
586 17         553 $self->store->remove_archive($path);
587 17         332 $deleted++;
588 25         29264 };
589              
590 25         2925 my $authors_dir = $self->config->authors_dir;
591 25         236 debug "Cleaning orphaned archives beneath $authors_dir";
592 25         1591 File::Find::find( { no_chdir => 1, wanted => $callback }, $authors_dir );
593              
594 25         341 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 1124 my ($self) = @_;
616              
617 381         9202 my $version_file = $self->config->version_file;
618              
619 381 50       1759 return undef if not -e $version_file; # Old repos have no version file
620              
621 381         18803 my $version = $version_file->slurp( chomp => 1 );
622              
623 381         99296 return $version;
624             }
625              
626             #-------------------------------------------------------------------------------
627              
628             sub set_version {
629 113     113 0 374 my ( $self, $version ) = @_;
630              
631 113   33     1410 $version ||= $REPOSITORY_VERSION;
632              
633 113         3826 my $version_fh = $self->config->version_file->openw;
634 113         22462 print {$version_fh} $version, "\n";
  113         1127  
635 113         3035 close $version_fh;
636              
637 113         637 return $self;
638             }
639              
640             #------------------------------------------------------------------------------
641              
642             sub assert_archive_not_duplicate {
643 163     163 0 488 my ( $self, $author, $archive ) = @_;
644              
645 163 50       1693 throw "Archive $archive does not exist" if not -e $archive;
646 163 50       10573 throw "Archive $archive is not readable" if not -r $archive;
647              
648 163         5883 my $basename = $archive->basename;
649 163 100       1267 if ( my $same_path = $self->get_distribution( author => $author, archive => $basename ) ) {
650 2         78 throw "A distribution already exists as $same_path";
651             }
652              
653 161         1480515 my $sha256 = Pinto::Util::sha256($archive);
654 161         5909 my $dupe = $self->db->schema->search_distribution( { sha256 => $sha256 } )->first;
655 161 50       401625 throw "Archive $archive is identical to $dupe" if $dupe;
656              
657 161         17506 return $self;
658             }
659              
660             #-------------------------------------------------------------------------------
661              
662             sub assert_version_ok {
663 380     380 0 1172 my ($self) = @_;
664              
665 380         2105 my $repo_version = $self->get_version;
666 380         4180 my $code_version = $REPOSITORY_VERSION;
667              
668 51     51   150418 no warnings qw(uninitialized);
  51         139  
  51         14726  
669 380 50       4333 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         1360 return $self;
683             }
684              
685             #-------------------------------------------------------------------------------
686              
687             sub assert_sanity_ok {
688 393     393 0 1277 my ($self) = @_;
689              
690 393         10446 my $root_dir = $self->config->root_dir;
691              
692 393 50       3495 throw "Directory $root_dir does not exist"
693             unless -e $root_dir;
694              
695 393 50       21614 throw "$root_dir is not a directory"
696             unless -d $root_dir;
697              
698 393 50       10112 throw "Directory $root_dir is not readable by you"
699             unless -r $root_dir;
700              
701 393 50       9477 throw "Directory $root_dir is not writable by you"
702             unless -w $root_dir;
703              
704 393 50 33     19053 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         13163 return $self;
708             }
709              
710             #-------------------------------------------------------------------------------
711              
712             sub clear_cache {
713 2     2 0 11 my ($self) = @_;
714              
715 2         50 $self->locator->refresh; # Clears cache file from disk
716              
717 2         5 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.14
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