/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 branch.py

  • Committer: Robert Collins
  • Date: 2007-07-15 15:40:37 UTC
  • mto: (2592.3.33 repository)
  • mto: This revision was merged to the branch mainline in revision 2624.
  • Revision ID: robertc@robertcollins.net-20070715154037-3ar8g89decddc9su
Make GraphIndex accept nodes as key, value, references, so that the method
signature is closer to what a simple key->value index delivers. Also
change the behaviour when the reference list count is zero to accept
key, value as nodes, and emit key, value to make it identical in that case
to a simple key->value index. This may not be a good idea, but for now it
seems ok.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007 Canonical Ltd
2
 
# Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
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
 
"""An adapter between a Git Branch and a Bazaar Branch"""
19
 
 
20
 
from dulwich.objects import (
21
 
    Commit,
22
 
    Tag,
23
 
    )
24
 
 
25
 
from bzrlib import (
26
 
    branch,
27
 
    config,
28
 
    foreign,
29
 
    repository,
30
 
    revision,
31
 
    tag,
32
 
    transport,
33
 
    )
34
 
from bzrlib.decorators import (
35
 
    needs_read_lock,
36
 
    )
37
 
from bzrlib.trace import (
38
 
    is_quiet,
39
 
    mutter,
40
 
    )
41
 
 
42
 
from bzrlib.plugins.git.config import (
43
 
    GitBranchConfig,
44
 
    )
45
 
from bzrlib.plugins.git.errors import (
46
 
    NoSuchRef,
47
 
    )
48
 
 
49
 
try:
50
 
    from bzrlib.foreign import ForeignBranch
51
 
except ImportError:
52
 
    class ForeignBranch(branch.Branch):
53
 
        def __init__(self, mapping):
54
 
            self.mapping = mapping
55
 
            super(ForeignBranch, self).__init__()
56
 
 
57
 
 
58
 
class GitPullResult(branch.PullResult):
59
 
 
60
 
    def _lookup_revno(self, revid):
61
 
        assert isinstance(revid, str), "was %r" % revid
62
 
        # Try in source branch first, it'll be faster
63
 
        return self.target_branch.revision_id_to_revno(revid)
64
 
 
65
 
    @property
66
 
    def old_revno(self):
67
 
        return self._lookup_revno(self.old_revid)
68
 
 
69
 
    @property
70
 
    def new_revno(self):
71
 
        return self._lookup_revno(self.new_revid)
72
 
 
73
 
 
74
 
class LocalGitTagDict(tag.BasicTags):
75
 
    """Dictionary with tags in a local repository."""
76
 
 
77
 
    def __init__(self, branch):
78
 
        self.branch = branch
79
 
        self.repository = branch.repository
80
 
 
81
 
    def get_tag_dict(self):
82
 
        ret = {}
83
 
        for k,v in self.repository._git.tags.iteritems():
84
 
            obj = self.repository._git.get_object(v)
85
 
            while isinstance(obj, Tag):
86
 
                v = obj.object[1]
87
 
                obj = self.repository._git.get_object(v)
88
 
            if not isinstance(obj, Commit):
89
 
                mutter("Tag %s points at object %r that is not a commit, "
90
 
                       "ignoring", k, obj)
91
 
                continue
92
 
            ret[k] = self.branch.mapping.revision_id_foreign_to_bzr(v)
93
 
        return ret
94
 
 
95
 
    def set_tag(self, name, revid):
96
 
        self.repository._git.tags[name] = revid
97
 
 
98
 
 
99
 
class GitBranchFormat(branch.BranchFormat):
100
 
 
101
 
    def get_format_description(self):
102
 
        return 'Git Branch'
103
 
 
104
 
    def supports_tags(self):
105
 
        return True
106
 
 
107
 
    def make_tags(self, branch):
108
 
        if getattr(branch.repository, "get_refs", None) is not None:
109
 
            from bzrlib.plugins.git.remote import RemoteGitTagDict
