~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Marius Kruger
  • Date: 2010-07-10 21:28:56 UTC
  • mto: (5384.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5385.
  • Revision ID: marius.kruger@enerweb.co.za-20100710212856-uq4ji3go0u5se7hx
* Update documentation
* add NEWS

Show diffs side-by-side

added added

removed removed

Lines of Context:
86
86
    registry,
87
87
    symbol_versioning,
88
88
    )
89
 
 
90
 
 
91
 
class BzrDir(object):
 
89
    
 
90
    
 
91
class ControlComponent(object):
 
92
    """Abstract base class for control directory components.
 
93
    
 
94
    This provides interfaces that are common across bzrdirs, 
 
95
    repositories, branches, and workingtree control directories.
 
96
    
 
97
    They all expose two urls and transports: the *user* URL is the 
 
98
    one that stops above the control directory (eg .bzr) and that 
 
99
    should normally be used in messages, and the *control* URL is
 
100
    under that in eg .bzr/checkout and is used to read the control
 
101
    files.
 
102
    
 
103
    This can be used as a mixin and is intended to fit with 
 
104
    foreign formats.
 
105
    """
 
106
    
 
107
    @property
 
108
    def control_transport(self):
 
109
        raise NotImplementedError
 
110
   
 
111
    @property
 
112
    def control_url(self):
 
113
        return self.control_transport.base
 
114
    
 
115
    @property
 
116
    def user_transport(self):
 
117
        raise NotImplementedError
 
118
        
 
119
    @property
 
120
    def user_url(self):
 
121
        return self.user_transport.base
 
122
    
 
123
 
 
124
class BzrDir(ControlComponent):
92
125
    """A .bzr control diretory.
93
126
 
94
127
    BzrDir instances let you create or open any of the things that can be
261
294
                # copied, and finally if we are copying up to a specific
262
295
                # revision_id then we can use the pending-ancestry-result which
263
296
                # does not require traversing all of history to describe it.
264
 
                if (result_repo.bzrdir.root_transport.base ==
265
 
                    result.root_transport.base and not require_stacking and
 
297
                if (result_repo.user_url == result.user_url
 
298
                    and not require_stacking and
266
299
                    revision_id is not None):
267
300
                    fetch_spec = graph.PendingAncestryResult(
268
301
                        [revision_id], local_repo)
342
375
            recurse = True
343
376
            try:
344
377
                bzrdir = BzrDir.open_from_transport(current_transport)
345
 
            except errors.NotBranchError:
 
378
            except (errors.NotBranchError, errors.PermissionDenied):
346
379
                pass
347
380
            else:
348
381
                recurse, value = evaluate(bzrdir)
349
382
                yield value
350
383
            try:
351
384
                subdirs = list_current(current_transport)
352
 
            except errors.NoSuchFile:
 
385
            except (errors.NoSuchFile, errors.PermissionDenied):
353
386
                continue
354
387
            if recurse:
355
388
                for subdir in sorted(subdirs, reverse=True):
361
394
        """
362
395
        try:
363
396
            return [self.open_branch()]
364
 
        except errors.NotBranchError:
 
397
        except (errors.NotBranchError, errors.NoRepositoryPresent):
365
398
            return []
366
399
 
367
400
    @staticmethod
396
429
        """Destroy the repository in this BzrDir"""
397
430
        raise NotImplementedError(self.destroy_repository)
398
431
 
399
 
    def create_branch(self):
 
432
    def create_branch(self, name=None):
400
433
        """Create a branch in this BzrDir.
401
434
 
 
435
        :param name: Name of the colocated branch to create, None for
 
436
            the default branch.
 
437
 
402
438
        The bzrdir's format will control what branch format is created.
403
439
        For more control see BranchFormatXX.create(a_bzrdir).
404
440
        """
405
441
        raise NotImplementedError(self.create_branch)
406
442
 
407
 
    def destroy_branch(self):
408
 
        """Destroy the branch in this BzrDir"""
 
443
    def destroy_branch(self, name=None):
 
444
        """Destroy a branch in this BzrDir.
 
445
        
 
446
        :param name: Name of the branch to destroy, None for the default 
 
447
            branch.
 
448
        """
