~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-06-05 04:05:05 UTC
  • mfrom: (3473.1.1 ianc-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20080605040505-i9kqxg2fps2qjdi0
Add the 'alias' command (Tim Penhey)

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
import os
18
18
import errno
19
 
from stat import S_ISREG, S_IEXEC
 
19
from stat import S_ISREG
 
20
import tempfile
20
21
 
21
22
from bzrlib.lazy_import import lazy_import
22
23
lazy_import(globals(), """
23
24
from bzrlib import (
24
 
    annotate,
25
25
    bzrdir,
26
26
    delta,
27
27
    errors,
28
28
    inventory,
29
 
    osutils,
30
29
    revision as _mod_revision,
31
30
    )
32
31
""")
35
34
                           ExistingLimbo, ImmortalLimbo, NoFinalPath,
36
35
                           UnableCreateSymlink)
37
36
from bzrlib.inventory import InventoryEntry
38
 
from bzrlib.osutils import (
39
 
    delete_any,
40
 
    file_kind,
41
 
    has_symlinks,
42
 
    lexists,
43
 
    pathjoin,
44
 
    sha_file,
45
 
    splitpath,
46
 
    supports_executable,
47
 
)
 
37
from bzrlib.osutils import (file_kind, supports_executable, pathjoin, lexists,
 
38
                            delete_any, has_symlinks)
48
39
from bzrlib.progress import DummyProgress, ProgressPhase
49
40
from bzrlib.symbol_versioning import (
50
41
        deprecated_function,
51
 
        deprecated_in,
52
42
        )
53
43
from bzrlib.trace import mutter, warning
54
44
from bzrlib import tree
130
120
        # Cache of relpath results, to speed up canonical_path
131
121
        self._relpaths = {}
132
122
        # The trans_id that will be used as the tree root
133
 
        root_id = tree.get_root_id()
134
 
        if root_id is not None:
135
 
            self._new_root = self.trans_id_tree_file_id(root_id)
136
 
        else:
137
 
            self._new_root = None
 
123
        self._new_root = self.trans_id_tree_file_id(tree.get_root_id())
138
124
        # Indictor of whether the transform has been applied
139
125
        self._done = False
140
126
        # A progress bar
201
187
        previous_name = self._new_name.get(trans_id)
202
188
        self._new_name[trans_id] = name
203
189
        self._new_parent[trans_id] = parent
204
 
        if parent == ROOT_PARENT:
205
 
            if self._new_root is not None:
206
 
                raise ValueError("Cannot have multiple roots.")
207
 
            self._new_root = trans_id
208
190
        if (trans_id in self._limbo_files and
209
191
            trans_id not in self._needs_rename):
210
192
            self._rename_in_limbo([trans_id])
267
249
        This reflects only files that already exist, not ones that will be
268
250
        added by transactions.
269
251
        """
270
 
        if inventory_id is None:
271
 
            raise ValueError('None is not a valid file id')
272
252
        path = self._tree.id2path(inventory_id)
273
253
        return self.trans_id_tree_path(path)
274
254
 
278
258
        a transaction has been unversioned, it is deliberately still returned.
279
259
        (this will likely lead to an unversioned parent conflict.)
280
260
        """
281
 
        if file_id is None:
282
 
            raise ValueError('None is not a valid file id')
283
261
        if file_id in self._r_new_id and self._r_new_id[file_id] is not None:
284
262
            return self._r_new_id[file_id]
 
263
        elif file_id in self._tree.inventory:
 
264
            return self.trans_id_tree_file_id(file_id)
 
265
        elif file_id in self._non_present_ids:
 
266
            return self._non_present_ids[file_id]
285
267
        else:
286
 
            try:
287
 
                self._tree.iter_entries_by_dir([file_id]).next()
288
 
            except StopIteration:
289
 
                if file_id in self._non_present_ids:
290
 
                    return self._non_present_ids[file_id]
291
 
                else:
292
 
                    trans_id = self._assign_id()
293
 
                    self._non_present_ids[file_id] = trans_id
294
 
                    return trans_id
295
 
            else:
296
 
                return self.trans_id_tree_file_id(file_id)
 
268
            trans_id = self._assign_id()
 
269
            self._non_present_ids[file_id] = trans_id
 
270
            return trans_id
297
271
 
298
272
    def canonical_path(self, path):
299
273
        """Get the canonical tree-relative path"""
372
346
        try:
373
347
            mode = os.stat(self._tree.abspath(old_path)).st_mode
374
348
        except OSError, e:
375
 
            if e.errno in (errno.ENOENT, errno.ENOTDIR):
376
 
                # Either old_path doesn't exist, or the parent of the
377
 
                # target is not a directory (but will be one eventually)
378
 
                # Either way, we know it doesn't exist *right now*
379
 
                # See also bug #248448
 
349
            if e.errno == errno.ENOENT:
380
350
                return
381
351
            else:
382
352
                raise
480
450
        del self._new_id[trans_id]
481
451
        del self._r_new_id[file_id]
482
452
 
483
 
    def new_paths(self, filesystem_only=False):
484
 
        """Determine the paths of all new and changed files.
485
 
 
486
 
        :param filesystem_only: if True, only calculate values for files
487
 
            that require renames or execute bit changes.
488
 
        """
489
 
        new_ids = set()
490
 
        if filesystem_only:
491
 
            stale_ids = self._needs_rename.difference(self._new_name)
492
 
            stale_ids.difference_update(self._new_parent)
493
 
            stale_ids.difference_update(self._new_contents)
494
 
            stale_ids.difference_update(self._new_id)
495
 
            needs_rename = self._needs_rename.difference(stale_ids)
496
 
            id_sets = (needs_rename, self._new_executability)
497
 
        else:
498
 
            id_sets = (self._new_name, self._new_parent, self._new_contents,
499
 
                       self._new_id, self._new_executability)
500
 
        for id_set in id_sets:
501
 
            new_ids.update(id_set)
502
 
        return sorted(FinalPaths(self).get_paths(new_ids))
503
 
 
504
 
    def _inventory_altered(self):
505
 
        """Get the trans_ids and paths of files needing new inv entries."""
506
 
        new_ids = set()
507
 
        for id_set in [self._new_name, self._new_parent, self._new_id,
508
 
                       self._new_executability]:
509
 
            new_ids.update(id_set)
510
 
        changed_kind = set(self._removed_contents)
511
 
        changed_kind.intersection_update(self._new_contents)
512
 
        changed_kind.difference_update(new_ids)
513
 
        changed_kind = (t for t in changed_kind if self.tree_kind(t) !=
514
 
                        self.final_kind(t))
515
 
        new_ids.update(changed_kind)
516
 
        return sorted(FinalPaths(self).get_paths(new_ids))
 
