~abentley/bzr/status

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Aaron Bentley
  • Date: 2009-04-24 15:21:01 UTC
  • mfrom: (1912.1.19 composite-tree)
  • Revision ID: aaron@aaronbentley.com-20090424152101-rsk84sy5n65x04im
Merge composite-tree into status

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
 
 
18
from cStringIO import StringIO
18
19
import sys
19
20
 
20
21
from bzrlib.lazy_import import lazy_import
30
31
        lockable_files,
31
32
        repository,
32
33
        revision as _mod_revision,
 
34
        rio,
33
35
        symbol_versioning,
34
36
        transport,
35
37
        tsort,
500
502
        """
501
503
        raise errors.UpgradeRequired(self.base)
502
504
 
 
505
    def set_reference_info(self, file_id, tree_path, branch_location):
 
506
        """Set the branch location to use for a tree reference."""
 
507
        raise errors.UnsupportedOperation(self.set_reference_info, self)
 
508
 
 
509
    def get_reference_info(self, file_id):
 
510
        """Get the tree_path and branch_location for a tree reference."""
 
511
        raise errors.UnsupportedOperation(self.get_reference_info, self)
 
512
 
503
513
    @needs_write_lock
504
514
    def fetch(self, from_branch, last_revision=None, pb=None):
505
515
        """Copy revisions from from_branch into this branch.
1070
1080
        revision_id: if not None, the revision history in the new branch will
1071
1081
                     be truncated to end with revision_id.
1072
1082
        """
 
1083
        self.update_references(destination)
1073
1084
        self._synchronize_history(destination, revision_id)
1074
1085
        try:
1075
1086
            parent = self.get_parent()
1081
1092
        if self._push_should_merge_tags():
1082
1093
            self.tags.merge_to(destination.tags)
1083
1094
 
 
1095
    def update_references(self, target):
 
1096
        if not getattr(self._format, 'supports_reference_locations', False):
 
1097
            return
 
1098
        reference_dict = self._get_all_reference_info()
 
1099
        if len(reference_dict) == 0:
 
1100
            return
 
1101
        old_base = self.base
 
1102
        new_base = target.base
 
1103
        target_reference_dict = target._get_all_reference_info()
 
1104
        for file_id, (tree_path, branch_location) in (
 
1105
            reference_dict.items()):
 
1106
            branch_location = urlutils.rebase_url(branch_location,
 
1107
                                                  old_base, new_base)
 
1108
            target_reference_dict.setdefault(
 
1109
                file_id, (tree_path, branch_location))
 
1110
        target._set_all_reference_info(target_reference_dict)
 
1111
 
1084
1112
    @needs_read_lock
1085
1113
    def check(self):
1086
1114
        """Check consistency of the branch.
1205
1233
        reconciler.reconcile()
1206
1234
        return reconciler
1207
1235
 
1208
 
    def reference_parent(self, file_id, path):
 
1236
    def reference_parent(self, file_id, path, possible_transports=None):
1209
1237
        """Return the parent branch for a tree-reference file_id
1210
1238
        :param file_id: The file_id of the tree reference
1211
1239
        :param path: The path of the file_id in the tree
1212
1240
        :return: A branch associated with the file_id
1213
1241
        """
1214
1242
        # FIXME should provide multiple branches, based on config
1215
 
        return Branch.open(self.bzrdir.root_transport.clone(path).base)
 
1243
        return Branch.open(self.bzrdir.root_transport.clone(path).base,
 
1244
                           possible_transports=possible_transports)
1216
1245
 
1217
1246
    def supports_tags(self):
1218
1247
        return self._format.supports_tags()
1716
1745
 
1717
1746
 
1718
1747
 
1719
 
class BzrBranchFormat7(BranchFormatMetadir):
 
1748
class BzrBranchFormat8(BranchFormatMetadir):
 
1749
    """Metadir format supporting storing locations of subtree branches."""
 