409
449
        raise NotImplementedError(self.destroy_branch)
410
450
 
411
451
    @staticmethod
451
491
            stop = False
452
492
            stack_on = config.get_default_stack_on()
453
493
            if stack_on is not None:
454
 
                stack_on_pwd = found_bzrdir.root_transport.base
 
494
                stack_on_pwd = found_bzrdir.user_url
455
495
                stop = True
456
496
            # does it have a repository ?
457
497
            try:
459
499
            except errors.NoRepositoryPresent:
460
500
                repository = None
461
501
            else:
462
 
                if ((found_bzrdir.root_transport.base !=
463
 
                     self.root_transport.base) and not repository.is_shared()):
 
502
                if (found_bzrdir.user_url != self.user_url 
 
503
                    and not repository.is_shared()):
464
504
                    # Don't look higher, can't use a higher shared repo.
465
505
                    repository = None
466
506
                    stop = True
575
615
        """
576
616
        raise NotImplementedError(self.create_workingtree)
577
617
 
 
618
    def generate_backup_name(self, base):
 
619
        """Generate a non-existing backup file name based on base."""
 
620
        counter = 1
 
621
        name = "%s.~%d~" % (base, counter)
 
622
        while self.root_transport.has(name):
 
623
            counter += 1
 
624
            name = "%s.~%d~" % (base, counter)
 
625
        return name
 
626
 
578
627
    def backup_bzrdir(self):
579
628
        """Backup this bzr control directory.
580
629
 
581
630
        :return: Tuple with old path name and new path name
582
631
        """
 
632
 
 
633
        backup_dir=self.generate_backup_name('backup.bzr')
583
634
        pb = ui.ui_factory.nested_progress_bar()
584
635
        try:
585
636
            # FIXME: bug 300001 -- the backup fails if the backup directory
586
637
            # already exists, but it should instead either remove it or make
587
638
            # a new backup directory.
588
639
            #
589
 
            # FIXME: bug 262450 -- the backup directory should have the same
590
 
            # permissions as the .bzr directory (probably a bug in copy_tree)
591
640
            old_path = self.root_transport.abspath('.bzr')
592
 
            new_path = self.root_transport.abspath('backup.bzr')
 
641
            new_path = self.root_transport.abspath(backup_dir)
593
642
            ui.ui_factory.note('making backup of %s\n  to %s' % (old_path, new_path,))
594
 
            self.root_transport.copy_tree('.bzr', 'backup.bzr')
 
643
            self.root_transport.copy_tree('.bzr', backup_dir)
595
644
            return (old_path, new_path)
596
645
        finally:
597
646
            pb.finished()
655
704
            if stop:
656
705
                return result
657
706
            next_transport = found_bzrdir.root_transport.clone('..')
658
 
            if (found_bzrdir.root_transport.base == next_transport.base):
 
707
            if (found_bzrdir.user_url == next_transport.base):
659
708
                # top of the file system
660
709
                return None
661
710
            # find the next containing bzrdir
678
727
                repository = found_bzrdir.open_repository()
679
728
            except errors.NoRepositoryPresent:
680
729
                return None, False
681
 
            if found_bzrdir.root_transport.base == self.root_transport.base:
 
730
            if found_bzrdir.user_url == self.user_url:
682
731
                return repository, True
683
732
            elif repository.is_shared():
684
733
                return repository, True
690
739
            raise errors.NoRepositoryPresent(self)
691
740
        return found_repo
692
741
 
693
 
    def get_branch_reference(self):
 
742
    def get_branch_reference(self, name=None):
694
743
        """Return the referenced URL for the branch in this bzrdir.
695
744
 
 
745
        :param name: Optional colocated branch name
696
746
        :raises NotBranchError: If there is no Branch.
 
747
        :raises NoColocatedBranchSupport: If a branch name was specified
 
748
            but colocated branches are not supported.
697
749
        :return: The URL the branch in this bzrdir references if it is a
698
750
            reference branch, or None for regular branches.