453
    def new_paths(self):
 
454
        """Determine the paths of all new and changed files"""
 
455
        new_ids = set()
 
456
        fp = FinalPaths(self)
 
457
        for id_set in (self._new_name, self._new_parent, self._new_contents,
 
458
                       self._new_id, self._new_executability):
 
459
            new_ids.update(id_set)
 
460
        new_paths = [(fp.get_path(t), t) for t in new_ids]
 
461
        new_paths.sort()
 
462
        return new_paths
517
463
 
518
464
    def tree_kind(self, trans_id):
519
465
        """Determine the file kind in the working tree.
555
501
        # the file is old; the old id is still valid
556
502
        if self._new_root == trans_id:
557
503
            return self._tree.get_root_id()
558
 
        return self._tree.path2id(path)
 
504
        return self._tree.inventory.path2id(path)
559
505
 
560
506
    def final_file_id(self, trans_id):
561
507
        """Determine the file id after any changes are applied, or None.
673
619
        try:
674
620
            children = os.listdir(self._tree.abspath(path))
675
621
        except OSError, e:
676
 
            if not (osutils._is_error_enotdir(e)
677
 
                    or e.errno in (errno.ENOENT, errno.ESRCH)):
 
622
            if e.errno not in (errno.ENOENT, errno.ESRCH, errno.ENOTDIR):
678
623
                raise
679
624
            return
680
 
 
 
625
            
681
626
        for child in children:
682
627
            childpath = joinpath(path, child)
683
628
            if self._tree.is_control_filename(childpath):
908
853
        self._limbo_files[trans_id] = limbo_name
909
854
        return limbo_name
910
855
 
911
 
    def _set_executability(self, path, trans_id):
 
856
    def _set_executability(self, path, entry, trans_id):
912
857
        """Set the executability of versioned files """
 
858
        new_executability = self._new_executability[trans_id]
 
859
        entry.executable = new_executability
913
860
        if supports_executable():
914
 
            new_executability = self._new_executability[trans_id]
915
861
            abspath = self._tree.abspath(path)
916
862
            current_mode = os.stat(abspath).st_mode
917
863
            if new_executability:
1012
958
        from_path = self._tree_id_paths.get(from_trans_id)
1013
959
        if from_versioned:
1014
960
            # get data from working tree if versioned
1015
 
            from_entry = self._tree.iter_entries_by_dir([file_id]).next()[1]
 
961
            from_entry = self._tree.inventory[file_id]
1016
962
            from_name = from_entry.name
1017
963
            from_parent = from_entry.parent_id
1018
964
        else:
1221
1167
                                   tree.case_sensitive)
1222
1168
        self._deletiondir = deletiondir
1223
1169
 
1224
 
    def apply(self, no_conflicts=False, precomputed_delta=None, _mover=None):
 
1170
    def apply(self, no_conflicts=False, _mover=None):
1225
1171
        """Apply all changes to the inventory and filesystem.
1226
1172
 
1227
1173
        If filesystem or inventory conflicts are present, MalformedTransform
1231
1177
 
1232
1178
        :param no_conflicts: if True, the caller guarantees there are no
1233
1179
            conflicts, so no check is made.
1234
 
        :param precomputed_delta: An inventory delta to use instead of
1235
 
            calculating one.
1236
1180
        :param _mover: Supply an alternate FileMover, for testing
1237
1181
        """
1238
1182
        if not no_conflicts:
1239
1183
            conflicts = self.find_conflicts()
1240
1184
            if len(conflicts) != 0:
1241
1185
                raise MalformedTransform(conflicts=conflicts)
 
1186
        inventory_delta = []
1242
1187
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1243
1188
        try:
1244
 
            if precomputed_delta is None:
1245
 
                child_pb.update('Apply phase', 0, 2)
1246
 
                inventory_delta = self._generate_inventory_delta()
1247
 
                offset = 1
1248
 
            else:
1249
 
                inventory_delta = precomputed_delta
1250
 
                offset = 0
1251
1189
            if _mover is None:
1252
1190
                mover = _FileMover()
1253
1191
            else:
1254
1192
                mover = _mover
1255
1193
            try:
1256
 
                child_pb.update('Apply phase', 0 + offset, 2 + offset)
1257
 
                self._apply_removals(mover)
1258
 
                child_pb.update('Apply phase', 1 + offset, 2 + offset)
1259
 
                modified_paths = self._apply_insertions(mover)
 
1194
                child_pb.update('Apply phase', 0, 2)
 
1195
                self._apply_removals(inventory_delta, mover)
 
1196
                child_pb.update('Apply phase', 1, 2)
 
1197
                modified_paths = self._apply_insertions(inventory_delta, mover)
1260
1198
            except:
1261
1199
                mover.rollback()
1262
1200
                raise
1269
1207
        self.finalize()
1270
1208
        return _TransformResults(modified_paths, self.rename_count)
1271
1209
 
1272
 
    def _generate_inventory_delta(self):
1273
 
        """Generate an inventory delta for the current transform."""
1274
 
        inventory_delta = []
1275
 
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1276
 
        new_paths = self._inventory_altered()
1277
 
        total_entries = len(new_paths) + len(self._removed_id)
1278
 
        try:
1279
 
            for num, trans_id in enumerate(self._removed_id):
1280
 
                if (num % 10) == 0:
1281
 
                    child_pb.update('removing file', num, total_entries)
1282
 
                if trans_id == self._new_root:
1283
 
                    file_id = self._tree.get_root_id()
1284
 
                else:
1285
 
                    file_id = self.tree_file_id(trans_id)
1286
 
                # File-id isn't really being deleted, just moved
1287
 
                if file_id in self._r_new_id:
1288
 
                    continue
1289
 
                path = self._tree_id_paths[trans_id]
1290
 
                inventory_delta.append((path, None, file_id, None))
1291
 
            new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in
1292
 
                                     new_paths)
1293
 
            entries = self._tree.iter_entries_by_dir(
1294
 
                new_path_file_ids.values())
1295
 
            old_paths = dict((e.file_id, p) for p, e in entries)
1296
 
            final_kinds = {}
1297
 
            for num, (path, trans_id) in enumerate(new_paths):
1298
 
                if (num % 10) == 0:
1299
 
                    child_pb.update('adding file',
1300
 
                                    num + len(self._removed_id), total_entries)
1301
 
                file_id = new_path_file_ids[trans_id]
1302
 
                if file_id is None:
1303
 
                    continue
1304
 
                needs_entry = False
1305
 
                try:
1306
 
                    kind = self.final_kind(trans_id)
1307
 
                except NoSuchFile:
1308
 
                    kind = self._tree.stored_kind(file_id)
1309
 
                parent_trans_id = self.final_parent(trans_id)
1310
 
                parent_file_id = new_path_file_ids.get(parent_trans_id)
1311
 
                if parent_file_id is None:
1312
 
                    parent_file_id = self.final_file_id(parent_trans_id)
1313
 
                if trans_id in self._new_reference_revision:
1314
 
                    new_entry = inventory.TreeReference(
1315
 
                        file_id,
1316
 
                        self._new_name[trans_id],
1317
 
                        self.final_file_id(self._new_parent[trans_id]),
1318
 
                        None, self._new_reference_revision[trans_id])
1319
 
                else:
1320
 
                    new_entry = inventory.make_entry(kind,
1321
 
                        self.final_name(trans_id),
1322
 
                        parent_file_id, file_id)
1323
 
                old_path = old_paths.get(new_entry.file_id)
1324
 
                new_executability = self._new_executability.get(trans_id)
1325
 
                if new_executability is not None:
1326
 
                    new_entry.executable = new_executability
1327
 
                inventory_delta.append(
1328
 
                    (old_path, path, new_entry.file_id, new_entry))
1329
 
        finally:
1330
 
            child_pb.finished()
1331
 
        return inventory_delta
1332
 
 
1333
 
    def _apply_removals(self, mover):
 
1210
    def _apply_removals(self, inventory_delta, mover):
1334
1211
        """Perform tree operations that remove directory/inventory names.
1335
1212
 
1336
1213
        That is, delete files that are to be deleted, and put any files that
1337
1214
        need renaming into limbo.  This must be done in strict child-to-parent
1338
1215
        order.
1339
 
 
1340
 
        If inventory_delta is None, no inventory delta generation is performed.
1341
1216
        """
1342
1217
        tree_paths = list(self._tree_path_ids.iteritems())
1343
1218
        tree_paths.sort(reverse=True)
1359
1234
                            raise
1360
1235
                    else:
1361
1236
                        self.rename_count += 1
 
1237
                if trans_id in self._removed_id:
 
1238
                    if trans_id == self._new_root:
 
1239
                        file_id = self._tree.get_root_id()
 
1240
                    else:
 
1241
                        file_id = self.tree_file_id(trans_id)
 
1242
                    # File-id isn't really being deleted, just moved
 
1243
                    if file_id in self._r_new_id:
 
1244
                        continue
 
1245
                    inventory_delta.append((path, None, file_id, None))
1362
1246
        finally:
1363
1247
            child_pb.finished()
1364
1248
 
1365
 
    def _apply_insertions(self, mover):
 
1249
    def _apply_insertions(self, inventory_delta, mover):
1366
1250
        """Perform tree operations that insert directory/inventory names.
1367
1251
 
1368
1252
        That is, create any files that need to be created, and restore from
1369
1253
        limbo any files that needed renaming.  This must be done in strict
1370
1254
        parent-to-child order.
1371
 
 
1372
 
        If inventory_delta is None, no inventory delta is calculated, and
1373
 
        no list of modified paths is returned.
1374
1255
        """
1375
 
        new_paths = self.new_paths(filesystem_only=True)
 
1256
        new_paths = self.new_paths()
1376
1257
        modified_paths = []
1377
 
        new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in
1378
 
                                 new_paths)
1379
1258
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
1259
        completed_new = []
1380
1260
        try:
1381
1261
            for num, (path, trans_id) in enumerate(new_paths):
1382
 
                if (num % 10) == 0:
1383
 
                    child_pb.update('adding file', num, len(new_paths))
1384
 
                full_path = self._tree.abspath(path)
1385
 
                if trans_id in self._needs_rename:
1386
 
                    try:
1387
 
                        mover.rename(self._limbo_name(trans_id), full_path)
1388
 
                    except OSError, e:
1389
 
                        # We may be renaming a dangling inventory id
1390
 
                        if e.errno != errno.ENOENT:
1391
 
                            raise
1392
 
                    else:
1393
 
                        self.rename_count += 1
1394
 
                if (trans_id in self._new_contents or
1395
 
                    self.path_changed(trans_id)):
 
1262
                new_entry = None
 
1263
                child_pb.update('adding file', num, len(new_paths))
 
1264
                if trans_id in self._new_contents or \
 
1265
                    self.path_changed(trans_id):
 
1266
                    full_path = self._tree.abspath(path)
 
1267
                    if trans_id in self._needs_rename:
 
1268
                        try:
 
1269
                            mover.rename(self._limbo_name(trans_id), full_path)
 
1270
                        except OSError, e:
 
1271
                            # We may be renaming a dangling inventory id
 
1272
                            if e.errno != errno.ENOENT:
 
1273
                                raise
 
1274
                        else:
 
1275
                            self.rename_count += 1
1396
1276
                    if trans_id in self._new_contents:
1397
1277
                        modified_paths.append(full_path)
 
1278
                        completed_new.append(trans_id)
 
1279
                file_id = self.final_file_id(trans_id)
 
1280
                if file_id is not None and (trans_id in self._new_id or
 
1281
                    trans_id in self._new_name or trans_id in self._new_parent
 
1282
                    or trans_id in self._new_executability):
 
1283
                    try:
 
1284
                        kind = self.final_kind(trans_id)
 
1285
                    except NoSuchFile:
 
1286
                        kind = self._tree.stored_kind(file_id)
 
1287
                    if trans_id in self._new_reference_revision:
 
1288
                        new_entry = inventory.TreeReference(
 
1289
                            self.final_file_id(trans_id),
 
1290
                            self._new_name[trans_id],
 
1291
                            self.final_file_id(self._new_parent[trans_id]),
 
1292
                            None, self._new_reference_revision[trans_id])
 
1293
                    else:
 
1294
                        new_entry = inventory.make_entry(kind,
 
1295
                            self.final_name(trans_id),
 
1296
                            self.final_file_id(self.final_parent(trans_id)),
 
1297
                            self.final_file_id(trans_id))
 
1298
                    try:
 
1299
                        old_path = self._tree.id2path(new_entry.file_id)
 
1300
                    except errors.NoSuchId:
 
1301
                        old_path = None
 
1302
                    inventory_delta.append((old_path, path, new_entry.file_id,
 
1303
                                            new_entry))
 
1304
 
1398
1305
                if trans_id in self._new_executability:
1399
 
                    self._set_executability(path, trans_id)
 
1306
                    self._set_executability(path, new_entry, trans_id)
1400
1307
        finally:
1401
1308
            child_pb.finished()
1402
 
        self._new_contents.clear()
 
1309
        for trans_id in completed_new:
 
1310
            del self._new_contents[trans_id]
1403
1311
        return modified_paths
1404
1312
 
1405
1313
 
1413
1321
 
1414
1322
    def __init__(self, tree, pb=DummyProgress(), case_sensitive=True):
