/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 23:15:15 UTC
  • mfrom: (7180 work)
  • mto: This revision was merged to the branch mainline in revision 7183.
  • Revision ID: jelmer@jelmer.uk-20181116231515-zqd2yn6kj8lfydyp
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):
2214
2212
        """See WorkingTree.list_files."""
2215
2213
        # XXX This should behave like WorkingTree.list_files, but is really
2216
2214
        # more like RevisionTree.list_files.
 
2215
        if from_dir == '.':
 
2216
            from_dir = None
2217
2217
        if recursive:
2218
2218
            prefix = None
2219
2219
            if from_dir:
2230
2230
        else:
2231
2231
            if from_dir is None and include_root is True:
2232
2232
                root_entry = inventory.make_entry('directory', '',
2233
 
                    ROOT_PARENT, self.get_root_id())
 
2233
                                                  ROOT_PARENT, self.get_root_id())
2234
2234
                yield '', 'V', 'directory', root_entry.file_id, root_entry
2235
2235
            entries = self._iter_entries_for_dir(from_dir or '')
2236
2236
            for path, entry in entries:
2237
2237
                yield path, 'V', entry.kind, entry.file_id, entry
2238
2238
 
2239
 
    def kind(self, path, file_id=None):
 
2239
    def kind(self, path):
2240
2240
        trans_id = self._path2trans_id(path)
2241
2241
        if trans_id is None:
2242
2242
            raise errors.NoSuchFile(path)
2243
2243
        return self._transform.final_kind(trans_id)
2244
2244
 
2245
 
    def stored_kind(self, path, file_id=None):
 
2245
    def stored_kind(self, path):
2246
2246
        trans_id = self._path2trans_id(path)
2247
2247
        if trans_id is None:
2248
2248
            raise errors.NoSuchFile(path)
2249
2249
        try:
2250
2250
            return self._transform._new_contents[trans_id]
2251
2251
        except KeyError:
2252
 
            return self._transform._tree.stored_kind(path, file_id)
 
2252
            return self._transform._tree.stored_kind(path)
2253
2253
 
2254
 
    def get_file_mtime(self, path, file_id=None):
 
2254
    def get_file_mtime(self, path):
2255
2255
        """See Tree.get_file_mtime"""
2256
 
        if file_id is None:
2257
 
            file_id = self.path2id(path)
 
2256
        file_id = self.path2id(path)
2258
2257
        if file_id is None:
2259
2258
            raise errors.NoSuchFile(path)
2260
2259
        if not self._content_change(file_id):
2261
2260
            return self._transform._tree.get_file_mtime(
2262
 
                    self._transform._tree.id2path(file_id), file_id)
 
2261
                self._transform._tree.id2path(file_id))
2263
2262
        trans_id = self._path2trans_id(path)
2264
2263
        return self._stat_limbo_file(trans_id).st_mtime
2265
2264
 
2266
 
    def get_file_size(self, path, file_id=None):
 
2265
    def get_file_size(self, path):
2267
2266
        """See Tree.get_file_size"""
2268
2267
        trans_id = self._path2trans_id(path)
2269
2268
        if trans_id is None:
2273
2272
            return None
2274
2273
        if trans_id in self._transform._new_contents:
2275
2274
            return self._stat_limbo_file(trans_id).st_size
2276
 
        if self.kind(path, file_id) == 'file':
2277
 
            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)
2278
2277
        else:
2279
2278
            return None
2280
2279
 
2281
 
    def get_file_verifier(self, path, file_id=None, stat_value=None):
 
2280
    def get_file_verifier(self, path, stat_value=None):
2282
2281
        trans_id = self._path2trans_id(path)
2283
2282
        if trans_id is None:
2284
2283
            raise errors.NoSuchFile(path)
2285
2284
        kind = self._transform._new_contents.get(trans_id)
2286
2285
        if kind is None:
2287
 
            return self._transform._tree.get_file_verifier(path, file_id)
 
2286
            return self._transform._tree.get_file_verifier(path)
2288
2287
        if kind == 'file':