699
751
        """
 
752
        if name is not None:
 
753
            raise errors.NoColocatedBranchSupport(self)
700
754
        return None
701
755
 
702
 
    def get_branch_transport(self, branch_format):
 
756
    def get_branch_transport(self, branch_format, name=None):
703
757
        """Get the transport for use by branch format in this BzrDir.
704
758
 
705
759
        Note that bzr dirs that do not support format strings will raise
800
854
        :param _transport: the transport this dir is based at.
801
855
        """
802
856
        self._format = _format
 
857
        # these are also under the more standard names of 
 
858
        # control_transport and user_transport
803
859
        self.transport = _transport.clone('.bzr')
804
860
        self.root_transport = _transport
805
861
        self._mode_check_done = False
 
862
        
 
863
    @property 
 
864
    def user_transport(self):
 
865
        return self.root_transport
 
866
        
 
867
    @property
 
868
    def control_transport(self):
 
869
        return self.transport
806
870
 
807
871
    def is_control_filename(self, filename):
808
872
        """True if filename is the name of a path which is reserved for bzrdir's.
883
947
        BzrDir._check_supported(format, _unsupported)
884
948
        return format.open(transport, _found=True)
885
949
 
886
 
    def open_branch(self, unsupported=False, ignore_fallbacks=False):
 
950
    def open_branch(self, name=None, unsupported=False,
 
951
                    ignore_fallbacks=False):
887
952
        """Open the branch object at this BzrDir if one is present.
888
953
 
889
954
        If unsupported is True, then no longer supported branch formats can
936
1001
                raise errors.NotBranchError(path=url)
937
1002
            a_transport = new_t
938
1003
 
939
 
    def _get_tree_branch(self):
 
1004
    def _get_tree_branch(self, name=None):
940
1005
        """Return the branch and tree, if any, for this bzrdir.
941
1006
 
 
1007
        :param name: Name of colocated branch to open.
 
1008
 
942
1009
        Return None for tree if not present or inaccessible.
943
1010
        Raise NotBranchError if no branch is present.
944
1011
        :return: (tree, branch)
947
1014
            tree = self.open_workingtree()
948
1015
        except (errors.NoWorkingTree, errors.NotLocalUrl):
949
1016
            tree = None
950
 
            branch = self.open_branch()
 
1017
            branch = self.open_branch(name=name)
951
1018
        else:
952
 
            branch = tree.branch
 
1019
            if name is not None:
 
1020
                branch = self.open_branch(name=name)
 
1021
            else:
 
1022
                branch = tree.branch
953
1023
        return tree, branch
954
1024
 
955
1025
    @classmethod
1027
1097
        """
1028
1098
        raise NotImplementedError(self.open_workingtree)
1029
1099
 
1030
 
    def has_branch(self):
 
1100
    def has_branch(self, name=None):
1031
1101
        """Tell if this bzrdir contains a branch.
1032
1102
 
1033
1103
        Note: if you're going to open the branch, you should just go ahead
1035
1105
        branch and discards it, and that's somewhat expensive.)
1036
1106
        """
1037
1107
        try:
1038
 
            self.open_branch()
 
1108
            self.open_branch(name)
1039
1109
            return True
1040
1110
        except errors.NotBranchError:
1041
1111
            return False
1176
1246
        repository_policy = result.determine_repository_policy(
1177
1247
            force_new_repo, stacked_branch_url, require_stacking=stacked)
1178
1248
        result_repo, is_new_repo = repository_policy.acquire_repository()
1179
 
        if is_new_repo and revision_id is not None and not stacked:
 
1249
        is_stacked = stacked or (len(result_repo._fallback_repositories) != 0)
 
1250
        if is_new_repo and revision_id is not None and not is_stacked:
1180
1251
            fetch_spec = graph.PendingAncestryResult(
1181
1252
                [revision_id], source_repository)
1182
1253
        else:
1315
1386
        self.create_hook(hooks.HookPoint('pre_open',
1316
1387
            "Invoked before attempting to open a BzrDir with the transport "
1317
1388
            "that the open will use.", (1, 14), None))
 
1389
        self.create_hook(hooks.HookPoint('post_repo_init',
 
1390
            "Invoked after a repository has been initialized. "
 
1391
            "post_repo_init is called with a "
 
1392
            "bzrlib.bzrdir.RepoInitHookParams.",
 
1393
            (2, 2), None))
1318
1394
 
1319
1395
# install the default hooks
1320
1396
BzrDir.hooks = BzrDirHooks()
1321
1397
 
1322
1398
 
 
1399
class RepoInitHookParams(object):
 
1400
    """Object holding parameters passed to *_repo_init hooks.
 
