/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

(broken) merge aaron's workingtree format changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
53
53
 
54
54
import bzrlib
55
55
from bzrlib import (
 
56
    branch,
56
57
    bzrdir,
57
58
    conflicts as _mod_conflicts,
58
59
    dirstate,
64
65
    merge,
65
66
    osutils,
66
67
    revisiontree,
 
68
    repository,
67
69
    textui,
68
70
    transform,
69
71
    urlutils,
70
72
    xml5,
71
73
    xml6,
 
74
    xml7,
72
75
    )
73
76
import bzrlib.branch
74
77
from bzrlib.transport import get_transport
78
81
 
79
82
from bzrlib import symbol_versioning
80
83
from bzrlib.decorators import needs_read_lock, needs_write_lock
81
 
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID
 
84
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
82
85
from bzrlib.lockable_files import LockableFiles, TransportLock
83
86
from bzrlib.lockdir import LockDir
84
87
import bzrlib.mutabletree
301
304
        self._control_files.break_lock()
302
305
        self.branch.break_lock()
303
306
 
 
307
    def requires_rich_root(self):
 
308
        return self._format.requires_rich_root
 
309
 
 
310
    def supports_tree_reference(self):
 
311
        return getattr(self._format, 'supports_tree_reference', False)
 
312
 
304
313
    def _set_inventory(self, inv, dirty):
305
314
        """Set the internal cached inventory.
306
315
 
820
829
            merger.other_basis = merger.other_rev_id
821
830
            merger.other_tree = self.branch.repository.revision_tree(
822
831
                merger.other_rev_id)
 
832
            merger.other_branch = branch
823
833
            merger.pp.next_phase()
824
834
            merger.find_base()
825
835
            if merger.base_rev_id == merger.other_rev_id:
835
845
            pb.finished()
836
846
        return conflicts
837
847
 
838
 
    @needs_read_lock
839
 
    def merge_modified(self):
840
 
        try:
841
 
            hashfile = self._control_files.get('merge-hashes')
842
 
        except errors.NoSuchFile:
843
 
            return {}
844
 
        merge_hashes = {}
845
 
        try:
846
 
            if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
847
 
                raise errors.MergeModifiedFormatError()
848
 
        except StopIteration:
849
 
            raise errors.MergeModifiedFormatError()
850
 
        for s in RioReader(hashfile):
851
 
            file_id = s.get("file_id")
852
 
            if file_id not in self.inventory:
853
 
                continue
854
 
            hash = s.get("hash")
855
 
            if hash == self.get_file_sha1(file_id):
856
 
                merge_hashes[file_id] = hash
857
 
        return merge_hashes
858
 
 
859
848
    @needs_write_lock
860
 
    def mkdir(self, path, file_id=None):
861
 
        """See MutableTree.mkdir()."""
862
 
        if file_id is None:
863
 
            file_id = generate_ids.gen_file_id(os.path.basename(path))
864
 
        os.mkdir(self.abspath(path))
865
 
        self.add(path, file_id, 'directory')
866
 
        return file_id
867
 
 
868
 
    def get_symlink_target(self, file_id):
869
 
        return os.readlink(self.id2abspath(file_id))
870
 
 
871
 
    def file_class(self, filename):
872
 
        if self.path2id(filename):
873
 
            return 'V'
874
 
        elif self.is_ignored(filename):
875
 
            return 'I'
876
 
        else:
877
 
            return '?'
 
849
    def subsume(self, other_tree):
 
850
        def add_children(inventory, entry):
 
851
            for child_entry in entry.children.values():
 
852
                inventory._byid[child_entry.file_id] = child_entry
 
853
                if child_entry.kind == 'directory':
 
854
                    add_children(inventory, child_entry)
 
855
        if other_tree.get_root_id() == self.get_root_id():
 
856
            raise errors.BadSubsumeSource(self, other_tree, 
 
857
                                          'Trees have the same root')
 
858
        try:
 
859
            other_tree_path = self.relpath(other_tree.basedir)
 
860
        except errors.PathNotChild:
 
861
            raise errors.BadSubsumeSource(self, other_tree, 
 
862
                'Tree is not contained by the other')
 
863
        new_root_parent = self.path2id(osutils.dirname(other_tree_path))
 
864
        if new_root_parent is None:
 
865
            raise errors.BadSubsumeSource(self, other_tree, 
 
866
                'Parent directory is not versioned.')
 
867
        # We need to ensure that the result of a fetch will have a
 
868
        # versionedfile for the other_tree root, and only fetching into
 
869
        # RepositoryKnit2 guarantees that.
 
870
        if not self.branch.repository.supports_rich_root():
 
871
            raise errors.SubsumeTargetNeedsUpgrade(other_tree)
 
872
        other_tree.lock_tree_write()
 
873
        try:
 
874
            for parent_id in other_tree.get_parent_ids():
 
875
                self.branch.fetch(other_tree.branch, parent_id)
 
876
                self.add_parent_tree_id(parent_id)
 
877
            other_root = other_tree.inventory.root
 
878
            other_root.parent_id = new_root_parent
 
879
            other_root.name = osutils.basename(other_tree_path)
 
880
            self.inventory.add(other_root)
 
881
            add_children(self.inventory, other_root)
 
882
            self._write_inventory(self.inventory)
 
883
        finally:
 
884
            other_tree.unlock()
 
885
        other_tree.bzrdir.destroy_workingtree_metadata()
 
886
 
 
887
    @needs_tree_write_lock
 
888
    def extract(self, file_id, format=None):
 
889
        """Extract a subtree from this tree.
 
