~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: John Arbash Meinel
  • Date: 2007-04-28 15:04:17 UTC
  • mfrom: (2466 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2566.
  • Revision ID: john@arbash-meinel.com-20070428150417-trp3pi0pzd411pu4
[merge] bzr.dev 2466

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
        revision as _mod_revision,
36
36
        transport,
37
37
        tree,
 
38
        tsort,
38
39
        ui,
39
40
        urlutils,
40
41
        )
100
101
    def __init__(self, *ignored, **ignored_too):
101
102
        self.tags = self._make_tags()
102
103
        self._revision_history_cache = None
 
104
        self._revision_id_to_revno_cache = None
103
105
 
104
106
    def break_lock(self):
105
107
        """Break a lock if one is present from another instance.
195
197
    def get_physical_lock_status(self):
196
198
        raise NotImplementedError(self.get_physical_lock_status)
197
199
 
 
200
    @needs_read_lock
 
201
    def get_revision_id_to_revno_map(self):
 
202
        """Return the revision_id => dotted revno map.
 
203
 
 
204
        This will be regenerated on demand, but will be cached.
 
205
 
 
206
        :return: A dictionary mapping revision_id => dotted revno.
 
207
            This dictionary should not be modified by the caller.
 
208
        """
 
209
        if self._revision_id_to_revno_cache is not None:
 
210
            mapping = self._revision_id_to_revno_cache
 
211
        else:
 
212
            mapping = self._gen_revno_map()
 
213
            self._cache_revision_id_to_revno(mapping)
 
214
        # TODO: jam 20070417 Since this is being cached, should we be returning
 
215
        #       a copy?
 
216
        # I would rather not, and instead just declare that users should not
 
217
        # modify the return value.
 
218
        return mapping
 
219
 
 
220
    def _gen_revno_map(self):
 
221
        """Create a new mapping from revision ids to dotted revnos.
 
222
 
 
223
        Dotted revnos are generated based on the current tip in the revision
 
224
        history.
 
225
        This is the worker function for get_revision_id_to_revno_map, which
 
226
        just caches the return value.
 
227
 
 
228
        :return: A dictionary mapping revision_id => dotted revno.
 
229
        """
 
230
        last_revision = self.last_revision()
 
231
        revision_graph = self.repository.get_revision_graph(last_revision)
 
232
        merge_sorted_revisions = tsort.merge_sort(
 
233
            revision_graph,
 
234
            last_revision,
 
235
            None,
 
236
            generate_revno=True)
 
237
        revision_id_to_revno = dict((rev_id, revno)
 
238
                                    for seq_num, rev_id, depth, revno, end_of_merge
 
239
                                     in merge_sorted_revisions)
 
240
        return revision_id_to_revno
 
241
 
 
242
    def leave_lock_in_place(self):
 
243
        """Tell this branch object not to release the physical lock when this
 
244
        object is unlocked.
 
245
        
 
246
        If lock_write doesn't return a token, then this method is not supported.
 
247
        """
 
248
        self.control_files.leave_in_place()
 
249
 
 
250
    def dont_leave_lock_in_place(self):
 
251
        """Tell this branch object to release the physical lock when this
 
252
        object is unlocked, even if it didn't originally acquire it.
 
253
 
 
254
        If lock_write doesn't return a token, then this method is not supported.
 
255
        """
 
256
        self.control_files.dont_leave_in_place()
 
257
 
198
258
    def abspath(self, name):
199
259
        """Return absolute filename for something in the branch
200
260
        
328
388
        """
329
389
        self._revision_history_cache = rev_history
330
390
 
 
391
    def _cache_revision_id_to_revno(self, revision_id_to_revno):
 
392
        """Set the cached revision_id => revno map to revision_id_to_revno.
 
393
 
 
394
        This API is semi-public; it only for use by subclasses, all other code
 
395
        should consider it to be private.
 
396
        """
 
397
        self._revision_id_to_revno_cache = revision_id_to_revno
 
398
 
331
399
    def _clear_cached_state(self):
332
400
        """Clear any cached data on this branch, e.g. cached revision history.
333
401
 
338
406
        should consider it to be private.
339
407
        """
340
408
        self._revision_history_cache = None
 
409
        self._revision_id_to_revno_cache = None
341
410
 
342
411
    def _gen_revision_history(self):
343
412
        """Return sequence of revision hashes on to this branch.
