File Coverage

blib/lib/Cogit/Pack/WithoutIndex.pm
Criterion Covered Total %
statement 15 80 18.7
branch 0 24 0.0
condition 0 29 0.0
subroutine 5 8 62.5
pod 0 3 0.0
total 20 144 13.8


line stmt bran cond sub pod time code
1             package Cogit::Pack::WithoutIndex;
2             $Cogit::Pack::WithoutIndex::VERSION = '0.001001';
3 4     4   18 use Moo;
  4         3  
  4         23  
4 4     4   9321 use IO::Digest;
  4         9445  
  4         102  
5 4     4   22 use MooX::Types::MooseLike::Base 'HashRef';
  4         7  
  4         177  
6 4     4   16 use Carp 'confess';
  4         4  
  4         139  
7 4     4   17 use namespace::clean;
  4         5  
  4         31  
8              
9             extends 'Cogit::Pack';
10              
11             has offsets => (
12             is => 'rw',
13             isa => HashRef,
14             );
15              
16             my @TYPES = (qw(none commit tree blob tag), '', 'ofs_delta', 'ref_delta' );
17              
18             sub create_index {
19 0     0 0   my ($self) = @_;
20 0           my $index_filename = $self->filename;
21 0           $index_filename =~ s/\.pack/.idx/;
22 0   0       my $index_fh = IO::File->new("> $index_filename") || die $!;
23              
24 0           my $iod = IO::Digest->new( $index_fh, 'SHA' );
25              
26 0           my $offsets = $self->create_index_offsets;
27 0           my @fan_out_table;
28 0           for my $sha1 ( sort keys %$offsets ) {
29 0           my $offset = $offsets->{$sha1};
30 0           my $slot = unpack( 'C', pack( 'H*', $sha1 ) );
31 0           $fan_out_table[$slot]++;
32             }
33 0           for my $i ( 0 .. 255 ) {
34 0 0 0       $index_fh->print( pack( 'N', $fan_out_table[$i] || 0 ) ) || die $!;
35 0   0       $fan_out_table[ $i + 1 ] += $fan_out_table[$i] || 0;
36             }
37 0           for my $sha1 ( sort keys %$offsets ) {
38 0           my $offset = $offsets->{$sha1};
39 0 0         $index_fh->print( pack( 'N', $offset ) ) || die $!;
40 0 0         $index_fh->print( pack( 'H*', $sha1 ) ) || die $!;
41             }
42              
43             # read the pack checksum from the end of the pack file
44 0           my $size = -s $self->filename;
45 0           my $fh = $self->fh;
46 0 0         $fh->seek( $size - 20, 0 ) || die $!;
47 0   0       my $read = $fh->read( my $pack_sha1, 20 ) || die $!;
48              
49 0 0         $index_fh->print($pack_sha1) || die $!;
50 0 0         $index_fh->print( $iod->digest ) || die $!;
51              
52 0 0         $index_fh->close() || die $!;
53             }
54              
55             sub create_index_offsets {
56 0     0 0   my ($self) = @_;
57 0           my $fh = $self->fh;
58              
59 0           $fh->read( my $signature, 4 );
60 0           $fh->read( my $version, 4 );
61 0           $version = unpack( 'N', $version );
62 0           $fh->read( my $objects, 4 );
63 0           $objects = unpack( 'N', $objects );
64              
65 0           my %offsets;
66 0           $self->offsets( \%offsets );
67              
68 0           for my $i ( 1 .. $objects ) {
69 0   0       my $offset = $fh->tell || die "Error telling filehandle: $!";
70 0           my $obj_offset = $offset;
71 0 0         $fh->read( my $c, 1 ) || die "Error reading from pack: $!";
72 0   0       $c = unpack( 'C', $c ) || die $!;
73 0           $offset++;
74              
75 0           my $size = ( $c & 0xf );
76 0           my $type_number = ( $c >> 4 ) & 7;
77 0   0       my $type = $TYPES[$type_number]
78             || confess
79             "invalid type $type_number at offset $offset, size $size";
80              
81 0           my $shift = 4;
82              
83 0           while ( ( $c & 0x80 ) != 0 ) {
84 0 0         $fh->read( $c, 1 ) || die $!;
85 0   0       $c = unpack( 'C', $c ) || die $!;
86 0           $offset++;
87 0           $size |= ( ( $c & 0x7f ) << $shift );
88 0           $shift += 7;
89             }
90              
91 0           my $content;
92              
93 0 0 0       if ( $type eq 'ofs_delta' || $type eq 'ref_delta' ) {
    0 0        
      0        
      0        
94 0           ( $type, $size, $content )
95             = $self->unpack_deltified( $type, $offset, $obj_offset, $size,
96             \%offsets );
97             } elsif ( $type eq 'commit'
98             || $type eq 'tree'
99             || $type eq 'blob'
100             || $type eq 'tag' )
101             {
102 0           $content = $self->read_compressed( $offset, $size );
103             } else {
104 0           confess "invalid type $type";
105             }
106              
107 0           my $raw = $type . ' ' . $size . "\0" . $content;
108 0           my $sha1 = Digest::SHA->new;
109 0           $sha1->add($raw);
110 0           my $sha1_hex = $sha1->hexdigest;
111 0           $offsets{$sha1_hex} = $obj_offset;
112             }
113              
114 0           return \%offsets;
115             }
116              
117             sub get_object {
118 0     0 0   my ( $self, $want_sha1 ) = @_;
119 0           my $offset = $self->offsets->{$want_sha1};
120 0 0         return unless $offset;
121 0           return $self->unpack_object($offset);
122             }
123              
124             1;
125              
126             __END__
127              
128             =pod
129              
130             =encoding UTF-8
131              
132             =head1 NAME
133              
134             Cogit::Pack::WithoutIndex
135              
136             =head1 VERSION
137              
138             version 0.001001
139              
140             =head1 AUTHOR
141              
142             Arthur Axel "fREW" Schmidt <cogit@afoolishmanifesto.com>
143              
144             =head1 COPYRIGHT AND LICENSE
145              
146             This software is copyright (c) 2017 by Arthur Axel "fREW" Schmidt.
147              
148             This is free software; you can redistribute it and/or modify it under
149             the same terms as the Perl 5 programming language system itself.
150              
151             =cut