/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 breezy/transform.py

  • Committer: Jelmer Vernooij
  • Date: 2018-11-16 19:47:19 UTC
  • mfrom: (7178 work)
  • mto: This revision was merged to the branch mainline in revision 7179.
  • Revision ID: jelmer@jelmer.uk-20181116194719-m5ut2wfuze5x9s1p
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
77
77
 
78
78
ROOT_PARENT = "root-parent"
79
79
 
 
80
 
80
81
def unique_add(map, key, value):
81
82
    if key in map:
82
83
        raise DuplicateKey(key=key)
83
84
    map[key] = value
84
85
 
85
86
 
86
 
 
87
87
class _TransformResults(object):
88
88
    def __init__(self, modified_paths, rename_count):
89
89
        object.__init__(self)
175
175
    def _assign_id(self):
176
176
        """Produce a new tranform id"""
177
177
        new_id = "new-%s" % self._id_number
178
 
        self._id_number +=1
 
178
        self._id_number += 1
179
179
        return new_id
180
180
 
181
181
    def create_path(self, name, parent):
259
259
            self.unversion_file(old_new_root)
260
260
        # if, at this stage, root still has an old file_id, zap it so we can
261
261
        # stick a new one in.
262
 
        if (self.tree_file_id(self._new_root) is not None and
263
 
            self._new_root not in self._removed_id):
 
262
        if (self.tree_file_id(self._new_root) is not None
 
263
                and self._new_root not in self._removed_id):
264
264
            self.unversion_file(self._new_root)
265
265
        if file_id is not None:
266
266
            self.version_file(file_id, self._new_root)
425
425
        changed_ids.update(changed_kind)
426
426
        # To find entries with changed parent_ids, find parents which existed,
427
427
        # but changed file_id.
428
 
        changed_file_id = set(t for t in new_file_id if t in self._removed_id)
429
428
        # Now add all their children to the set.
430
429
        for parent_trans_id in new_file_id:
431
430
            changed_ids.update(self.iter_tree_children(parent_trans_id))
512
511
        by_parent = {}
513
512
        items = list(viewitems(self._new_parent))
514
513
        items.extend((t, self.final_parent(t))
515
 
            for t in list(self._tree_id_paths))
 
514
                     for t in list(self._tree_id_paths))
516
515
        for trans_id, parent_id in items:
517
516
            if parent_id not in by_parent:
518
517
                by_parent[parent_id] = set()
643
642
            for child_id in children:
644
643
                if self.final_file_id(child_id) is not None:
645
644
                    conflicts.append(('unversioned parent', parent_id))
646
 
                    break;
 
645
                    break
647
646
        return conflicts
648
647
 
649
648
    def _improper_versioning(self):
686
685
                continue
687
686
            if trans_id not in self._removed_contents:
688
687
                conflicts.append(('overwrite', trans_id,
689
 
                                 self.final_name(trans_id)))
 
688
                                  self.final_name(trans_id)))
690
689
        return conflicts
691
690
 
692
691
    def _duplicate_entries(self, by_parent):
713
712
                    continue
714
713
                if name == last_name:
715
714
                    conflicts.append(('duplicate', last_trans_id, trans_id,
716
 
                    name))
 
715
                                      name))
717
716
                last_name = name
718
717
                last_trans_id = trans_id
719
718
        return conflicts
903
902
        if from_versioned:
904
903
            # get data from working tree if versioned
905
904
            from_entry = next(self._tree.iter_entries_by_dir(
906
 
                    specific_files=[from_path]))[1]
 
905
                specific_files=[from_path]))[1]
907
906
            from_name = from_entry.name
908
907
            from_parent = from_entry.parent_id
909
908
        else:
990
989
            if from_kind != to_kind:
991
990
                modified = True
992
991
            elif to_kind in ('file', 'symlink') and (
993
 
                to_trans_id != from_trans_id or
994
 
                to_trans_id in self._new_contents):
 
992
                    to_trans_id != from_trans_id
 
993
                    or to_trans_id in self._new_contents):
995
994
                modified = True
996
 
            if (not modified and from_versioned == to_versioned and
997
 
                from_parent==to_parent and from_name == to_name and
998
 
                from_executable == to_executable):
 
995
            if (not modified and from_versioned == to_versioned
 
996
                and from_parent == to_parent and from_name == to_name
 
997
                    and from_executable == to_executable):
999
998
                continue
1000
999
            results.append((file_id, (from_path, to_path), modified,
1001
 
                   (from_versioned, to_versioned),
1002
 
                   (from_parent, to_parent),
1003
 
                   (from_name, to_name),
1004
 
                   (from_kind, to_kind),
1005
 
                   (from_executable, to_executable)))
 
1000
                            (from_versioned, to_versioned),
 
1001
                            (from_parent, to_parent),
 
1002
                            (from_name, to_name),
 
1003
                            (from_kind, to_kind),
 
1004
                            (from_executable, to_executable)))
1006
1005
 
1007
1006
        def path_key(t):
1008
1007
            paths = t[1]
1146
1145
                if not isinstance(content, bytes):
1147
1146
                    content = content.encode('utf-8')
1148
1147
            yield serializer.bytes_record(
1149
 
                    content, ((trans_id.encode('utf-8'), kind.encode('ascii')),))
 
1148
                content, ((trans_id.encode('utf-8'), kind.encode('ascii')),))
1150
1149
 
1151
1150
    def deserialize(self, records):