1401
 
 
1402
    There are 4 fields that hooks may wish to access:
 
1403
 
 
1404
    :ivar repository: Repository created
 
1405
    :ivar format: Repository format
 
1406
    :ivar bzrdir: The bzrdir for the repository
 
1407
    :ivar shared: The repository is shared
 
1408
    """
 
1409
 
 
1410
    def __init__(self, repository, format, a_bzrdir, shared):
 
1411
        """Create a group of RepoInitHook parameters.
 
1412
 
 
1413
        :param repository: Repository created
 
1414
        :param format: Repository format
 
1415
        :param bzrdir: The bzrdir for the repository
 
1416
        :param shared: The repository is shared
 
1417
        """
 
1418
        self.repository = repository
 
1419
        self.format = format
 
1420
        self.bzrdir = a_bzrdir
 
1421
        self.shared = shared
 
1422
 
 
1423
    def __eq__(self, other):
 
1424
        return self.__dict__ == other.__dict__
 
1425
 
 
1426
    def __repr__(self):
 
1427
        if self.repository:
 
1428
            return "<%s for %s>" % (self.__class__.__name__,
 
1429
                self.repository)
 
1430
        else:
 
1431
            return "<%s for %s>" % (self.__class__.__name__,
 
1432
                self.bzrdir)
 
1433
 
 
1434
 
1323
1435
class BzrDirPreSplitOut(BzrDir):
1324
1436
    """A common class for the all-in-one formats."""
1325
1437
 
1364
1476
            tree.clone(result)
1365
1477
        return result
1366
1478
 
1367
 
    def create_branch(self):
 
1479
    def create_branch(self, name=None):
1368
1480
        """See BzrDir.create_branch."""
1369
 
        return self._format.get_branch_format().initialize(self)
 
1481
        return self._format.get_branch_format().initialize(self, name=name)
1370
1482
 
1371
 
    def destroy_branch(self):
 
1483
    def destroy_branch(self, name=None):
1372
1484
        """See BzrDir.destroy_branch."""
1373
1485
        raise errors.UnsupportedOperation(self.destroy_branch, self)
1374
1486
 
1430
1542
        raise errors.UnsupportedOperation(self.destroy_workingtree_metadata,
1431
1543
                                          self)
1432
1544
 
1433
 
    def get_branch_transport(self, branch_format):
 
1545
    def get_branch_transport(self, branch_format, name=None):
1434
1546
        """See BzrDir.get_branch_transport()."""
 
1547
        if name is not None:
 
1548
            raise errors.NoColocatedBranchSupport(self)
1435
1549
        if branch_format is None:
1436
1550
            return self.transport
1437
1551
        try:
1470
1584
            format = BzrDirFormat.get_default_format()
1471
1585
        return not isinstance(self._format, format.__class__)
1472
1586
 
1473
 
    def open_branch(self, unsupported=False, ignore_fallbacks=False):
 
1587
    def open_branch(self, name=None, unsupported=False,
 
1588
                    ignore_fallbacks=False):
1474
1589
        """See BzrDir.open_branch."""
1475
1590
        from bzrlib.branch import BzrBranchFormat4
1476
1591
        format = BzrBranchFormat4()
1477
1592
        self._check_supported(format, unsupported)
1478
 
        return format.open(self, _found=True)
 
1593
        return format.open(self, name, _found=True)
1479
1594
 
1480
1595
    def sprout(self, url, revision_id=None, force_new_repo=False,
1481
1596
               possible_transports=None, accelerator_tree=None,
1598
1713
        """See BzrDir.can_convert_format()."""
1599
1714
        return True
1600
1715
 
1601
 
    def create_branch(self):
 
1716
    def create_branch(self, name=None):
1602
1717
        """See BzrDir.create_branch."""
1603
 
        return self._format.get_branch_format().initialize(self)
 
1718
        return self._format.get_branch_format().initialize(self, name=name)
1604
1719
 
1605
 
    def destroy_branch(self):
 
1720
    def destroy_branch(self, name=None):
1606
1721
        """See BzrDir.create_branch."""
 
1722
        if name is not None:
 
1723
            raise errors.NoColocatedBranchSupport(self)
1607
1724
        self.transport.delete_tree('branch')
1608
1725
 
1609
1726
    def create_repository(self, shared=False):
1632
1749
    def destroy_workingtree_metadata(self):
1633
1750
        self.transport.delete_tree('checkout')
1634
1751
 
1635
 
    def find_branch_format(self):
 
1752
    def find_branch_format(self, name=None):
1636
1753
        """Find the branch 'format' for this bzrdir.
