File Coverage

blib/lib/Git/PurePerl/Pack/WithoutIndex.pm
Criterion Covered Total %
statement 73 74 98.6
branch 13 24 54.1
condition 16 29 55.1
subroutine 6 6 100.0
pod 0 3 0.0
total 108 136 79.4


line stmt bran cond sub pod time code
1             package Git::PurePerl::Pack::WithoutIndex;
2 4     4   16 use Moose;
  4         5  
  4         25  
3 4     4   16445 use MooseX::StrictConstructor;
  4         4  
  4         29  
4 4     4   7756 use namespace::autoclean;
  4         5  
  4         26  
5              
6             extends 'Git::PurePerl::Pack';
7              
8             has 'offsets' => ( is => 'rw', isa => 'HashRef', required => 0 );
9              
10             my @TYPES = ( 'none', 'commit', 'tree', 'blob', 'tag', '', 'ofs_delta',
11             'ref_delta' );
12              
13             sub create_index {
14 1     1 0 3 my ($self) = @_;
15 1         33 my $index_filename = $self->filename;
16 1         4 $index_filename =~ s/\.pack/.idx/;
17 1   50     47 my $index_fh = IO::File->new("> $index_filename") || die $!;
18              
19 1         130 my $iod = IO::Digest->new( $index_fh, 'SHA' );
20              
21 1         3397 my $offsets = $self->create_index_offsets;
22 1         2 my @fan_out_table;
23 1         343 foreach my $sha1 ( sort keys %$offsets ) {
24 752         499 my $offset = $offsets->{$sha1};
25 752         811 my $slot = unpack( 'C', pack( 'H*', $sha1 ) );
26 752         517 $fan_out_table[$slot]++;
27             }
28 1         20 foreach my $i ( 0 .. 255 ) {
29 256 50 50     710 $index_fh->print( pack( 'N', $fan_out_table[$i] || 0 ) ) || die $!;
30 256   50     7637 $fan_out_table[ $i + 1 ] += $fan_out_table[$i] || 0;
31             }
32 1         285 foreach my $sha1 ( sort keys %$offsets ) {
33 752         21482 my $offset = $offsets->{$sha1};
34 752 50       1686 $index_fh->print( pack( 'N', $offset ) ) || die $!;
35 752 50       22139 $index_fh->print( pack( 'H*', $sha1 ) ) || die $!;
36             }
37              
38             # read the pack checksum from the end of the pack file
39 1         151 my $size = -s $self->filename;
40 1         159 my $fh = $self->fh;
41 1 50       8 $fh->seek( $size - 20, 0 ) || die $!;
42 1   50     18 my $read = $fh->read( my $pack_sha1, 20 ) || die $!;
43              
44 1 50       21 $index_fh->print($pack_sha1) || die $!;
45 1 50       51 $index_fh->print( $iod->digest ) || die $!;
46              
47 1 50       34 $index_fh->close() || die $!;
48             }
49              
50             sub create_index_offsets {
51 1     1 0 2 my ($self) = @_;
52 1         36 my $fh = $self->fh;
53              
54 1         7 $fh->read( my $signature, 4 );
55 1         12 $fh->read( my $version, 4 );
56 1         8 $version = unpack( 'N', $version );
57 1         3 $fh->read( my $objects, 4 );
58 1         3 $objects = unpack( 'N', $objects );
59              
60 1         2 my %offsets;
61 1         31 $self->offsets( \%offsets );
62              
63 1         3 foreach my $i ( 1 .. $objects ) {
64 752   50     1656 my $offset = $fh->tell || die "Error telling filehandle: $!";
65 752         2926 my $obj_offset = $offset;
66 752 50       1238 $fh->read( my $c, 1 ) || die "Error reading from pack: $!";
67 752   50     6326 $c = unpack( 'C', $c ) || die $!;
68 752         600 $offset++;
69              
70 752         741 my $size = ( $c & 0xf );
71 752         734 my $type_number = ( $c >> 4 ) & 7;
72 752   33     1378 my $type = $TYPES[$type_number]
73             || confess
74             "invalid type $type_number at offset $offset, size $size";
75              
76 752         634 my $shift = 4;
77              
78 752         1364 while ( ( $c & 0x80 ) != 0 ) {
79 676 50       1038 $fh->read( $c, 1 ) || die $!;
80 676   50     3163 $c = unpack( 'C', $c ) || die $!;
81 676         516 $offset++;
82 676         664 $size |= ( ( $c & 0x7f ) << $shift );
83 676         1159 $shift += 7;
84             }
85              
86 752         481 my $content;
87              
88 752 100 66     3971 if ( $type eq 'ofs_delta' || $type eq 'ref_delta' ) {
    50 100        
      66        
      33        
89 375         1027 ( $type, $size, $content )
90             = $self->unpack_deltified( $type, $offset, $obj_offset, $size,
91             \%offsets );
92             } elsif ( $type eq 'commit'
93             || $type eq 'tree'
94             || $type eq 'blob'
95             || $type eq 'tag' )
96             {
97 377         765 $content = $self->read_compressed( $offset, $size );
98             } else {
99 0         0 confess "invalid type $type";
100             }
101              
102 752         2210 my $raw = $type . ' ' . $size . "\0" . $content;
103 752         2070 my $sha1 = Digest::SHA->new;
104 752         11594 $sha1->add($raw);
105 752         2429 my $sha1_hex = $sha1->hexdigest;
106 752         2987 $offsets{$sha1_hex} = $obj_offset;
107             }
108              
109 1         3 return \%offsets;
110             }
111              
112             sub get_object {
113 1484     1484 0 1387 my ( $self, $want_sha1 ) = @_;
114 1484         39204 my $offset = $self->offsets->{$want_sha1};
115 1484 50       2029 return unless $offset;
116 1484         2865 return $self->unpack_object($offset);
117             }
118              
119             __PACKAGE__->meta->make_immutable;
120