/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.200.1 by Robert Collins
Commit initial content.
1
# Copyright (C) 2006 Canonical Ltd
2
# Authors: Robert Collins <robert.collins@canonical.com>
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18
19
"""A GIT branch and repository format implementation for bzr."""
20
21
0.200.2 by Aaron Bentley
Get viz working, with new -r support
22
from StringIO import StringIO
23
0.200.1 by Robert Collins
Commit initial content.
24
import stgit
25
import stgit.git as git
26
0.200.4 by Aaron Bentley
Supply a BranchConfig instead of a Transport
27
from bzrlib import config, urlutils
0.200.1 by Robert Collins
Commit initial content.
28
from bzrlib.decorators import *
29
import bzrlib.branch
30
import bzrlib.bzrdir
31
import bzrlib.errors as errors
32
import bzrlib.repository
33
from bzrlib.revision import Revision
34
35
0.200.4 by Aaron Bentley
Supply a BranchConfig instead of a Transport
36
class GitBranchConfig(config.BranchConfig):
37
    """BranchConfig that uses locations.conf in place of branch.conf""" 
38
39
    def __init__(self, branch):
40
        config.BranchConfig.__init__(self, branch)
41
        # do not provide a BranchDataConfig
42
        self.option_sources = self.option_sources[0], self.option_sources[2]
43
44
    def set_user_option(self, name, value, local=False):
45
        """Force local to True"""
46
        config.BranchConfig.set_user_option(self, name, value, local=True)
0.200.2 by Aaron Bentley
Get viz working, with new -r support
47
48
0.200.1 by Robert Collins
Commit initial content.
49
def gitrevid_from_bzr(revision_id):
50
    return revision_id[4:]
51
52
53
def bzrrevid_from_git(revision_id):
54
    return "git:" + revision_id
55
56
57
class GitLock(object):
58
    """A lock that thunks through to Git."""
59
60
    def lock_write(self):
61
        pass
62
63
    def lock_read(self):
64
        pass
65
66
    def unlock(self):
67
        pass
68
69
70
class GitLockableFiles(bzrlib.lockable_files.LockableFiles):
71
    """Git specific lockable files abstraction."""
72
73
    def __init__(self, lock):
74
        self._lock = lock
75
        self._transaction = None
76
        self._lock_mode = None
77
        self._lock_count = 0
78
79
80
class GitDir(bzrlib.bzrdir.BzrDir):
81
    """An adapter to the '.git' dir used by git."""
82
83
    def __init__(self, transport, lockfiles, format):
84
        self._format = format
85
        self.root_transport = transport
86
        self.transport = transport.clone('.git')
87
        self._lockfiles = lockfiles
88
89
    def get_branch_transport(self, branch_format):
90
        if branch_format is None:
91
            return self.transport
92
        if isinstance(branch_format, GitBzrDirFormat):
93
            return self.transport
94
        raise errors.IncompatibleFormat(branch_format, self._format)
95
96
    get_repository_transport = get_branch_transport
97
    get_workingtree_transport = get_branch_transport
98
99
    def is_supported(self):
100
        return True
101
102
    def open_branch(self, ignored=None):
103
        """'crate' a branch for this dir."""
104
        return GitBranch(self, self._lockfiles)
105
106
    def open_repository(self, shared=False):
107
        """'open' a repository for this dir."""
108
        return GitRepository(self._gitrepo, self, self._lockfiles)
109
0.200.3 by Aaron Bentley
Avoid ugly errors opening working trees
110
    def open_workingtree(self):
111
        loc = urlutils.unescape_for_display(self.root_transport.base, 'ascii')
112
        raise errors.NoWorkingTree(loc)
113
0.200.1 by Robert Collins
Commit initial content.
114
115
class GitBzrDirFormat(bzrlib.bzrdir.BzrDirFormat):
116
    """The .git directory control format."""
117
118
    @classmethod
119
    def _known_formats(self):
120
        return set([GitBzrDirFormat()])
121
122
    def open(self, transport, _create=False, _found=None):
123
        """Open this directory.
124
        
125
        :param _create: create the git dir on the fly. private to GitDirFormat.
126
        """
127
        # we dont grok readonly - git isn't integrated with transport.
128
        url = transport.base
129
        if url.startswith('readonly+'):
130
            url = url[len('readonly+'):]
131
        if url.startswith('file://'):
132
            url = url[len('file://'):]
133
        url = url.encode('utf8')