1637
1754
 
1638
1755
        This might be a synthetic object for e.g. RemoteBranch and SVN.
1639
1756
        """
1640
1757
        from bzrlib.branch import BranchFormat
1641
 
        return BranchFormat.find_format(self)
 
1758
        return BranchFormat.find_format(self, name=name)
1642
1759
 
1643
1760
    def _get_mkdir_mode(self):
1644
1761
        """Figure out the mode to use when creating a bzrdir subdir."""
1646
1763
                                     lockable_files.TransportLock)
1647
1764
        return temp_control._dir_mode
1648
1765
 
1649
 
    def get_branch_reference(self):
 
1766
    def get_branch_reference(self, name=None):
1650
1767
        """See BzrDir.get_branch_reference()."""
1651
1768
        from bzrlib.branch import BranchFormat
1652
 
        format = BranchFormat.find_format(self)
1653
 
        return format.get_reference(self)
 
1769
        format = BranchFormat.find_format(self, name=name)
 
1770
        return format.get_reference(self, name=name)
1654
1771
 
1655
 
    def get_branch_transport(self, branch_format):
 
1772
    def get_branch_transport(self, branch_format, name=None):
1656
1773
        """See BzrDir.get_branch_transport()."""
 
1774
        if name is not None:
 
1775
            raise errors.NoColocatedBranchSupport(self)
1657
1776
        # XXX: this shouldn't implicitly create the directory if it's just
1658
1777
        # promising to get a transport -- mbp 20090727
1659
1778
        if branch_format is None:
1730
1849
                return True
1731
1850
        except errors.NoRepositoryPresent:
1732
1851
            pass
1733
 
        try:
1734
 
            if not isinstance(self.open_branch()._format,
 
1852
        for branch in self.list_branches():
 
1853
            if not isinstance(branch._format,
1735
1854
                              format.get_branch_format().__class__):
1736
1855
                # the branch needs an upgrade.
1737
1856
                return True
1738
 
        except errors.NotBranchError:
1739
 
            pass
1740
1857
        try:
1741
1858
            my_wt = self.open_workingtree(recommend_upgrade=False)
1742
1859
            if not isinstance(my_wt._format,
1747
1864
            pass
1748
1865
        return False
1749
1866
 
1750
 
    def open_branch(self, unsupported=False, ignore_fallbacks=False):
 
1867
    def open_branch(self, name=None, unsupported=False,
 
1868
                    ignore_fallbacks=False):
1751
1869
        """See BzrDir.open_branch."""
1752
 
        format = self.find_branch_format()
 
1870
        format = self.find_branch_format(name=name)
1753
1871
        self._check_supported(format, unsupported)
1754
 
        return format.open(self, _found=True, ignore_fallbacks=ignore_fallbacks)
 
1872
        return format.open(self, name=name,
 
1873
            _found=True, ignore_fallbacks=ignore_fallbacks)
1755
1874
 
1756
1875
    def open_repository(self, unsupported=False):
1757
1876
        """See BzrDir.open_repository."""
1789
1908
    Once a format is deprecated, just deprecate the initialize and open
1790
1909
    methods on the format class. Do not deprecate the object, as the
1791
1910
    object will be created every system load.
 
1911
 
 
1912
    :cvar colocated_branches: Whether this formats supports colocated branches.
1792
1913
    """