1152
1151
        """Deserialize a stored TreeTransform.
1161
1160
                          for k, v in viewitems(attribs[b'_new_name'])}
1162
1161
        self._new_parent = {k.decode('utf-8'): v.decode('utf-8')
1163
1162
                            for k, v in viewitems(attribs[b'_new_parent'])}
1164
 
        self._new_executability = {k.decode('utf-8'): bool(v)
 
1163
        self._new_executability = {
 
1164
            k.decode('utf-8'): bool(v)
1165
1165
            for k, v in viewitems(attribs[b'_new_executability'])}
1166
1166
        self._new_id = {k.decode('utf-8'): v
1167
1167
                        for k, v in viewitems(attribs[b'_new_id'])}
1175
1175
            self._tree_id_paths[trans_id] = path
1176
1176
        self._removed_id = {trans_id.decode('utf-8')
1177
1177
                            for trans_id in attribs[b'_removed_id']}
1178
 
        self._removed_contents = set(trans_id.decode('utf-8')
1179
 
                                     for trans_id in attribs[b'_removed_contents'])
1180
 
        self._non_present_ids = {k: v.decode('utf-8')
1181
 
                                 for k, v in viewitems(attribs[b'_non_present_ids'])}
 
1178
        self._removed_contents = set(
 
1179
            trans_id.decode('utf-8')
 
1180
            for trans_id in attribs[b'_removed_contents'])
 
1181
        self._non_present_ids = {
 
1182
            k: v.decode('utf-8')
 
1183
            for k, v in viewitems(attribs[b'_non_present_ids'])}
1182
1184
        for ((trans_id, kind),), content in records:
1183
1185
            trans_id = trans_id.decode('utf-8')
1184
1186
            kind = kind.decode('ascii')
1281
1283
        previous_parent = self._new_parent.get(trans_id)
1282
1284
        previous_name = self._new_name.get(trans_id)
1283
1285
        TreeTransformBase.adjust_path(self, name, parent, trans_id)
1284
 
        if (trans_id in self._limbo_files and
1285
 
            trans_id not in self._needs_rename):
 
1286
        if (trans_id in self._limbo_files
 
1287
                and trans_id not in self._needs_rename):
1286
1288
            self._rename_in_limbo([trans_id])
1287
1289
            if previous_parent != parent:
1288
1290
                self._limbo_children[previous_parent].remove(trans_id)
1370
1372
            raise errors.HardLinkNotSupported(path)
1371
1373
        try:
1372
1374
            unique_add(self._new_contents, trans_id, 'file')
1373
 
        except:
 
1375
        except BaseException:
1374
1376
            # Clean up the file, it never got registered so
1375
1377
            # TreeTransform.finalize() won't clean it up.
1376
1378
            os.unlink(name)
1556
1558
    FileMover does not delete files until it is sure that a rollback will not
1557
1559
    happen.
1558
1560
    """
 
1561
 
1559
1562
    def __init__(self, tree, pb=None):
1560
1563
        """Note: a tree_write lock is taken on the tree.
1561
1564
 
1574
1577
            osutils.ensure_empty_directory_exists(
1575
1578
                deletiondir,
1576
1579
                errors.ExistingPendingDeletion)
1577
 
        except:
 
1580
        except BaseException:
1578
1581
            tree.unlock()
1579
1582
            raise
1580
1583
 
1653
1656
        try:
1654
1657
            children = os.listdir(self._tree.abspath(path))
1655
1658
        except OSError as e:
1656
 
            if not (osutils._is_error_enotdir(e)
1657
 
                    or e.errno in (errno.ENOENT, errno.ESRCH)):
 
1659
            if not (osutils._is_error_enotdir(e) or
 
1660
                    e.errno in (errno.ENOENT, errno.ESRCH)):
1658
1661
                raise
1659
1662
            return
1660
1663
 
1691
1694
                # if it is already associated with this trans_id.
1692
1695
                elif self._case_sensitive_target:
1693
1696
                    if (self._limbo_children_names[parent].get(filename)
1694
 
                        in (trans_id, None)):
 
1697
                            in (trans_id, None)):
1695
1698
                        use_direct_path = True
1696
1699
                else:
1697
1700
                    for l_filename, l_trans_id in viewitems(
1746
1749
                self._apply_removals(mover)
1747
1750
                child_pb.update(gettext('Apply phase'), 1 + offset, 2 + offset)
1748
1751
                modified_paths = self._apply_insertions(mover)
1749
 
            except:
 
1752
            except BaseException:
1750
1753
                mover.rollback()
1751
1754
                raise
1752
1755
            else:
1767
1770
        with ui.ui_factory.nested_progress_bar() as child_pb:
1768
1771
            for num, trans_id in enumerate(self._removed_id):
1769
1772
                if (num % 10) == 0:
1770
 
                    child_pb.update(gettext('removing file'), num, total_entries)
 
1773
                    child_pb.update(gettext('removing file'),
 
1774
                                    num, total_entries)
1771
1775
                if trans_id == self._new_root:
1772
1776
                    file_id = self._tree.get_root_id()
1773
1777
                else:
1779
1783
                inventory_delta.append((path, None, file_id, None))
1780
1784
            new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in
1781
1785
                                     new_paths)
1782
 
            final_kinds = {}
1783
1786
            for num, (path, trans_id) in enumerate(new_paths):
1784
1787
                if (num % 10) == 0:
1785
1788
                    child_pb.update(gettext('adding file'),
1787
1790
                file_id = new_path_file_ids[trans_id]
1788
1791
                if file_id is None:
1789
1792
                    continue
1790
 
                needs_entry = False
1791
1793
                kind = self.final_kind(trans_id)
1792
1794
                if kind is None:
1793
1795
                    kind = self._tree.stored_kind(
1794
 
                            self._tree.id2path(file_id), file_id)
 
1796
                        self._tree.id2path(file_id), file_id)
1795
1797
                parent_trans_id = self.final_parent(trans_id)
1796
1798
                parent_file_id = new_path_file_ids.get(parent_trans_id)
1797
1799
                if parent_file_id is None:
1804
1806
                        None, self._new_reference_revision[trans_id])
1805
1807
                else:
1806
1808
                    new_entry = inventory.make_entry(kind,
1807
 
                        self.final_name(trans_id),
1808
 
                        parent_file_id, file_id)
 
1809
                                                     self.final_name(trans_id),
 
1810
                                                     parent_file_id, file_id)
1809
1811
                try:
1810
1812
                    old_path = self._tree.id2path(new_entry.file_id)
1811
1813
                except errors.NoSuchId:
1837
1839
                if trans_id in self._removed_contents:
1838
1840
                    delete_path = os.path.join(self._deletiondir, trans_id)
1839
1841
                    mover.pre_delete(full_path, delete_path)
1840
 
                elif (trans_id in self._new_name
1841
 
                      or trans_id in self._new_parent):
 
1842
                elif (trans_id in self._new_name or
 
1843
                      trans_id in self._new_parent):
1842
1844
                    try:
1843
1845
                        mover.rename(full_path, self._limbo_name(trans_id))
1844
1846
                    except errors.TransformRenameFailed as e:
1859
1861
        """
