~jelmer/bzr-svn/svn-1.5

« back to all changes in this revision

Viewing changes to branch.py

  • Committer: Jelmer Vernooij
  • Date: 2008-07-07 11:29:11 UTC
  • mfrom: (1196.1.245 0.4)
  • Revision ID: jelmer@samba.org-20080707112911-fca6wpxr457n690x
MergeĀ 0.4.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
from bzrlib.branch import Branch, BranchFormat, BranchCheckResult, PullResult
20
20
from bzrlib.bzrdir import BzrDir
21
21
from bzrlib.errors import (NoSuchFile, DivergedBranches, NoSuchRevision, 
22
 
                           NotBranchError, UnstackableBranchFormat)
 
22
                           NoSuchTag, NotBranchError, UnstackableBranchFormat,
 
23
                           UnrelatedBranches)
23
24
from bzrlib.inventory import (Inventory)
24
25
from bzrlib.revision import is_null, ensure_null, NULL_REVISION
 
26
from bzrlib.tag import BasicTags
 
27
from bzrlib.trace import mutter
25
28
from bzrlib.workingtree import WorkingTree
26
29
 
27
 
from bzrlib.plugins.svn import core
 
30
from bzrlib.plugins.svn import core, wc
28
31
from bzrlib.plugins.svn.auth import create_auth_baton
29
32
from bzrlib.plugins.svn.client import Client, get_config
30
33
from bzrlib.plugins.svn.commit import push
35
38
from bzrlib.plugins.svn.repository import SvnRepository
36
39
from bzrlib.plugins.svn.transport import bzr_to_svn_url
37
40
 
 
41
import os
38
42
 
39
43
class FakeControlFiles(object):
40
44
    """Dummy implementation of ControlFiles.
51
55
        pass
52
56
 
53
57
 
 
58
class SubversionTags(BasicTags):
 
59
    def __init__(self, branch, layout=None, project=""):
 
60
        self.branch = branch
 
61
        self.repository = branch.repository
 
62
        self.layout = layout or self.repository.get_layout()
 
63
        self.project = project
 
64
 
 
65
    def set_tag(self, tag_name, tag_target):
 
66
        path = self.layout.get_tag_path(tag_name, self.project)
 
67
        parent = urlutils.dirname(path)
 
68
        try:
 
69
            (from_bp, from_revnum, mapping) = self.repository.lookup_revision_id(tag_target)
 
70
        except NoSuchRevision:
 
71
            mutter("not setting tag %s; unknown revision %s", tag_name, tag_target)
 
72
            return
 
73
        if from_bp == path:
 
74
            return
 
75
        conn = self.repository.transport.connections.get(urlutils.join(self.repository.base, parent))
 
76
        deletefirst = (conn.check_path(urlutils.basename(path), self.repository.get_latest_revnum()) != core.NODE_NONE)
 
77
        try:
 
78
            ci = conn.get_commit_editor({"svn:log": "Add tag %s" % tag_name})
 
79
            try:
 
80
                root = ci.open_root()
 
81
                if deletefirst:
 
82
                    root.delete_entry(urlutils.basename(path))
 
83
                root.add_directory(urlutils.basename(path), urlutils.join(self.repository.base, from_bp), from_revnum)
 
84
                root.close()
 
85
            except:
 
86
                ci.abort()
 
87
                raise
 
88
            ci.close()
 
89
        finally:
 
90
            self.repository.transport.add_connection(conn)
 
91
 
 
92
    def lookup_tag(self, tag_name):
 
93
        try:
 
94
            return self.get_tag_dict()[tag_name]
 
95
        except KeyError:
 
96
            raise NoSuchTag(tag_name)
 
97
 
 
98
    def get_tag_dict(self):
 
99
        return self.repository.find_tags(project=self.project, 
 
100
                                         layout=self.layout)
 
101
 
 
102
    def get_reverse_tag_dict(self):
 
103
        """Returns a dict with revisions as keys
 
104
           and a list of tags for that revision as value"""
 
105
        d = self.get_tag_dict()
 
106
        rev = {}
 
107
        for key in d:
 
108
            try:
 
109
                rev[d[key]].append(key)
 
110
            except KeyError:
 
111
                rev[d[key]] = [key]
 
112
        return rev
 
113
 
 
114
    def delete_tag(self, tag_name):
 
115
        path = self.layout.get_tag_path(tag_name, self.project)
 
116
        parent = urlutils.dirname(path)
 
117
        conn = self.repository.transport.connections.get(urlutils.join(self.repository.base, parent))
 
118
        if conn.check_path(urlutils.basename(path), self.repository.get_latest_revnum()) != core.NODE_DIR:
 
119
            raise NoSuchTag(tag_name)
 
120
        try:
 
121
            ci = conn.get_commit_editor({"svn:log": "Remove tag %s" % tag_name})
 
122
            try:
 
123
                root = ci.open_root()
 
124
                root.delete_entry(urlutils.basename(path))
 
125
                root.close()
 
126
            except:
 
127
                ci.abort()
 
128
                raise
 
129
            ci.close()
 
130
        finally:
 
131
            self.repository.transport.add_connection(conn)
 
132
 
 
133
    def _set_tag_dict(self, dest_dict):
 
134
        cur_dict = self.get_tag_dict()
 
135
        for k,v in dest_dict.iteritems():
 
136
            if cur_dict.get(k) != v:
 
137
                self.set_tag(k, v)
 
138
        for k in cur_dict:
 
139
            if k not in dest_dict:
 
140
                self.delete_tag(k)
 
141
 
 
142
 
54
143
class SvnBranch(Branch):
55
144
    """Maps to a Branch in a Subversion repository """
56
145
    def __init__(self, repository, branch_path):
62
151
        :param revnum: Subversion revision number of the branch to 
63
152
            look at; none for latest.
64
153
        """
 
