~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
"""
31
31
 
32
32
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
 
33
CONFLICT_HEADER_1 = "BZR conflict list format 1"
33
34
 
34
35
# TODO: Give the workingtree sole responsibility for the working inventory;
35
36
# remove the variable and references to it from the branch.  This may require
49
50
from bzrlib.atomicfile import AtomicFile
50
51
from bzrlib.branch import (Branch,
51
52
                           quotefn)
 
53
from bzrlib.conflicts import Conflict, ConflictList, CONFLICT_SUFFIXES
52
54
import bzrlib.bzrdir as bzrdir
53
55
from bzrlib.decorators import needs_read_lock, needs_write_lock
54
56
import bzrlib.errors as errors
55
57
from bzrlib.errors import (BzrCheckError,
56
58
                           BzrError,
 
59
                           ConflictFormatError,
57
60
                           DivergedBranches,
58
61
                           WeaveRevisionNotPresent,
59
62
                           NotBranchError,
60
63
                           NoSuchFile,
61
64
                           NotVersionedError,
62
 
                           MergeModifiedFormatError)
 
65
                           MergeModifiedFormatError,
 
66
                           UnsupportedOperation,
 
67
                           )
63
68
from bzrlib.inventory import InventoryEntry, Inventory
64
69
from bzrlib.lockable_files import LockableFiles, TransportLock
65
70
from bzrlib.lockdir import LockDir
84
89
                            )
85
90
from bzrlib.progress import DummyProgress, ProgressPhase
86
91
from bzrlib.revision import NULL_REVISION
87
 
from bzrlib.rio import RioReader, RioWriter, Stanza
 
92
from bzrlib.rio import RioReader, rio_file, Stanza
88
93
from bzrlib.symbol_versioning import *
89
94
from bzrlib.textui import show_status
90
95
import bzrlib.tree
91
 
from bzrlib.trace import mutter
92
96
from bzrlib.transform import build_tree
 
97
from bzrlib.trace import mutter, note
93
98
from bzrlib.transport import get_transport
94
99
from bzrlib.transport.local import LocalTransport
95
100
import bzrlib.ui
234
239
        if deprecated_passed(branch):
235
240
            if not _internal:
236
241
                warn("WorkingTree(..., branch=XXX) is deprecated as of bzr 0.8."
237
 
                     " Please use bzrdir.open_workingtree() or WorkingTree.open().",
 
242
                     " Please use bzrdir.open_workingtree() or"
 
243
                     " WorkingTree.open().",
238
244
                     DeprecationWarning,
239
245
                     stacklevel=2
240
246
                     )
607
613
 
608
614
    @needs_write_lock
609
615
    def set_merge_modified(self, modified_hashes):
610
 
        my_file = StringIO()
611
 
        my_file.write(MERGE_MODIFIED_HEADER_1 + '\n')
612
 
        writer = RioWriter(my_file)
613
 
        for file_id, hash in modified_hashes.iteritems():
614
 
            s = Stanza(file_id=file_id, hash=hash)
615
 
            writer.write_stanza(s)
616
 
        my_file.seek(0)
617
 
        self._control_files.put('merge-hashes', my_file)
 
616
        def iter_stanzas():
 
617
            for file_id, hash in modified_hashes.iteritems():
 
618
                yield Stanza(file_id=file_id, hash=hash)
 
619
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
 
620
 
 
621
    @needs_write_lock
 
622
    def _put_rio(self, filename, stanzas, header):
 
623
        my_file = rio_file(stanzas, header)
 
624
        self._control_files.put(filename, my_file)
618
625
 
619
626
    @needs_read_lock
620
627
    def merge_modified(self):
630
637
            raise MergeModifiedFormatError()
631
638
        for s in RioReader(hashfile):
632
639
            file_id = s.get("file_id")
 
640
            if file_id not in self.inventory:
 
641
                continue
633
642
            hash = s.get("hash")
634
643
            if hash == self.get_file_sha1(file_id):
635
644
                merge_hashes[file_id] = hash
861
870
            if not self.is_ignored(subp):
862
871
                yield subp
863
872
 
 
873
    @deprecated_method(zero_eight)
864
874
    def iter_conflicts(self):
 
875
        """List all files in the tree that have text or content conflicts.
 