1750
 
 
1751
    def _branch_class(self):
 
1752
        return BzrBranch8
 
1753
 
 
1754
    def get_format_string(self):
 
1755
        """See BranchFormat.get_format_string()."""
 
1756
        return "Bazaar Branch Format 8 (needs bzr 1.15)\n"
 
1757
 
 
1758
    def get_format_description(self):
 
1759
        """See BranchFormat.get_format_description()."""
 
1760
        return "Branch format 8"
 
1761
 
 
1762
    def initialize(self, a_bzrdir):
 
1763
        """Create a branch of this format in a_bzrdir."""
 
1764
        utf8_files = [('last-revision', '0 null:\n'),
 
1765
                      ('branch.conf', ''),
 
1766
                      ('tags', ''),
 
1767
                      ('references', '')
 
1768
                      ]
 
1769
        return self._initialize_helper(a_bzrdir, utf8_files)
 
1770
 
 
1771
    def __init__(self):
 
1772
        super(BzrBranchFormat8, self).__init__()
 
1773
        self._matchingbzrdir.repository_format = \
 
1774
            RepositoryFormatKnitPack5RichRoot()
 
1775
 
 
1776
    def make_tags(self, branch):
 
1777
        """See bzrlib.branch.BranchFormat.make_tags()."""
 
1778
        return BasicTags(branch)
 
1779
 
 
1780
    def supports_stacking(self):
 
1781
        return True
 
1782
 
 
1783
    supports_reference_locations = True
 
1784
 
 
1785
 
 
1786
class BzrBranchFormat7(BzrBranchFormat8):
1720
1787
    """Branch format with last-revision, tags, and a stacked location pointer.
1721
1788
 
1722
1789
    The stacked location pointer is passed down to the repository and requires
1725
1792
    This format was introduced in bzr 1.6.
1726
1793
    """
1727
1794
 
 
1795
    def initialize(self, a_bzrdir):
 
1796
        """Create a branch of this format in a_bzrdir."""
 
1797
        utf8_files = [('last-revision', '0 null:\n'),
 
1798
                      ('branch.conf', ''),
 
1799
                      ('tags', ''),
 
1800
                      ]
 
1801
        return self._initialize_helper(a_bzrdir, utf8_files)
 
1802
 
1728
1803
    def _branch_class(self):
1729
1804
        return BzrBranch7
1730
1805
 
1736
1811
        """See BranchFormat.get_format_description()."""
1737
1812
        return "Branch format 7"
1738
1813
 
1739
 
    def initialize(self, a_bzrdir):
1740
 
        """Create a branch of this format in a_bzrdir."""
1741
 
        utf8_files = [('last-revision', '0 null:\n'),
1742
 
                      ('branch.conf', ''),
1743
 
                      ('tags', ''),
1744
 
                      ]
1745
 
        return self._initialize_helper(a_bzrdir, utf8_files)
1746
 
 
1747
 
    def __init__(self):
1748
 
        super(BzrBranchFormat7, self).__init__()
1749
 
        self._matchingbzrdir.repository_format = \
1750
 
            RepositoryFormatKnitPack5RichRoot()
1751
 
 
1752
 
    def make_tags(self, branch):
1753
 
        """See bzrlib.branch.BranchFormat.make_tags()."""
1754
 
        return BasicTags(branch)
1755
 
 
1756
 
    def supports_stacking(self):
1757
 
        return True
 
1814
    supports_reference_locations = False
1758
1815
 
1759
1816
 
1760
1817
class BranchReferenceFormat(BranchFormat):
1867
1924
__format5 = BzrBranchFormat5()
1868
1925
__format6 = BzrBranchFormat6()
1869
1926
__format7 = BzrBranchFormat7()
 
1927
__format8 = BzrBranchFormat8()
1870
1928
BranchFormat.register_format(__format5)
1871
1929
BranchFormat.register_format(BranchReferenceFormat())
1872
1930
BranchFormat.register_format(__format6)
1873
1931
BranchFormat.register_format(__format7)
 