1860
1862
        new_paths = self.new_paths(filesystem_only=True)
1861
1863
        modified_paths = []
1862
 
        new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in
1863
 
                                 new_paths)
1864
1864
        with ui.ui_factory.nested_progress_bar() as child_pb:
1865
1865
            for num, (path, trans_id) in enumerate(new_paths):
1866
1866
                if (num % 10) == 0:
1867
 
                    child_pb.update(gettext('adding file'), num, len(new_paths))
 
1867
                    child_pb.update(gettext('adding file'),
 
1868
                                    num, len(new_paths))
1868
1869
                full_path = self._tree.abspath(path)
1869
1870
                if trans_id in self._needs_rename:
1870
1871
                    try:
1878
1879
                    # TODO: if trans_id in self._observed_sha1s, we should
1879
1880
                    #       re-stat the final target, since ctime will be
1880
1881
                    #       updated by the change.
1881
 
                if (trans_id in self._new_contents or
1882
 
                    self.path_changed(trans_id)):
 
1882
                if (trans_id in self._new_contents
 
1883
                        or self.path_changed(trans_id)):
1883
1884
                    if trans_id in self._new_contents:
1884
1885
                        modified_paths.append(full_path)
1885
1886
                if trans_id in self._new_executability:
1914
1915
        paths = FinalPaths(self)
1915
1916
        for trans_id, observed in viewitems(self._observed_sha1s):
1916
1917
            path = paths.get_path(trans_id)
1917
 
            # We could get the file_id, but dirstate prefers to use the path
1918
 
            # anyway, and it is 'cheaper' to determine.
1919
 
            # file_id = self._new_id[trans_id]
1920
 
            self._tree._observed_sha1(None, path, observed)
 
1918
            self._tree._observed_sha1(path, observed)
1921
1919
 
1922
1920
 
1923
1921
class TransformPreview(DiskTreeTransform):
1962
1960
            return
1963
1961
        try:
1964
1962
            entry = next(self._tree.iter_entries_by_dir(
1965
 
                    specific_files=[path]))[1]
 
1963
                specific_files=[path]))[1]
1966
1964
        except StopIteration:
1967
1965
            return
1968
1966
        children = getattr(entry, 'children', {})
2010
2008
 
2011
2009
    def _get_file_revision(self, path, file_id, vf, tree_revision):
2012
2010
        parent_keys = [
2013
 
                (file_id, t.get_file_revision(t.id2path(file_id), file_id))
2014
 
                for t in self._iter_parent_trees()]
 
2011
            (file_id, t.get_file_revision(t.id2path(file_id)))
 
2012
            for t in self._iter_parent_trees()]
2015
2013
        vf.add_lines((file_id, tree_revision), parent_keys,
2016
 
                     self.get_file_lines(path, file_id))
 
2014
                     self.get_file_lines(path))
2017
2015
        repo = self._get_repository()
2018
2016
        base_vf = repo.texts
2019
2017
        if base_vf not in vf.fallback_versionedfiles:
2037
2035
            executable = False
2038
2036
        else:
2039
2037
            file_id = self._transform.final_file_id(self._path2trans_id(path))
2040
 
            executable = self.is_executable(path, file_id)
 
2038
            executable = self.is_executable(path)
2041
2039
        return kind, executable, None
2042
2040
 
2043
2041
    def is_locked(self):
2072
2070
        if file_id in self._transform._r_new_id:
2073
2071
            return True
2074
2072
        elif file_id in {self._transform.tree_file_id(trans_id) for
2075
 
            trans_id in self._transform._removed_id}:
 
2073
                         trans_id in self._transform._removed_id}:
2076
2074
            return False
2077
2075
        else:
2078
2076
            return fallback_check(file_id)
2149
2147
            file_id = self._transform.final_file_id(trans_id)
2150
2148
            if file_id is None:
2151
2149
                continue
2152
 
            if (specific_files is not None and
2153
 
                self._final_paths.get_path(trans_id) not in specific_files):
 
2150
            if (specific_files is not None
 
2151
                    and self._final_paths.get_path(trans_id) not in specific_files):
2154
2152
                continue
2155
2153
            kind = self._transform.final_kind(trans_id)
2156
2154
            if kind is None:
2177
2175
                ordered_ids.append((trans_id, parent_file_id))
2178
2176
        return ordered_ids
2179
2177
 
2180
 
    def iter_child_entries(self, path, file_id=None):
 
2178
    def iter_child_entries(self, path):
2181
2179
        trans_id = self._path2trans_id(path)
2182
2180
        if trans_id is None:
2183
2181
            raise errors.NoSuchFile(path)
2194
2192
        # position.
2195
2193
        ordered_ids = self._list_files_by_dir()