1415
1323
        tree.lock_read()
1416
 
        limbodir = osutils.mkdtemp(prefix='bzr-limbo-')
 
1324
        limbodir = tempfile.mkdtemp(prefix='bzr-limbo-')
1417
1325
        TreeTransformBase.__init__(self, tree, limbodir, pb, case_sensitive)
1418
1326
 
1419
1327
    def canonical_path(self, path):
1442
1350
        except KeyError:
1443
1351
            return
1444
1352
        file_id = self.tree_file_id(parent_id)
1445
 
        if file_id is None:
1446
 
            return
1447
 
        entry = self._tree.iter_entries_by_dir([file_id]).next()[1]
1448
 
        children = getattr(entry, 'children', {})
1449
 
        for child in children:
 
1353
        for child in self._tree.inventory[file_id].children.iterkeys():
1450
1354
            childpath = joinpath(path, child)
1451
1355
            yield self.trans_id_tree_path(childpath)
1452
1356
 
1457
1361
    def __init__(self, transform):
1458
1362
        self._transform = transform
1459
1363
        self._final_paths = FinalPaths(transform)
1460
 
        self.__by_parent = None
1461
 
        self._parent_ids = []
1462
 
        self._all_children_cache = {}
1463
 
        self._path2trans_id_cache = {}
1464
 
        self._final_name_cache = {}
1465
1364
 
1466
1365
    def _changes(self, file_id):
1467
1366
        for changes in self._transform.iter_changes():
1475
1374
        # InterTree.iter_changes.
1476
1375
        return (changes is not None and changes[2])
1477
1376
 
1478
 
    def _get_repository(self):
1479
 
        repo = getattr(self._transform._tree, '_repository', None)
1480
 
        if repo is None:
1481
 
            repo = self._transform._tree.branch.repository
1482
 
        return repo
1483
 
 
1484
 
    def _iter_parent_trees(self):
1485
 
        for revision_id in self.get_parent_ids():
1486
 
            try:
1487
 
                yield self.revision_tree(revision_id)
1488
 
            except errors.NoSuchRevisionInTree:
1489
 
                yield self._get_repository().revision_tree(revision_id)
1490
 
 
1491
1377
    def _get_file_revision(self, file_id, vf, tree_revision):
1492
 
        parent_keys = [(file_id, self._file_revision(t, file_id)) for t in
1493
 
                       self._iter_parent_trees()]
1494
 
        vf.add_lines((file_id, tree_revision), parent_keys,
1495
 
                     self.get_file(file_id).readlines())
1496
 
        repo = self._get_repository()
1497
 
        base_vf = repo.texts
1498
 
        if base_vf not in vf.fallback_versionedfiles:
1499
 
            vf.fallback_versionedfiles.append(base_vf)
1500
 
        return tree_revision
 
1378
        return self._transform._tree._get_file_revision(file_id, vf,
 
1379
                                                        tree_revision)
1501
1380
 
1502
1381
    def _stat_limbo_file(self, file_id):
1503
1382
        trans_id = self._transform.trans_id_file_id(file_id)
1504
1383
        name = self._transform._limbo_name(trans_id)
1505
1384
        return os.lstat(name)
1506
1385
 
1507
 
    @property
1508
 
    def _by_parent(self):
1509
 
        if self.__by_parent is None:
1510
 
            self.__by_parent = self._transform.by_parent()
1511
 
        return self.__by_parent
1512
 
 
1513
 
    def _comparison_data(self, entry, path):
1514
 
        kind, size, executable, link_or_sha1 = self.path_content_summary(path)
1515
 
        if kind == 'missing':
1516
 
            kind = None
1517
 
            executable = False
1518
 
        else:
1519
 
            file_id = self._transform.final_file_id(self._path2trans_id(path))
1520
 
            executable = self.is_executable(file_id, path)
1521
 
        return kind, executable, None
1522
 
 
1523
1386
    def lock_read(self):
1524
1387
        # Perhaps in theory, this should lock the TreeTransform?
1525
1388
        pass
1536
1399
        return self._transform.final_file_id(self._transform.root)
1537
1400
 
1538
1401
    def all_file_ids(self):
1539
 
        tree_ids = set(self._transform._tree.all_file_ids())
1540
 
        tree_ids.difference_update(self._transform.tree_file_id(t)
1541
 
                                   for t in self._transform._removed_id)
1542
 
        tree_ids.update(self._transform._new_id.values())
1543
 
        return tree_ids
 
1402
        return self._transform._tree.all_file_ids()
1544
1403
 
1545
1404
    def __iter__(self):
1546
1405
        return iter(self.all_file_ids())
1547
1406
 
1548
 
    def has_id(self, file_id):
1549
 
        if file_id in self._transform._r_new_id:
1550
 
            return True
1551
 
        elif file_id in self._transform._removed_id:
1552
 
            return False
1553
 
        else:
1554
 
            return self._transform._tree.has_id(file_id)
1555
 
 
1556
 
    def _path2trans_id(self, path):
1557
 
        # We must not use None here, because that is a valid value to store.
1558
 
        trans_id = self._path2trans_id_cache.get(path, object)
1559
 
        if trans_id is not object:
1560
 
            return trans_id
1561
 
        segments = splitpath(path)
1562
 
        cur_parent = self._transform.root
1563
 
        for cur_segment in segments:
1564
 
            for child in self._all_children(cur_parent):
1565
 
                final_name = self._final_name_cache.get(child)
1566
 
                if final_name is None:
1567
 
                    final_name = self._transform.final_name(child)
1568
 
                    self._final_name_cache[child] = final_name
1569
 
                if final_name == cur_segment:
1570
 
                    cur_parent = child
1571
 
                    break
1572
 
            else:
1573
 
                self._path2trans_id_cache[path] = None
1574
 
                return None
1575
 
        self._path2trans_id_cache[path] = cur_parent
1576
 
        return cur_parent
 
1407
    def paths2ids(self, specific_files, trees=None, require_versioned=False):
 
1408
        """See Tree.paths2ids"""
 
1409
        to_find = set(specific_files)
 
1410
        result = set()
 
1411
        for (file_id, paths, changed, versioned, parent, name, kind,
 
1412
             executable) in self._transform.iter_changes():
 
1413
            if paths[1] in to_find:
 
1414
                result.append(file_id)
 
1415
                to_find.remove(paths[1])
 
1416
        result.update(self._transform._tree.paths2ids(to_find,
 
1417
                      trees=[], require_versioned=require_versioned))
 
1418
        return result
1577
1419
 
1578
1420
    def path2id(self, path):
1579
 
        return self._transform.final_file_id(self._path2trans_id(path))
 
1421
        return self._transform._tree.path2id(path)
1580
1422
 
1581
1423
    def id2path(self, file_id):