890
        
 
891
        A new branch will be created, relative to the path for this tree.
 
892
        """
 
893
        def mkdirs(path):
 
894
            segments = osutils.splitpath(path)
 
895
            transport = self.branch.bzrdir.root_transport
 
896
            for name in segments:
 
897
                transport = transport.clone(name)
 
898
                try:
 
899
                    transport.mkdir('.')
 
900
                except errors.FileExists:
 
901
                    pass
 
902
            return transport
 
903
            
 
904
        sub_path = self.id2path(file_id)
 
905
        branch_transport = mkdirs(sub_path)
 
906
        if format is None:
 
907
            format = bzrdir.format_registry.make_bzrdir('experimental-knit2')
 
908
        try:
 
909
            branch_transport.mkdir('.')
 
910
        except errors.FileExists:
 
911
            pass
 
912
        branch_bzrdir = format.initialize_on_transport(branch_transport)
 
913
        try:
 
914
            repo = branch_bzrdir.find_repository()
 
915
        except errors.NoRepositoryPresent:
 
916
            repo = branch_bzrdir.create_repository()
 
917
            assert repo.supports_rich_root()
 
918
        else:
 
919
            if not repo.supports_rich_root():
 
920
                raise errors.RootNotRich()
 
921
        new_branch = branch_bzrdir.create_branch()
 
922
        new_branch.pull(self.branch)
 
923
        for parent_id in self.get_parent_ids():
 
924
            new_branch.fetch(self.branch, parent_id)
 
925
        tree_transport = self.bzrdir.root_transport.clone(sub_path)
 
926
        if tree_transport.base != branch_transport.base:
 
927
            tree_bzrdir = format.initialize_on_transport(tree_transport)
 
928
            branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
 
929
        else:
 
930
            tree_bzrdir = branch_bzrdir
 
931
        wt = tree_bzrdir.create_workingtree(NULL_REVISION)
 
932
        wt.set_parent_ids(self.get_parent_ids())
 
933
        my_inv = self.inventory
 
934
        child_inv = Inventory(root_id=None)
 
935
        new_root = my_inv[file_id]
 
936
        my_inv.remove_recursive_id(file_id)
 
937
        new_root.parent_id = None
 
938
        child_inv.add(new_root)
 
939
        self._write_inventory(my_inv)
 
940
        wt._write_inventory(child_inv)
 
941
        return wt
 
942
 
 
943
    def _serialize(self, inventory, out_file):
 
944
        xml5.serializer_v5.write_inventory(self._inventory, out_file)
 
945
 
 
946
    def _deserialize(selt, in_file):
 
947
        return xml5.serializer_v5.read_inventory(in_file)
878
948
 
879
949
    def flush(self):
880
950
        """Write the in memory inventory to disk."""
882
952
        if self._control_files._lock_mode != 'w':
883
953
            raise errors.NotWriteLocked(self)
884
954
        sio = StringIO()
885
 
        xml5.serializer_v5.write_inventory(self._inventory, sio)
 
955
        self._serialize(self._inventory, sio)
886
956
        sio.seek(0)
887
957
        self._control_files.put('inventory', sio)
888
958
        self._inventory_is_modified = False
1594
1664
        #       as all callers should have already converted the revision_id to
1595
1665
        #       utf8
1596
1666
        inventory.revision_id = osutils.safe_revision_id(revision_id)
1597
 
        return xml6.serializer_v6.write_inventory_to_string(inventory)
 
1667
        return xml7.serializer_v7.write_inventory_to_string(inventory)
1598
1668
 
1599
1669
    def _cache_basis_inventory(self, new_revision):
1600
1670
        """Cache new_revision as the basis inventory."""
1615
1685
            xml = self.branch.repository.get_inventory_xml(new_revision)
1616
1686
            firstline = xml.split('\n', 1)[0]
1617
1687
            if (not 'revision_id="' in firstline or 
1618
 
                'format="6"' not in firstline):
 
1688
                'format="7"' not in firstline):
1619
1689
                inv = self.branch.repository.deserialise_inventory(
1620
1690
                    new_revision, xml)
1621
1691
                xml = self._create_basis_xml_from_inventory(new_revision, inv)
1641
1711
        # binary.
1642
1712
        if self._inventory_is_modified:
1643
1713
            raise errors.InventoryModified(self)
1644
 
        result = xml5.serializer_v5.read_inventory(
1645
 
            self._control_files.get('inventory'))
 
1714
        result = self._deserialize(self._control_files.get('inventory'))
1646
1715
        self._set_inventory(result, dirty=False)
1647
1716
        return result
1648
1717
 
1714
1783
                pass
1715
1784
            else:
1716
1785
                try:
1717
 
                    inv = xml6.serializer_v6.read_inventory_from_string(xml)
 
1786
                    inv = xml7.serializer_v7.read_inventory_from_string(xml)
1718
1787
                    # dont use the repository revision_tree api because we want
1719
1788
                    # to supply the inventory.
1720
1789
                    if inv.revision_id == revision_id:
1869
1938
            basis.lock_read()
1870
1939
            try:
1871
1940
                to_tree = self.branch.basis_tree()
1872
 
                if basis.inventory.root is None and self.inventory.root is None:
 
1941
                if basis.inventory.root is None:
1873
1942
                    self.set_root_id(to_tree.inventory.root.file_id)
 
1943
                    self.flush()
1874
1944
                result += merge.merge_inner(
1875
1945
                                      self.branch,
1876
1946
                                      to_tree,
2221
2291
            self.branch.unlock()
2222
2292
 
2223
2293
 
 
2294
class WorkingTreeAB1(WorkingTree3):
 
2295
 
 
2296
    def _serialize(self, inventory, out_file):
 
2297
        xml7.serializer_v7.write_inventory(self._inventory, out_file)
 
2298
 
 
2299
    def _deserialize(selt, in_file):
 
2300
        return xml7.serializer_v7.read_inventory(in_file)
 
2301
 
 
2302
    def _comparison_data(self, entry, path):
 
2303
        kind, executable, stat_value = \
 
2304
            WorkingTree3._comparison_data(self, entry, path)
 
2305
        if kind == 'directory' and entry.kind == 'tree-reference':
 
2306
            kind = 'tree-reference'
 
2307
        return kind, executable, stat_value
 
2308
 
 
2309
    def kind(self, file_id):
 
2310
        kind = WorkingTree3.kind(self, file_id)
 
2311
        if kind == 'directory':
 
2312
            entry = self.inventory[file_id]
 
2313
            if entry.kind == 'tree-reference':
 
2314
                kind = 'tree-reference'
 
2315
        return kind
 
2316
 
 
2317
    def add_reference(self, sub_tree):
 
2318
        return self._add_reference(sub_tree)
 
2319
 
 
2320
    def get_nested_tree(self, entry, path=None):
 
2321
        if path is None:
 
2322
            path = self.id2path(entry.file_id)
 
2323
        return WorkingTree.open(self.abspath(path))
 
2324
 
 
2325
    def get_reference_revision(self, entry, path=None):
 
2326
        return self.get_nested_tree(entry, path).last_revision()
 
2327
 
 
2328
 
2224
2329
def get_conflicted_stem(path):
2225
2330
    for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
2226
2331
        if path.endswith(suffix):
2267
2372
    _formats = {}
2268
2373
    """The known formats."""
2269
2374
 
 
2375
    requires_rich_root = False
 
2376
 
2270
2377
    @classmethod
2271
2378
    def find_format(klass, a_bzrdir):
2272
2379
        """Return the format for the working tree object in a_bzrdir."""
2279
2386
        except KeyError:
2280
2387
            raise errors.UnknownFormatError(format=format_string)
2281
2388
 
 
2389
    def __eq__(self, other):
 
2390
        return self.__class__ is other.__class__
 
2391
 
 
2392
    def __ne__(self, other):
 
2393
        return not (self == other)
 
2394
 
2282
2395
    @classmethod
2283
2396
    def get_default_format(klass):
2284
2397
        """Return the current default format."""
2419
2532
    _lock_file_name = 'lock'
2420
2533
    _lock_class = LockDir
2421
2534
 
 
2535
    _tree_class = WorkingTree3
 
2536
 
 
2537
    def __get_matchingbzrdir(self):
 
2538
        return bzrdir.BzrDirMetaFormat1()
 
2539
 
 
2540
    _matchingbzrdir = property(__get_matchingbzrdir)
 
2541
 
2422
2542
    def _open_control_files(self, a_bzrdir):
2423
2543
        transport = a_bzrdir.get_workingtree_transport(None)
2424
2544
        return LockableFiles(transport, self._lock_file_name, 
2447
2567
        # those trees. And because there isn't a format bump inbetween, we
2448
2568
        # are maintaining compatibility with older clients.
2449
2569
        # inv = Inventory(root_id=gen_root_id())
2450
 
        inv = Inventory()
2451
 
        wt = WorkingTree3(a_bzrdir.root_transport.local_abspath('.'),
 
2570
        inv = self._initial_inventory()
 
2571
        wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
2452
2572
                         branch,
2453
2573
                         inv,
2454
2574
                         _internal=True,
2473
2593
            wt.unlock()
2474
2594
        return wt
2475
2595
 
 
2596
    def _initial_inventory(self):
 
2597
        return Inventory()
 
2598
 
2476
2599
    def __init__(self):
2477
2600
        super(WorkingTreeFormat3, self).__init__()
2478
 
        self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
2479
2601
 
2480
2602
    def open(self, a_bzrdir, _found=False):
2481
2603
        """Return the WorkingTree object for a_bzrdir