154
        self.repository = repository
65
155
        super(SvnBranch, self).__init__()
66
 
        self.repository = repository
67
156
        assert isinstance(self.repository, SvnRepository)
68
157
        self.control_files = FakeControlFiles()
69
158
        self._format = SvnBranchFormat()
86
175
        if not self.mapping.is_branch(branch_path):
87
176
            raise NotSvnBranchPath(branch_path, mapping=self.mapping)
88
177
 
 
178
    def _make_tags(self):
 
179
        return SubversionTags(self)
 
180
 
89
181
    def set_branch_path(self, branch_path):
90
182
        """Change the branch path for this branch.
91
183
 
102
194
 
103
195
        :param relpath: path from the repository root.
104
196
        """
105
 
        assert relpath.startswith(self.get_branch_path())
 
197
        assert relpath.startswith(self.get_branch_path()), \
 
198
                "expected %s prefix, got %s" % (self.get_branch_path(), relpath)
106
199
        return relpath[len(self.get_branch_path()):].strip("/")
107
200
 
108
201
    def get_branch_path(self, revnum=None):
180
273
        :param revision_id: Tip of the checkout.
181
274
        :return: WorkingTree object of the checkout.
182
275
        """
183
 
        if revision_id is None:
184
 
            rev = "HEAD"
 
276
        from bzrlib.plugins.svn.workingtree import update_wc
 
277
        if revision_id is not None:
 
278
            revnum = self.lookup_revision_id(revision_id)
185
279
        else:
186
 
            rev = self.lookup_revision_id(revision_id)
 
280
            revnum = self.get_revnum()
187
281
 
188
282
        svn_url = bzr_to_svn_url(self.base)
189
 
        client_ctx = Client(auth=create_auth_baton(svn_url))
190
 
        client_ctx.checkout(svn_url, to_location, rev, "HEAD", True)
191
 
 
192
 
        return WorkingTree.open(to_location)
 
283
        os.mkdir(to_location)
 
284
        wc.ensure_adm(to_location, self.repository.uuid, svn_url,
 
285
                      bzr_to_svn_url(self.repository.base), revnum)
 
286
        adm = wc.WorkingCopy(None, to_location, write_lock=True)
 
287
        try:
 
288
            conn = self.repository.transport.connections.get(svn_url)
 
289
            try:
 
290
                update_wc(adm, to_location, conn, revnum)
 
291
            finally:
 
292
                if not conn.busy:
 
293
                    self.repository.transport.add_connection(conn)
 
294
        finally:
 
295
            adm.close()
 
296
        wt = WorkingTree.open(to_location)
 
297
        return wt
193
298
 
194
299
    def create_checkout(self, to_location, revision_id=None, lightweight=False,
195
300
                        accelerator_tree=None, hardlink=False):
232
337
    def set_last_revision_info(self, revno, revid):
233
338
        """See Branch.set_last_revision_info()."""
234
339
 
 
340
    def mainline_missing_revisions(self, other, stop_revision):
 
341
        missing = []
 
342
        lastrevid = self.last_revision()
 
343
        for revid in other.repository.iter_reverse_revision_history(stop_revision):
 
344
            if lastrevid == revid:
 
345
                missing.reverse()
 
346
                return missing
 
347
            missing.append(revid)
 
348
        raise UnrelatedBranches()
 
349
 
235
350
    def last_revision_info(self):
236
351
        """See Branch.last_revision_info()."""
237
352
        last_revid = self.last_revision()
308
423
                    raise NotImplementedError('overwrite not supported for '
309
424
                                              'Subversion branches')
310
425
                raise
 
426
            result.tag_conflicts = source.tags.merge_to(self.tags, overwrite)
311
427
            (result.new_revno, result.new_revid) = self.last_revision_info()
312
428
            return result
313
429
        finally:
362
478
                                                       self.last_revision()):
363
479
                return
364
480
            raise DivergedBranches(self, other)
365
 
        todo = self.repository.lhs_missing_revisions(other.revision_history(), 
366
 
                                                     stop_revision)
 
481
        todo = self.mainline_missing_revisions(other, stop_revision)
367
482
        pb = ui.ui_factory.nested_progress_bar()
368
483
        try:
369
484
            for revid in todo:
439
554
    def __str__(self):
440
555
        return '%s(%r)' % (self.__class__.__name__, self.base)
441
556
 
 
557
    def supports_tags(self):
 
558
        return self._format.supports_tags()
 
559
 
442
560
    __repr__ = __str__
443
561
 
444
562
 
466
584
        """See BranchFormat.initialize()."""
467
585
        raise NotImplementedError(self.initialize)
468
586
 
 
587
    def supports_tags(self):
 
588
        return True