445
514
        try:
446
515
            return history.index(revision_id) + 1
447
516
        except ValueError:
448
 
            raise bzrlib.errors.NoSuchRevision(self, revision_id)
 
517
            raise errors.NoSuchRevision(self, revision_id)
449
518
 
450
519
    def get_rev_id(self, revno, history=None):
451
520
        """Find the revision id of the specified revno."""
454
523
        if history is None:
455
524
            history = self.revision_history()
456
525
        if revno <= 0 or revno > len(history):
457
 
            raise bzrlib.errors.NoSuchRevision(self, revno)
 
526
            raise errors.NoSuchRevision(self, revno)
458
527
        return history[revno - 1]
459
528
 
460
529
    def pull(self, source, overwrite=False, stop_revision=None):
563
632
 
564
633
    def get_push_location(self):
565
634
        """Return the None or the location to push this branch to."""
566
 
        raise NotImplementedError(self.get_push_location)
 
635
        push_loc = self.get_config().get_user_option('push_location')
 
636
        return push_loc
567
637
 
568
638
    def set_push_location(self, location):
569
639
        """Set a new push location for this branch."""
691
761
 
692
762
    def _get_checkout_format(self):
693
763
        """Return the most suitable metadir for a checkout of this branch.
694
 
        Weaves are used if this branch's repostory uses weaves.
 
764
        Weaves are used if this branch's repository uses weaves.
695
765
        """
696
766
        if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
697
767
            from bzrlib.repofmt import weaverepo
797
867
        """Return the current default format."""
798
868
        return klass._default_format
799
869
 
 
870
    def get_reference(self, a_bzrdir):
 
871
        """Get the target reference of the branch in a_bzrdir.
 
872
 
 
873
        format probing must have been completed before calling
 
874
        this method - it is assumed that the format of the branch
 
875
        in a_bzrdir is correct.
 
876
 
 
877
        :param a_bzrdir: The bzrdir to get the branch data from.
 
878
        :return: None if the branch is not a reference branch.
 
879
        """
 
880
        return None
 
881
 
800
882
    def get_format_string(self):
801
883
        """Return the ASCII format string that identifies this format."""
802
884
        raise NotImplementedError(self.get_format_string)
1033
1115
        if not _found:
1034
1116
            format = BranchFormat.find_format(a_bzrdir)
1035
1117
            assert format.__class__ == self.__class__
1036
 
        transport = a_bzrdir.get_branch_transport(None)
1037
 
        control_files = lockable_files.LockableFiles(transport, 'lock',
1038
 
                                                     lockdir.LockDir)
1039
 
        return BzrBranch5(_format=self,
1040
 
                          _control_files=control_files,
1041
 
                          a_bzrdir=a_bzrdir,
1042
 
                          _repository=a_bzrdir.find_repository())
 
1118
        try:
 
1119
            transport = a_bzrdir.get_branch_transport(None)
 
1120
            control_files = lockable_files.LockableFiles(transport, 'lock',
 
1121
                                                         lockdir.LockDir)
 
1122
            return BzrBranch5(_format=self,
 
1123
                              _control_files=control_files,
 
1124
                              a_bzrdir=a_bzrdir,
 
1125
                              _repository=a_bzrdir.find_repository())
 
1126
        except NoSuchFile:
 
1127
            raise NotBranchError(path=transport.base)
1043
1128
 
1044
1129
 
1045
1130
class BzrBranchFormat6(BzrBranchFormat5):
1109
1194
        """See BranchFormat.get_format_description()."""
1110
1195
        return "Checkout reference format 1"
1111
1196
        
 
1197
    def get_reference(self, a_bzrdir):
 
1198
        """See BranchFormat.get_reference()."""
 
1199
        transport = a_bzrdir.get_branch_transport(None)
 
1200
        return transport.get('location').read()
 
1201
 
1112
1202
    def initialize(self, a_bzrdir, target_branch=None):
1113
1203
        """Create a branch of this format in a_bzrdir."""
1114
1204
        if target_branch is None:
1136
1226
            # emit some sort of warning/error to the caller ?!
1137
1227
        return clone
1138
1228
 
1139
 
    def open(self, a_bzrdir, _found=False):
 