2289
 
            with self.get_file(path, file_id) as fileobj:
 
2288
            with self.get_file(path) as fileobj:
2290
2289
                return ("SHA1", sha_file(fileobj))
2291
2290
 
2292
 
    def get_file_sha1(self, path, file_id=None, stat_value=None):
 
2291
    def get_file_sha1(self, path, stat_value=None):
2293
2292
        trans_id = self._path2trans_id(path)
2294
2293
        if trans_id is None:
2295
2294
            raise errors.NoSuchFile(path)
2296
2295
        kind = self._transform._new_contents.get(trans_id)
2297
2296
        if kind is None:
2298
 
            return self._transform._tree.get_file_sha1(path, file_id)
 
2297
            return self._transform._tree.get_file_sha1(path)
2299
2298
        if kind == 'file':
2300
 
            with self.get_file(path, file_id) as fileobj:
 
2299
            with self.get_file(path) as fileobj:
2301
2300
                return sha_file(fileobj)
2302
2301
 
2303
 
    def is_executable(self, path, file_id=None):
 
2302
    def is_executable(self, path):
2304
2303
        trans_id = self._path2trans_id(path)
2305
2304
        if trans_id is None:
2306
2305
            return False
2308
2307
            return self._transform._new_executability[trans_id]
2309
2308
        except KeyError:
2310
2309
            try:
2311
 
                return self._transform._tree.is_executable(path, file_id)
 
2310
                return self._transform._tree.is_executable(path)
2312
2311
            except OSError as e:
2313
2312
                if e.errno == errno.ENOENT:
2314
2313
                    return False
2358
2357
        return kind, size, executable, link_or_sha1
2359
2358
 
2360
2359
    def iter_changes(self, from_tree, include_unchanged=False,
2361
 
                      specific_files=None, pb=None, extra_trees=None,
2362
 
                      require_versioned=True, want_unversioned=False):
 
2360
                     specific_files=None, pb=None, extra_trees=None,
 
2361
                     require_versioned=True, want_unversioned=False):
2363
2362
        """See InterTree.iter_changes.
2364
2363
 
2365
2364
        This has a fast path that is only used when the from_tree matches
2366
2365
        the transform tree, and no fancy options are supplied.
2367
2366
        """
2368
 
        if (from_tree is not self._transform._tree or include_unchanged or
2369
 
            specific_files or want_unversioned):
 
2367
        if (from_tree is not self._transform._tree or include_unchanged
 
2368
                or specific_files or want_unversioned):
2370
2369
            return tree.InterTree(from_tree, self).iter_changes(
2371
2370
                include_unchanged=include_unchanged,
2372
2371
                specific_files=specific_files,
2378
2377
            raise ValueError('want_unversioned is not supported')
2379
2378
        return self._transform.iter_changes()
2380
2379
 
2381
 
    def get_file(self, path, file_id=None):
 
2380
    def get_file(self, path):
2382
2381
        """See Tree.get_file"""
2383
 
        if file_id is None:
2384
 
            file_id = self.path2id(path)
 
2382
        file_id = self.path2id(path)
2385
2383
        if not self._content_change(file_id):
2386
 
            return self._transform._tree.get_file(path, file_id)
 
2384
            return self._transform._tree.get_file(path)
2387
2385
        trans_id = self._path2trans_id(path)
2388
2386
        name = self._transform._limbo_name(trans_id)
2389
2387
        return open(name, 'rb')
2390
2388
 
2391
 
    def get_file_with_stat(self, path, file_id=None):
2392
 
        return self.get_file(path, file_id), None
 
2389
    def get_file_with_stat(self, path):
 
2390
        return self.get_file(path), None
2393
2391
 
2394
 
    def annotate_iter(self, path, file_id=None,
 
2392
    def annotate_iter(self, path,
2395
2393
                      default_revision=_mod_revision.CURRENT_REVISION):
2396
 
        if file_id is None:
2397
 
            file_id = self.path2id(path)
 
2394
        file_id = self.path2id(path)
2398
2395
        changes = self._iter_changes_cache.get(file_id)
2399
2396
        if changes is None:
2400
2397
            get_old = True
2406
2403
            get_old = (kind[0] == 'file' and versioned[0])
2407
2404
        if get_old:
2408
2405
            old_annotation = self._transform._tree.annotate_iter(
2409
 
                    path, file_id=file_id, default_revision=default_revision)
 
2406
                path, default_revision=default_revision)
2410
2407
        else:
2411
2408
            old_annotation = []
2412
2409
        if changes is None:
2421
2418
        #       It would be nice to be able to use the new Annotator based
2422
2419
        #       approach, as well.
2423
2420
        return annotate.reannotate([old_annotation],
2424
 
                                   self.get_file(path, file_id).readlines(),
 
2421
                                   self.get_file(path).readlines(),
2425
2422
                                   default_revision)
2426
2423
 
2427
 
    def get_symlink_target(self, path, file_id=None):
 
2424
    def get_symlink_target(self, path):
2428
2425
        """See Tree.get_symlink_target"""
2429
 
        if file_id is None:
2430
 
            file_id = self.path2id(path)
 
2426
        file_id = self.path2id(path)
2431
2427
        if not self._content_change(file_id):
2432
2428
            return self._transform._tree.get_symlink_target(path)
2433
2429
        trans_id = self._path2trans_id(path)
2447
2443
                path_from_root = self._final_paths.get_path(child_id)
2448
2444
                basename = self._transform.final_name(child_id)
2449
2445
                file_id = self._transform.final_file_id(child_id)
2450
 
                kind  = self._transform.final_kind(child_id)
 
2446
                kind = self._transform.final_kind(child_id)
2451
2447
                if kind is not None:
2452
2448
                    versioned_kind = kind
2453
2449
                else:
2454
2450
                    kind = 'unknown'
2455
2451
                    versioned_kind = self._transform._tree.stored_kind(
2456
 
                            self._transform._tree.id2path(file_id),
2457
 
                            file_id)
 
2452
                        self._transform._tree.id2path(file_id))
2458
2453
                if versioned_kind == 'directory':
2459
2454
                    subdirs.append(child_id)