876
        DEPRECATED.  Use conflicts instead."""
 
877
        return self._iter_conflicts()
 
878
 
 
879
    def _iter_conflicts(self):
865
880
        conflicted = set()
866
881
        for path in (s[0] for s in self.list_files()):
867
882
            stem = get_conflicted_stem(path)
1130
1145
    def revert(self, filenames, old_tree=None, backups=True, 
1131
1146
               pb=DummyProgress()):
1132
1147
        from transform import revert
 
1148
        from conflicts import resolve
1133
1149
        if old_tree is None:
1134
1150
            old_tree = self.basis_tree()
1135
 
        revert(self, old_tree, filenames, backups, pb)
 
1151
        conflicts = revert(self, old_tree, filenames, backups, pb)
1136
1152
        if not len(filenames):
1137
1153
            self.set_pending_merges([])
 
1154
            resolve(self)
 
1155
        else:
 
1156
            resolve(self, filenames, ignore_misses=True)
 
1157
        return conflicts
1138
1158
 
 
1159
    # XXX: This method should be deprecated in favour of taking in a proper
 
1160
    # new Inventory object.
1139
1161
    @needs_write_lock
1140
1162
    def set_inventory(self, new_inventory_list):
1141
1163
        from bzrlib.inventory import (Inventory,
1272
1294
        self._set_inventory(inv)
1273
1295
        mutter('wrote working inventory')
1274
1296
 
 
1297
    def set_conflicts(self, arg):
 
1298
        raise UnsupportedOperation(self.set_conflicts, self)
 
1299
 
 
1300
    @needs_read_lock
 
1301
    def conflicts(self):
 
1302
        conflicts = ConflictList()
 
1303
        for conflicted in self._iter_conflicts():
 
1304
            text = True
 
1305
            try:
 
1306
                if file_kind(self.abspath(conflicted)) != "file":
 
1307
                    text = False
 
1308
            except OSError, e:
 
1309
                if e.errno == errno.ENOENT:
 
1310
                    text = False
 
1311
                else:
 
1312
                    raise
 
1313
            if text is True:
 
1314
                for suffix in ('.THIS', '.OTHER'):
 
1315
                    try:
 
1316
                        kind = file_kind(self.abspath(conflicted+suffix))
 
1317
                    except OSError, e:
 
1318
                        if e.errno == errno.ENOENT:
 
1319
                            text = False
 
1320
                            break
 
1321
                        else:
 
1322
                            raise
 
1323
                    if kind != "file":
 
1324
                        text = False
 
1325
                        break
 
1326
            ctype = {True: 'text conflict', False: 'contents conflict'}[text]
 
1327
            conflicts.append(Conflict.factory(ctype, path=conflicted,
 
1328
                             file_id=self.path2id(conflicted)))
 
1329
        return conflicts
 
1330
 
1275
1331
 
1276
1332
class WorkingTree3(WorkingTree):
1277
1333
    """This is the Format 3 working tree.
1307
1363
            self._control_files.put_utf8('last-revision', revision_id)
1308
1364
            return True
1309
1365
 
1310
 
 
1311
 
CONFLICT_SUFFIXES = ('.THIS', '.BASE', '.OTHER')
 
1366
    @needs_write_lock
 
1367
    def set_conflicts(self, conflicts):
 
1368
        self._put_rio('conflicts', conflicts.to_stanzas(), 
 
1369
                      CONFLICT_HEADER_1)
 
1370
 
 
1371
    @needs_read_lock
 
1372
    def conflicts(self):
 
1373
        try:
 
1374
            confile = self._control_files.get('conflicts')
 
1375
        except NoSuchFile:
 
1376
            return ConflictList()
 
1377
        try:
 
1378
            if confile.next() != CONFLICT_HEADER_1 + '\n':
 
1379
                raise ConflictFormatError()
 
1380
        except StopIteration:
 
1381
            raise ConflictFormatError()
 
1382
        return ConflictList.from_stanzas(RioReader(confile))
 
1383
 
 
1384
 
1312
1385
def get_conflicted_stem(path):
1313
1386
    for suffix in CONFLICT_SUFFIXES:
1314
1387
        if path.endswith(suffix):
1375
1448
        """Return the ASCII format string that identifies this format."""
1376
1449
        raise NotImplementedError(self.get_format_string)
1377
1450
 
 
1451
    def get_format_description(self):
 
1452
        """Return the short description for this format."""
 
1453
        raise NotImplementedError(self.get_format_description)
 
1454
 
1378
1455
    def is_supported(self):
1379
1456
        """Is this format supported?
1380
1457
 
1405
1482
    This format modified the hash cache from the format 1 hash cache.
1406
1483
    """
1407
1484
 
 
1485
    def get_format_description(self):
 
1486
        """See WorkingTreeFormat.get_format_description()."""
 
1487
        return "Working tree format 2"
 
1488
 
1408
1489
    def initialize(self, a_bzrdir, revision_id=None):
1409
1490
        """See WorkingTreeFormat.initialize()."""
1410
1491
        if not isinstance(a_bzrdir.transport, LocalTransport):
1473
1554
        """See WorkingTreeFormat.get_format_string()."""
1474
1555
        return "Bazaar-NG Working Tree format 3"
1475
1556
 
 
1557
    def get_format_description(self):
 
1558
        """See WorkingTreeFormat.get_format_description()."""
 
1559
        return "Working tree format 3"
 
1560
 
1476
1561
    _lock_file_name = 'lock'
1477
1562
    _lock_class = LockDir
1478
1563