1793
1914
 
1794
1915
    _default_format = None
1811
1932
 
1812
1933
    _lock_file_name = 'branch-lock'
1813
1934
 
 
1935
    colocated_branches = False
 
1936
    """Whether co-located branches are supported for this control dir format.
 
1937
    """
 
1938
 
1814
1939
    # _lock_class must be set in subclasses to the lock type, typ.
1815
1940
    # TransportLock or LockDir
1816
1941
 
1836
1961
            format_string = transport.get_bytes(".bzr/branch-format")
1837
1962
        except errors.NoSuchFile:
1838
1963
            raise errors.NotBranchError(path=transport.base)
1839
 
 
1840
1964
        try:
1841
1965
            return klass._formats[format_string]
1842
1966
        except KeyError:
2623
2747
            if isinstance(self.bzrdir.transport, local.LocalTransport):
2624
2748
                self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2625
2749
            self._convert_to_weaves()
2626
 
            return BzrDir.open(self.bzrdir.root_transport.base)
 
2750
            return BzrDir.open(self.bzrdir.user_url)
2627
2751
        finally:
2628
2752
            self.pb.finished()
2629
2753
 
2751
2875
            self.revisions[rev_id] = rev
2752
2876
 
2753
2877
    def _load_old_inventory(self, rev_id):
2754
 
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
 
2878
        f = self.branch.repository.inventory_store.get(rev_id)
 
2879
        try:
 
2880
            old_inv_xml = f.read()
 
2881
        finally:
 
2882
            f.close()
2755
2883
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2756
2884
        inv.revision_id = rev_id
2757
2885
        rev = self.revisions[rev_id]
2835
2963
                ie.revision = previous_ie.revision
2836
2964
                return
2837
2965
        if ie.has_text():
2838
 
            text = self.branch.repository._text_store.get(ie.text_id)
2839
 
            file_lines = text.readlines()
 
2966
            f = self.branch.repository._text_store.get(ie.text_id)
 
2967
            try:
 
2968
                file_lines = f.readlines()
 
2969
            finally:
 
2970
                f.close()
2840
2971
            w.add_lines(rev_id, previous_revisions, file_lines)
2841
2972
            self.text_count += 1
2842
2973
        else:
2876
3007
        try:
2877
3008
            ui.ui_factory.note('starting upgrade from format 5 to 6')
2878
3009
            self._convert_to_prefixed()
2879
 
            return BzrDir.open(self.bzrdir.root_transport.base)
 
3010
            return BzrDir.open(self.bzrdir.user_url)
2880
3011
        finally:
2881
3012
            pb.finished()
2882
3013
 
3004
3135
            BzrDirMetaFormat1().get_format_string(),
3005
3136
            mode=self.file_mode)
3006
3137
        self.pb.finished()
3007
 
        return BzrDir.open(self.bzrdir.root_transport.base)
 
3138
        return BzrDir.open(self.bzrdir.user_url)
3008
3139
 
3009
3140
    def make_lock(self, name):
3010
3141
        """Make a lock for the new control dir name."""
3123
3254
        # XXX: It's a bit ugly that the network name is here, because we'd
3124
3255
        # like to believe that format objects are stateless or at least
3125
3256
        # immutable,  However, we do at least avoid mutating the name after
3126
 
        # it's returned.  See <https://bugs.edge.launchpad.net/bzr/+bug/504102>
 
3257
        # it's returned.  See <https://bugs.launchpad.net/bzr/+bug/504102>
3127
3258
        self._network_name = None
3128
3259
 
3129
3260
    def __repr__(self):
3591
3722
            try:
3592
3723
                stack_on = urlutils.rebase_url(self._stack_on,
3593
3724
                    self._stack_on_pwd,
3594
 
                    branch.bzrdir.root_transport.base)
 
3725
                    branch.user_url)
3595
3726
            except errors.InvalidRebaseURLs:
3596
3727
                stack_on = self._get_full_stack_on()
3597
3728
        try: