aboutsummaryrefslogtreecommitdiffstats
path: root/lib/LXRng/Repo/Git.pm
blob: 36194277b9c069deef5173b650d6296002e639e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package LXRng::Repo::Git;

use strict;
use Memoize;
use LXRng::Cached;
use LXRng::Repo::Git::Iterator;
use LXRng::Repo::Git::File;
use LXRng::Repo::Git::Directory;

sub _git_cmd {
    my ($self, $cmd, @args) = @_;

    my $git;
    my $pid = open($git, "-|");
    die $! unless defined $pid;
    if ($pid == 0) {
	$ENV{'GIT_DIR'} = $$self{'root'};
	exec('git', $cmd, @args);
	warn $!;
	kill(9, $$);
    }
    return $git;
}

sub new {
    my ($class, $root, %args) = @_;

    memoize('_release_timestamp');

    return bless({root => $root, %args}, $class);
}

sub cache_key {
    my ($self) = @_;

    return $$self{'root'};
}

sub _release_timestamp {
    my ($self, $release) = @_;

    my $cinfo = $self->_git_cmd('cat-file', 'commit', $release);

    my $time;
    while (<$cinfo>) {
	$time = $1 if /^author .*? (\d+(?: [-+]\d+|))$/ ;
	$time ||= $1 if /^committer .*? (\d+(?: [-+]\d+|))$/ ;
    }
    
    return $time;
}

sub _use_author_timestamp {
    my ($self) = @_;

    return $$self{'author_timestamp'};
}

sub _sort_key {
    my ($v) = @_;

    $v =~ s/(\d+)/sprintf("%05d", $1)/ge;
    return $v;
}

sub allversions {
    my ($self) = @_;

    cached {
	my @tags;
	my $tags = $self->_git_cmd('tag', '-l');
	while (<$tags>) {
	    chomp;
	    next if $$self{'release_re'} and $_ !~ $$self{'release_re'};
	    push(@tags, $_);
	}

	return (sort {_sort_key($b) cmp _sort_key($a) } @tags);
    };
}

sub node {
    my ($self, $path, $release, $rev) = @_;

    $path =~ s,^/+,,;
    $path =~ s,/+$,,;

    if ($path eq '') {
	open(my $tag, '<', $$self{'root'}.'/refs/tags/'.$release)
	    or return undef;
	my $ref = <$tag>;
	close($tag);
	chomp($ref);
	return LXRng::Repo::Git::Directory->new($self, '', $ref);
    }

    my $type;
    if ($rev) {
	$type = 'blob';
    }
    else {
	my $git = $self->_git_cmd('ls-tree', $release, $path);
	my ($mode, $gitpath);
	($mode, $type, $rev, $gitpath) = split(" ", <$git>);
    }

    if ($type eq 'tree') {
	return LXRng::Repo::Git::Directory->new($self, $path, $rev, $release);
    }
    elsif ($type eq 'blob') {
	return LXRng::Repo::Git::File->new($self, $path, $rev, $release);
    }
    else {
	return undef;
    }
}

sub iterator {
    my ($self, $release) = @_;

    return LXRng::Repo::Git::Iterator->new($self, $release);
}

1;