110
 
            return RemoteGitTagDict(branch)
111
 
        else:
112
 
            return LocalGitTagDict(branch)
113
 
 
114
 
 
115
 
class GitBranch(ForeignBranch):
116
 
    """An adapter to git repositories for bzr Branch objects."""
117
 
 
118
 
    def __init__(self, bzrdir, repository, name, head, lockfiles):
119
 
        self.repository = repository
120
 
        self._format = GitBranchFormat()
121
 
        self.control_files = lockfiles
122
 
        self.bzrdir = bzrdir
123
 
        super(GitBranch, self).__init__(repository.get_mapping())
124
 
        self.name = name
125
 
        self.head = head
126
 
        self.base = bzrdir.transport.base
127
 
 
128
 
    def _get_nick(self, local=False, possible_master_transports=None):
129
 
        """Find the nick name for this branch.
130
 
 
131
 
        :return: Branch nick
132
 
        """
133
 
        return self.name
134
 
 
135
 
    def _set_nick(self, nick):
136
 
        raise NotImplementedError
137
 
 
138
 
    nick = property(_get_nick, _set_nick)
139
 
 
140
 
    def __repr__(self):
141
 
        return "%s(%r, %r)" % (self.__class__.__name__, self.repository.base, self.name)
142
 
 
143
 
    def dpull(self, source, stop_revision=None):
144
 
        if stop_revision is None:
145
 
            stop_revision = source.last_revision()
146
 
        # FIXME: Check for diverged branches
147
 
        revidmap = self.repository.dfetch(source.repository, stop_revision)
148
 
        if revidmap != {}:
149
 
            self.generate_revision_history(revidmap[stop_revision])
150
 
        return revidmap
151
 
 
152
 
    def generate_revision_history(self, revid, old_revid=None):
153
 
        # FIXME: Check that old_revid is in the ancestry of revid
154
 
        newhead, self.mapping = self.mapping.revision_id_bzr_to_foreign(revid)
155
 
        self._set_head(newhead)
156
 
 
157
 
    def _set_head(self, head):
158
 
        self.head = head
159
 
        self.repository._git.set_ref(self.name, self.head)
160
 
 
161
 
    def lock_write(self):
162
 
        self.control_files.lock_write()
163
 
 
164
 
    def get_stacked_on_url(self):
165
 
        # Git doesn't do stacking (yet...)
166
 
        return None
167
 
 
168
 
    def get_parent(self):
169
 
        """See Branch.get_parent()."""
170
 
        # FIXME: Set "origin" url from .git/config ?
171
 
        return None
172
 
 
173
 
    def set_parent(self, url):
174
 
        # FIXME: Set "origin" url in .git/config ?
175
 
        pass
176
 
 
177
 
    def lock_read(self):
178
 
        self.control_files.lock_read()
179
 
 
180
 
    def unlock(self):
181
 
        self.control_files.unlock()
182
 
 
183
 
    def get_physical_lock_status(self):
184
 
        return False
185
 
 
186
 
 
187
 
class LocalGitBranch(GitBranch):
188
 
    """A local Git branch."""
189
 
 
190
 
    @needs_read_lock
191
 
    def last_revision(self):
192
 
        # perhaps should escape this ?
193
 
        if self.head is None:
194
 
            return revision.NULL_REVISION
195
 
        return self.mapping.revision_id_foreign_to_bzr(self.head)
196
 
 
197
 
    def _get_checkout_format(self):
198
 
        """Return the most suitable metadir for a checkout of this branch.
199
 
        Weaves are used if this branch's repository uses weaves.
200
 
        """
201
 
        format = self.repository.bzrdir.checkout_metadir()
202
 
        format.set_branch_format(self._format)
203
 
        return format
204
 
 
205
 
    def create_checkout(self, to_location, revision_id=None, lightweight=False,
206
 
        accelerator_tree=None, hardlink=False):
207
 
        if lightweight:
208
 
            t = transport.get_transport(to_location)
