diff options
Diffstat (limited to 'lib/LXRng/Repo/Git')
-rw-r--r-- | lib/LXRng/Repo/Git/Directory.pm | 56 | ||||
-rw-r--r-- | lib/LXRng/Repo/Git/File.pm | 80 | ||||
-rw-r--r-- | lib/LXRng/Repo/Git/Iterator.pm | 33 | ||||
-rw-r--r-- | lib/LXRng/Repo/Git/TarFile.pm | 98 |
4 files changed, 267 insertions, 0 deletions
diff --git a/lib/LXRng/Repo/Git/Directory.pm b/lib/LXRng/Repo/Git/Directory.pm new file mode 100644 index 0000000..592e608 --- /dev/null +++ b/lib/LXRng/Repo/Git/Directory.pm @@ -0,0 +1,56 @@ +package LXRng::Repo::Git::Directory; + +use strict; + +use base qw(LXRng::Repo::Directory); + +sub new { + my ($class, $repo, $name, $ref, $rel) = @_; + + $name =~ s,/*$,/,; + return bless({repo => $repo, name => $name, ref => $ref, rel => $rel}, + $class); +} + +sub time { + my ($self) = @_; + + return 0; +# return $$self{'stat'}[9]; +} + +sub size { + my ($self) = @_; + + return ''; +} + +sub contents { + my ($self) = @_; + + my $git = $$self{'repo'}->_git_cmd('ls-tree', $$self{'ref'}); + + my $prefix = $$self{'name'}; + $prefix =~ s,^/+,,; + my (@dirs, @files); + while (<$git>) { + chomp; + my ($mode, $type, $ref, $node) = split(" ", $_); + if ($type eq 'tree') { + push(@dirs, LXRng::Repo::Git::Directory->new($$self{'repo'}, + $prefix.$node, + $ref, + $$self{'rel'})); + } + elsif ($type eq 'blob') { + push(@files, LXRng::Repo::Git::File->new($$self{'repo'}, + $prefix.$node, + $ref, + $$self{'rel'})); + } + } + + return (@dirs, @files); +} + +1; diff --git a/lib/LXRng/Repo/Git/File.pm b/lib/LXRng/Repo/Git/File.pm new file mode 100644 index 0000000..b0bb9a3 --- /dev/null +++ b/lib/LXRng/Repo/Git/File.pm @@ -0,0 +1,80 @@ +package LXRng::Repo::Git::File; + +use strict; + +use base qw(LXRng::Repo::File); +use LXRng::Repo::TmpFile; +use File::Temp qw(tempdir); + +sub new { + my ($class, $repo, $name, $ref, $rel) = @_; + + return bless({repo => $repo, name => $name, ref => $ref, rel => $rel}, + $class); +} + +sub time { + my ($self) = @_; + + if ($$self{'repo'}->_use_author_timestamp) { + # This is painfully slow. It is only performed index-time, + # but that might stil be bad enough that you would want to + # just use the release-timestamp insted. + my $cinfo = $$self{'repo'}->_git_cmd('log', '--pretty=raw', + '--max-count=1', '--all', + '..'.$$self{'rel'}, + '--', $self->name); + + my $time; + while (<$cinfo>) { + $time = $1 if /^author .*? (\d+(?: [-+]\d+|))$/ ; + $time ||= $1 if /^committer .*? (\d+(?: [-+]\d+|))$/ ; + } + + return $time if $time; + } + + return $$self{'repo'}->_release_timestamp($$self{'rel'}); +} + +sub size { + my ($self) = @_; + + my $git = $$self{'repo'}->_git_cmd('cat-file', '-s', $$self{'ref'}); + my $size = <$git>; + close($git); + chomp($size); + return $size; +} + +sub handle { + my ($self) = @_; + + return $$self{'repo'}->_git_cmd('cat-file', 'blob', $$self{'ref'}); +} + +sub revision { + my ($self) = @_; + + return $$self{'ref'}; +} + +sub phys_path { + my ($self) = @_; + + my $tmpdir = tempdir() or die($!); + open(my $phys, ">", $tmpdir.'/'.$self->node) or die($!); + + my $handle = $self->handle(); + my $buf = ''; + while (sysread($handle, $buf, 64*1024) > 0) { + print($phys $buf) or die($!); + } + close($handle); + close($phys) or die($!); + + return LXRng::Repo::TmpFile->new(dir => $tmpdir, + node => $self->node); +} + +1; diff --git a/lib/LXRng/Repo/Git/Iterator.pm b/lib/LXRng/Repo/Git/Iterator.pm new file mode 100644 index 0000000..978e584 --- /dev/null +++ b/lib/LXRng/Repo/Git/Iterator.pm @@ -0,0 +1,33 @@ +package LXRng::Repo::Git::Iterator; + +use strict; +use LXRng::Repo::Git::File; + +sub new { + my ($class, $repo, $release) = @_; + + my @refs; + my $git = $repo->_git_cmd('ls-tree', '-r', $release); + while (<$git>) { + if (/\S+\s+blob\s+(\S+)\s+(\S+)/) { + push(@refs, [$2, $1]); + } + } + close($git); + + return bless({refs => \@refs, repo => $repo, rel => $release}, $class); +} + +sub next { + my ($self) = @_; + + return undef unless @{$$self{'refs'}} > 0; + my $file = shift(@{$$self{'refs'}}); + + return LXRng::Repo::Git::File->new($$self{'repo'}, + $$file[0], + $$file[1], + $$self{'rel'}); +} + +1; diff --git a/lib/LXRng/Repo/Git/TarFile.pm b/lib/LXRng/Repo/Git/TarFile.pm new file mode 100644 index 0000000..33af87d --- /dev/null +++ b/lib/LXRng/Repo/Git/TarFile.pm @@ -0,0 +1,98 @@ +package LXRng::Repo::Git::TarFile; + +use strict; +use File::Temp qw(tempdir); +use Fcntl qw(F_GETFD F_SETFD FD_CLOEXEC); + +use base qw(LXRng::Repo::File); + +sub new { + my ($class, $tar, $ref) = @_; + + return bless({tar => $tar, ref => $ref}, $class); +} + +sub name { + my ($self) = @_; + + return $$self{'tar'}->name(); +} + +sub node { + my ($self) = @_; + + $self->name =~ m,.*/([^/]+), and return $1; +} + +sub time { + my ($self) = @_; + + return $$self{'tar'}->mtime(); +} + +sub size { + my ($self) = @_; + + return $$self{'tar'}->size; +} + +sub phys_path { + my ($self) = @_; + + my $tmpdir = tempdir() or die($!); + open(my $phys, ">", $tmpdir.'/'.$self->node); + + my $data = $$self{'tar'}->get_content_by_ref(); + my $len = $$self{'tar'}->size(); + my $pos = 0; + while ($pos < $len) { + print($phys substr($$data, $pos, 64*1024)); + $pos += 64*1024; + } + close($phys); + + return LXRng::Repo::Git::TarFile::Virtual->new(dir => $tmpdir, + node => $self->node); +} + +sub handle { + my ($self) = @_; + + my $data = $$self{'tar'}->get_content_by_ref(); + open(my $fh, "<", $data); + + return $fh; +} + +sub revision { + my ($self) = @_; + + $$self{'ref'} ||= $self->time.'.'.$self->size; + return $$self{'ref'}; +} + +package LXRng::Repo::Git::TarFile::Virtual; + +use strict; +use overload '""' => \&filename; + +sub new { + my ($class, %args) = @_; + + return bless(\%args, $class); +} + +sub filename { + my ($self) = @_; + + return $$self{'dir'}.'/'.$$self{'node'}; +} + +sub DESTROY { + my ($self) = @_; + unlink($$self{'dir'}.'/'.$$self{'node'}); + rmdir($$self{'dir'}); +# kill(9, $$self{'pid'}); +} + +1; |