1229
    def open(self, a_bzrdir, _found=False, location=None):
1140
1230
        """Return the branch that the branch reference in a_bzrdir points at.
1141
1231
 
1142
1232
        _found is a private parameter, do not use it. It is used to indicate
1145
1235
        if not _found:
1146
1236
            format = BranchFormat.find_format(a_bzrdir)
1147
1237
            assert format.__class__ == self.__class__
1148
 
        transport = a_bzrdir.get_branch_transport(None)
1149
 
        real_bzrdir = bzrdir.BzrDir.open(transport.get('location').read())
 
1238
        if location is None:
 
1239
            location = self.get_reference(a_bzrdir)
 
1240
        real_bzrdir = bzrdir.BzrDir.open(location)
1150
1241
        result = real_bzrdir.open_branch()
1151
1242
        # this changes the behaviour of result.clone to create a new reference
1152
1243
        # rather than a copy of the content of the branch.
1223
1314
    def is_locked(self):
1224
1315
        return self.control_files.is_locked()
1225
1316
 
1226
 
    def lock_write(self):
1227
 
        self.repository.lock_write()
 
1317
    def lock_write(self, token=None):
 
1318
        repo_token = self.repository.lock_write()
1228
1319
        try:
1229
 
            self.control_files.lock_write()
 
1320
            token = self.control_files.lock_write(token=token)
1230
1321
        except:
1231
1322
            self.repository.unlock()
1232
1323
            raise
 
1324
        return token
1233
1325
 
1234
1326
    def lock_read(self):
1235
1327
        self.repository.lock_read()
1286
1378
    def set_revision_history(self, rev_history):
1287
1379
        """See Branch.set_revision_history."""
1288
1380
        rev_history = [osutils.safe_revision_id(r) for r in rev_history]
 
1381
        self._clear_cached_state()
1289
1382
        self._write_revision_history(rev_history)
1290
1383
        self._cache_revision_history(rev_history)
1291
1384
        for hook in Branch.hooks['set_rh']:
1484
1577
        except errors.InvalidURLJoin, e:
1485
1578
            raise errors.InaccessibleParent(parent, self.base)
1486
1579
 
1487
 
    def get_push_location(self):
1488
 
        """See Branch.get_push_location."""
1489
 
        push_loc = self.get_config().get_user_option('push_location')
1490
 
        return push_loc
1491
 
 
1492
1580
    def set_push_location(self, location):
1493
1581
        """See Branch.set_push_location."""
1494
1582
        self.get_config().set_user_option(
1508
1596
                try: 
1509
1597
                    url = url.encode('ascii')
1510
1598
                except UnicodeEncodeError:
1511
 
                    raise bzrlib.errors.InvalidURL(url,
 
1599
                    raise errors.InvalidURL(url,
1512
1600
                        "Urls must be 7-bit ascii, "
1513
1601
                        "use bzrlib.urlutils.escape")
1514
1602
            url = urlutils.relative_url(self.base, url)
1728
1816
        return "Experimental branch format"
1729
1817
 
1730
1818
    @classmethod
 
1819
    def get_reference(cls, a_bzrdir):
 
1820
        """Get the target reference of the branch in a_bzrdir.
 
1821
 
 
1822
        format probing must have been completed before calling
 
1823
        this method - it is assumed that the format of the branch
 
1824
        in a_bzrdir is correct.
 
1825
 
 
1826
        :param a_bzrdir: The bzrdir to get the branch data from.
 
1827
        :return: None if the branch is not a reference branch.
 
1828
        """
 
1829
        return None
 
1830
 
 
1831
    @classmethod
1731
1832
    def _initialize_control_files(cls, a_bzrdir, utf8_files, lock_filename,
1732
1833
            lock_class):
1733
1834
        branch_transport = a_bzrdir.get_branch_transport(cls)
1965
2066
    easy to identify.
1966
2067
    """
1967
2068
 
1968
 
    def __init__(self, transport_server, transport_readonly_server, formats):
 
2069
    def __init__(self, transport_server, transport_readonly_server, formats,
 
2070
        vfs_transport_factory=None):
1969
2071
        self._transport_server = transport_server
1970
2072
        self._transport_readonly_server = transport_readonly_server
1971
2073
        self._formats = formats