134
        lockfiles = GitLockableFiles(GitLock())
135
        return GitDir(transport, lockfiles, self)
136
137
    @classmethod
138
    def probe_transport(klass, transport):
139
        """Our format is present if the transport ends in '.not/'."""
140
        # little ugly, but works
141
        format = klass() 
142
        # try a manual probe first, its a little faster perhaps ?
143
        if transport.has('.git'):
144
            return format
145
        # delegate to the main opening code. This pays a double rtt cost at the
146
        # moment, so perhaps we want probe_transport to return the opened thing
147
        # rather than an openener ? or we could return a curried thing with the
148
        # dir to open already instantiated ? Needs more thought.
149
        try:
150
            format.open(transport)
151
            return format
152
        except Exception, e:
153
            raise errors.NotBranchError(path=transport.base)
154
        raise errors.NotBranchError(path=transport.base)
155
156
157
bzrlib.bzrdir.BzrDirFormat.register_control_format(GitBzrDirFormat)
158
159
160
class GitBranch(bzrlib.branch.Branch):
161
    """An adapter to git repositories for bzr Branch objects."""
162
163
    def __init__(self, gitdir, lockfiles):
164
        self.bzrdir = gitdir
165
        self.control_files = lockfiles
166
        self.repository = GitRepository(gitdir, lockfiles)
167
        self.base = gitdir.root_transport.base
168
169
    def lock_write(self):
170
        self.control_files.lock_write()
171
172
    @needs_read_lock
173
    def last_revision(self):
174
        # perhaps should escape this ?
175
        return bzrrevid_from_git(git.get_head())
176
0.200.4 by Aaron Bentley
Supply a BranchConfig instead of a Transport
177
    @needs_read_lock
0.200.2 by Aaron Bentley
Get viz working, with new -r support
178
    def revision_history(self):
179
        history = [self.last_revision()]
180
        while True:
181
            revision = self.repository.get_revision(history[-1])
182
            if len(revision.parent_ids) == 0:
183
                break
184
            history.append(revision.parent_ids[0])
185
        return list(reversed(history))
186
0.200.4 by Aaron Bentley
Supply a BranchConfig instead of a Transport
187
    def get_config(self):
188
        return GitBranchConfig(self)
189
0.200.1 by Robert Collins
Commit initial content.
190
    def lock_read(self):
191
        self.control_files.lock_read()
192
193
    def unlock(self):
194
        self.control_files.unlock()
195
0.200.4 by Aaron Bentley
Supply a BranchConfig instead of a Transport
196
    def get_push_location(self):
197
        """See Branch.get_push_location."""
198
        push_loc = self.get_config().get_user_option('push_location')
199
        return push_loc
200
201
    def set_push_location(self, location):
202
        """See Branch.set_push_location."""
203
        self.get_config().set_user_option('push_location', location, 
204
                                          local=True)
205
0.200.1 by Robert Collins
Commit initial content.
206
207
class GitRepository(bzrlib.repository.Repository):
208
    """An adapter to git repositories for bzr."""
209
210
    def __init__(self, gitdir, lockfiles):
211
        self.bzrdir = gitdir
212
        self.control_files = lockfiles
213
214
    def get_revision(self, revision_id):
215
        raw = stgit.git._output_lines('git-rev-list --header --max-count=1 %s' % gitrevid_from_bzr(revision_id))
216
        # first field is the rev itself.
217
        # then its 'field value'
218
        # until the EOF??
219
        parents = []
220
        log = []
221
        in_log = False
222
        committer = None
223
        for field in raw[1:]:
224
            #if field.startswith('author '):
225
            #    committer = field[7:]
226
            if field.startswith('parent '):
227
                parents.append(bzrrevid_from_git(field.split()[1]))
228
            elif field.startswith('committer '):
229
                commit_fields = field.split()
230
                if committer is None:
231
                    committer = ' '.join(commit_fields[1:-3])
232
                timestamp = commit_fields[-2]
233
                timezone = commit_fields[-1]
234
            elif in_log:
235
                log.append(field)
236
            elif field == '\n':
237
                in_log = True
238
239
        log = ''.join(log)
240
        result = Revision(revision_id)
241
        result.parent_ids = parents
242
        result.message = log
243
        result.inventory_sha1 = ""
244
        result.timezone = timezone and int(timezone)
245
        result.timestamp = float(timestamp)
246
        result.committer = committer 
247
        return result