209
 
            t.ensure_base()
210
 
            format = self._get_checkout_format()
211
 
            checkout = format.initialize_on_transport(t)
212
 
            from_branch = branch.BranchReferenceFormat().initialize(checkout, 
213
 
                self)
214
 
            tree = checkout.create_workingtree(revision_id,
215
 
                from_branch=from_branch, hardlink=hardlink)
216
 
            return tree
217
 
        else:
218
 
            return self._create_heavyweight_checkout(to_location, revision_id,
219
 
            hardlink)
220
 
 
221
 
    def _create_heavyweight_checkout(self, to_location, revision_id=None, 
222
 
                                     hardlink=False):
223
 
        """Create a new heavyweight checkout of this branch.
224
 
 
225
 
        :param to_location: URL of location to create the new checkout in.
226
 
        :param revision_id: Revision that should be the tip of the checkout.
227
 
        :param hardlink: Whether to hardlink
228
 
        :return: WorkingTree object of checkout.
229
 
        """
230
 
        checkout_branch = BzrDir.create_branch_convenience(
231
 
            to_location, force_new_tree=False, format=get_rich_root_format())
232
 
        checkout = checkout_branch.bzrdir
233
 
        checkout_branch.bind(self)
234
 
        # pull up to the specified revision_id to set the initial 
235
 
        # branch tip correctly, and seed it with history.
236
 
        checkout_branch.pull(self, stop_revision=revision_id)
237
 
        return checkout.create_workingtree(revision_id, hardlink=hardlink)
238
 
 
239
 
    def _gen_revision_history(self):
240
 
        if self.head is None:
241
 
            return []
242
 
        ret = list(self.repository.iter_reverse_revision_history(
243
 
            self.last_revision()))
244
 
        ret.reverse()
245
 
        return ret
246
 
 
247
 
    def get_config(self):
248
 
        return GitBranchConfig(self)
249
 
 
250
 
    def get_push_location(self):
251
 
        """See Branch.get_push_location."""
252
 
        push_loc = self.get_config().get_user_option('push_location')
253
 
        return push_loc
254
 
 
255
 
    def set_push_location(self, location):
256
 
        """See Branch.set_push_location."""
257
 
        self.get_config().set_user_option('push_location', location,
258
 
                                          store=config.STORE_LOCATION)
259
 
 
260
 
    def supports_tags(self):
261
 
        return True
262
 
 
263
 
 
264
 
class GitBranchPullResult(branch.PullResult):
265
 
 
266
 
    def report(self, to_file):
267
 
        if not is_quiet():
268
 
            if self.old_revid == self.new_revid:
269
 
                to_file.write('No revisions to pull.\n')
270
 
            else:
271
 
                to_file.write('Now on revision %d (git sha: %s).\n' % 
272
 
                        (self.new_revno, self.new_git_head))
273
 
        self._show_tag_conficts(to_file)
274
 
 
275
 
 
276
 
class InterGitGenericBranch(branch.InterBranch):
277
 
    """InterBranch implementation that pulls from Git into bzr."""
278
 
 
279
 
    @classmethod
280
 
    def is_compatible(self, source, target):
281
 
        return (isinstance(source, GitBranch) and 
282
 
                not isinstance(target, GitBranch))
283
 
 
284
 
    def update_revisions(self, stop_revision=None, overwrite=False,
285
 
        graph=None):
286
 
        """See InterBranch.update_revisions()."""
287
 
        interrepo = repository.InterRepository.get(self.source.repository, 
288
 
            self.target.repository)
289
 
        self._head = None
290
 
        self._last_revid = None
291
 
        def determine_wants(heads):
292
 
            if not self.source.name in heads:
293
 
                raise NoSuchRef(self.source.name, heads.keys())
294
 
            if stop_revision is not None:
295
 
                self._last_revid = stop_revision
296
 
                self._head, mapping = self.source.repository.lookup_git_revid(
297
 
                    stop_revision)
298
 
            else:
299
 
                self._head = heads[self.source.name]
300
 
                self._last_revid = \
301
 
                    self.source.mapping.revision_id_foreign_to_bzr(self._head)
302
 
            if self.target.repository.has_revision(self._last_revid):
303
 
                return []
304
 
            return [self._head]
305
 
        interrepo.fetch_objects(determine_wants, self.source.mapping)
306
 
        if overwrite:
307
 
            prev_last_revid = None
308
 
        else:
309
 
            prev_last_revid = self.target.last_revision()
310
 
        self.target.generate_revision_history(self._last_revid, prev_last_revid)
311
 
 
312
 
    def pull(self, overwrite=False, stop_revision=None,
313
 
             possible_transports=None, _hook_master=None, run_hooks=True,
314
 
             _override_hook_target=None):
315
 
        """See Branch.pull.
316
 
 
317
 
        :param _hook_master: Private parameter - set the branch to
318
 
            be supplied as the master to pull hooks.
319
 
        :param run_hooks: Private parameter - if false, this branch
320
 
            is being called because it's the master of the primary branch,
321
 
            so it should not run its hooks.
322
 
        :param _override_hook_target: Private parameter - set the branch to be
323
 
            supplied as the target_branch to pull hooks.
324
 
        """
325
 
        result = GitBranchPullResult()
326
 
        result.source_branch = self.source
327
 
        if _override_hook_target is None:
328
 
            result.target_branch = self.target
329
 
        else:
330
 
            result.target_branch = _override_hook_target
331
 
        self.source.lock_read()
332
 
        try:
333
 
            # We assume that during 'pull' the target repository is closer than
334
 
            # the source one.
335
 
            graph = self.target.repository.get_graph(self.source.repository)
336
 
            result.old_revno, result.old_revid = \
337
 
                self.target.last_revision_info()
338
 
            self.update_revisions(stop_revision, overwrite=overwrite, 
339
 
                graph=graph)
340
 
            result.new_git_head = self._head
341
 
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
342
 
                overwrite)
343
 
            result.new_revno, result.new_revid = self.target.last_revision_info()
344
 
            if _hook_master:
345
 
                result.master_branch = _hook_master
346
 
                result.local_branch = result.target_branch
347
 
            else:
348
 
                result.master_branch = result.target_branch
349
 
                result.local_branch = None
350
 
            if run_hooks:
351
 
                for hook in branch.Branch.hooks['post_pull']:
352
 
                    hook(result)
353
 
        finally:
354
 
            self.source.unlock()
355
 
        return result
356
 
 
357
 
 
358
 
 
359
 
 
360
 
branch.InterBranch.register_optimiser(InterGitGenericBranch)
361
 
 
362
 
 
363
 
class InterGitRemoteLocalBranch(branch.InterBranch):
364
 
    """InterBranch implementation that pulls between Git branches."""
365
 
 
366
 
    @classmethod
367
 
    def is_compatible(self, source, target):
368
 
        from bzrlib.plugins.git.remote import RemoteGitBranch
369
 
        return (isinstance(source, RemoteGitBranch) and 
370
 
                isinstance(target, LocalGitBranch))
371
 
 
372
 
    def pull(self, stop_revision=None, overwrite=False, 
373
 
        possible_transports=None):
374
 
        result = GitPullResult()
375
 
        result.source_branch = self.source
376
 
        result.target_branch = self.target
377
 
        interrepo = repository.InterRepository.get(self.source.repository, 
378
 
            self.target.repository)
379
 
        result.old_revid = self.target.last_revision()
380
 
        if stop_revision is None:
381
 
            stop_revision = self.source.last_revision()
382
 
        interrepo.fetch(revision_id=stop_revision)
383
 
        self.target.generate_revision_history(stop_revision, result.old_revid)
384
 
        result.new_revid = self.target.last_revision()
385
 
        return result
386
 
 
387
 
 
388
 
branch.InterBranch.register_optimiser(InterGitRemoteLocalBranch)