2196
2194
        for entry, trans_id in self._make_inv_entries(ordered_ids,
2197
 
            specific_files):
 
2195
                                                      specific_files):
2198
2196
            yield self._final_paths.get_path(trans_id), entry
2199
2197
 
2200
2198
    def _iter_entries_for_dir(self, dir_path):
2232
2230
        else:
2233
2231
            if from_dir is None and include_root is True:
2234
2232
                root_entry = inventory.make_entry('directory', '',
2235
 
                    ROOT_PARENT, self.get_root_id())
 
2233
                                                  ROOT_PARENT, self.get_root_id())
2236
2234
                yield '', 'V', 'directory', root_entry.file_id, root_entry
2237
2235
            entries = self._iter_entries_for_dir(from_dir or '')
2238
2236
            for path, entry in entries:
2239
2237
                yield path, 'V', entry.kind, entry.file_id, entry
2240
2238
 
2241
 
    def kind(self, path, file_id=None):
 
2239
    def kind(self, path):
2242
2240
        trans_id = self._path2trans_id(path)
2243
2241
        if trans_id is None:
2244
2242
            raise errors.NoSuchFile(path)
2245
2243
        return self._transform.final_kind(trans_id)
2246
2244
 
2247
 
    def stored_kind(self, path, file_id=None):
 
2245
    def stored_kind(self, path):
2248
2246
        trans_id = self._path2trans_id(path)
2249
2247
        if trans_id is None:
2250
2248
            raise errors.NoSuchFile(path)
2251
2249
        try:
2252
2250
            return self._transform._new_contents[trans_id]
2253
2251
        except KeyError:
2254
 
            return self._transform._tree.stored_kind(path, file_id)
 
2252
            return self._transform._tree.stored_kind(path)
2255
2253
 
2256
 
    def get_file_mtime(self, path, file_id=None):
 
2254
    def get_file_mtime(self, path):
2257
2255
        """See Tree.get_file_mtime"""
2258
 
        if file_id is None:
2259
 
            file_id = self.path2id(path)
 
2256
        file_id = self.path2id(path)
2260
2257
        if file_id is None:
2261
2258
            raise errors.NoSuchFile(path)
2262
2259
        if not self._content_change(file_id):
2263
2260
            return self._transform._tree.get_file_mtime(
2264
 
                    self._transform._tree.id2path(file_id), file_id)
 
2261
                self._transform._tree.id2path(file_id))
2265
2262
        trans_id = self._path2trans_id(path)
2266
2263
        return self._stat_limbo_file(trans_id).st_mtime
2267
2264
 
2268
 
    def get_file_size(self, path, file_id=None):
 
2265
    def get_file_size(self, path):
2269
2266
        """See Tree.get_file_size"""
2270
2267
        trans_id = self._path2trans_id(path)
2271
2268
        if trans_id is None:
2275
2272
            return None
2276
2273
        if trans_id in self._transform._new_contents:
2277
2274
            return self._stat_limbo_file(trans_id).st_size
2278
 
        if self.kind(path, file_id) == 'file':
2279
 
            return self._transform._tree.get_file_size(path, file_id)
 
2275
        if self.kind(path) == 'file':
 
2276
            return self._transform._tree.get_file_size(path)
2280
2277
        else:
2281
2278
            return None
2282
2279
 
2283
 
    def get_file_verifier(self, path, file_id=None, stat_value=None):
 
2280
    def get_file_verifier(self, path, stat_value=None):
2284
2281
        trans_id = self._path2trans_id(path)
2285
2282
        if trans_id is None:
2286
2283
            raise errors.NoSuchFile(path)
2287
2284
        kind = self._transform._new_contents.get(trans_id)
2288
2285
        if kind is None:
2289
 
            return self._transform._tree.get_file_verifier(path, file_id)
 
2286
            return self._transform._tree.get_file_verifier(path)
2290
2287
        if kind == 'file':
2291
 
            with self.get_file(path, file_id) as fileobj:
 
2288
            with self.get_file(path) as fileobj:
2292
2289
                return ("SHA1", sha_file(fileobj))
2293
2290
 
2294
 
    def get_file_sha1(self, path, file_id=None, stat_value=None):
 
2291
    def get_file_sha1(self, path, stat_value=None):
2295
2292
        trans_id = self._path2trans_id(path)
2296
2293
        if trans_id is None:
2297
2294
            raise errors.NoSuchFile(path)
2298
2295
        kind = self._transform._new_contents.get(trans_id)
2299
2296
        if kind is None:
2300
 
            return self._transform._tree.get_file_sha1(path, file_id)
 
2297
            return self._transform._tree.get_file_sha1(path)
2301
2298
        if kind == 'file':
2302
 
            with self.get_file(path, file_id) as fileobj:
 
2299
            with self.get_file(path) as fileobj:
2303
2300
                return sha_file(fileobj)
2304
2301
 
2305
 
    def is_executable(self, path, file_id=None):
 
2302
    def is_executable(self, path):
2306
2303
        trans_id = self._path2trans_id(path)
2307
2304
        if trans_id is None:
2308
2305
            return False
2310
2307
            return self._transform._new_executability[trans_id]
2311
2308
        except KeyError:
2312
2309
            try:
2313
 
                return self._transform._tree.is_executable(path, file_id)
 
2310
                return self._transform._tree.is_executable(path)
2314
2311
            except OSError as e:
2315
2312
                if e.errno == errno.ENOENT:
2316
2313
                    return False
2360
2357
        return kind, size, executable, link_or_sha1
2361
2358
 
2362
2359
    def iter_changes(self, from_tree, include_unchanged=False,
2363
 
                      specific_files=None, pb=None, extra_trees=None,
2364
 
                      require_versioned=True, want_unversioned=False):
 
