| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Git::FastExport::Stitch; | 
| 2 |  |  |  |  |  |  | $Git::FastExport::Stitch::VERSION = '0.108'; | 
| 3 | 2 |  |  | 2 |  | 259998 | use strict; | 
|  | 2 |  |  |  |  | 12 |  | 
|  | 2 |  |  |  |  | 58 |  | 
| 4 | 2 |  |  | 2 |  | 11 | use warnings; | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 55 |  | 
| 5 | 2 |  |  | 2 |  | 11 | use Cwd qw( cwd ); | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 89 |  | 
| 6 | 2 |  |  | 2 |  | 11 | use Carp; | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 110 |  | 
| 7 | 2 |  |  | 2 |  | 14 | use Scalar::Util qw( blessed ); | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 102 |  | 
| 8 | 2 |  |  | 2 |  | 12 | use List::Util qw( first ); | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 123 |  | 
| 9 | 2 |  |  | 2 |  | 14 | use File::Basename qw( basename ); | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 191 |  | 
| 10 | 2 |  |  | 2 |  | 844 | use Git::FastExport; | 
|  | 2 |  |  |  |  | 6 |  | 
|  | 2 |  |  |  |  | 4015 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | sub new { | 
| 13 | 48 |  |  | 48 | 1 | 9713813 | my ( $class, $options, @args ) = @_; | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | # create the object | 
| 16 | 48 |  |  |  |  | 1230 | my $self = bless { | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | # internal structures | 
| 19 |  |  |  |  |  |  | mark     => 1_000_000,    # mark counter in the new repo | 
| 20 |  |  |  |  |  |  | mark_map => {}, | 
| 21 |  |  |  |  |  |  | commits  => {}, | 
| 22 |  |  |  |  |  |  | repo     => {}, | 
| 23 |  |  |  |  |  |  | name     => {}, | 
| 24 |  |  |  |  |  |  | cache    => {}, | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | # default options | 
| 27 |  |  |  |  |  |  | select => 'last', | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | }, $class; | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | # set the options | 
| 32 | 48 |  |  |  |  | 398 | for my $key (qw( select )) { | 
| 33 | 48 | 100 |  |  |  | 326 | $self->{$key} = $options->{$key} if exists $options->{$key}; | 
| 34 |  |  |  |  |  |  | } | 
| 35 |  |  |  |  |  |  | croak "Invalid value for 'select' option: '$self->{select}'" | 
| 36 | 48 | 100 |  |  |  | 976 | if $self->{select} !~ /^(?:first|last|random)$/; | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | # process the remaining args | 
| 39 | 47 |  |  |  |  | 242 | $self->stitch( splice @args, 0, 2 ) while @args; | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 46 |  |  |  |  | 181 | return $self; | 
| 42 |  |  |  |  |  |  | } | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | # add a new repo to stich in | 
| 45 |  |  |  |  |  |  | sub stitch { | 
| 46 | 66 |  |  | 66 | 1 | 4730 | my ( $self, $repo, $dir ) = @_; | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | # $repo is either a Git::Repository object or a valid path | 
| 49 |  |  |  |  |  |  | my $export = blessed($repo) && $repo->isa('Git::Repository') | 
| 50 |  |  |  |  |  |  | ? $repo     # a Git::Repository object | 
| 51 | 66 | 100 | 66 |  |  | 944 | : eval {    # assume a path | 
| 52 | 45 |  |  |  |  | 114 | my $r; | 
| 53 | 45 |  |  |  |  | 115035 | my $orig = cwd; | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | # chdir and create a Git::Repository object there | 
| 56 | 45 | 50 |  |  |  | 685 | if ( defined $repo ) { | 
| 57 | 45 | 100 |  |  |  | 1420 | chdir $repo or croak "Can't chdir to $repo: $!"; | 
| 58 | 44 |  |  |  |  | 2073 | $r = Git::Repository->new(); | 
| 59 | 44 | 50 |  |  |  | 1987128 | chdir $orig or croak "Can't chdir back to $orig: $!"; | 
| 60 |  |  |  |  |  |  | } | 
| 61 | 0 |  |  |  |  | 0 | else { die "Undefined repository path" } | 
| 62 | 44 |  |  |  |  | 248 | $r; | 
| 63 |  |  |  |  |  |  | }; | 
| 64 | 66 | 100 |  |  |  | 501 | $@ =~ s/ at .*\z//s, croak $@ if !$export; | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | # do not stich a repo with itself | 
| 67 | 65 |  |  |  |  | 934 | $repo = $export->git_dir; | 
| 68 | 65 | 100 |  |  |  | 1351 | croak "Already stitching repository $repo" if exists $self->{repo}{$repo}; | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | # pick the refs suffix: | 
| 71 |  |  |  |  |  |  | # use base directory without the .git extension or non ASCII characters | 
| 72 | 63 |  |  |  |  | 2375 | my @parts = File::Spec->splitdir( ( File::Spec->splitpath( $repo, 1 ) )[1] ); | 
| 73 | 63 |  |  |  |  | 381 | my $name = pop @parts; | 
| 74 | 63 | 50 |  |  |  | 291 | $name = pop @parts if $name eq '.git'; | 
| 75 | 63 |  |  |  |  | 217 | $name =~ s/\.git$//; | 
| 76 | 63 | 50 |  |  |  | 452 | $dir = $name if not defined $dir; | 
| 77 | 63 |  |  |  |  | 289 | $name =~ y/-A-Za-z0-9_/-/cs; | 
| 78 | 63 |  |  |  |  | 669 | $name =~ s/^-|-$//g; | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | # check if the name is not used already and pick a replacement if it is | 
| 81 | 63 | 50 |  |  |  | 354 | if ( exists $self->{name}{$name} ) { | 
| 82 | 0 |  |  |  |  | 0 | my $suffix = "A"; | 
| 83 | 0 |  |  |  |  | 0 | $suffix++ while ( exists $self->{name}{"$name-$suffix"} ); | 
| 84 | 0 |  |  |  |  | 0 | $name .= "-$suffix"; | 
| 85 |  |  |  |  |  |  | } | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | # git fast-export appeared in git 1.5.4 | 
| 88 | 63 | 50 |  |  |  | 5268 | croak "stitch() requires a git version greater or equal to 1.5.4, this is only version ${\$export->version}" | 
|  | 0 |  |  |  |  | 0 |  | 
| 89 |  |  |  |  |  |  | if $export->version_lt('1.5.4'); | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | # initiate the Git::FastExport stream | 
| 92 | 63 |  |  |  |  | 671799 | my $stream = | 
| 93 |  |  |  |  |  |  | $export->command(qw( fast-export --progress=1 --all --date-order )) | 
| 94 |  |  |  |  |  |  | ->stdout; | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | # set up the internal structures | 
| 97 | 63 |  |  |  |  | 627355 | $self->{repo}{$repo}{repo}   = $repo; | 
| 98 | 63 |  |  |  |  | 664 | $self->{repo}{$repo}{dir}    = $dir; | 
| 99 | 63 |  |  |  |  | 699 | $self->{repo}{$repo}{git}    = $export; | 
| 100 | 63 |  |  |  |  | 1559 | $self->{repo}{$repo}{parser} = Git::FastExport->new($stream); | 
| 101 | 63 |  |  |  |  | 579 | $self->{repo}{$repo}{name}   = $name; | 
| 102 | 63 |  |  |  |  | 654 | $self->{repo}{$repo}{block}  = $self->{repo}{$repo}{parser}->next_block(); | 
| 103 | 63 |  |  |  |  | 1185 | $self->_translate_block($repo); | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 63 |  |  |  |  | 646 | return $self; | 
| 106 |  |  |  |  |  |  | } | 
| 107 |  |  |  |  |  |  |  | 
| 108 |  |  |  |  |  |  | # return the next block in the stitched stream | 
| 109 |  |  |  |  |  |  | sub next_block { | 
| 110 | 752 |  |  | 752 | 1 | 299091 | my ($self) = @_; | 
| 111 | 752 |  |  |  |  | 1503 | my $repo = $self->{repo}; | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | # keep a list of next blocks (per repo) | 
| 114 |  |  |  |  |  |  | # any undef block means the stream is finished | 
| 115 | 752 |  |  |  |  | 2053 | delete $repo->{$_} for grep { !defined $repo->{$_}{block} } keys %$repo; | 
|  | 1390 |  |  |  |  | 4940 |  | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | # no repo left, we're done | 
| 118 | 752 | 100 |  |  |  | 8147 | return if ! keys %$repo; | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | # return any non-commit block directly | 
| 121 | 720 | 100 |  |  |  | 4350 | if ( my $next | 
| 122 | 1153 |  |  | 1153 |  | 3144 | = first { $repo->{$_}{block}{type} ne 'commit' } keys %$repo ) | 
| 123 |  |  |  |  |  |  | { | 
| 124 | 456 |  |  |  |  | 751 | my $block = $repo->{$next}{block}; | 
| 125 | 456 |  |  |  |  | 1551 | $repo->{$next}{block} = $repo->{$next}{parser}->next_block(); | 
| 126 | 456 |  |  |  |  | 1509 | $self->_translate_block( $next ); | 
| 127 | 456 |  |  |  |  | 1479 | return $block; | 
| 128 |  |  |  |  |  |  | } | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | # select the oldest available commit | 
| 131 | 264 |  |  |  |  | 841 | my ($next) = keys %$repo; | 
| 132 |  |  |  |  |  |  | $next | 
| 133 |  |  |  |  |  |  | = $repo->{$next}{block}{committer_date} < $repo->{$_}{block}{committer_date} ? $next : $_ | 
| 134 | 264 | 100 |  |  |  | 1465 | for keys %$repo; | 
| 135 | 264 |  |  |  |  | 515 | my $commit = $repo->{$next}{block}; | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | # fetch the next block | 
| 138 | 264 |  |  |  |  | 713 | $repo->{$next}{block} = $repo->{$next}{parser}->next_block(); | 
| 139 | 264 |  |  |  |  | 676 | $self->_translate_block( $next ); | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | # prepare the attachement algorithm | 
| 142 | 264 |  |  |  |  | 496 | $repo = $repo->{$next}; | 
| 143 | 264 |  |  |  |  | 424 | my $commits  = $self->{commits}; | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | # first commit in the old repo linked to latest commit in new repo | 
| 146 | 264 | 100 | 100 |  |  | 1244 | if ( $self->{last} && !$commit->{from} ) { | 
| 147 | 30 |  |  |  |  | 177 | $commit->{from} = ["from :$self->{last}"]; | 
| 148 |  |  |  |  |  |  | } | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | # update historical information | 
| 151 | 264 |  |  |  |  | 1339 | my ($id) = $commit->{mark}[0] =~ /:(\d+)/g; | 
| 152 | 264 |  |  |  |  | 792 | $self->{last} = $id;    # last commit applied | 
| 153 | 264 |  |  |  |  | 906 | my $ref = ( split / /, $commit->{header} )[1]; | 
| 154 |  |  |  |  |  |  | my $node = $commits->{$id} = { | 
| 155 |  |  |  |  |  |  | name     => $id, | 
| 156 |  |  |  |  |  |  | repo     => $repo->{repo}, | 
| 157 |  |  |  |  |  |  | ref      => $ref, | 
| 158 |  |  |  |  |  |  | children => [], | 
| 159 |  |  |  |  |  |  | parents  => {}, | 
| 160 |  |  |  |  |  |  | merge    => exists $commit->{merge}, | 
| 161 | 264 |  |  |  |  | 3210 | }; | 
| 162 |  |  |  |  |  |  |  | 
| 163 |  |  |  |  |  |  | # mark our original source | 
| 164 | 264 |  |  |  |  | 1835 | $commit->{header} =~ s/$/-$repo->{name}/; | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | # this commit's parents | 
| 167 | 274 | 100 |  |  |  | 1307 | my @parents = map {/:(\d+)/g} @{ $commit->{from} || [] }, | 
|  | 264 |  |  |  |  | 926 |  | 
| 168 | 264 | 100 |  |  |  | 539 | @{ $commit->{merge} || [] }; | 
|  | 264 |  |  |  |  | 1213 |  | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | # get the reference parent list used by _last_alien_child() | 
| 171 | 264 |  |  |  |  | 626 | my $parents = {}; | 
| 172 | 264 |  |  |  |  | 506 | for my $parent (@parents) { | 
| 173 | 274 | 100 |  |  |  | 707 | if ( $commits->{$parent}{repo} eq $node->{repo} ) { | 
| 174 | 244 |  |  |  |  | 341 | push @{ $parents->{ $node->{repo} } }, $parent; | 
|  | 244 |  |  |  |  | 808 |  | 
| 175 |  |  |  |  |  |  | } | 
| 176 |  |  |  |  |  |  | else {    # record the parents from the other repositories | 
| 177 | 30 |  |  |  |  | 75 | for my $repo ( grep $_ ne $node->{repo}, | 
| 178 | 30 |  |  |  |  | 166 | keys %{ $commits->{$parent}{parents} } ) | 
| 179 |  |  |  |  |  |  | { | 
| 180 | 8 |  |  |  |  | 23 | push @{ $parents->{$repo} }, | 
| 181 | 8 | 50 |  |  |  | 19 | @{ $commits->{$parent}{parents}{$repo} || [] }; | 
|  | 8 |  |  |  |  | 40 |  | 
| 182 |  |  |  |  |  |  | } | 
| 183 |  |  |  |  |  |  | } | 
| 184 |  |  |  |  |  |  | } | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | # map each parent to its last "alien" commit | 
| 187 |  |  |  |  |  |  | my %parent_map = map { | 
| 188 | 264 |  |  |  |  | 444 | $_ => $self->_last_alien_child( $commits->{$_}, $ref, $parents )->{name} | 
| 189 | 274 |  |  |  |  | 686 | } @parents; | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | # map parent marks | 
| 192 | 264 | 100 |  |  |  | 465 | for ( @{ $commit->{from} || [] }, @{ $commit->{merge} || [] } ) { | 
|  | 264 | 100 |  |  |  | 893 |  | 
|  | 264 |  |  |  |  | 1043 |  | 
| 193 | 274 |  |  |  |  | 1781 | s/:(\d+)/:$parent_map{$1}/g; | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | # update the parents information | 
| 197 | 264 |  |  |  |  | 669 | for my $parent ( map { $commits->{ $parent_map{$_} } } @parents ) { | 
|  | 274 |  |  |  |  | 679 |  | 
| 198 | 274 |  |  |  |  | 421 | push @{ $parent->{children} }, $node->{name}; | 
|  | 274 |  |  |  |  | 594 |  | 
| 199 | 274 |  |  |  |  | 413 | push @{ $node->{parents}{ $parent->{repo} } }, $parent->{name}; | 
|  | 274 |  |  |  |  | 863 |  | 
| 200 |  |  |  |  |  |  | } | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | # dump the commit | 
| 203 | 264 |  |  |  |  | 1092 | return $commit; | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  | sub _translate_block { | 
| 207 | 783 |  |  | 783 |  | 1590 | my ( $self, $repo ) = @_; | 
| 208 | 783 |  |  |  |  | 1605 | my $mark_map = $self->{mark_map}; | 
| 209 | 783 |  |  |  |  | 1349 | my $block    = $self->{repo}{$repo}{block}; | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | # nothing to do | 
| 212 | 783 | 100 |  |  |  | 1729 | return if !defined $block; | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | # mark our original source | 
| 215 |  |  |  |  |  |  | $block->{header} =~ s/$/-$self->{repo}{$repo}{name}/ | 
| 216 | 721 | 100 |  |  |  | 4268 | if $block->{type} =~ /^(?:reset|tag)$/; | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | # map to the new mark | 
| 219 | 721 | 100 |  |  |  | 1209 | for ( @{ $block->{mark} || [] } ) { | 
|  | 721 |  |  |  |  | 3346 |  | 
| 220 | 264 |  |  |  |  | 1718 | s/:(\d+)/:$self->{mark}/; | 
| 221 | 264 |  |  |  |  | 2004 | $mark_map->{$repo}{$1} = $self->{mark}++; | 
| 222 |  |  |  |  |  |  | } | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | # update marks in from & merge | 
| 225 | 721 | 100 |  |  |  | 1390 | for ( @{ $block->{from} || [] }, @{ $block->{merge} || [] } ) { | 
|  | 721 | 100 |  |  |  | 2349 |  | 
|  | 721 |  |  |  |  | 2525 |  | 
| 226 | 312 |  |  |  |  | 1807 | s/:(\d+)/:$mark_map->{$repo}{$1}/g; | 
| 227 |  |  |  |  |  |  | } | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | # update marks & dir in files | 
| 230 | 721 |  |  |  |  | 1167 | for ( @{ $block->{files} } ) { | 
|  | 721 |  |  |  |  | 2587 |  | 
| 231 | 0 |  |  |  |  | 0 | s/^M (\d+) :(\d+)/M $1 :$mark_map->{$repo}{$2}/; | 
| 232 | 0 |  |  |  |  | 0 | my $dir = $self->{repo}{$repo}{dir}; | 
| 233 | 0 | 0 | 0 |  |  | 0 | if ( defined $dir && $dir ne '' ) { | 
| 234 | 0 |  |  |  |  | 0 | s!^(M \d+ :\d+) (\"?)(.*)!$1 $2$dir/$3!;    # filemodify | 
| 235 | 0 |  |  |  |  | 0 | s!^D (\"?)(.*)!D $1$dir/$2!;                # filedelete | 
| 236 |  |  |  |  |  |  |  | 
| 237 |  |  |  |  |  |  | # /!\ quotes may happen - die and fix if needed | 
| 238 | 0 | 0 |  |  |  | 0 | die "Choked on quoted paths in $repo! Culprit:\n$_\n" | 
| 239 |  |  |  |  |  |  | if /^[CR] \S+ \S+ /; | 
| 240 |  |  |  |  |  |  |  | 
| 241 |  |  |  |  |  |  | # filecopy | filerename | 
| 242 | 0 |  |  |  |  | 0 | s!^([CR]) (\"?)(\S+) (\"?)(\S+)!$1 $2$dir/$3 $4$dir/$5!; | 
| 243 |  |  |  |  |  |  | } | 
| 244 |  |  |  |  |  |  | } | 
| 245 |  |  |  |  |  |  | } | 
| 246 |  |  |  |  |  |  |  | 
| 247 |  |  |  |  |  |  | # find the last child of this node | 
| 248 |  |  |  |  |  |  | # that has either no child | 
| 249 |  |  |  |  |  |  | # or a child in our repo | 
| 250 |  |  |  |  |  |  | # or an alien child that has the same parent list | 
| 251 |  |  |  |  |  |  | sub _last_alien_child { | 
| 252 | 274 |  |  | 274 |  | 632 | my ( $self, $node, $ref, $parents ) = @_; | 
| 253 | 274 |  |  |  |  | 471 | my $commits = $self->{commits}; | 
| 254 |  |  |  |  |  |  |  | 
| 255 | 274 |  |  |  |  | 448 | my $from = $node->{name}; | 
| 256 | 274 |  |  |  |  | 406 | my $repo = $node->{repo}; | 
| 257 |  |  |  |  |  |  |  | 
| 258 | 274 |  |  |  |  | 371 | while (1) { | 
| 259 |  |  |  |  |  |  |  | 
| 260 |  |  |  |  |  |  | # no children nodes | 
| 261 | 457 | 100 |  |  |  | 578 | return $node if ( !@{ $node->{children} } ); | 
|  | 457 |  |  |  |  | 1622 |  | 
| 262 |  |  |  |  |  |  |  | 
| 263 |  |  |  |  |  |  | # some children nodes are local | 
| 264 |  |  |  |  |  |  | return $node | 
| 265 | 235 | 100 |  |  |  | 401 | if grep { $commits->{$_}{repo} eq $repo } @{ $node->{children} }; | 
|  | 295 |  |  |  |  | 1047 |  | 
|  | 235 |  |  |  |  | 440 |  | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | # all children are alien to us | 
| 268 | 183 |  |  |  |  | 292 | my @valid; | 
| 269 | 183 |  |  |  |  | 261 | for my $id ( @{ $node->{children} } ) { | 
|  | 183 |  |  |  |  | 438 |  | 
| 270 |  |  |  |  |  |  |  | 
| 271 | 237 |  |  |  |  | 430 | my $peer = $commits->{$id}; | 
| 272 |  |  |  |  |  |  |  | 
| 273 |  |  |  |  |  |  | # parents of $peer in $peer's repo contains | 
| 274 |  |  |  |  |  |  | # all parents from $parent in $peer's repo | 
| 275 | 237 |  |  |  |  | 330 | my %pparents; | 
| 276 | 237 | 100 |  |  |  | 334 | @{pparents}{ @{ $peer->{parents}{ $peer->{repo} } || [] } } = (); | 
|  | 237 |  |  |  |  | 1027 |  | 
| 277 |  |  |  |  |  |  | next | 
| 278 |  |  |  |  |  |  | if grep !exists $pparents{$_}, | 
| 279 | 237 | 50 |  |  |  | 404 | @{ $parents->{ $peer->{repo} } }; | 
|  | 237 |  |  |  |  | 632 |  | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | # this child node has a valid parent list | 
| 282 | 237 |  |  |  |  | 634 | push @valid, $id; | 
| 283 |  |  |  |  |  |  | } | 
| 284 |  |  |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | # compute the commit to attach to, using the requested algorithm | 
| 286 | 183 | 50 |  |  |  | 413 | if (@valid) { | 
| 287 |  |  |  |  |  |  | my $node_id = $self->{cache}{"$from $node->{name}"} ||= | 
| 288 |  |  |  |  |  |  | $self->{select} eq 'last'  ? $valid[-1] | 
| 289 | 183 | 50 | 66 |  |  | 1649 | : $self->{select} eq 'first' ? $valid[0] | 
|  |  | 100 |  |  |  |  |  | 
| 290 |  |  |  |  |  |  | :                              $valid[ rand @valid ]; | 
| 291 | 183 |  |  |  |  | 440 | $node = $commits->{$node_id}; | 
| 292 |  |  |  |  |  |  | } | 
| 293 |  |  |  |  |  |  | } | 
| 294 |  |  |  |  |  |  |  | 
| 295 |  |  |  |  |  |  | # return last valid child | 
| 296 | 0 |  |  |  |  |  | return $node; | 
| 297 |  |  |  |  |  |  | } | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | 'progress 1 objects'; | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  | __END__ |