~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: Robert Collins
  • Date: 2008-09-02 05:28:37 UTC
  • mfrom: (3675 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3677.
  • Revision ID: robertc@robertcollins.net-20080902052837-ec3qlv41q5e7f6fl
Resolve conflicts with NEWS.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
import os
18
18
import errno
19
19
from stat import S_ISREG, S_IEXEC
20
 
import tempfile
21
20
 
22
21
from bzrlib.lazy_import import lazy_import
23
22
lazy_import(globals(), """
129
128
        # Cache of relpath results, to speed up canonical_path
130
129
        self._relpaths = {}
131
130
        # The trans_id that will be used as the tree root
132
 
        self._new_root = self.trans_id_tree_file_id(tree.get_root_id())
 
131
        root_id = tree.get_root_id()
 
132
        if root_id is not None:
 
133
            self._new_root = self.trans_id_tree_file_id(root_id)
 
134
        else:
 
135
            self._new_root = None
133
136
        # Indictor of whether the transform has been applied
134
137
        self._done = False
135
138
        # A progress bar
196
199
        previous_name = self._new_name.get(trans_id)
197
200
        self._new_name[trans_id] = name
198
201
        self._new_parent[trans_id] = parent
 
202
        if parent == ROOT_PARENT:
 
203
            if self._new_root is not None:
 
204
                raise ValueError("Cannot have multiple roots.")
 
205
            self._new_root = trans_id
199
206
        if (trans_id in self._limbo_files and
200
207
            trans_id not in self._needs_rename):
201
208
            self._rename_in_limbo([trans_id])
258
265
        This reflects only files that already exist, not ones that will be
259
266
        added by transactions.
260
267
        """
 
268
        if inventory_id is None:
 
269
            raise ValueError('None is not a valid file id')
261
270
        path = self._tree.id2path(inventory_id)
262
271
        return self.trans_id_tree_path(path)
263
272
 
267
276
        a transaction has been unversioned, it is deliberately still returned.
268
277
        (this will likely lead to an unversioned parent conflict.)
269
278
        """
 
279
        if file_id is None:
 
280
            raise ValueError('None is not a valid file id')
270
281
        if file_id in self._r_new_id and self._r_new_id[file_id] is not None:
271
282
            return self._r_new_id[file_id]
272
283
        elif file_id in self._tree.inventory:
1324
1335
        """
1325
1336
        tree_paths = list(self._tree_path_ids.iteritems())
1326
1337
        tree_paths.sort(reverse=True)
1327
 
        kind_changes = set()
1328
1338
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1329
1339
        try:
1330
1340
            for num, data in enumerate(tree_paths):
1345
1355
                        self.rename_count += 1
1346
1356
        finally:
1347
1357
            child_pb.finished()
1348
 
        return kind_changes
1349
1358
 
1350
1359
    def _apply_insertions(self, mover):
1351
1360
        """Perform tree operations that insert directory/inventory names.
1356
1365
 
1357
1366
        If inventory_delta is None, no inventory delta is calculated, and
1358
1367
        no list of modified paths is returned.
1359
 
 
1360
 
        kind_changes is a set of trans ids where the entry has changed
1361
 
        kind, and so an inventory delta entry should be created for them.
1362
1368
        """
1363
1369
        new_paths = self.new_paths(filesystem_only=True)
1364
1370
        modified_paths = []
1401
1407
 
1402
1408
    def __init__(self, tree, pb=DummyProgress(), case_sensitive=True):
1403
1409
        tree.lock_read()
1404
 
        limbodir = tempfile.mkdtemp(prefix='bzr-limbo-')
 
1410
        limbodir = osutils.mkdtemp(prefix='bzr-limbo-')
1405
1411
        TreeTransformBase.__init__(self, tree, limbodir, pb, case_sensitive)
1406
1412
 
1407
1413
    def canonical_path(self, path):
1526
1532
        for (file_id, paths, changed, versioned, parent, name, kind,
1527
1533
             executable) in self._transform.iter_changes():
1528
1534
            if paths[1] in to_find:
1529
 
                result.append(file_id)
 
1535
                result.add(file_id)
1530
1536
                to_find.remove(paths[1])
1531
1537
        result.update(self._transform._tree.paths2ids(to_find,
1532
1538
                      trees=[], require_versioned=require_versioned))
1579
1585
                parent_file_id, file_id)
1580
1586
            yield new_entry, trans_id
1581
1587
 
1582
 
    def iter_entries_by_dir(self, specific_file_ids=None):
1583
 
        # This may not be a maximally efficient implementation, but it is
1584
 
        # reasonably straightforward.  An implementation that grafts the
1585
 
        # TreeTransform changes onto the tree's iter_entries_by_dir results
1586
 
        # might be more efficient, but requires tricky inferences about stack
1587
 
        # position.
 
1588
    def _list_files_by_dir(self):
1588
1589
        todo = [ROOT_PARENT]
1589
1590
        ordered_ids = []
1590
1591
        while len(todo) > 0:
1596
1597
            todo.extend(reversed(children))
1597
1598
            for trans_id in children:
1598
1599
                ordered_ids.append((trans_id, parent_file_id))
 
1600
        return ordered_ids
 
1601
 
 
1602
    def iter_entries_by_dir(self, specific_file_ids=None):
 
1603
        # This may not be a maximally efficient implementation, but it is
 
1604
        # reasonably straightforward.  An implementation that grafts the
 
1605
        # TreeTransform changes onto the tree's iter_entries_by_dir results
 
1606
        # might be more efficient, but requires tricky inferences about stack
 
1607
        # position.
 
1608
        ordered_ids = self._list_files_by_dir()
1599
1609
        for entry, trans_id in self._make_inv_entries(ordered_ids,
1600
1610
                                                      specific_file_ids):
1601
1611
            yield unicode(self._final_paths.get_path(trans_id)), entry
1602
1612
 
 
1613
    def list_files(self, include_root=False):
 
1614
        """See Tree.list_files."""
 
1615
        # XXX This should behave like WorkingTree.list_files, but is really
 
1616
        # more like RevisionTree.list_files.
 
1617
        for path, entry in self.iter_entries_by_dir():
 
1618
            if entry.name == '' and not include_root:
 
1619
                continue
 
1620
            yield path, 'V', entry.kind, entry.file_id, entry
 
1621
 
1603
1622
    def kind(self, file_id):
1604
1623
        trans_id = self._transform.trans_id_file_id(file_id)
1605
1624
        return self._transform.final_kind(trans_id)
1731
1750
        name = self._transform._limbo_name(trans_id)
1732
1751
        return os.readlink(name)
1733
1752
 
1734
 
    def list_files(self, include_root=False):
1735
 
        return self._transform._tree.list_files(include_root)
1736
 
 
1737
 
    def walkdirs(self, prefix=""):
1738
 
        return self._transform._tree.walkdirs(prefix)
 
1753
    def walkdirs(self, prefix=''):
 
1754
        pending = [self._transform.root]
 
1755
        while len(pending) > 0:
 
1756
            parent_id = pending.pop()
 
1757
            children = []
 
1758
            subdirs = []
 
1759
            prefix = prefix.rstrip('/')
 
1760
            parent_path = self._final_paths.get_path(parent_id)
 
1761
            parent_file_id = self._transform.final_file_id(parent_id)
 
1762
            for child_id in self._all_children(parent_id):
 
1763
                path_from_root = self._final_paths.get_path(child_id)
 
1764
                basename = self._transform.final_name(child_id)
 
1765
                file_id = self._transform.final_file_id(child_id)
 
1766
                try:
 
1767
                    kind = self._transform.final_kind(child_id)
 
1768
                    versioned_kind = kind
 
1769
                except NoSuchFile:
 
1770
                    kind = 'unknown'
 
1771
                    versioned_kind = self._transform._tree.stored_kind(file_id)
 
1772
                if versioned_kind == 'directory':
 
1773
                    subdirs.append(child_id)
 
1774
                children.append((path_from_root, basename, kind, None,
 
1775
                                 file_id, versioned_kind))
 
1776
            children.sort()
 
1777
            if parent_path.startswith(prefix):
 
1778
                yield (parent_path, parent_file_id), children
 
1779
            pending.extend(sorted(subdirs, key=self._final_paths.get_path,
 
1780
                                  reverse=True))
1739
1781
 
1740
1782
    def get_parent_ids(self):
1741
1783
        return self._parent_ids
2121
2163
    tt = TreeTransform(working_tree, pb)
2122
2164
    try:
2123
2165
        pp = ProgressPhase("Revert phase", 3, pb)
2124
 
        pp.next_phase()
2125
 
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2126
 
        try:
2127
 
            merge_modified = _alter_files(working_tree, target_tree, tt,
2128
 
                                          child_pb, filenames, backups)
2129
 
        finally:
2130
 
            child_pb.finished()
2131
 
        pp.next_phase()
2132
 
        child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2133
 
        try:
2134
 
            raw_conflicts = resolve_conflicts(tt, child_pb,
2135
 
                lambda t, c: conflict_pass(t, c, target_tree))
2136
 
        finally:
2137
 
            child_pb.finished()
2138
 
        conflicts = cook_conflicts(raw_conflicts, tt)
 
2166
        conflicts, merge_modified = _prepare_revert_transform(
 
2167
            working_tree, target_tree, tt, filenames, backups, pp)
2139
2168
        if change_reporter:
2140
2169
            change_reporter = delta._ChangeReporter(
2141
2170
                unversioned_filter=working_tree.is_ignored)
2152
2181
    return conflicts
2153
2182
 
2154
2183
 
 
2184
def _prepare_revert_transform(working_tree, target_tree, tt, filenames,
 
2185
                              backups, pp, basis_tree=None,
 
2186
                              merge_modified=None):
 
2187
    pp.next_phase()
 
2188
    child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
2189
    try:
 
2190
        if merge_modified is None:
 
2191
            merge_modified = working_tree.merge_modified()
 
2192
        merge_modified = _alter_files(working_tree, target_tree, tt,
 
2193
                                      child_pb, filenames, backups,
 
2194
                                      merge_modified, basis_tree)
 
2195
    finally:
 
2196
        child_pb.finished()
 
2197
    pp.next_phase()
 
2198
    child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
2199
    try:
 
2200
        raw_conflicts = resolve_conflicts(tt, child_pb,
 
2201
            lambda t, c: conflict_pass(t, c, target_tree))
 
2202
    finally:
 
2203
        child_pb.finished()
 
2204
    conflicts = cook_conflicts(raw_conflicts, tt)
 
2205
    return conflicts, merge_modified
 
2206
 
 
2207
 
2155
2208
def _alter_files(working_tree, target_tree, tt, pb, specific_files,
2156
 
                 backups):
2157
 
    merge_modified = working_tree.merge_modified()
 
2209
                 backups, merge_modified, basis_tree=None):
 