2460
2455
                children.append((path_from_root, basename, kind, None,
2489
2484
    The underlying tree must not be manipulated between calls, or else
2490
2485
    the results will likely be incorrect.
2491
2486
    """
 
2487
 
2492
2488
    def __init__(self, transform):
2493
2489
        object.__init__(self)
2494
2490
        self._known_paths = {}
2514
2510
        return [(self.get_path(t), t) for t in trans_ids]
2515
2511
 
2516
2512
 
2517
 
 
2518
2513
def topology_sorted_ids(tree):
2519
2514
    """Determine the topological order of the ids in a tree"""
2520
2515
    file_ids = list(tree)
2601
2596
                for dir, files in wt.walkdirs():
2602
2597
                    existing_files.update(f[0] for f in files)
2603
2598
            for num, (tree_path, entry) in \
2604
 
                enumerate(tree.iter_entries_by_dir()):
2605
 
                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)
2606
2602
                if entry.parent_id is None:
2607
2603
                    continue
2608
2604
                reparent = False
2619
2615
                            pass
2620
2616
                        else:
2621
2617
                            divert.add(file_id)
2622
 
                    if (file_id not in divert and
2623
 
                        _content_match(tree, entry, tree_path, file_id, kind,
2624
 
                        target_path)):
 
2618
                    if (file_id not in divert
 
2619
                        and _content_match(
 
2620
                            tree, entry, tree_path, file_id, kind,
 
2621
                            target_path)):
2625
2622
                        tt.delete_contents(tt.trans_id_tree_path(tree_path))
2626
2623
                        if kind == 'directory':
2627
2624
                            reparent = True
2632
2629
                    trans_id = tt.create_path(entry.name, parent_id)
2633
2630
                    file_trans_id[file_id] = trans_id
2634
2631
                    tt.version_file(file_id, trans_id)
2635
 
                    executable = tree.is_executable(tree_path, file_id)
 
2632
                    executable = tree.is_executable(tree_path)
2636
2633
                    if executable:
2637
2634
                        tt.set_executability(executable, trans_id)
2638
 
                    trans_data = (trans_id, file_id, tree_path, entry.text_sha1)
 
2635
                    trans_data = (trans_id, file_id,
 
2636
                                  tree_path, entry.text_sha1)
2639
2637
                    deferred_contents.append((tree_path, trans_data))
2640
2638
                else:
2641
2639
                    file_trans_id[file_id] = new_by_entry(
2642
 
                            tree_path, tt, entry, parent_id, tree)
 
2640
                        tree_path, tt, entry, parent_id, tree)
2643
2641
                if reparent:
2644
2642
                    new_trans_id = file_trans_id[file_id]
2645
2643
                    old_parent = tt.trans_id_tree_path(tree_path)
2649
2647
                          accelerator_tree, hardlink)
2650
2648
        pp.next_phase()
2651
2649
        divert_trans = set(file_trans_id[f] for f in divert)
2652
 
        resolver = lambda t, c: resolve_checkout(t, c, divert_trans)
 
2650
 
 
2651
        def resolver(t, c):
 
2652
            return resolve_checkout(t, c, divert_trans)
2653
2653
        raw_conflicts = resolve_conflicts(tt, pass_func=resolver)
2654
2654
        if len(raw_conflicts) > 0:
2655
2655
            precomputed_delta = None
2688
2688
            accelerator_path = unchanged.get(tree_path)
2689
2689
            if accelerator_path is None:
2690
2690
                new_desired_files.append((tree_path,
2691
 
                    (trans_id, file_id, tree_path, text_sha1)))
 
2691
                                          (trans_id, file_id, tree_path, text_sha1)))
2692
2692
                continue
2693
2693
            pb.update(gettext('Adding file contents'), count + offset, total)
2694
2694
            if hardlink:
2700
2700
                    if wt.supports_content_filtering():
2701
2701
                        filters = wt._content_filter_stack(tree_path)
2702
2702
                        chunks = filtered_output_bytes(chunks, filters,
2703
 
                            ContentFilterContext(tree_path, tree))
 
2703
                                                       ContentFilterContext(tree_path, tree))
2704
2704
                    tt.create_file(chunks, trans_id, sha1=text_sha1)
2705
2705
            count += 1
2706
2706
        offset += count
2709
2709
        if wt.supports_content_filtering():
2710
2710
            filters = wt._content_filter_stack(tree_path)
2711
2711
            contents = filtered_output_bytes(contents, filters,
2712
 
                ContentFilterContext(tree_path, tree))
 
2712
                                             ContentFilterContext(tree_path, tree))
2713
2713
        tt.create_file(contents, trans_id, sha1=text_sha1)
2714
2714
        pb.update(gettext('Adding file contents'), count + offset, total)
2715
2715
 
2733
2733
        return True
2734
2734
    if entry.kind == "file":
2735
2735
        with open(target_path, 'rb') as f1, \
2736
 
             tree.get_file(tree_path, file_id) as f2:
 
2736
                tree.get_file(tree_path) as f2:
2737
2737
            if osutils.compare_files(f1, f2):
2738
2738
                return True
2739
2739
    elif entry.kind == "symlink":
2740
 
        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):
2741
2741
            return True
2742
2742
    return False
2743
2743
 
2760
2760
        # resolved
2761
2761
        final_parent = tt.final_parent(old_file)
2762
2762
        if new_file in divert:
2763
 
            new_name = tt.final_name(old_file)+'.diverted'
 
2763
            new_name = tt.final_name(old_file) + '.diverted'
2764
2764
            tt.adjust_path(new_name, final_parent, new_file)
2765
2765
            new_conflicts.add((c_type, 'Diverted to',
2766
2766
                               new_file, old_file))
2767
2767
        else:
2768
 
            new_name = tt.final_name(old_file)+'.moved'
 
2768
            new_name = tt.final_name(old_file) + '.moved'
2769
2769
            tt.adjust_path(new_name, final_parent, old_file)
2770
2770
            new_conflicts.add((c_type, 'Moved existing file to',
2771
2771
                               old_file, new_file))
2777
2777
    name = entry.name
2778
2778
    kind = entry.kind
2779
2779
    if kind == 'file':
2780
 
        with tree.get_file(path, entry.file_id) as f:
2781
 
            executable = tree.is_executable(path, entry.file_id)
 
2780
        with tree.get_file(path) as f:
 
2781
            executable = tree.is_executable(path)
2782
2782
            return tt.new_file(
2783
 
                    name, parent_id, osutils.file_iterator(f), entry.file_id,
2784
 
                    executable)
 
2783
                name, parent_id, osutils.file_iterator(f), entry.file_id,
 
2784
                executable)
2785
2785
    elif kind in ('directory', 'tree-reference'):
2786
2786
        trans_id = tt.new_directory(name, parent_id, entry.file_id)
2787
2787
        if kind == 'tree-reference':
2788
2788
            tt.set_tree_reference(entry.reference_revision, trans_id)
2789
2789
        return trans_id
2790
2790
    elif kind == 'symlink':
2791
 
        target = tree.get_symlink_target(path, entry.file_id)
 
2791
        target = tree.get_symlink_target(path)
2792
2792
        return tt.new_symlink(name, parent_id, target, entry.file_id)
2793
2793
    else:
2794
2794
        raise errors.BadFileKindError(name, kind)
2795
2795
 
2796
2796
 
2797
2797
def create_from_tree(tt, trans_id, tree, path, file_id=None, chunks=None,
2798
 
    filter_tree_path=None):
 
2798
                     filter_tree_path=None):
2799
2799
    """Create new file contents according to tree contents.
2800
2800
 
2801
2801
    :param filter_tree_path: the tree path to use to lookup
2802
2802
      content filters to apply to the bytes output in the working tree.
2803
2803
      This only applies if the working tree supports content filtering.
2804
2804
    """
2805
 
    kind = tree.kind(path, file_id)
 
2805
    kind = tree.kind(path)
2806
2806
    if kind == 'directory':
2807
2807
        tt.create_directory(trans_id)
2808
2808
    elif kind == "file":
2809
2809
        if chunks is None:
2810
 
            f = tree.get_file(path, file_id)
 
2810
            f = tree.get_file(path)
2811
2811
            chunks = osutils.file_iterator(f)
2812
2812
        else:
2813
2813
            f = None
2815
2815
            wt = tt._tree
2816
2816
            if wt.supports_content_filtering() and filter_tree_path is not None:
2817
2817
                filters = wt._content_filter_stack(filter_tree_path)
2818
 
                chunks = filtered_output_bytes(chunks, filters,
 
2818
                chunks = filtered_output_bytes(
 
2819
                    chunks, filters,
2819
2820
                    ContentFilterContext(filter_tree_path, tree))
2820
2821
            tt.create_file(chunks, trans_id)
2821
2822
        finally:
2822
2823
            if f is not None:
2823
2824
                f.close()
2824
2825
    elif kind == "symlink":
2825
 
        tt.create_symlink(tree.get_symlink_target(path, file_id), trans_id)
 
2826
        tt.create_symlink(tree.get_symlink_target(path), trans_id)
2826
2827
    else:
2827
2828
        raise AssertionError('Unknown kind %r' % kind)
2828
2829
 
2867
2868
                                      child_pb, filenames, backups,
2868
2869
                                      merge_modified, basis_tree)
2869
2870
    with ui.ui_factory.nested_progress_bar() as child_pb:
2870
 
        raw_conflicts = resolve_conflicts(tt, child_pb,
2871
 
            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))
2872
2873
    conflicts = cook_conflicts(raw_conflicts, tt)
2873
2874
    return conflicts, merge_modified
2874
2875
 
2881
2882
    # than the target changes relative to the working tree. Because WT4 has an
2882
2883
    # optimizer to compare itself to a target, but no optimizer for the
2883
2884
    # reverse.
2884
 
    change_list = working_tree.iter_changes(target_tree,
2885
 
        specific_files=specific_files, pb=pb)
 
2885
    change_list = working_tree.iter_changes(
 
2886
        target_tree, specific_files=specific_files, pb=pb)
2886
2887
    if not target_tree.is_versioned(u''):
2887
2888
        skip_root = True
2888
2889
    else:
2890
2891
    try:
2891
2892
        deferred_files = []
2892
2893
        for id_num, (file_id, path, changed_content, versioned, parent, name,
2893
 
                kind, executable) in enumerate(change_list):
 
2894
                     kind, executable) in enumerate(change_list):
2894
2895
            target_path, wt_path = path
2895
2896
            target_versioned, wt_versioned = versioned
2896
2897
            target_parent, wt_parent = parent
2904
2905
            if changed_content:
2905
2906
                keep_content = False
2906
2907
                if wt_kind == 'file' and (backups or target_kind is None):
2907
 
                    wt_sha1 = working_tree.get_file_sha1(wt_path, file_id)
 
2908
                    wt_sha1 = working_tree.get_file_sha1(wt_path)
2908
2909
                    if merge_modified.get(file_id) != wt_sha1:
2909
2910
                        # acquire the basis tree lazily to prevent the
2910
2911
                        # expense of accessing it when it's not needed ?
2912
2913
                        if basis_tree is None:
2913
2914
                            basis_tree = working_tree.basis_tree()
2914
2915
                            basis_tree.lock_read()
2915
 
                        basis_path = find_previous_path(working_tree, basis_tree, wt_path)
 
2916
                        basis_path = find_previous_path(
 
2917
                            working_tree, basis_tree, wt_path)
2916
2918
                        if basis_path is None:
2917
2919
                            if target_kind is None and not target_versioned:
2918
2920
                                keep_content = True
2919
2921
                        else:
2920
 
                            if wt_sha1 != basis_tree.get_file_sha1(basis_path, file_id):
 
2922
                            if wt_sha1 != basis_tree.get_file_sha1(basis_path):
2921
2923
                                keep_content = True
2922
2924
                if wt_kind is not None:
2923
2925
                    if not keep_content:
2939
2941
                    tt.create_directory(trans_id)
2940
2942
                    if target_kind == 'tree-reference':
2941
2943
                        revision = target_tree.get_reference_revision(
2942
 
                                target_path, file_id)
 
2944
                            target_path)
2943
2945
                        tt.set_tree_reference(revision, trans_id)
2944
2946
                elif target_kind == 'symlink':
2945
2947
                    tt.create_symlink(target_tree.get_symlink_target(
2946
 
                            target_path, file_id), trans_id)
 
2948
                        target_path), trans_id)
2947
2949
                elif target_kind == 'file':
2948
 
                    deferred_files.append((target_path, (trans_id, mode_id, file_id)))
 
2950
                    deferred_files.append(
 
2951
                        (target_path, (trans_id, mode_id, file_id)))
2949
2952
                    if basis_tree is None:
2950
2953
                        basis_tree = working_tree.basis_tree()
2951
2954
                        basis_tree.lock_read()
2952
 
                    new_sha1 = target_tree.get_file_sha1(target_path, file_id)
 
2955
                    new_sha1 = target_tree.get_file_sha1(target_path)
2953
2956
                    basis_path = find_previous_path(target_tree, basis_tree, target_path)
2954
2957
                    if (basis_path is not None and
2955
 
                        new_sha1 == basis_tree.get_file_sha1(basis_path, file_id)):
 
2958
                            new_sha1 == basis_tree.get_file_sha1(basis_path)):
2956
2959
                        if file_id in merge_modified:
2957
2960
                            del merge_modified[file_id]
2958
2961
                    else:
2967
2970
                tt.version_file(file_id, trans_id)
2968
2971
            if wt_versioned and not target_versioned:
2969
2972
                tt.unversion_file(trans_id)
2970
 
            if (target_name is not None and
2971
 
                (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)):
2972
2975
                if target_name == '' and target_parent is None:
2973
2976
                    parent_trans = ROOT_PARENT
2974
2977
                else:
2981
2984
                tt.set_executability(target_executable, trans_id)
2982
2985
        if working_tree.supports_content_filtering():
2983
2986
            for (trans_id, mode_id, file_id), bytes in (
2984
 
                target_tree.iter_files_bytes(deferred_files)):
 
2987
                    target_tree.iter_files_bytes(deferred_files)):
2985
2988
                # We're reverting a tree to the target tree so using the
2986
2989
                # target tree to find the file path seems the best choice
2987
2990
                # here IMO - Ian C 27/Oct/2009
2988
2991
                filter_tree_path = target_tree.id2path(file_id)
2989
2992
                filters = working_tree._content_filter_stack(filter_tree_path)
2990
 
                bytes = filtered_output_bytes(bytes, filters,
 
2993
                bytes = filtered_output_bytes(
 
2994
                    bytes, filters,
2991
2995
                    ContentFilterContext(filter_tree_path, working_tree))
2992
2996
                tt.create_file(bytes, trans_id, mode_id)
2993
2997
        else:
2994
2998
            for (trans_id, mode_id, file_id), bytes in target_tree.iter_files_bytes(
2995
 
                deferred_files):
 
2999
                    deferred_files):
2996
3000
                tt.create_file(bytes, trans_id, mode_id)
2997
3001
        tt.fixup_new_roots()
2998
3002
    finally:
3008
3012
    new_conflicts = set()
3009
3013
    with ui.ui_factory.nested_progress_bar() as pb:
3010
3014
        for n in range(10):
3011
 
            pb.update(gettext('Resolution pass'), n+1, 10)
 
3015
            pb.update(gettext('Resolution pass'), n + 1, 10)
3012
3016
            conflicts = tt.find_conflicts()
3013
3017
            if len(conflicts) == 0:
3014
3018
                return new_conflicts
3107
3111
            # special-case the other tree root (move its children instead)
3108
3112
            if path_tree and path_tree.path2id('') == file_id:
3109
3113
                    # This is the root entry, skip it
3110
 
                    continue
 
3114
                continue
3111
3115
            tt.version_file(file_id, conflict[1])
3112
3116
            new_conflicts.add((c_type, 'Versioned directory', conflict[1]))
3113
3117
        elif c_type == 'non-directory parent':
3116
3120
            parent_name = tt.final_name(parent_id)
3117
3121
            parent_file_id = tt.final_file_id(parent_id)
3118
3122
            new_parent_id = tt.new_directory(parent_name + '.new',
3119
 
                parent_parent, parent_file_id)
 
3123
                                             parent_parent, parent_file_id)
3120
3124
            _reparent_transform_children(tt, parent_id, new_parent_id)
3121
3125
            if parent_file_id is not None:
3122
3126
                tt.unversion_file(parent_id)
3190
3194
            except OSError as e:
3191
3195
                raise errors.TransformRenameFailed(to, from_, str(e), e.errno)
3192
3196
        # after rollback, don't reuse _FileMover
3193
 
        past_renames = None
3194
 
        pending_deletions = None
 
3197
        self.past_renames = None
 
3198
        self.pending_deletions = None
3195
3199
 
3196
3200
    def apply_deletions(self):
3197
3201
        """Apply all marked deletions"""
3198
3202
        for path in self.pending_deletions:
3199
3203
            delete_any(path)
3200
3204
        # after apply_deletions, don't reuse _FileMover
3201
 
        past_renames = None
3202
 
        pending_deletions = None
 
3205
        self.past_renames = None
 
3206
        self.pending_deletions = None
3203
3207
 
3204
3208
 
3205
3209
def link_tree(target_tree, source_tree):
3212
3216
    try:
3213
3217
        for (file_id, paths, changed_content, versioned, parent, name, kind,
3214
3218
             executable) in target_tree.iter_changes(source_tree,
3215
 
             include_unchanged=True):
 
3219
                                                     include_unchanged=True):
3216
3220
            if changed_content:
3217
3221
                continue
3218
3222
            if kind != ('file', 'file'):