aboutsummaryrefslogtreecommitdiffstats
path: root/lib/LXRng/Repo/Git
diff options
context:
space:
mode:
Diffstat (limited to 'lib/LXRng/Repo/Git')
-rw-r--r--lib/LXRng/Repo/Git/Directory.pm56
-rw-r--r--lib/LXRng/Repo/Git/File.pm80
-rw-r--r--lib/LXRng/Repo/Git/Iterator.pm33
-rw-r--r--lib/LXRng/Repo/Git/TarFile.pm98
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;