2496
2618
        :param a_bzrdir: the dir for the tree.
2497
2619
        :param control_files: the control files for the tree.
2498
2620
        """
2499
 
        return WorkingTree3(a_bzrdir.root_transport.local_abspath('.'),
2500
 
                           _internal=True,
2501
 
                           _format=self,
2502
 
                           _bzrdir=a_bzrdir,
2503
 
                           _control_files=control_files)
 
2621
        return self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
 
2622
                                _internal=True,
 
2623
                                _format=self,
 
2624
                                _bzrdir=a_bzrdir,
 
2625
                                _control_files=control_files)
2504
2626
 
2505
2627
    def __str__(self):
2506
2628
        return self.get_format_string()
2507
2629
 
2508
2630
 
 
2631
class WorkingTreeFormatAB1(WorkingTreeFormat3):
 
2632
    """Working tree format that supports unique roots and nested trees"""
 
2633
 
 
2634
    _tree_class = WorkingTreeAB1
 
2635
 
 
2636
    requires_rich_root = True
 
2637
 
 
2638
    supports_tree_reference = True
 
2639
 
 
2640
    def __init__(self):
 
2641
        WorkingTreeFormat3.__init__(self)
 
2642
        
 
2643
    def __get_matchingbzrdir(self):
 
2644
        return bzrdir.format_registry.make_bzrdir('experimental-knit3')
 
2645
 
 
2646
    _matchingbzrdir = property(__get_matchingbzrdir)
 
2647
 
 
2648
    def get_format_string(self):
 
2649
        """See WorkingTreeFormat.get_format_string()."""
 
2650
        return "Bazaar-NG Working Tree format AB1"
 
2651
 
 
2652
    def get_format_description(self):
 
2653
        """See WorkingTreeFormat.get_format_description()."""
 
2654
        return "Working tree format 4"
 
2655
 
 
2656
    def _initial_inventory(self):
 
2657
        return Inventory(root_id=generate_ids.gen_root_id())
 
2658
 
 
2659
# formats which have no format string are not discoverable
 
2660
# and not independently creatable, so are not registered.
2509
2661
__default_format = WorkingTreeFormat3()
2510
2662
WorkingTreeFormat.register_format(__default_format)
2511
2663
WorkingTreeFormat.register_format(WorkingTreeFormat4())
 
2664
WorkingTreeFormat.register_format(WorkingTreeFormatAB1())
2512
2665
WorkingTreeFormat.set_default_format(__default_format)
2513
2666
# formats which have no format string are not discoverable
2514
2667
# and not independently creatable, so are not registered.