1582
1424
        trans_id = self._transform.trans_id_file_id(file_id)
1585
1427
        except NoFinalPath:
1586
1428
            raise errors.NoSuchId(self, file_id)
1587
1429
 
1588
 
    def _all_children(self, trans_id):
1589
 
        children = self._all_children_cache.get(trans_id)
1590
 
        if children is not None:
1591
 
            return children
1592
 
        children = set(self._transform.iter_tree_children(trans_id))
1593
 
        # children in the _new_parent set are provided by _by_parent.
1594
 
        children.difference_update(self._transform._new_parent.keys())
1595
 
        children.update(self._by_parent.get(trans_id, []))
1596
 
        self._all_children_cache[trans_id] = children
1597
 
        return children
1598
 
 
1599
 
    def iter_children(self, file_id):
1600
 
        trans_id = self._transform.trans_id_file_id(file_id)
1601
 
        for child_trans_id in self._all_children(trans_id):
1602
 
            yield self._transform.final_file_id(child_trans_id)
1603
 
 
1604
 
    def extras(self):
1605
 
        possible_extras = set(self._transform.trans_id_tree_path(p) for p
1606
 
                              in self._transform._tree.extras())
1607
 
        possible_extras.update(self._transform._new_contents)
1608
 
        possible_extras.update(self._transform._removed_id)
1609
 
        for trans_id in possible_extras:
1610
 
            if self._transform.final_file_id(trans_id) is None:
1611
 
                yield self._final_paths._determine_path(trans_id)
1612
 
 
1613
 
    def _make_inv_entries(self, ordered_entries, specific_file_ids):
1614
 
        for trans_id, parent_file_id in ordered_entries:
1615
 
            file_id = self._transform.final_file_id(trans_id)
1616
 
            if file_id is None:
1617
 
                continue
1618
 
            if (specific_file_ids is not None
1619
 
                and file_id not in specific_file_ids):
1620
 
                continue
1621
 
            try:
1622
 
                kind = self._transform.final_kind(trans_id)
1623
 
            except NoSuchFile:
1624
 
                kind = self._transform._tree.stored_kind(file_id)
1625
 
            new_entry = inventory.make_entry(
1626
 
                kind,
1627
 
                self._transform.final_name(trans_id),
1628
 
                parent_file_id, file_id)
1629
 
            yield new_entry, trans_id
1630
 
 
1631
 
    def _list_files_by_dir(self):
1632
 
        todo = [ROOT_PARENT]
1633
 
        ordered_ids = []
1634
 
        while len(todo) > 0:
1635
 
            parent = todo.pop()
1636
 
            parent_file_id = self._transform.final_file_id(parent)
1637
 
            children = list(self._all_children(parent))
1638
 
            paths = dict(zip(children, self._final_paths.get_paths(children)))
1639
 
            children.sort(key=paths.get)
1640
 
            todo.extend(reversed(children))
1641
 
            for trans_id in children:
1642
 
                ordered_ids.append((trans_id, parent_file_id))
1643
 
        return ordered_ids
1644
 
 
1645
1430
    def iter_entries_by_dir(self, specific_file_ids=None):
1646
 
        # This may not be a maximally efficient implementation, but it is
1647
 
        # reasonably straightforward.  An implementation that grafts the
1648
 
        # TreeTransform changes onto the tree's iter_entries_by_dir results
1649
 
        # might be more efficient, but requires tricky inferences about stack
1650
 
        # position.
1651
 
        ordered_ids = self._list_files_by_dir()
1652
 
        for entry, trans_id in self._make_inv_entries(ordered_ids,
1653
 
                                                      specific_file_ids):
1654
 
            yield unicode(self._final_paths.get_path(trans_id)), entry
1655
 
 
1656
 
    def list_files(self, include_root=False):
1657
 
        """See Tree.list_files."""
1658
 
        # XXX This should behave like WorkingTree.list_files, but is really
1659
 
        # more like RevisionTree.list_files.
1660
 
        for path, entry in self.iter_entries_by_dir():
1661
 
            if entry.name == '' and not include_root:
1662
 
                continue
1663
 
            yield path, 'V', entry.kind, entry.file_id, entry
 
1431
        return self._transform._tree.iter_entries_by_dir(specific_file_ids)
1664
1432
 
1665
1433
    def kind(self, file_id):
1666
1434
        trans_id = self._transform.trans_id_file_id(file_id)
1667
1435
        return self._transform.final_kind(trans_id)
1668
1436
 
1669
1437
    def stored_kind(self, file_id):
1670
 
        trans_id = self._transform.trans_id_file_id(file_id)
1671
 
        try:
1672
 
            return self._transform._new_contents[trans_id]
1673
 
        except KeyError:
1674
 
            return self._transform._tree.stored_kind(file_id)
 
1438
        return self._transform._tree.stored_kind(file_id)
1675
1439
 
1676
1440
    def get_file_mtime(self, file_id, path=None):
1677
1441
        """See Tree.get_file_mtime"""
1679
1443
            return self._transform._tree.get_file_mtime(file_id, path)
1680
1444
        return self._stat_limbo_file(file_id).st_mtime
1681
1445
 
1682
 
    def _file_size(self, entry, stat_value):
1683
 
        return self.get_file_size(entry.file_id)
1684
 
 
1685
1446
    def get_file_size(self, file_id):
1686
1447
        """See Tree.get_file_size"""
1687
1448
        if self.kind(file_id) == 'file':
1690
1451
            return None
1691
1452
 
1692
1453
    def get_file_sha1(self, file_id, path=None, stat_value=None):
1693
 
        trans_id = self._transform.trans_id_file_id(file_id)
1694
 
        kind = self._transform._new_contents.get(trans_id)
1695
 
        if kind is None:
1696
 
            return self._transform._tree.get_file_sha1(file_id)
1697
 
        if kind == 'file':
1698
 
            fileobj = self.get_file(file_id)
1699
 
            try:
1700
 
                return sha_file(fileobj)
1701
 
            finally:
1702
 
                fileobj.close()
 
1454
        return self._transform._tree.get_file_sha1(file_id)
1703
1455
 
1704
1456
    def is_executable(self, file_id, path=None):
1705
 
        if file_id is None:
1706
 
            return False
1707
 
        trans_id = self._transform.trans_id_file_id(file_id)
1708
 
        try:
1709
 
            return self._transform._new_executability[trans_id]
1710
 
        except KeyError:
1711
 
            try:
1712
 
                return self._transform._tree.is_executable(file_id, path)
1713
 
            except OSError, e:
1714
 
                if e.errno == errno.ENOENT:
1715
 
                    return False
1716
 
                raise
1717
 
            except errors.NoSuchId:
1718
 
                return False
 
