~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-07-14 08:21:19 UTC
  • mfrom: (3517.4.20 stacking)
  • Revision ID: pqm@pqm.ubuntu.com-20080714082119-ju6qe5weo8pp7f1c
merge integrated branch stacking

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
from bzrlib.lazy_import import lazy_import
19
19
lazy_import(globals(), """
 
20
from itertools import chain
20
21
from bzrlib import (
21
22
        bzrdir,
22
23
        cache_utf8,
33
34
        urlutils,
34
35
        )
35
36
from bzrlib.config import BranchConfig
 
37
from bzrlib.repofmt.pack_repo import RepositoryFormatPackDevelopment1Subtree
36
38
from bzrlib.tag import (
37
39
    BasicTags,
38
40
    DisabledTags,
86
88
        self._revision_history_cache = None
87
89
        self._revision_id_to_revno_cache = None
88
90
        self._last_revision_info_cache = None
 
91
        self._open_hook()
 
92
 
 
93
    def _open_hook(self):
 
94
        """Called by init to allow simpler extension of the base class."""
89
95
 
90
96
    def break_lock(self):
91
97
        """Break a lock if one is present from another instance.
325
331
            raise errors.InvalidRevisionNumber(revno)
326
332
        return self.repository.get_revision_delta(rh[revno-1])
327
333
 
 
334
    def get_stacked_on(self):
 
335
        """Get the URL this branch is stacked against.
 
336
 
 
337
        :raises NotStacked: If the branch is not stacked.
 
338
        :raises UnstackableBranchFormat: If the branch does not support
 
339
            stacking.
 
340
        """
 
341
        raise NotImplementedError(self.get_stacked_on)
 
342
 
328
343
    def print_file(self, file, revision_id):
329
344
        """Print `file` to stdout."""
330
345
        raise NotImplementedError(self.print_file)
332
347
    def set_revision_history(self, rev_history):
333
348
        raise NotImplementedError(self.set_revision_history)
334
349
 
 
350
    def set_stacked_on(self, url):
 
351
        """Set the URL this branch is stacked against.
 
352
 
 
353
        :raises UnstackableBranchFormat: If the branch does not support
 
354
            stacking.
 
355
        :raises UnstackableRepositoryFormat: If the repository does not support
 
356
            stacking.
 
357
        """
 
358
        raise NotImplementedError(self.set_stacked_on)
 
359
 
335
360
    def _cache_revision_history(self, rev_history):
336
361
        """Set the cached revision history to rev_history.
337
362
 
1207
1232
        return "Bazaar-NG branch format 4"
1208
1233
 
1209
1234
 
1210
 
class BzrBranchFormat5(BranchFormat):
 
1235
class BranchFormatMetadir(BranchFormat):
 
1236
    """Common logic for meta-dir based branch formats."""
 
1237
 
 
1238
    def _branch_class(self):
 
1239
        """What class to instantiate on open calls."""
 
1240
        raise NotImplementedError(self._branch_class)
 
1241
 
 
1242
    def open(self, a_bzrdir, _found=False):
 
1243
        """Return the branch object for a_bzrdir.
 
1244
 
 
1245
        _found is a private parameter, do not use it. It is used to indicate
 
1246
               if format probing has already be done.
 
1247
        """
 
1248
        if not _found:
 
1249
            format = BranchFormat.find_format(a_bzrdir)
 
1250
            if format.__class__ != self.__class__:
 
1251
                raise AssertionError("wrong format %r found for %r" %
 
1252
                    (format, self))
 
1253
        try:
 
1254
            transport = a_bzrdir.get_branch_transport(None)
 
1255
            control_files = lockable_files.LockableFiles(transport, 'lock',
 
1256
                                                         lockdir.LockDir)
 
1257
            return self._branch_class()(_format=self,
 
1258
                              _control_files=control_files,
 
1259
                              a_bzrdir=a_bzrdir,
 
1260
                              _repository=a_bzrdir.find_repository())
 
1261
        except errors.NoSuchFile:
 
1262
            raise errors.NotBranchError(path=transport.base)
 
1263
 
 
1264
    def __init__(self):
 
1265
        super(BranchFormatMetadir, self).__init__()
 
1266
        self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
 
1267
 
 
1268
    def supports_tags(self):
 
1269
        return True
 
1270
 
 
1271
 
 
1272
class BzrBranchFormat5(BranchFormatMetadir):
1211
1273
    """Bzr branch format 5.
1212
1274
 
1213
1275
    This format has:
1220
1282
    This format is new in bzr 0.8.
1221
1283
    """
1222
1284
 
 
1285
    def _branch_class(self):
 
1286
        return BzrBranch5
 
1287
 
1223
1288
    def get_format_string(self):
1224
1289
        """See BranchFormat.get_format_string()."""
1225
1290
        return "Bazaar-NG branch format 5\n"
1235
1300
                      ]
1236
1301
        return self._initialize_helper(a_bzrdir, utf8_files)
1237
1302
 
1238
 
    def __init__(self):
1239
 
        super(BzrBranchFormat5, self).__init__()
1240
 
        self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
1241
 
 
1242
 
    def open(self, a_bzrdir, _found=False):
1243
 
        """Return the branch object for a_bzrdir
1244
 
 
1245
 
        _found is a private parameter, do not use it. It is used to indicate
1246
 
               if format probing has already be done.
1247
 
        """
1248
 
        if not _found:
1249
 
            format = BranchFormat.find_format(a_bzrdir)
1250
 
            if format.__class__ != self.__class__:
1251
 
                raise AssertionError("wrong format %r found for %r" %
1252
 
                    (format, self))
1253
 
        try:
1254
 
            transport = a_bzrdir.get_branch_transport(None)
1255
 
            control_files = lockable_files.LockableFiles(transport, 'lock',
1256
 
                                                         lockdir.LockDir)
1257
 
            return BzrBranch5(_format=self,
1258
 
                              _control_files=control_files,
1259
 
                              a_bzrdir=a_bzrdir,
1260
 
                              _repository=a_bzrdir.find_repository())
1261
 
        except errors.NoSuchFile:
1262
 
            raise errors.NotBranchError(path=transport.base)
1263
 
 
1264
 
 
1265
 
class BzrBranchFormat6(BzrBranchFormat5):
 
1303
    def supports_tags(self):
 
1304
        return False
 
1305
 
 
1306
 
 
1307
class BzrBranchFormat6(BranchFormatMetadir):
1266
1308
    """Branch format with last-revision and tags.
1267
1309
 
1268
1310
    Unlike previous formats, this has no explicit revision history. Instead,
1273
1315
    and became the default in 0.91.
1274
1316
    """
1275
1317
 
 
1318
    def _branch_class(self):
 
1319
        return BzrBranch6
 
1320
 
1276
1321
    def get_format_string(self):
1277
1322
        """See BranchFormat.get_format_string()."""
1278
1323
        return "Bazaar Branch Format 6 (bzr 0.15)\n"
1289
1334
                      ]
1290
1335
        return self._initialize_helper(a_bzrdir, utf8_files)
1291
1336
 
1292
 
    def open(self, a_bzrdir, _found=False):
1293
 
        """Return the branch object for a_bzrdir
1294
 
 
1295
 
        _found is a private parameter, do not use it. It is used to indicate
1296
 
               if format probing has already be done.
1297
 
        """
1298
 
        if not _found:
1299
 
            format = BranchFormat.find_format(a_bzrdir)
1300
 
            if format.__class__ != self.__class__:
1301
 
                raise AssertionError("wrong format %r found for %r" %
1302
 
                    (format, self))
1303
 
        transport = a_bzrdir.get_branch_transport(None)
1304
 
        control_files = lockable_files.LockableFiles(transport, 'lock',
1305
 
                                                     lockdir.LockDir)
1306
 
        return BzrBranch6(_format=self,
1307
 
                          _control_files=control_files,
1308
 
                          a_bzrdir=a_bzrdir,
1309
 
                          _repository=a_bzrdir.find_repository())
1310
 
 
1311
 
    def supports_tags(self):
1312
 
        return True
 
1337
 
 
1338
class BzrBranchFormat7(BranchFormatMetadir):
 
1339
    """Branch format with last-revision, tags, and a stacked location pointer.
 
1340
 
 
1341
    The stacked location pointer is passed down to the repository and requires
 
1342
    a repository format with supports_external_lookups = True.
 
1343
 
 
1344
    This format was introduced in bzr 1.6.
 
1345
    """
 
1346
 
 
1347
    def _branch_class(self):
 
1348
        return BzrBranch7
 
1349
 
 
1350
    def get_format_string(self):
 
1351
        """See BranchFormat.get_format_string()."""
 
1352
        return "Bazaar Branch Format 7 (needs bzr 1.6)\n"
 
1353
 
 
1354
    def get_format_description(self):
 
1355
        """See BranchFormat.get_format_description()."""
 
1356
        return "Branch format 7"
 
1357
 
 
1358
    def initialize(self, a_bzrdir):
 
1359
        """Create a branch of this format in a_bzrdir."""
 
1360
        utf8_files = [('last-revision', '0 null:\n'),
 
1361
                      ('branch.conf', ''),
 
1362
                      ('tags', ''),
 
1363
                      ]
 
1364
        return self._initialize_helper(a_bzrdir, utf8_files)
 
1365
 
 
1366
    def __init__(self):
 
1367
        super(BzrBranchFormat7, self).__init__()
 
1368
        self._matchingbzrdir.repository_format = \
 
1369
            RepositoryFormatPackDevelopment1Subtree()
1313
1370
 
1314
1371
 
1315
1372
class BranchReferenceFormat(BranchFormat):
1403
1460
# and not independently creatable, so are not registered.
1404
1461
__format5 = BzrBranchFormat5()
1405
1462
__format6 = BzrBranchFormat6()
 
1463
__format7 = BzrBranchFormat7()
1406
1464
BranchFormat.register_format(__format5)
1407
1465
BranchFormat.register_format(BranchReferenceFormat())
1408
1466
BranchFormat.register_format(__format6)
 
1467
BranchFormat.register_format(__format7)
1409
1468
BranchFormat.set_default_format(__format6)
1410
1469
_legacy_formats = [BzrBranchFormat4(),
1411
1470
                   ]
1427
1486
    def __init__(self, _format=None,
1428
1487
                 _control_files=None, a_bzrdir=None, _repository=None):
1429
1488
        """Create new branch object at a particular location."""
1430
 
        Branch.__init__(self)
1431
1489
        if a_bzrdir is None:
1432
1490
            raise ValueError('a_bzrdir must be supplied')
1433
1491
        else:
1442
1500
        self.control_files = _control_files
1443
1501
        self._transport = _control_files._transport
1444
1502
        self.repository = _repository
 
1503
        Branch.__init__(self)
1445
1504
 
1446
1505
    def __str__(self):
1447
1506
        return '%s(%r)' % (self.__class__.__name__, self.base)
1778
1837
        except errors.InvalidURLJoin, e:
1779
1838
            raise errors.InaccessibleParent(parent, self.base)
1780
1839
 
 
1840
    def get_stacked_on(self):
 
1841
        raise errors.UnstackableBranchFormat(self._format, self.base)
 
1842
 
1781
1843
    def set_push_location(self, location):
1782
1844
        """See Branch.set_push_location."""
1783
1845
        self.get_config().set_user_option(
1809
1871
            self._transport.put_bytes('parent', url + '\n',
1810
1872
                mode=self.bzrdir._get_file_mode())
1811
1873
 
 
1874
    def set_stacked_on(self, url):
 
1875
        raise errors.UnstackableBranchFormat(self._format, self.base)
 
1876
 
1812
1877
 
1813
1878
class BzrBranch5(BzrBranch):
1814
1879
    """A format 5 branch. This supports new features over plain branches.
1816
1881
    It has support for a master_branch which is the data for bound branches.
1817
1882
    """
1818
1883
 
1819
 
    def __init__(self,
1820
 
                 _format,
1821
 
                 _control_files,
1822
 
                 a_bzrdir,
1823
 
                 _repository):
1824
 
        super(BzrBranch5, self).__init__(_format=_format,
1825
 
                                         _control_files=_control_files,
1826
 
                                         a_bzrdir=a_bzrdir,
1827
 
                                         _repository=_repository)
1828
 
        
1829
1884
    @needs_write_lock
1830
1885
    def pull(self, source, overwrite=False, stop_revision=None,
1831
1886
             run_hooks=True, possible_transports=None,
1947
2002
        return None
1948
2003
 
1949
2004
 
1950
 
class BzrBranch6(BzrBranch5):
 
2005
class BzrBranch7(BzrBranch5):
 
2006
    """A branch with support for a fallback repository."""
 
2007
 
 
2008
    def _get_fallback_repository(self, url):
 
2009
        """Get the repository we fallback to at url."""
 
2010
        return bzrdir.BzrDir.open(url).open_branch().repository
 
2011
 
 
2012
    def _activate_fallback_location(self, url):
 
2013
        """Activate the branch/repository from url as a fallback repository."""
 
2014
        self.repository.add_fallback_repository(
 
2015
            self._get_fallback_repository(url))
 
2016
 
 
2017
    def _open_hook(self):
 
2018
        try:
 
2019
            url = self.get_stacked_on()
 
2020
        except (errors.UnstackableRepositoryFormat, errors.NotStacked,
 
2021
            errors.UnstackableBranchFormat):
 
2022
            pass
 
2023
        else:
 
2024
            self._activate_fallback_location(url)
 
2025
 
 
2026
    def _check_stackable_repo(self):
 
2027
        if not self.repository._format.supports_external_lookups:
 
2028
            raise errors.UnstackableRepositoryFormat(self.repository._format,
 
2029
                self.repository.base)
1951
2030
 
1952
2031
    def __init__(self, *args, **kwargs):
1953
 
        super(BzrBranch6, self).__init__(*args, **kwargs)
 
2032
        super(BzrBranch7, self).__init__(*args, **kwargs)
 
2033
        self._last_revision_info_cache = None
1954
2034
        self._partial_revision_history_cache = []
1955
2035
 
1956
2036
    def _clear_cached_state(self):
1957
 
        super(BzrBranch6, self)._clear_cached_state()
 
2037
        super(BzrBranch7, self)._clear_cached_state()
 
2038
        self._last_revision_info_cache = None
1958
2039
        self._partial_revision_history_cache = []
1959
2040
 
1960
2041
    def _last_revision_info(self):
2097
2178
        """See Branch.get_old_bound_location"""
2098
2179
        return self._get_bound_location(False)
2099
2180
 
 
2181
    def get_stacked_on(self):
 
2182
        self._check_stackable_repo()
 
2183
        stacked_url = self._get_config_location('stacked_on_location')
 
2184
        if stacked_url is None:
 
2185
            raise errors.NotStacked(self)
 
2186
        return stacked_url
 
2187
 
2100
2188
    def set_append_revisions_only(self, enabled):
2101
2189
        if enabled:
2102
2190
            value = 'True'
2105
2193
        self.get_config().set_user_option('append_revisions_only', value,
2106
2194
            warn_masked=True)
2107
2195
 
 
2196
    def set_stacked_on(self, url):
 
2197
        self._check_stackable_repo()
 
2198
        if not url:
 
2199
            try:
 
2200
                old_url = self.get_stacked_on()
 
2201
            except (errors.NotStacked, errors.UnstackableBranchFormat,
 
2202
                errors.UnstackableRepositoryFormat):
 
2203
                return
 
2204
            url = ''
 
2205
            # repositories don't offer an interface to remove fallback
 
2206
            # repositories today; take the conceptually simpler option and just
 
2207
            # reopen it.
 
2208
            self.repository = self.bzrdir.find_repository()
 
2209
            # for every revision reference the branch has, ensure it is pulled
 
2210
            # in.
 
2211
            source_repository = self._get_fallback_repository(old_url)
 
2212
            for revision_id in chain([self.last_revision()],
 
2213
                self.tags.get_reverse_tag_dict()):
 
2214
                self.repository.fetch(source_repository, revision_id,
 
2215
                    find_ghosts=True)
 
2216
        else:
 
2217
            self._activate_fallback_location(url)
 
2218
        # write this out after the repository is stacked to avoid setting a
 
2219
        # stacked config that doesn't work.
 
2220
        self._set_config_location('stacked_on_location', url)
 
2221
 
2108
2222
    def _get_append_revisions_only(self):
2109
2223
        value = self.get_config().get_user_option('append_revisions_only')
2110
2224
        return value == 'True'
2185
2299
        return self.revno() - index
2186
2300
 
2187
2301
 
 
2302
class BzrBranch6(BzrBranch7):
 
2303
    """See BzrBranchFormat6 for the capabilities of this branch.
 
2304
 
 
2305
    This subclass of BzrBranch7 disables the new features BzrBranch7 added,
 
2306
    i.e. stacking.
 
2307
    """
 
2308
 
 
2309
    def get_stacked_on(self):
 
2310
        raise errors.UnstackableBranchFormat(self._format, self.base)
 
2311
 
 
2312
    def set_stacked_on(self, url):
 
2313
        raise errors.UnstackableBranchFormat(self._format, self.base)
 
2314
 
 
2315
 
2188
2316
######################################################################
2189
2317
# results of operations
2190
2318
 
2301
2429
        except errors.NoSuchFile:
2302
2430
            pass
2303
2431
        branch.set_bound_location(None)
 
2432
 
 
2433
 
 
2434
class Converter6to7(object):
 
2435
    """Perform an in-place upgrade of format 6 to format 7"""
 
2436
 
 
2437
    def convert(self, branch):
 
2438
        format = BzrBranchFormat7()
 
2439
        branch._set_config_location('stacked_on_location', '')
 
2440
        # update target format
 
2441
        branch._transport.put_bytes('format', format.get_format_string())