1932
BranchFormat.register_format(__format8)
1874
1933
BranchFormat.set_default_format(__format6)
1875
1934
_legacy_formats = [BzrBranchFormat4(),
1876
1935
    ]
2119
2178
        try:
2120
2179
            # We assume that during 'pull' the local repository is closer than
2121
2180
            # the remote one.
 
2181
            source.update_references(self)
2122
2182
            graph = self.repository.get_graph(source.repository)
2123
2183
            result.old_revno, result.old_revid = self.last_revision_info()
2124
2184
            self.update_revisions(source, stop_revision, overwrite=overwrite,
2221
2281
        result.source_branch = self
2222
2282
        result.target_branch = target
2223
2283
        result.old_revno, result.old_revid = target.last_revision_info()
 
2284
        self.update_references(target)
2224
2285
        if result.old_revid != self.last_revision():
2225
2286
            # We assume that during 'push' this repository is closer than
2226
2287
            # the target.
2376
2437
        return None
2377
2438
 
2378
2439
 
2379
 
class BzrBranch7(BzrBranch5):
2380
 
    """A branch with support for a fallback repository."""
 
2440
class BzrBranch8(BzrBranch5):
 
2441
    """A branch that stores tree-reference locations."""
2381
2442
 
2382
2443
    def _open_hook(self):
2383
2444
        if self._ignore_fallbacks:
2399
2460
 
2400
2461
    def __init__(self, *args, **kwargs):
2401
2462
        self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
2402
 
        super(BzrBranch7, self).__init__(*args, **kwargs)
 
2463
        super(BzrBranch8, self).__init__(*args, **kwargs)
2403
2464
        self._last_revision_info_cache = None
2404
2465
        self._partial_revision_history_cache = []
 
2466
        self._reference_info = None
2405
2467
 
2406
2468
    def _clear_cached_state(self):
2407
 
        super(BzrBranch7, self)._clear_cached_state()
 
2469
        super(BzrBranch8, self)._clear_cached_state()
2408
2470
        self._last_revision_info_cache = None
2409
2471
        self._partial_revision_history_cache = []
 
2472
        self._reference_info = None
2410
2473
 
2411
2474
    def _last_revision_info(self):
2412
2475
        revision_string = self._transport.get_bytes('last-revision')
2522
2585
        """Set the parent branch"""
2523
2586
        return self._get_config_location('parent_location')
2524
2587
 
 
2588
    @needs_write_lock
 
2589
    def _set_all_reference_info(self, info_dict):
 
2590
        """Replace all reference info stored in a branch.
 
2591
 
 
2592
        :param info_dict: A dict of {file_id: (tree_path, branch_location)}
 
2593
        """
 
2594
        s = StringIO()
 
2595
        writer = rio.RioWriter(s)
 
2596
        for key, (tree_path, branch_location) in info_dict.iteritems():
 
2597
            stanza = rio.Stanza(file_id=key, tree_path=tree_path,
 
2598
                                branch_location=branch_location)
 
2599
            writer.write_stanza(stanza)
 
2600
        self._transport.put_bytes('references', s.getvalue())
 
2601
        self._reference_info = info_dict
 
2602
 
 
2603
    @needs_read_lock
 
2604
    def _get_all_reference_info(self):
 
2605
        """Return all the reference info stored in a branch.
 
2606
 
 
2607
        :return: A dict of {file_id: (tree_path, branch_location)}
 
2608
        """
 
2609
        if self._reference_info is not None:
 
2610
            return self._reference_info
 
2611
        rio_file = self._transport.get('references')
 
2612
        try:
 
2613
            stanzas = rio.read_stanzas(rio_file)
 
2614
            info_dict = dict((s['file_id'], (s['tree_path'],
 
2615
                             s['branch_location'])) for s in stanzas)
 
2616
        finally:
 
2617
            rio_file.close()
 
2618
        self._reference_info = info_dict
 
2619
        return info_dict
 
2620
 
 
2621
    def set_reference_info(self, file_id, tree_path, branch_location):
 
2622
        """Set the branch location to use for a tree reference.
 
2623
 
 
2624
        :param file_id: The file-id of the tree reference.
 
2625
        :param tree_path: The path of the tree reference in the tree.
 
2626
        :param branch_location: The location of the branch to retrieve tree
 
2627
            references from.
 
2628
        """
 
2629
        info_dict = self._get_all_reference_info()
 
2630
        info_dict[file_id] = (tree_path, branch_location)
 
2631
        if None in (tree_path, branch_location):
 
2632
            if tree_path is not None:
 
2633
                raise ValueError('tree_path must be None when branch_location'
 
2634
                                 ' is None.')
 
2635
            if branch_location is not None:
 
2636
                raise ValueError('branch_location must be None when tree_path'
 
2637
                                 ' is None.')
 
2638
            del info_dict[file_id]
 
2639
        self._set_all_reference_info(info_dict)
 
2640
 
 
2641
    def get_reference_info(self, file_id):
 
2642
        """Get the tree_path and branch_location for a tree reference.
 
2643
 
 
2644
        :return: a tuple of (tree_path, branch_location)
 
2645
        """
 
2646
        return self._get_all_reference_info().get(file_id, (None, None))
 
2647
 
 
2648
    def reference_parent(self, file_id, path, possible_transports=None):
 
2649
        """Return the parent branch for a tree-reference file_id.
 
2650
 
 
2651
        :param file_id: The file_id of the tree reference
 
2652
        :param path: The path of the file_id in the tree
 
2653
        :return: A branch associated with the file_id
 
2654
        """
 
2655
        branch_location = self.get_reference_info(file_id)[1]
 
2656
        if branch_location is None:
 
2657
            return Branch.reference_parent(self, file_id, path,
 
2658
                                           possible_transports)
 
2659
        branch_location = urlutils.join(self.base, branch_location)
 
2660
        return Branch.open(branch_location,
 
2661
                           possible_transports=possible_transports)
 
2662
 
2525
2663
    def set_push_location(self, location):
2526
2664
        """See Branch.set_push_location."""
2527
2665
        self._set_config_location('push_location', location)
2625
2763
        return self.revno() - index
2626
2764
 
2627
2765
 
 
2766
class BzrBranch7(BzrBranch8):
 
2767
    """A branch with support for a fallback repository."""
 
2768
 
 
2769
    def set_reference_info(self, file_id, tree_path, branch_location):
 
2770
        Branch.set_reference_info(self, file_id, tree_path, branch_location)
 
2771
 
 
2772
    def get_reference_info(self, file_id):
 
2773
        Branch.get_reference_info(self, file_id)
 
2774
 
 
2775
    def reference_parent(self, file_id, path, possible_transports=None):
 
2776
        return Branch.reference_parent(self, file_id, path,
 
2777
                                       possible_transports)
 
2778
 
 
2779
 
2628
2780
class BzrBranch6(BzrBranch7):
2629
2781
    """See BzrBranchFormat6 for the capabilities of this branch.
2630
2782
 
2771
2923
        branch._transport.put_bytes('format', format.get_format_string())
2772
2924
 
2773
2925
 
 
2926
class Converter7to8(object):
 
2927
    """Perform an in-place upgrade of format 6 to format 7"""
 
2928
 
 
2929
    def convert(self, branch):
 
2930
        format = BzrBranchFormat8()
 
2931
        branch._transport.put_bytes('references', '')
 
2932
        # update target format
 
2933
        branch._transport.put_bytes('format', format.get_format_string())
 
2934
 
2774
2935
 
2775
2936
def _run_with_write_locked_target(target, callable, *args, **kwargs):
2776
2937
    """Run ``callable(*args, **kwargs)``, write-locking target for the