1457
        return self._transform._tree.is_executable(file_id, path)
1719
1458
 
1720
1459
    def path_content_summary(self, path):
1721
 
        trans_id = self._path2trans_id(path)
1722
 
        tt = self._transform
1723
 
        tree_path = tt._tree_id_paths.get(trans_id)
1724
 
        kind = tt._new_contents.get(trans_id)
1725
 
        if kind is None:
1726
 
            if tree_path is None or trans_id in tt._removed_contents:
1727
 
                return 'missing', None, None, None
1728
 
            summary = tt._tree.path_content_summary(tree_path)
1729
 
            kind, size, executable, link_or_sha1 = summary
1730
 
        else:
1731
 
            link_or_sha1 = None
1732
 
            limbo_name = tt._limbo_name(trans_id)
1733
 
            if trans_id in tt._new_reference_revision:
1734
 
                kind = 'tree-reference'
1735
 
            if kind == 'file':
1736
 
                statval = os.lstat(limbo_name)
1737
 
                size = statval.st_size
1738
 
                if not supports_executable():
1739
 
                    executable = None
1740
 
                else:
1741
 
                    executable = statval.st_mode & S_IEXEC
1742
 
            else:
1743
 
                size = None
1744
 
                executable = None
1745
 
            if kind == 'symlink':
1746
 
                link_or_sha1 = os.readlink(limbo_name)
1747
 
        if supports_executable():
1748
 
            executable = tt._new_executability.get(trans_id, executable)
1749
 
        return kind, size, executable, link_or_sha1
 
1460
        return self._transform._tree.path_content_summary(path)
1750
1461
 
1751
1462
    def iter_changes(self, from_tree, include_unchanged=False,
1752
1463
                      specific_files=None, pb=None, extra_trees=None,
1753
1464
                      require_versioned=True, want_unversioned=False):
1754
1465
        """See InterTree.iter_changes.
1755
1466
 
1756
 
        This has a fast path that is only used when the from_tree matches
1757
 
        the transform tree, and no fancy options are supplied.
 
1467
        This implementation does not support include_unchanged, specific_files,
 
1468
        or want_unversioned.  extra_trees, require_versioned, and pb are
 
1469
        ignored.
1758
1470
        """
1759
 
        if (from_tree is not self._transform._tree or include_unchanged or
1760
 
            specific_files or want_unversioned):
1761
 
            return tree.InterTree(from_tree, self).iter_changes(
1762
 
                include_unchanged=include_unchanged,
1763
 
                specific_files=specific_files,
1764
 
                pb=pb,
1765
 
                extra_trees=extra_trees,
1766
 
                require_versioned=require_versioned,
1767
 
                want_unversioned=want_unversioned)
 
1471
        if from_tree is not self._transform._tree:
 
1472
            raise ValueError('from_tree must be transform source tree.')
 
1473
        if include_unchanged:
 
1474
            raise ValueError('include_unchanged is not supported')
 
1475
        if specific_files is not None:
 
1476
            raise ValueError('specific_files is not supported')
1768
1477
        if want_unversioned:
1769
1478
            raise ValueError('want_unversioned is not supported')
1770
1479
        return self._transform.iter_changes()
1777
1486
        name = self._transform._limbo_name(trans_id)
1778
1487
        return open(name, 'rb')
1779
1488
 
 
1489
    def get_file_text(self, file_id):
 
1490
        text_file = self.get_file(file_id)
 
1491
        try:
 
1492
            return text_file.read()
 
1493
        finally:
 
1494
            text_file.close()
 
1495
 
1780
1496
    def annotate_iter(self, file_id,
1781
1497
                      default_revision=_mod_revision.CURRENT_REVISION):
1782
 
        changes = self._changes(file_id)
1783
 
        if changes is None:
1784
 
            get_old = True
1785
 
        else:
1786
 
            changed_content, versioned, kind = (changes[2], changes[3],
1787
 
                                                changes[6])
1788
 
            if kind[1] is None:
1789
 
                return None
1790
 
            get_old = (kind[0] == 'file' and versioned[0])
1791
 
        if get_old:
1792
 
            old_annotation = self._transform._tree.annotate_iter(file_id,
1793
 
                default_revision=default_revision)
1794
 
        else:
1795
 
            old_annotation = []
1796
 
        if changes is None:
1797
 
            return old_annotation
1798
 
        if not changed_content:
1799
 
            return old_annotation
1800
 
        return annotate.reannotate([old_annotation],
1801
 
                                   self.get_file(file_id).readlines(),
1802
 
                                   default_revision)
 
1498
        return self._transform._tree.annotate_iter(file_id,
 
1499
            default_revision=default_revision)
1803
1500
 
1804
1501
    def get_symlink_target(self, file_id):
1805
1502
        """See Tree.get_symlink_target"""
1809
1506
        name = self._transform._limbo_name(trans_id)
1810
1507
        return os.readlink(name)
1811
1508
 
1812
 
    def walkdirs(self, prefix=''):
1813
 
        pending = [self._transform.root]
1814
 
        while len(pending) > 0:
1815
 
            parent_id = pending.pop()
1816
 
            children = []
1817
 
            subdirs = []
1818
 
            prefix = prefix.rstrip('/')
1819
 
            parent_path = self._final_paths.get_path(parent_id)
1820
 
            parent_file_id = self._transform.final_file_id(parent_id)
1821
 
            for child_id in self._all_children(parent_id):
1822
 
                path_from_root = self._final_paths.get_path(child_id)
1823
 
                basename = self._transform.final_name(child_id)
1824
 
                file_id = self._transform.final_file_id(child_id)
1825
 
                try:
1826
 
                    kind = self._transform.final_kind(child_id)
1827
 
                    versioned_kind = kind
1828
 
                except NoSuchFile:
1829
 
                    kind = 'unknown'
1830
 
                    versioned_kind = self._transform._tree.stored_kind(file_id)
1831
 
                if versioned_kind == 'directory':
1832
 
                    subdirs.append(child_id)
1833
 
                children.append((path_from_root, basename, kind, None,
1834
 
                                 file_id, versioned_kind))
1835
 
            children.sort()
1836
 
            if parent_path.startswith(prefix):
1837
 
                yield (parent_path, parent_file_id), children
1838
 
            pending.extend(sorted(subdirs, key=self._final_paths.get_path,
1839
 
                                  reverse=True))
 
1509
    def list_files(self, include_root=False):
 
1510
        return self._transform._tree.list_files(include_root)
 
1511
 
 
1512
    def walkdirs(self, prefix=""):
 
1513
        return self._transform._tree.walkdirs(prefix)
1840
1514
 
1841
1515
    def get_parent_ids(self):
1842
 
        return self._parent_ids
1843
 
 
1844
 
    def set_parent_ids(self, parent_ids):
