/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to model.py

  • Committer: Robert Collins
  • Date: 2010-05-04 06:46:59 UTC
  • mto: This revision was merged to the branch mainline in revision 5206.
  • Revision ID: robertc@robertcollins.net-20100504064659-d5ybq23qlzov7w90
Document what note does a little.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
19
 
import os
20
 
import subprocess
21
 
import tarfile
22
 
 
23
 
from bzrlib.plugins.git import errors
24
 
 
25
 
 
26
 
class GitModel(object):
27
 
    """API that follows GIT model closely"""
28
 
 
29
 
    def __init__(self, git_dir):
30
 
        self.git_dir = git_dir
31
 
 
32
 
    def git_command(self, command, args):
33
 
        return ['git', command] + args
34
 
 
35
 
    def git_lines(self, command, args):
36
 
        cmd = self.git_command(command, args)
37
 
        env = os.environ.copy()
38
 
        env['GIT_DIR'] = self.git_dir
39
 
        p = subprocess.Popen(cmd,
40
 
                             stdout=subprocess.PIPE,
41
 
                             stderr=subprocess.PIPE,
42
 
                             env=env)
43
 
        lines = p.stdout.readlines()
44
 
        if p.wait() != 0:
45
 
            raise errors.GitCommandError(cmd, p.returncode,
46
 
                                         p.stderr.read().strip())
47
 
        return lines
48
 
 
49
 
    def git_line(self, command, args):
50
 
        lines = self.git_lines(command, args)
51
 
        return lines[0]
52
 
 
53
 
    def cat_file(self, type, object_id, pretty=False):
54
 
        args = []
55
 
        if pretty:
56
 
            args.append('-p')
57
 
        else:
58
 
            args.append(type)
59
 
        args.append(object_id)
60
 
        return self.git_lines('cat-file', args)
61
 
 
62
 
    def rev_list(self, heads, max_count=None, header=False, parents=False,
63
 
                 topo_order=False, paths=None):
64
 
        args = []
65
 
        if max_count is not None:
66
 
            args.append('--max-count=%d' % max_count)
67
 
        if header:
68
 
            args.append('--header')
69
 
        if parents:
70
 
            args.append('--parents')
71
 
        if topo_order:
72
 
            args.append('--topo-order')
73
 
        if heads is None:
74
 
            args.append('--all')
75
 
        else:
76
 
            args.extend(heads)
77
 
        if paths is not None:
78
 
            args.append('--')
79
 
            args.extend(paths)
80
 
        return self.git_lines('rev-list', args)
81
 
 
82
 
    def rev_parse(self, git_id):
83
 
        args = ['--verify', git_id]
84
 
        return self.git_line('rev-parse', args).strip()
85
 
 
86
 
    def get_head(self):
87
 
        try:
88
 
            return self.rev_parse('HEAD')
89
 
        except errors.GitCommandError, e:
90
 
            # Most likely, this is a null branch, so treat it as such
91
 
            if e.stderr == 'fatal: Needed a single revision':
92
 
                return None
93
 
            raise
94
 
 
95
 
    def get_revision_graph(self, revisions):
96
 
        ancestors = {}
97
 
        for line in self.rev_list(revisions, parents=True):
98
 
            entries = line.split()
99
 
            ancestors[entries[0]] = entries[1:]
100
 
        return ancestors
101
 
 
102
 
    def get_ancestry(self, revisions):
103
 
        args = ['--topo-order', '--reverse'] + revisions
104
 
        return [line[:-1] for line in self.git_lines('rev-list', args)]
105
 
 
106
 
    def ancestor_lines(self, revisions):
107
 
        revision_lines = []
108
 
        for line in self.rev_list(revisions, header=True):
109
 
            if line.startswith('\x00'):
110
 
                yield revision_lines
111
 
                revision_lines = [line[1:].decode('latin-1')]
112
 
            else:
113
 
                revision_lines.append(line.decode('latin-1'))
114
 
        assert revision_lines == ['']
115
 
 
116
 
    def get_inventory(self, tree_id):
117
 
        for line in self.git_lines('ls-tree', ['-r', '-t', tree_id]):
118
 
            # Ideally, we would use -z so we would not have to handle escaped
119
 
            # file names. But then we could not use readlines() to split the
120
 
            # data as it is read.
121
 
            permissions, type, hash_and_path = line.split(' ', 2)
122
 
            hash, name = hash_and_path.split('\t', 1)
123
 
            name = name[:-1] # strip trailing newline
124
 
            if name.startswith('"'):
125
 
                name = name[1:-1].decode('string_escape')
126
 
            name = name.decode('utf-8')
127
 
            yield permissions, type, hash, name
128
 
 
129
 
    def get_tarpipe(self, tree_id):
130
 
        cmd = self.git_command('archive', [tree_id])
131
 
        env = os.environ.copy()
132
 
        env['GIT_DIR'] = self.git_dir
133
 
        p = subprocess.Popen(cmd,
134
 
                             stdin=subprocess.PIPE,
135
 
                             stdout=subprocess.PIPE,
136
 
                             stderr=subprocess.PIPE,
137
 
                             env=env)
138
 
        p.stdin.close()
139
 
        tarpipe = TarPipe.open(mode='r|', fileobj=p.stdout)
140
 
        def close_callback():
141
 
            if p.wait() != 0:
142
 
                raise errors.GitCommandError(cmd, p.returncode,
143
 
                                             p.stderr.read().strip())
144
 
        tarpipe.set_close_callback(close_callback)
145
 
        return tarpipe
146
 
 
147
 
 
148
 
class TarPipe(tarfile.TarFile):
149
 
 
150
 
    def set_close_callback(self, close_callback):
151
 
        self.__close_callback = close_callback
152
 
 
153
 
    def close(self):
154
 
        super(TarPipe, self).close()
155
 
        self.__close_callback()