2360
                     specific_files=None, pb=None, extra_trees=None,
 
2361
                     require_versioned=True, want_unversioned=False):
2365
2362
        """See InterTree.iter_changes.
2366
2363
 
2367
2364
        This has a fast path that is only used when the from_tree matches
2368
2365
        the transform tree, and no fancy options are supplied.
2369
2366
        """
2370
 
        if (from_tree is not self._transform._tree or include_unchanged or
2371
 
            specific_files or want_unversioned):
 
2367
        if (from_tree is not self._transform._tree or include_unchanged
 
2368
                or specific_files or want_unversioned):
2372
2369
            return tree.InterTree(from_tree, self).iter_changes(
2373
2370
                include_unchanged=include_unchanged,
2374
2371
                specific_files=specific_files,
2380
2377
            raise ValueError('want_unversioned is not supported')
2381
2378
        return self._transform.iter_changes()
2382
2379
 
2383
 
    def get_file(self, path, file_id=None):
 
2380
    def get_file(self, path):
2384
2381
        """See Tree.get_file"""
2385
 
        if file_id is None:
2386
 
            file_id = self.path2id(path)
 
2382
        file_id = self.path2id(path)
2387
2383
        if not self._content_change(file_id):
2388
 
            return self._transform._tree.get_file(path, file_id)
 
2384
            return self._transform._tree.get_file(path)
2389
2385
        trans_id = self._path2trans_id(path)
2390
2386
        name = self._transform._limbo_name(trans_id)
2391
2387
        return open(name, 'rb')
2392
2388
 
2393
 
    def get_file_with_stat(self, path, file_id=None):
2394
 
        return self.get_file(path, file_id), None
 
2389
    def get_file_with_stat(self, path):
 
2390
        return self.get_file(path), None
2395
2391
 
2396
 
    def annotate_iter(self, path, file_id=None,
 
2392
    def annotate_iter(self, path,
2397
2393
                      default_revision=_mod_revision.CURRENT_REVISION):
2398
 
        if file_id is None:
2399
 
            file_id = self.path2id(path)
 
2394
        file_id = self.path2id(path)
2400
2395
        changes = self._iter_changes_cache.get(file_id)
2401
2396
        if changes is None:
2402
2397
            get_old = True
2408
2403
            get_old = (kind[0] == 'file' and versioned[0])
2409
2404
        if get_old:
2410
2405
            old_annotation = self._transform._tree.annotate_iter(
2411
 
                    path, file_id=file_id, default_revision=default_revision)
 
2406
                path, default_revision=default_revision)
2412
2407
        else:
2413
2408
            old_annotation = []
2414
2409
        if changes is None:
2423
2418
        #       It would be nice to be able to use the new Annotator based
2424
2419
        #       approach, as well.
2425
2420
        return annotate.reannotate([old_annotation],
2426
 
                                   self.get_file(path, file_id).readlines(),
 
2421
                                   self.get_file(path).readlines(),
2427
2422
                                   default_revision)
2428
2423
 
2429
 
    def get_symlink_target(self, path, file_id=None):
 
2424
    def get_symlink_target(self, path):
2430
2425
        """See Tree.get_symlink_target"""
2431
 
        if file_id is None:
2432
 
            file_id = self.path2id(path)
 
2426
        file_id = self.path2id(path)
2433
2427
        if not self._content_change(file_id):
2434
2428
            return self._transform._tree.get_symlink_target(path)
2435
2429
        trans_id = self._path2trans_id(path)
2449
2443
                path_from_root = self._final_paths.get_path(child_id)
2450
2444
                basename = self._transform.final_name(child_id)
2451
2445
                file_id = self._transform.final_file_id(child_id)
2452
 
                kind  = self._transform.final_kind(child_id)
 
2446
                kind = self._transform.final_kind(child_id)
2453
2447
                if kind is not None:
2454
2448
                    versioned_kind = kind
2455
2449
                else:
2456
2450
                    kind = 'unknown'
2457
2451
                    versioned_kind = self._transform._tree.stored_kind(
2458
 
                            self._transform._tree.id2path(file_id),
2459
 
                            file_id)
 
2452
                        self._transform._tree.id2path(file_id))
2460
2453
                if versioned_kind == 'directory':
2461
2454
                    subdirs.append(child_id)