1845
 
        self._parent_ids = parent_ids
 
1516
        return self._transform._tree.get_parent_ids()
1846
1517
 
1847
1518
    def get_revision_tree(self, revision_id):
1848
1519
        return self._transform._tree.get_revision_tree(revision_id)
1883
1554
            self._known_paths[trans_id] = self._determine_path(trans_id)
1884
1555
        return self._known_paths[trans_id]
1885
1556
 
1886
 
    def get_paths(self, trans_ids):
1887
 
        return [(self.get_path(t), t) for t in trans_ids]
1888
 
 
1889
 
 
1890
1557
 
1891
1558
def topology_sorted_ids(tree):
1892
1559
    """Determine the topological order of the ids in a tree"""
1895
1562
    return file_ids
1896
1563
 
1897
1564
 
1898
 
def build_tree(tree, wt, accelerator_tree=None, hardlink=False,
1899
 
               delta_from_tree=False):
 
1565
def build_tree(tree, wt, accelerator_tree=None, hardlink=False):
1900
1566
    """Create working tree for a branch, using a TreeTransform.
1901
1567
    
1902
1568
    This function should be used on empty trees, having a tree root at most.
1918
1584
    :param hardlink: If true, hard-link files to accelerator_tree, where
1919
1585
        possible.  accelerator_tree must implement abspath, i.e. be a
1920
1586
        working tree.
1921
 
    :param delta_from_tree: If true, build_tree may use the input Tree to
1922
 
        generate the inventory delta.
1923
1587
    """
1924
1588
    wt.lock_tree_write()
1925
1589
    try:
1928
1592
            if accelerator_tree is not None:
1929
1593
                accelerator_tree.lock_read()
1930
1594
            try:
1931
 
                return _build_tree(tree, wt, accelerator_tree, hardlink,
1932
 
                                   delta_from_tree)
 
1595
                return _build_tree(tree, wt, accelerator_tree, hardlink)
1933
1596
            finally:
1934
1597
                if accelerator_tree is not None:
1935
1598
                    accelerator_tree.unlock()
1939
1602
        wt.unlock()
1940
1603
 
1941
1604
 
1942
 
def _build_tree(tree, wt, accelerator_tree, hardlink, delta_from_tree):
 
1605
def _build_tree(tree, wt, accelerator_tree, hardlink):
1943
1606
    """See build_tree."""
1944
1607
    for num, _unused in enumerate(wt.all_file_ids()):
1945
1608
        if num > 0:  # more than just a root
1946
1609
            raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
1947
 
    existing_files = set()
1948
 
    for dir, files in wt.walkdirs():
1949
 
        existing_files.update(f[0] for f in files)
1950
1610
    file_trans_id = {}
1951
1611
    top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1952
1612
    pp = ProgressPhase("Build phase", 2, top_pb)
1971
1631
        try:
1972
1632
            deferred_contents = []
1973
1633
            num = 0
1974
 
            total = len(tree.inventory)
1975
 
            if delta_from_tree:
1976
 
                precomputed_delta = []
1977
 
            else:
1978
 
                precomputed_delta = None
1979
1634
            for num, (tree_path, entry) in \
1980
1635
                enumerate(tree.inventory.iter_entries_by_dir()):
1981
 
                pb.update("Building tree", num - len(deferred_contents), total)
 
1636
                pb.update("Building tree", num - len(deferred_contents),
 
1637
                          len(tree.inventory))
1982
1638
                if entry.parent_id is None:
1983
1639
                    continue
1984
1640
                reparent = False
1985
1641
                file_id = entry.file_id
1986
 
                if delta_from_tree:
1987
 
                    precomputed_delta.append((None, tree_path, file_id, entry))
1988
 
                if tree_path in existing_files:
1989
 
                    target_path = wt.abspath(tree_path)
 
1642
                target_path = wt.abspath(tree_path)
 
1643
                try:
1990
1644
                    kind = file_kind(target_path)
 
1645
                except NoSuchFile:
 
1646
                    pass
 
1647
                else:
1991
1648
                    if kind == "directory":
1992
1649
                        try:
1993
1650
                            bzrdir.BzrDir.open(target_path)
2001
1658
                        tt.delete_contents(tt.trans_id_tree_path(tree_path))
2002
1659
                        if kind == 'directory':
2003
1660
                            reparent = True
 
1661
                if entry.parent_id not in file_trans_id:
 
1662
                    raise AssertionError(
 
1663
                        'entry %s parent id %r is not in file_trans_id %r'
 
1664
                        % (entry, entry.parent_id, file_trans_id))
2004
1665
                parent_id = file_trans_id[entry.parent_id]
2005
1666
                if entry.kind == 'file':
2006
1667
                    # We *almost* replicate new_by_entry, so that we can defer
2007
1668
                    # getting the file text, and get them all at once.
2008
1669
                    trans_id = tt.create_path(entry.name, parent_id)
2009
1670
                    file_trans_id[file_id] = trans_id
2010
 
                    tt.version_file(file_id, trans_id)
2011
 
                    executable = tree.is_executable(file_id, tree_path)
2012
 
                    if executable:
 
1671
                    tt.version_file(entry.file_id, trans_id)
 
1672
                    executable = tree.is_executable(entry.file_id, tree_path)
 
1673
                    if executable is not None:
2013
1674
                        tt.set_executability(executable, trans_id)
2014
 
                    deferred_contents.append((file_id, trans_id))
 
1675
                    deferred_contents.append((entry.file_id, trans_id))
2015
1676
                else:
2016
1677
                    file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,
2017
1678
                                                          tree)
2028
1689
        divert_trans = set(file_trans_id[f] for f in divert)
2029
1690
        resolver = lambda t, c: resolve_checkout(t, c, divert_trans)
2030
1691
        raw_conflicts = resolve_conflicts(tt, pass_func=resolver)
2031
 
        if len(raw_conflicts) > 0:
2032
 
            precomputed_delta = None
2033
1692
        conflicts = cook_conflicts(raw_conflicts, tt)
2034
1693
        for conflict in conflicts:
2035
1694
            warning(conflict)
2037
1696
            wt.add_conflicts(conflicts)
2038
1697
        except errors.UnsupportedOperation:
2039
1698
            pass
2040
 
        result = tt.apply(no_conflicts=True,
2041
 
                          precomputed_delta=precomputed_delta)
 
1699
        result = tt.apply(no_conflicts=True)
2042
1700
    finally:
2043
1701
        tt.finalize()
2044
1702
        top_pb.finished()
2154
1812
        raise errors.BadFileKindError(name, kind)
2155
1813
 
2156
1814
 
2157
 
