/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.200.19 by John Arbash Meinel
More refactoring. Add some direct tests for GitModel.
1
# Copyright (C) 2007 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""The model for interacting with the git process, etc."""
18
0.200.20 by John Arbash Meinel
All tests are passing again
19
import os
0.200.19 by John Arbash Meinel
More refactoring. Add some direct tests for GitModel.
20
import subprocess
21
0.200.27 by David Allouche
Flat is better than nested, remove the gitlib hierarchy.
22
from bzrlib.plugins.git import errors
0.200.19 by John Arbash Meinel
More refactoring. Add some direct tests for GitModel.
23
24
25
class GitModel(object):
26
    """API that follows GIT model closely"""
27
28
    def __init__(self, git_dir):
29
        self.git_dir = git_dir
30
31
    def git_command(self, command, args):
0.200.20 by John Arbash Meinel
All tests are passing again
32
        return ['git', command] + args
0.200.19 by John Arbash Meinel
More refactoring. Add some direct tests for GitModel.
33
34
    def git_lines(self, command, args):
35
        cmd = self.git_command(command, args)
0.200.20 by John Arbash Meinel
All tests are passing again
36
        env = os.environ.copy()
37
        env['GIT_DIR'] = self.git_dir
0.200.19 by John Arbash Meinel
More refactoring. Add some direct tests for GitModel.
38
        p = subprocess.Popen(cmd,
39
                             stdout=subprocess.PIPE,
0.200.20 by John Arbash Meinel
All tests are passing again
40
                             stderr=subprocess.PIPE,
41
                             env=env)
0.200.19 by John Arbash Meinel
More refactoring. Add some direct tests for GitModel.
42
        lines = p.stdout.readlines()
43
        if p.wait() != 0:
44
            raise errors.GitCommandError(cmd, p.returncode,
45
                                         p.stderr.read().strip())
46
        return lines
47
48
    def git_line(self, command, args):
49
        lines = self.git_lines(command, args)
50
        return lines[0]
51
52
    def cat_file(self, type, object_id, pretty=False):
53
        args = []
54
        if pretty:
55
            args.append('-p')
56
        else:
57
            args.append(type)
58
        args.append(object_id)
59
        return self.git_lines('cat-file', args)
60
61
    def rev_list(self, heads, max_count=None, header=False, parents=False):
62
        args = []
63
        if max_count is not None:
64
            args.append('--max-count=%d' % max_count)
65
        if header:
66
            args.append('--header')
67
        if parents:
68
            args.append('--parents')
69
        if heads is None:
70
            args.append('--all')
71
        else:
72
            args.extend(heads)
73
        return self.git_lines('rev-list', args)
74
75
    def rev_parse(self, git_id):
76
        args = ['--verify', git_id]
0.200.20 by John Arbash Meinel
All tests are passing again
77
        return self.git_line('rev-parse', args).strip()
0.200.19 by John Arbash Meinel
More refactoring. Add some direct tests for GitModel.
78
79
    def get_head(self):
80
        try:
81
            return self.rev_parse('HEAD')
82
        except errors.GitCommandError, e:
83
            # Most likely, this is a null branch, so treat it as such
84
            if e.stderr == 'fatal: Needed a single revision':
85
                return None
86
            raise
87
88
    def ancestry(self, revisions):
89
        ancestors = {}
90
        for line in self.rev_list(revisions, parents=True):
91
            entries = line.split()
92
            ancestors[entries[0]] = entries[1:]
93
        return ancestors
94
95
    def ancestor_lines(self, revisions):
96
        revision_lines = []
97
        for line in self.rev_list(revisions, header=True):
98
            if line.startswith('\x00'):
99
                yield revision_lines
100
                revision_lines = [line[1:].decode('latin-1')]
101
            else:
102
                revision_lines.append(line.decode('latin-1'))
103
        assert revision_lines == ['']
104
105
    def get_inventory(self, tree_id):
0.200.37 by David Allouche
Reimplement GitModel.get_inventory to retrieve the full inventory in a single git run.
106
        for line in self.git_lines('ls-tree', ['-r', '-t', tree_id]):
107
            # Ideally, we would use -z so we would not have to handle escaped
108
            # file names. But then we could not use readlines() to split the
109
            # data as it is read.
110
            permissions, type, hash_and_path = line.split(' ', 2)
111
            hash, name = hash_and_path.split('\t', 1)
112
            name = name[:-1] # strip trailing newline
0.200.19 by John Arbash Meinel
More refactoring. Add some direct tests for GitModel.
113
            if name.startswith('"'):
0.200.37 by David Allouche
Reimplement GitModel.get_inventory to retrieve the full inventory in a single git run.
114
                name = name[1:-1].decode('string_escape')
115
            name = name.decode('utf-8')
116
            yield permissions, type, hash, name