2462
2455
                children.append((path_from_root, basename, kind, None,
2491
2484
    The underlying tree must not be manipulated between calls, or else
2492
2485
    the results will likely be incorrect.
2493
2486
    """
 
2487
 
2494
2488
    def __init__(self, transform):
2495
2489
        object.__init__(self)
2496
2490
        self._known_paths = {}
2516
2510
        return [(self.get_path(t), t) for t in trans_ids]
2517
2511
 
2518
2512
 
2519
 
 
2520
2513
def topology_sorted_ids(tree):
2521
2514
    """Determine the topological order of the ids in a tree"""
2522
2515
    file_ids = list(tree)
2603
2596
                for dir, files in wt.walkdirs():
2604
2597
                    existing_files.update(f[0] for f in files)
2605
2598
            for num, (tree_path, entry) in \
2606
 
                enumerate(tree.iter_entries_by_dir()):
2607
 
                pb.update(gettext("Building tree"), num - len(deferred_contents), total)
 
2599
                    enumerate(tree.iter_entries_by_dir()):
 
2600
                pb.update(gettext("Building tree"), num
 
2601
                          - len(deferred_contents), total)
2608
2602
                if entry.parent_id is None:
2609
2603
                    continue
2610
2604
                reparent = False
2621
2615
                            pass
2622
2616
                        else:
2623
2617
                            divert.add(file_id)
2624
 
                    if (file_id not in divert and
2625
 
                        _content_match(tree, entry, tree_path, file_id, kind,
2626
 
                        target_path)):
 
2618
                    if (file_id not in divert
 
2619
                        and _content_match(
 
2620
                            tree, entry, tree_path, file_id, kind,
 
2621
                            target_path)):
2627
2622
                        tt.delete_contents(tt.trans_id_tree_path(tree_path))
2628
2623
                        if kind == 'directory':
2629
2624
                            reparent = True
2634
2629
                    trans_id = tt.create_path(entry.name, parent_id)
2635
2630
                    file_trans_id[file_id] = trans_id
2636
2631
                    tt.version_file(file_id, trans_id)
2637
 
                    executable = tree.is_executable(tree_path, file_id)
 
2632
                    executable = tree.is_executable(tree_path)
2638
2633
                    if executable:
2639
2634
                        tt.set_executability(executable, trans_id)
2640
 
                    trans_data = (trans_id, file_id, tree_path, entry.text_sha1)
 
2635
                    trans_data = (trans_id, file_id,
 
2636
                                  tree_path, entry.text_sha1)
2641
2637
                    deferred_contents.append((tree_path, trans_data))
2642
2638
                else:
2643
2639
                    file_trans_id[file_id] = new_by_entry(
2644
 
                            tree_path, tt, entry, parent_id, tree)
 
2640
                        tree_path, tt, entry, parent_id, tree)
2645
2641
                if reparent:
2646
2642
                    new_trans_id = file_trans_id[file_id]
2647
2643
                    old_parent = tt.trans_id_tree_path(tree_path)
2651
2647
                          accelerator_tree, hardlink)
2652
2648
        pp.next_phase()
2653
2649
        divert_trans = set(file_trans_id[f] for f in divert)
2654
 
        resolver = lambda t, c: resolve_checkout(t, c, divert_trans)
 
2650
 
 
2651
        def resolver(t, c):
 
2652
            return resolve_checkout(t, c, divert_trans)
2655
2653
        raw_conflicts = resolve_conflicts(tt, pass_func=resolver)
2656
2654
        if len(raw_conflicts) > 0:
2657
2655
            precomputed_delta = None
2690
2688
            accelerator_path = unchanged.get(tree_path)
2691
2689
            if accelerator_path is None:
2692
2690
                new_desired_files.append((tree_path,
2693
 
                    (trans_id, file_id, tree_path, text_sha1)))
 
2691
                                          (trans_id, file_id, tree_path, text_sha1)))
2694
2692
                continue
2695
2693
            pb.update(gettext('Adding file contents'), count + offset, total)
2696
2694
            if hardlink:
2702
2700
                    if wt.supports_content_filtering():
2703
2701
                        filters = wt._content_filter_stack(tree_path)
2704
2702
                        chunks = filtered_output_bytes(chunks, filters,
2705
 
                            ContentFilterContext(tree_path, tree))
 
2703
                                                       ContentFilterContext(tree_path, tree))
2706
2704
                    tt.create_file(chunks, trans_id, sha1=text_sha1)
2707
2705
            count += 1
2708
2706
        offset += count
2711
2709
        if wt.supports_content_filtering():
2712
2710
            filters = wt._content_filter_stack(tree_path)
2713
2711
            contents = filtered_output_bytes(contents, filters,
2714
 
                ContentFilterContext(tree_path, tree))
 
2712
                                             ContentFilterContext(tree_path, tree))
2715
2713
        tt.create_file(contents, trans_id, sha1=text_sha1)
2716
2714
        pb.update(gettext('Adding file contents'), count + offset, total)
2717
2715
 
2735
2733
        return True
2736
2734
    if entry.kind == "file":
2737
2735
        with open(target_path, 'rb') as f1, \
2738
 
             tree.get_file(tree_path, file_id) as f2:
 
2736
                tree.get_file(tree_path) as f2:
2739
2737
            if osutils.compare_files(f1, f2):
2740
2738
                return True
2741
2739
    elif entry.kind == "symlink":
2742
 
        if tree.get_symlink_target(tree_path, file_id) == os.readlink(target_path):
 
2740
        if tree.get_symlink_target(tree_path) == os.readlink(target_path):
2743
2741
            return True
2744
2742
    return False
2745
2743
 
2762
2760
        # resolved
2763
2761
        final_parent = tt.final_parent(old_file)
2764
2762
        if new_file in divert:
2765
 
            new_name = tt.final_name(old_file)+'.diverted'
 
2763
            new_name = tt.final_name(old_file) + '.diverted'
2766
2764
            tt.adjust_path(new_name, final_parent, new_file)
2767
2765
            new_conflicts.add((c_type, 'Diverted to',
2768
2766
                               new_file, old_file))
2769
2767
        else:
2770
 
            new_name = tt.final_name(old_file)+'.moved'
 
2768
            new_name = tt.final_name(old_file) + '.moved'
2771
2769
            tt.adjust_path(new_name, final_parent, old_file)
2772
2770
            new_conflicts.add((c_type, 'Moved existing file to',
2773
2771
                               old_file, new_file))
2779
2777
    name = entry.name
2780
2778
    kind = entry.kind
2781
2779
    if kind == 'file':
2782
 
        with tree.get_file(path, entry.file_id) as f:
2783
 
            executable = tree.is_executable(path, entry.file_id)
 
2780
        with tree.get_file(path) as f:
 
2781
            executable = tree.is_executable(path)
2784
2782
            return tt.new_file(
2785
 
                    name, parent_id, osutils.file_iterator(f), entry.file_id,
2786
 
                    executable)
 
2783
                name, parent_id, osutils.file_iterator(f), entry.file_id,
 
2784
                executable)
2787
2785
    elif kind in ('directory', 'tree-reference'):
2788
2786
        trans_id = tt.new_directory(name, parent_id, entry.file_id)
2789
2787
        if kind == 'tree-reference':
2790
2788
            tt.set_tree_reference(entry.reference_revision, trans_id)
2791
2789
        return trans_id
2792
2790
    elif kind == 'symlink':
2793
 
        target = tree.get_symlink_target(path, entry.file_id)
 
2791
        target = tree.get_symlink_target(path)
2794
2792
        return tt.new_symlink(name, parent_id, target, entry.file_id)
2795
2793
    else:
2796
2794
        raise errors.BadFileKindError(name, kind)
2797
2795
 
2798
2796
 
2799
2797
def create_from_tree(tt, trans_id, tree, path, file_id=None, chunks=None,
2800
 
    filter_tree_path=None):
 
2798
                     filter_tree_path=None):
2801
2799
    """Create new file contents according to tree contents.
2802
2800
 
2803
2801
    :param filter_tree_path: the tree path to use to lookup
2804
2802
      content filters to apply to the bytes output in the working tree.
2805
2803
      This only applies if the working tree supports content filtering.
2806
2804
    """
2807
 
    kind = tree.kind(path, file_id)
 
2805
    kind = tree.kind(path)
2808
2806
    if kind == 'directory':
2809
2807
        tt.create_directory(trans_id)
2810
2808
    elif kind == "file":
2811
2809
        if chunks is None:
2812
 
            f = tree.get_file(path, file_id)
 
2810
            f = tree.get_file(path)
2813
2811
            chunks = osutils.file_iterator(f)
2814
2812
        else:
2815
2813
            f = None
2817
2815
            wt = tt._tree
2818
2816
            if wt.supports_content_filtering() and filter_tree_path is not None:
2819
2817
                filters = wt._content_filter_stack(filter_tree_path)
2820
 
                chunks = filtered_output_bytes(chunks, filters,
 
2818
                chunks = filtered_output_bytes(
 
2819
                    chunks, filters,
2821
2820
                    ContentFilterContext(filter_tree_path, tree))
2822
2821
            tt.create_file(chunks, trans_id)
2823
2822
        finally:
2824
2823
            if f is not None:
2825
2824
                f.close()
2826
2825
    elif kind == "symlink":
2827
 
        tt.create_symlink(tree.get_symlink_target(path, file_id), trans_id)
 
2826
        tt.create_symlink(tree.get_symlink_target(path), trans_id)
2828
2827
    else:
2829
2828
        raise AssertionError('Unknown kind %r' % kind)
2830
2829
 
2869
2868
                                      child_pb, filenames, backups,
2870
2869
                                      merge_modified, basis_tree)
2871
2870
    with ui.ui_factory.nested_progress_bar() as child_pb:
2872
 
        raw_conflicts = resolve_conflicts(tt, child_pb,
2873
 
            lambda t, c: conflict_pass(t, c, target_tree))
 
2871
        raw_conflicts = resolve_conflicts(
 
2872
            tt, child_pb, lambda t, c: conflict_pass(t, c, target_tree))
2874
2873
    conflicts = cook_conflicts(raw_conflicts, tt)
2875
2874
    return conflicts, merge_modified
2876
2875
 
2883
2882
    # than the target changes relative to the working tree. Because WT4 has an
2884
2883
    # optimizer to compare itself to a target, but no optimizer for the
2885
2884
    # reverse.
2886
 
    change_list = working_tree.iter_changes(target_tree,
2887
 
        specific_files=specific_files, pb=pb)
 
2885
    change_list = working_tree.iter_changes(
 
2886
        target_tree, specific_files=specific_files, pb=pb)
2888
2887
    if not target_tree.is_versioned(u''):
2889
2888
        skip_root = True
2890
2889
    else:
2892
2891
    try:
2893
2892
        deferred_files = []
2894
2893
        for id_num, (file_id, path, changed_content, versioned, parent, name,
2895
 
                kind, executable) in enumerate(change_list):
 
2894
                     kind, executable) in enumerate(change_list):
2896
2895
            target_path, wt_path = path
2897
2896
            target_versioned, wt_versioned = versioned
2898
2897
            target_parent, wt_parent = parent
2906
2905
            if changed_content:
2907
2906
                keep_content = False
2908
2907
                if wt_kind == 'file' and (backups or target_kind is None):
2909
 
                    wt_sha1 = working_tree.get_file_sha1(wt_path, file_id)
 
2908
                    wt_sha1 = working_tree.get_file_sha1(wt_path)
2910
2909
                    if merge_modified.get(file_id) != wt_sha1:
2911
2910
                        # acquire the basis tree lazily to prevent the
2912
2911
                        # expense of accessing it when it's not needed ?
2914
2913
                        if basis_tree is None:
2915
2914
                            basis_tree = working_tree.basis_tree()
2916
2915
                            basis_tree.lock_read()
2917
 
                        basis_path = find_previous_path(working_tree, basis_tree, wt_path)
 
2916
                        basis_path = find_previous_path(
 
2917
                            working_tree, basis_tree, wt_path)
2918
2918
                        if basis_path is None:
2919
2919
                            if target_kind is None and not target_versioned:
2920
2920
                                keep_content = True
2921
2921
                        else:
2922
 
                            if wt_sha1 != basis_tree.get_file_sha1(basis_path, file_id):
 
2922
                            if wt_sha1 != basis_tree.get_file_sha1(basis_path):
2923
2923
                                keep_content = True
2924
2924
                if wt_kind is not None:
2925
2925
                    if not keep_content:
2941
2941
                    tt.create_directory(trans_id)
2942
2942
                    if target_kind == 'tree-reference':
2943
2943
                        revision = target_tree.get_reference_revision(
2944
 
                                target_path, file_id)
 
2944
                            target_path)
2945
2945
                        tt.set_tree_reference(revision, trans_id)
2946
2946
                elif target_kind == 'symlink':
2947
2947
                    tt.create_symlink(target_tree.get_symlink_target(
2948
 
                            target_path, file_id), trans_id)
 
2948
                        target_path), trans_id)
2949
2949
                elif target_kind == 'file':
2950
 
                    deferred_files.append((target_path, (trans_id, mode_id, file_id)))
 
2950
                    deferred_files.append(
 
2951
                        (target_path, (trans_id, mode_id, file_id)))
2951
2952
                    if basis_tree is None:
2952
2953
                        basis_tree = working_tree.basis_tree()
2953
2954
                        basis_tree.lock_read()
2954
 
                    new_sha1 = target_tree.get_file_sha1(target_path, file_id)
 
2955
                    new_sha1 = target_tree.get_file_sha1(target_path)
2955
2956
                    basis_path = find_previous_path(target_tree, basis_tree, target_path)
2956
2957
                    if (basis_path is not None and
2957
 
                        new_sha1 == basis_tree.get_file_sha1(basis_path, file_id)):
 
2958
                            new_sha1 == basis_tree.get_file_sha1(basis_path)):
2958
2959
                        if file_id in merge_modified:
2959
2960
                            del merge_modified[file_id]
2960
2961
                    else:
2969
2970
                tt.version_file(file_id, trans_id)
2970
2971
            if wt_versioned and not target_versioned:
2971
2972
                tt.unversion_file(trans_id)
2972
 
            if (target_name is not None and
2973
 
                (wt_name != target_name or wt_parent != target_parent)):
 
2973
            if (target_name is not None
 
2974
                    and (wt_name != target_name or wt_parent != target_parent)):
2974
2975
                if target_name == '' and target_parent is None:
2975
2976
                    parent_trans = ROOT_PARENT
2976
2977
                else:
2983
2984
                tt.set_executability(target_executable, trans_id)
2984
2985
        if working_tree.supports_content_filtering():
2985
2986
            for (trans_id, mode_id, file_id), bytes in (
2986
 
                target_tree.iter_files_bytes(deferred_files)):
 
2987
                    target_tree.iter_files_bytes(deferred_files)):
2987
2988
                # We're reverting a tree to the target tree so using the
2988
2989
                # target tree to find the file path seems the best choice
2989
2990
                # here IMO - Ian C 27/Oct/2009
2990
2991
                filter_tree_path = target_tree.id2path(file_id)
2991
2992
                filters = working_tree._content_filter_stack(filter_tree_path)
2992
 
                bytes = filtered_output_bytes(bytes, filters,
 
2993
                bytes = filtered_output_bytes(
 
2994
                    bytes, filters,
2993
2995
                    ContentFilterContext(filter_tree_path, working_tree))
2994
2996
                tt.create_file(bytes, trans_id, mode_id)
2995
2997
        else:
2996
2998
            for (trans_id, mode_id, file_id), bytes in target_tree.iter_files_bytes(
2997
 
                deferred_files):
 
2999
                    deferred_files):
2998
3000
                tt.create_file(bytes, trans_id, mode_id)
2999
3001
        tt.fixup_new_roots()
3000
3002
    finally:
3010
3012
    new_conflicts = set()
3011
3013
    with ui.ui_factory.nested_progress_bar() as pb:
3012
3014
        for n in range(10):
3013
 
            pb.update(gettext('Resolution pass'), n+1, 10)
 
3015
            pb.update(gettext('Resolution pass'), n + 1, 10)
3014
3016
            conflicts = tt.find_conflicts()
3015
3017
            if len(conflicts) == 0:
3016
3018
                return new_conflicts
3109
3111
            # special-case the other tree root (move its children instead)
3110
3112
            if path_tree and path_tree.path2id('') == file_id:
3111
3113
                    # This is the root entry, skip it
3112
 
                    continue
 
3114
                continue
3113
3115
            tt.version_file(file_id, conflict[1])
3114
3116
            new_conflicts.add((c_type, 'Versioned directory', conflict[1]))
3115
3117
        elif c_type == 'non-directory parent':
3118
3120
            parent_name = tt.final_name(parent_id)
3119
3121
            parent_file_id = tt.final_file_id(parent_id)
3120
3122
            new_parent_id = tt.new_directory(parent_name + '.new',
3121
 
                parent_parent, parent_file_id)
 
3123
                                             parent_parent, parent_file_id)
3122
3124
            _reparent_transform_children(tt, parent_id, new_parent_id)
3123
3125
            if parent_file_id is not None:
3124
3126
                tt.unversion_file(parent_id)
3192
3194
            except OSError as e:
3193
3195
                raise errors.TransformRenameFailed(to, from_, str(e), e.errno)
3194
3196
        # after rollback, don't reuse _FileMover
3195
 
        past_renames = None
3196
 
        pending_deletions = None
 
3197
        self.past_renames = None
 
3198
        self.pending_deletions = None
3197
3199
 
3198
3200
    def apply_deletions(self):
3199
3201
        """Apply all marked deletions"""
3200
3202
        for path in self.pending_deletions:
3201
3203
            delete_any(path)
3202
3204
        # after apply_deletions, don't reuse _FileMover
3203
 
        past_renames = None
3204
 
        pending_deletions = None
 
3205
        self.past_renames = None
 
3206
        self.pending_deletions = None
3205
3207
 
3206
3208
 
3207
3209
def link_tree(target_tree, source_tree):
3214
3216
    try:
3215
3217
        for (file_id, paths, changed_content, versioned, parent, name, kind,
3216
3218
             executable) in target_tree.iter_changes(source_tree,
3217
 
             include_unchanged=True):
 
3219
                                                     include_unchanged=True):
3218
3220
            if changed_content:
3219
3221
                continue
3220
3222
            if kind != ('file', 'file'):