@deprecated_function(deprecated_in((1, 9, 0)))
2158
1815
def create_by_entry(tt, entry, tree, trans_id, lines=None, mode_id=None):
2159
 
    """Create new file contents according to an inventory entry.
2160
 
 
2161
 
    DEPRECATED.  Use create_from_tree instead.
2162
 
    """
 
1816
    """Create new file contents according to an inventory entry."""
2163
1817
    if entry.kind == "file":
2164
1818
        if lines is None:
2165
1819
            lines = tree.get_file(entry.file_id).readlines()
2170
1824
        tt.create_directory(trans_id)
2171
1825
 
2172
1826
 
2173
 
def create_from_tree(tt, trans_id, tree, file_id, bytes=None):
2174
 
    """Create new file contents according to tree contents."""
2175
 
    kind = tree.kind(file_id)
2176
 
    if kind == 'directory':
2177
 
        tt.create_directory(trans_id)
2178
 
    elif kind == "file":
2179
 
        if bytes is None:
2180
 
            tree_file = tree.get_file(file_id)
2181
 
            try:
2182
 
                bytes = tree_file.readlines()
2183
 
            finally:
2184
 
                tree_file.close()
2185
 
        tt.create_file(bytes, trans_id)
2186
 
    elif kind == "symlink":
2187
 
        tt.create_symlink(tree.get_symlink_target(file_id), trans_id)
2188
 
    else:
2189
 
        raise AssertionError('Unknown kind %r' % kind)
2190
 
 
2191
 
 
2192
1827
def create_entry_executability(tt, entry, trans_id):
2193
1828
    """Set the executability of a trans_id according to an inventory entry"""
2194
1829
    if entry.kind == "file":
2245
1880
    tt = TreeTransform(working_tree, pb)
2246
1881
    try:
2247
1882
        pp = ProgressPhase("Revert phase", 3, pb)
2248
 
        conflicts, merge_modified = _prepare_revert_transform(
2249
 
            working_tree, target_tree, tt, filenames, backups, pp)
 
1883
        pp.next_phase()
 
1884
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
1885
        try:
 
1886
            merge_modified = _alter_files(working_tree, target_tree, tt,
 
1887
                                          child_pb, filenames, backups)
 
1888
        finally:
 
1889
            child_pb.finished()
 
1890
        pp.next_phase()
 
1891
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
1892
        try:
 
1893
            raw_conflicts = resolve_conflicts(tt, child_pb,
 
1894
                lambda t, c: conflict_pass(t, c, target_tree))
 
1895
        finally:
 
1896
            child_pb.finished()
 
1897
        conflicts = cook_conflicts(raw_conflicts, tt)
2250
1898
        if change_reporter:
2251
1899
            change_reporter = delta._ChangeReporter(
2252
1900
                unversioned_filter=working_tree.is_ignored)
2263
1911
    return conflicts
2264
1912
 
2265
1913
 
2266
 
def _prepare_revert_transform(working_tree, target_tree, tt, filenames,
2267
 
                              backups, pp, basis_tree=None,
2268
 
                              merge_modified=None):
2269
 
    pp.next_phase()
2270
 
    child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2271
 
    try:
2272
 
        if merge_modified is None:
2273
 
            merge_modified = working_tree.merge_modified()
2274
 
        merge_modified = _alter_files(working_tree, target_tree, tt,
2275
 
                                      child_pb, filenames, backups,
2276
 
                                      merge_modified, basis_tree)
2277
 
    finally:
2278
 
        child_pb.finished()
2279
 
    pp.next_phase()
2280
 
    child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2281
 
    try:
2282
 
        raw_conflicts = resolve_conflicts(tt, child_pb,
2283
 
            lambda t, c: conflict_pass(t, c, target_tree))
2284
 
    finally:
2285
 
        child_pb.finished()
2286
 
    conflicts = cook_conflicts(raw_conflicts, tt)
2287
 
    return conflicts, merge_modified
2288
 
 
2289
 
 
2290
1914
def _alter_files(working_tree, target_tree, tt, pb, specific_files,
2291
 
                 backups, merge_modified, basis_tree=None):
2292
 
    if basis_tree is not None:
2293
 
        basis_tree.lock_read()
 
1915
                 backups):
 
1916
    merge_modified = working_tree.merge_modified()
2294
1917
    change_list = target_tree.iter_changes(working_tree,
2295
1918
        specific_files=specific_files, pb=pb)
2296
 
    if target_tree.get_root_id() is None:
 
1919
    if target_tree.inventory.root is None:
2297
1920
        skip_root = True
2298
1921
    else:
2299
1922
        skip_root = False
 
1923
    basis_tree = None
2300
1924
    try:
2301
1925
        deferred_files = []
2302
1926
        for id_num, (file_id, path, changed_content, versioned, parent, name,
2338
1962
                        # contents
2339
1963
                        mode_id = trans_id
2340
1964
                        trans_id = new_trans_id
2341
 
                if kind[1] in ('directory', 'tree-reference'):
 
1965
                if kind[1] == 'directory':
2342
1966
                    tt.create_directory(trans_id)
2343
 
                    if kind[1] == 'tree-reference':
2344
 
                        revision = target_tree.get_reference_revision(file_id,
2345
 
                                                                      path[1])
2346
 
                        tt.set_tree_reference(revision, trans_id)
2347
1967
                elif kind[1] == 'symlink':
2348
1968
                    tt.create_symlink(target_tree.get_symlink_target(file_id),
2349
1969
                                      trans_id)
2369
1989
                tt.version_file(file_id, trans_id)
2370
1990
            if versioned == (True, False):
2371
1991
                tt.unversion_file(trans_id)
2372
 
            if (name[1] is not None and
 
1992
            if (name[1] is not None and 
2373
1993
                (name[0] != name[1] or parent[0] != parent[1])):
2374
 
                if name[1] == '' and parent[1] is None:
2375
 
                    parent_trans = ROOT_PARENT
2376
 
                else:
2377
 
                    parent_trans = tt.trans_id_file_id(parent[1])
2378
 
                tt.adjust_path(name[1], parent_trans, trans_id)
 
1994
                tt.adjust_path(
 
1995
                    name[1], tt.trans_id_file_id(parent[1]), trans_id)
2379
1996
            if executable[0] != executable[1] and kind[1] == "file":
2380
1997
                tt.set_executability(executable[1], trans_id)
2381
1998
        for (trans_id, mode_id), bytes in target_tree.iter_files_bytes(
2489
2106
            if parent_file_id is not None:
2490
2107
                tt.unversion_file(parent_id)
2491
2108
            new_conflicts.add((c_type, 'Created directory', new_parent_id))
2492
 
        elif c_type == 'versioning no contents':
2493
 
            tt.cancel_versioning(conflict[1])
2494
2109
    return new_conflicts
2495
2110
 
2496
2111