2210
    if basis_tree is not None:
 
2211
        basis_tree.lock_read()
2158
2212
    change_list = target_tree.iter_changes(working_tree,
2159
2213
        specific_files=specific_files, pb=pb)
2160
 
    if target_tree.inventory.root is None:
 
2214
    if target_tree.get_root_id() is None:
2161
2215
        skip_root = True
2162
2216
    else:
2163
2217
        skip_root = False
2164
 
    basis_tree = None
2165
2218
    try:
2166
2219
        deferred_files = []
2167
2220
        for id_num, (file_id, path, changed_content, versioned, parent, name,
2203
2256
                        # contents
2204
2257
                        mode_id = trans_id
2205
2258
                        trans_id = new_trans_id
2206
 
                if kind[1] == 'directory':
 
2259
                if kind[1] in ('directory', 'tree-reference'):
2207
2260
                    tt.create_directory(trans_id)
 
2261
                    if kind[1] == 'tree-reference':
 
2262
                        revision = target_tree.get_reference_revision(file_id,
 
2263
                                                                      path[1])
 
2264
                        tt.set_tree_reference(revision, trans_id)
2208
2265
                elif kind[1] == 'symlink':
2209
2266
                    tt.create_symlink(target_tree.get_symlink_target(file_id),
2210
2267
                                      trans_id)
2230
2287
                tt.version_file(file_id, trans_id)
2231
2288
            if versioned == (True, False):
2232
2289
                tt.unversion_file(trans_id)
2233
 
            if (name[1] is not None and 
 
2290
            if (name[1] is not None and
2234
2291
                (name[0] != name[1] or parent[0] != parent[1])):
2235
 
                tt.adjust_path(
2236
 
                    name[1], tt.trans_id_file_id(parent[1]), trans_id)
 
2292
                if name[1] == '' and parent[1] is None:
 
2293
                    parent_trans = ROOT_PARENT
 
2294
                else:
 
2295
                    parent_trans = tt.trans_id_file_id(parent[1])
 
2296
                tt.adjust_path(name[1], parent_trans, trans_id)
2237
2297
            if executable[0] != executable[1] and kind[1] == "file":
2238
2298
                tt.set_executability(executable[1], trans_id)
2239
2299
        for (trans_id, mode_id), bytes in target_tree.iter_files_bytes(
2347
2407
            if parent_file_id is not None:
2348
2408
                tt.unversion_file(parent_id)
2349
2409
            new_conflicts.add((c_type, 'Created directory', new_parent_id))
 
2410
        elif c_type == 'versioning no contents':
 
2411
            tt.cancel_versioning(conflict[1])
2350
2412
    return new_conflicts
2351
2413
 
2352
2414