~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-04-26 21:11:03 UTC
  • mfrom: (2447.1.7 bundle_empty_properties)
  • Revision ID: pqm@pqm.ubuntu.com-20070426211103-h84prqh7a4ad3ez2
(John Arbash Meinel) Fix bug #109613 by teaching Bundle how to properly read/write revision properties with no value.

Show diffs side-by-side

added added

removed removed

Lines of Context:
413
413
 
414
414
        file_abspath = self.abspath(path)
415
415
        state = self.current_dirstate()
416
 
        if stat_value is None:
417
 
            try:
418
 
                stat_value = os.lstat(file_abspath)
419
 
            except OSError, e:
420
 
                if e.errno == errno.ENOENT:
421
 
                    return None
422
 
                else:
423
 
                    raise
424
416
        link_or_sha1 = state.update_entry(entry, file_abspath,
425
417
                                          stat_value=stat_value)
426
418
        if entry[1][0][0] == 'f':
472
464
 
473
465
    @needs_read_lock
474
466
    def id2path(self, file_id):
475
 
        "Convert a file-id to a path."
476
467
        file_id = osutils.safe_file_id(file_id)
477
468
        state = self.current_dirstate()
478
469
        entry = self._get_entry(file_id=file_id)
482
473
        return path_utf8.decode('utf8')
483
474
 
484
475
    if not osutils.supports_executable():
 
476
        @needs_read_lock
485
477
        def is_executable(self, file_id, path=None):
486
 
            """Test if a file is executable or not.
487
 
 
488
 
            Note: The caller is expected to take a read-lock before calling this.
489
 
            """
490
478
            file_id = osutils.safe_file_id(file_id)
491
479
            entry = self._get_entry(file_id=file_id, path=path)
492
480
            if entry == (None, None):
493
481
                return False
494
482
            return entry[1][0][3]
495
483
    else:
 
484
        @needs_read_lock
496
485
        def is_executable(self, file_id, path=None):
497
 
            """Test if a file is executable or not.
498
 
 
499
 
            Note: The caller is expected to take a read-lock before calling this.
500
 
            """
501
486
            if not path:
502
487
                file_id = osutils.safe_file_id(file_id)
503
488
                path = self.id2path(file_id)
537
522
                # path is missing on disk.
538
523
                continue
539
524
 
 
525
    @needs_read_lock
540
526
    def kind(self, file_id):
541
527
        """Return the kind of a file.
542
528
 
543
529
        This is always the actual kind that's on disk, regardless of what it
544
530
        was added as.
545
 
 
546
 
        Note: The caller is expected to take a read-lock before calling this.
547
531
        """
548
532
        relpath = self.id2path(file_id)
549
533
        assert relpath != None, \
1068
1052
            except (errors.NoSuchRevision, errors.RevisionNotPresent):
1069
1053
                revtree = None
1070
1054
            trees.append((revision_id, revtree))
 
1055
        self.current_dirstate()._validate()
1071
1056
        self.set_parent_trees(trees,
1072
1057
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
 
1058
        self.current_dirstate()._validate()
1073
1059
 
1074
1060
    @needs_tree_write_lock
1075
1061
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
1080
1066
            parent tree - i.e. a ghost.
1081
1067
        """
1082
1068
        dirstate = self.current_dirstate()
 
1069
        dirstate._validate()
1083
1070
        if len(parents_list) > 0:
1084
1071
            if not allow_leftmost_as_ghost and parents_list[0][1] is None:
1085
1072
                raise errors.GhostRevisionUnusableHere(parents_list[0][0])
1095
1082
                real_trees.append((rev_id,
1096
1083
                    self.branch.repository.revision_tree(None)))
1097
1084
                ghosts.append(rev_id)
 
1085
        dirstate._validate()
1098
1086
        dirstate.set_parent_trees(real_trees, ghosts=ghosts)
 
1087
        dirstate._validate()
1099
1088
        self._make_dirty(reset_inventory=False)
 
1089
        dirstate._validate()
1100
1090
 
1101
1091
    def _set_root_id(self, file_id):
1102
1092
        """See WorkingTree.set_root_id."""
1285
1275
                         _control_files=control_files)
1286
1276
        wt._new_tree()
1287
1277
        wt.lock_tree_write()
 
1278
        wt.current_dirstate()._validate()
1288
1279
        try:
1289
1280
            if revision_id in (None, NULL_REVISION):
1290
1281
                if branch.repository.supports_rich_root():
1292
1283
                else:
1293
1284
                    wt._set_root_id(ROOT_ID)
1294
1285
                wt.flush()
 
1286
                wt.current_dirstate()._validate()
1295
1287
            wt.set_last_revision(revision_id)
1296
1288
            wt.flush()
1297
1289
            basis = wt.basis_tree()
1674
1666
            output. An unversioned file is defined as one with (False, False)
1675
1667
            for the versioned pair.
1676
1668
        """
1677
 
        utf8_decode = cache_utf8._utf8_decode
 
1669
        utf8_decode_or_none = cache_utf8._utf8_decode_with_None
1678
1670
        _minikind_to_kind = dirstate.DirState._minikind_to_kind
1679
1671
        # NB: show_status depends on being able to pass in non-versioned files
1680
1672
        # and report them as unknown
1808
1800
        NULL_PARENT_DETAILS = dirstate.DirState.NULL_PARENT_DETAILS
1809
1801
        # Using a list so that we can access the values and change them in
1810
1802
        # nested scope. Each one is [path, file_id, entry]
1811
 
        last_source_parent = [None, None]
1812
 
        last_target_parent = [None, None]
 
1803
        last_source_parent = [None, None, None]
 
1804
        last_target_parent = [None, None, None]
1813
1805
 
1814
1806
        use_filesystem_for_exec = (sys.platform != 'win32')
1815
1807
 
1816
 
        # Just a sentry, so that _process_entry can say that this
1817
 
        # record is handled, but isn't interesting to process (unchanged)
1818
 
        uninteresting = object()
1819
 
 
1820
 
 
1821
 
        old_dirname_to_file_id = {}
1822
 
        new_dirname_to_file_id = {}
1823
 
        # TODO: jam 20070516 - Avoid the _get_entry lookup overhead by
1824
 
        #       keeping a cache of directories that we have seen.
1825
 
 
1826
1808
        def _process_entry(entry, path_info):
1827
1809
            """Compare an entry and real disk to generate delta information.
1828
1810
 
1832
1814
                Basename is returned as a utf8 string because we expect this
1833
1815
                tuple will be ignored, and don't want to take the time to
1834
1816
                decode.
1835
 
            :return: None if these don't match
1836
 
                     A tuple of information about the change, or
1837
 
                     the object 'uninteresting' if these match, but are
1838
 
                     basically identical.
1839
1817
            """
1840
1818
            if source_index is None:
1841
1819
                source_details = NULL_PARENT_DETAILS
1852
1830
                target_minikind = target_details[0]
1853
1831
            else:
1854
1832
                link_or_sha1 = None
1855
 
            file_id = entry[0][2]
1856
1833
            source_minikind = source_details[0]
1857
1834
            if source_minikind in 'fdltr' and target_minikind in 'fdlt':
1858
1835
                # claimed content in both: diff
1880
1857
                else:
1881
1858
                    old_dirname = entry[0][0]
1882
1859
                    old_basename = entry[0][1]
1883
 
                    old_path = path = None
 
1860
                    old_path = path = pathjoin(old_dirname, old_basename)
1884
1861
                if path_info is None:
1885
1862
                    # the file is missing on disk, show as removed.
1886
1863
                    content_change = True
1890
1867
                    # source and target are both versioned and disk file is present.
1891
1868
                    target_kind = path_info[2]
1892
1869
                    if target_kind == 'directory':
1893
 
                        if path is None:
1894
 
                            old_path = path = pathjoin(old_dirname, old_basename)
1895
 
                        new_dirname_to_file_id[path] = file_id
1896
1870
                        if source_minikind != 'd':
1897
1871
                            content_change = True
1898
1872
                        else:
1927
1901
                        target_exec = False
1928
1902
                    else:
1929
1903
                        raise Exception, "unknown kind %s" % path_info[2]
1930
 
                if source_minikind == 'd':
1931
 
                    if path is None:
1932
 
                        old_path = path = pathjoin(old_dirname, old_basename)
1933
 
                    old_dirname_to_file_id[old_path] = file_id
1934
1904
                # parent id is the entry for the path in the target tree
1935
1905
                if old_dirname == last_source_parent[0]:
1936
1906
                    source_parent_id = last_source_parent[1]
1937
1907
                else:
1938
 
                    try:
1939
 
                        source_parent_id = old_dirname_to_file_id[old_dirname]
1940
 
                    except KeyError:
1941
 
                        source_parent_entry = state._get_entry(source_index,
1942
 
                                                               path_utf8=old_dirname)
1943
 
                        source_parent_id = source_parent_entry[0][2]
 
1908
                    source_parent_entry = state._get_entry(source_index,
 
1909
                                                           path_utf8=old_dirname)
 
1910
                    source_parent_id = source_parent_entry[0][2]
1944
1911
                    if source_parent_id == entry[0][2]:
1945
1912
                        # This is the root, so the parent is None
1946
1913
                        source_parent_id = None
1947
1914
                    else:
1948
1915
                        last_source_parent[0] = old_dirname
1949
1916
                        last_source_parent[1] = source_parent_id
 
1917
                        last_source_parent[2] = source_parent_entry
1950
1918
                new_dirname = entry[0][0]
1951
1919
                if new_dirname == last_target_parent[0]:
1952
1920
                    target_parent_id = last_target_parent[1]
1953
1921
                else:
1954
 
                    try:
1955
 
                        target_parent_id = new_dirname_to_file_id[new_dirname]
1956
 
                    except KeyError:
1957
 
                        # TODO: We don't always need to do the lookup, because the
1958
 
                        #       parent entry will be the same as the source entry.
1959
 
                        target_parent_entry = state._get_entry(target_index,
1960
 
                                                               path_utf8=new_dirname)
1961
 
                        assert target_parent_entry != (None, None), (
1962
 
                            "Could not find target parent in wt: %s\nparent of: %s"
1963
 
                            % (new_dirname, entry))
1964
 
                        target_parent_id = target_parent_entry[0][2]
 
1922
                    # TODO: We don't always need to do the lookup, because the
 
1923
                    #       parent entry will be the same as the source entry.
 
1924
                    target_parent_entry = state._get_entry(target_index,
 
1925
                                                           path_utf8=new_dirname)
 
1926
                    assert target_parent_entry != (None, None), (
 
1927
                        "Could not find target parent in wt: %s\nparent of: %s"
 
1928
                        % (new_dirname, entry))
 
1929
                    target_parent_id = target_parent_entry[0][2]
1965
1930
                    if target_parent_id == entry[0][2]:
1966
1931
                        # This is the root, so the parent is None
1967
1932
                        target_parent_id = None
1968
1933
                    else:
1969
1934
                        last_target_parent[0] = new_dirname
1970
1935
                        last_target_parent[1] = target_parent_id
 
1936
                        last_target_parent[2] = target_parent_entry
1971
1937
 
1972
1938
                source_exec = source_details[3]
1973
 
                if (include_unchanged
1974
 
                    or content_change
1975
 
                    or source_parent_id != target_parent_id
1976
 
                    or old_basename != entry[0][1]
1977
 
                    or source_exec != target_exec
1978
 
                    ):
1979
 
                    if old_path is None:
1980
 
                        old_path = path = pathjoin(old_dirname, old_basename)
1981
 
                        old_path_u = utf8_decode(old_path)[0]
1982
 
                        path_u = old_path_u
1983
 
                    else:
1984
 
                        old_path_u = utf8_decode(old_path)[0]
1985
 
                        if old_path == path:
1986
 
                            path_u = old_path_u
1987
 
                        else:
1988
 
                            path_u = utf8_decode(path)[0]
1989
 
                    source_kind = _minikind_to_kind[source_minikind]
1990
 
                    return (entry[0][2],
1991
 
                           (old_path_u, path_u),
1992
 
                           content_change,
1993
 
                           (True, True),
1994
 
                           (source_parent_id, target_parent_id),
1995
 
                           (utf8_decode(old_basename)[0], utf8_decode(entry[0][1])[0]),
1996
 
                           (source_kind, target_kind),
1997
 
                           (source_exec, target_exec))
1998
 
                else:
1999
 
                    return uninteresting
 
1939
                return ((entry[0][2], (old_path, path), content_change,
 
1940
                        (True, True),
 
1941
                        (source_parent_id, target_parent_id),
 
1942
                        (old_basename, entry[0][1]),
 
1943
                        (_minikind_to_kind[source_minikind], target_kind),
 
1944
                        (source_exec, target_exec)),)
2000
1945
            elif source_minikind in 'a' and target_minikind in 'fdlt':
2001
1946
                # looks like a new file
2002
1947
                if path_info is not None:
2015
1960
                            and stat.S_IEXEC & path_info[3].st_mode)
2016
1961
                    else:
2017
1962
                        target_exec = target_details[3]
2018
 
                    return (entry[0][2],
2019
 
                           (None, utf8_decode(path)[0]),
2020
 
                           True,
2021
 
                           (False, True),
2022
 
                           (None, parent_id),
2023
 
                           (None, utf8_decode(entry[0][1])[0]),
2024
 
                           (None, path_info[2]),
2025
 
                           (None, target_exec))
 
1963
                    return ((entry[0][2], (None, path), True,
 
1964
                            (False, True),
 
1965
                            (None, parent_id),
 
1966
                            (None, entry[0][1]),
 
1967
                            (None, path_info[2]),
 
1968
                            (None, target_exec)),)
2026
1969
                else:
2027
1970
                    # but its not on disk: we deliberately treat this as just
2028
1971
                    # never-present. (Why ?! - RBC 20070224)
2037
1980
                parent_id = state._get_entry(source_index, path_utf8=entry[0][0])[0][2]
2038
1981
                if parent_id == entry[0][2]:
2039
1982
                    parent_id = None
2040
 
                return (entry[0][2],
2041
 
                       (utf8_decode(old_path)[0], None),
2042
 
                       True,
2043
 
                       (True, False),
2044
 
                       (parent_id, None),
2045
 
                       (utf8_decode(entry[0][1])[0], None),
2046
 
                       (_minikind_to_kind[source_minikind], None),
2047
 
                       (source_details[3], None))
 
1983
                return ((entry[0][2], (old_path, None), True,
 
1984
                        (True, False),
 
1985
                        (parent_id, None),
 
1986
                        (entry[0][1], None),
 
1987
                        (_minikind_to_kind[source_minikind], None),
 
1988
                        (source_details[3], None)),)
2048
1989
            elif source_minikind in 'fdlt' and target_minikind in 'r':
2049
1990
                # a rename; could be a true rename, or a rename inherited from
2050
1991
                # a renamed parent. TODO: handle this efficiently. Its not
2062
2003
                    "source_minikind=%r, target_minikind=%r"
2063
2004
                    % (source_minikind, target_minikind))
2064
2005
                ## import pdb;pdb.set_trace()
2065
 
            return None
 
2006
            return ()
2066
2007
 
2067
2008
        while search_specific_files:
2068
2009
            # TODO: the pending list should be lexically sorted?  the
2098
2039
                continue
2099
2040
            path_handled = False
2100
2041
            for entry in root_entries:
2101
 
                result = _process_entry(entry, root_dir_info)
2102
 
                if result is not None:
 
2042
                for result in _process_entry(entry, root_dir_info):
 
2043
                    # this check should probably be outside the loop: one
 
2044
                    # 'iterate two trees' api, and then _iter_changes filters
 
2045
                    # unchanged pairs. - RBC 20070226
2103
2046
                    path_handled = True
2104
 
                    if result is not uninteresting:
2105
 
                        yield result
 
2047
                    if (include_unchanged
 
2048
                        or result[2]                    # content change
 
2049
                        or result[3][0] != result[3][1] # versioned status
 
2050
                        or result[4][0] != result[4][1] # parent id
 
2051
                        or result[5][0] != result[5][1] # name
 
2052
                        or result[6][0] != result[6][1] # kind
 
2053
                        or result[7][0] != result[7][1] # executable
 
2054
                        ):
 
2055
                        yield (result[0],
 
2056
                               (utf8_decode_or_none(result[1][0]),
 
2057
                                utf8_decode_or_none(result[1][1])),
 
2058
                               result[2],
 
2059
                               result[3],
 
2060
                               result[4],
 
2061
                               (utf8_decode_or_none(result[5][0]),
 
2062
                                utf8_decode_or_none(result[5][1])),
 
2063
                               result[6],
 
2064
                               result[7],
 
2065
                              )
2106
2066
            if want_unversioned and not path_handled and root_dir_info:
2107
2067
                new_executable = bool(
2108
2068
                    stat.S_ISREG(root_dir_info[3].st_mode)
2162
2122
                   current_block is not None):
2163
2123
                if (current_dir_info and current_block
2164
2124
                    and current_dir_info[0][0] != current_block[0]):
2165
 
                    if current_dir_info[0][0].split('/') < current_block[0].split('/'):
 
2125
                    if current_dir_info[0][0] < current_block[0] :
2166
2126
                        # filesystem data refers to paths not covered by the dirblock.
2167
2127
                        # this has two possibilities:
2168
2128
                        # A) it is versioned but empty, so there is no block for it
2172
2132
                        # new unknown files or directories.
2173
2133
                        # if (B) then we should ignore it, because we don't
2174
2134
                        # recurse into unknown directories.
2175
 
                        path_index = 0
2176
 
                        while path_index < len(current_dir_info[1]):
2177
 
                                current_path_info = current_dir_info[1][path_index]
2178
 
                                if want_unversioned:
 
2135
                        if want_unversioned:
 
2136
                            path_index = 0
 
2137
                            while path_index < len(current_dir_info[1]):
 
2138
                                    current_path_info = current_dir_info[1][path_index]
2179
2139
                                    if current_path_info[2] == 'directory':
2180
2140
                                        if self.target._directory_is_tree_reference(
2181
2141
                                            current_path_info[0].decode('utf8')):
2185
2145
                                        stat.S_ISREG(current_path_info[3].st_mode)
2186
2146
                                        and stat.S_IEXEC & current_path_info[3].st_mode)
2187
2147
                                    yield (None,
2188
 
                                        (None, utf8_decode(current_path_info[0])[0]),
 
2148
                                        (None, utf8_decode_or_none(current_path_info[0])),
2189
2149
                                        True,
2190
2150
                                        (False, False),
2191
2151
                                        (None, None),
2192
 
                                        (None, utf8_decode(current_path_info[1])[0]),
 
2152
                                        (None, utf8_decode_or_none(current_path_info[1])),
2193
2153
                                        (None, current_path_info[2]),
2194
2154
                                        (None, new_executable))
2195
 
                                # dont descend into this unversioned path if it is
2196
 
                                # a dir
2197
 
                                if current_path_info[2] in ('directory',
2198
 
                                                            'tree-reference'):
2199
 
                                    del current_dir_info[1][path_index]
2200
 
                                    path_index -= 1
2201
 
                                path_index += 1
 
2155
                                    # dont descend into this unversioned path if it is
 
2156
                                    # a dir
 
2157
                                    if current_path_info[2] in ('directory',
 
2158
                                                                'tree-reference'):
 
2159
                                        del current_dir_info[1][path_index]
 
2160
                                        path_index -= 1
 
2161
                                    path_index += 1
2202
2162
 
2203
2163
                        # This dir info has been handled, go to the next
2204
2164
                        try:
2216
2176
                        for current_entry in current_block[1]:
2217
2177
                            # entry referring to file not present on disk.
2218
2178
                            # advance the entry only, after processing.
2219
 
                            result = _process_entry(current_entry, None)
2220
 
                            if result is not None:
2221
 
                                if result is not uninteresting:
2222
 
                                    yield result
 
2179
                            for result in _process_entry(current_entry, None):
 
2180
                                # this check should probably be outside the loop: one
 
2181
                                # 'iterate two trees' api, and then _iter_changes filters
 
2182
                                # unchanged pairs. - RBC 20070226
 
2183
                                if (include_unchanged
 
2184
                                    or result[2]                    # content change
 
2185
                                    or result[3][0] != result[3][1] # versioned status
 
2186
                                    or result[4][0] != result[4][1] # parent id
 
2187
                                    or result[5][0] != result[5][1] # name
 
2188
                                    or result[6][0] != result[6][1] # kind
 
2189
                                    or result[7][0] != result[7][1] # executable
 
2190
                                    ):
 
2191
                                    yield (result[0],
 
2192
                                           (utf8_decode_or_none(result[1][0]),
 
2193
                                            utf8_decode_or_none(result[1][1])),
 
2194
                                           result[2],
 
2195
                                           result[3],
 
2196
                                           result[4],
 
2197
                                           (utf8_decode_or_none(result[5][0]),
 
2198
                                            utf8_decode_or_none(result[5][1])),
 
2199
                                           result[6],
 
2200
                                           result[7],
 
2201
                                          )
2223
2202
                        block_index +=1
2224
2203
                        if (block_index < len(state._dirblocks) and
2225
2204
                            osutils.is_inside(current_root,
2254
2233
                        pass
2255
2234
                    elif current_path_info is None:
2256
2235
                        # no path is fine: the per entry code will handle it.
2257
 
                        result = _process_entry(current_entry, current_path_info)
2258
 
                        if result is not None:
2259
 
                            if result is not uninteresting:
2260
 
                                yield result
2261
 
                    elif (current_entry[0][1] != current_path_info[1]
2262
 
                          or current_entry[1][target_index][0] in 'ar'):
2263
 
                        # The current path on disk doesn't match the dirblock
2264
 
                        # record. Either the dirblock is marked as absent, or
2265
 
                        # the file on disk is not present at all in the
2266
 
                        # dirblock. Either way, report about the dirblock
2267
 
                        # entry, and let other code handle the filesystem one.
2268
 
                        if current_path_info[1].split('/') < current_entry[0][1].split('/'):
 
2236
                        for result in _process_entry(current_entry, current_path_info):
 
2237
                            # this check should probably be outside the loop: one
 
2238
                            # 'iterate two trees' api, and then _iter_changes filters
 
2239
                            # unchanged pairs. - RBC 20070226
 
2240
                            if (include_unchanged
 
2241
                                or result[2]                    # content change
 
2242
                                or result[3][0] != result[3][1] # versioned status
 
2243
                                or result[4][0] != result[4][1] # parent id
 
2244
                                or result[5][0] != result[5][1] # name
 
2245
                                or result[6][0] != result[6][1] # kind
 
2246
                                or result[7][0] != result[7][1] # executable
 
2247
                                ):
 
2248
                                yield (result[0],
 
2249
                                       (utf8_decode_or_none(result[1][0]),
 
2250
                                        utf8_decode_or_none(result[1][1])),
 
2251
                                       result[2],
 
2252
                                       result[3],
 
2253
                                       result[4],
 
2254
                                       (utf8_decode_or_none(result[5][0]),
 
2255
                                        utf8_decode_or_none(result[5][1])),
 
2256
                                       result[6],
 
2257
                                       result[7],
 
2258
                                      )
 
2259
                    elif current_entry[0][1] != current_path_info[1]:
 
2260
                        if current_path_info[1] < current_entry[0][1]:
2269
2261
                            # extra file on disk: pass for now, but only
2270
2262
                            # increment the path, not the entry
2271
2263
                            advance_entry = False
2272
2264
                        else:
2273
2265
                            # entry referring to file not present on disk.
2274
2266
                            # advance the entry only, after processing.
2275
 
                            result = _process_entry(current_entry, None)
2276
 
                            if result is not None:
2277
 
                                if result is not uninteresting:
2278
 
                                    yield result
 
2267
                            for result in _process_entry(current_entry, None):
 
2268
                                # this check should probably be outside the loop: one
 
2269
                                # 'iterate two trees' api, and then _iter_changes filters
 
2270
                                # unchanged pairs. - RBC 20070226
 
2271
                                path_handled = True
 
2272
                                if (include_unchanged
 
2273
                                    or result[2]                    # content change
 
2274
                                    or result[3][0] != result[3][1] # versioned status
 
2275
                                    or result[4][0] != result[4][1] # parent id
 
2276
                                    or result[5][0] != result[5][1] # name
 
2277
                                    or result[6][0] != result[6][1] # kind
 
2278
                                    or result[7][0] != result[7][1] # executable
 
2279
                                    ):
 
2280
                                    yield (result[0],
 
2281
                                           (utf8_decode_or_none(result[1][0]),
 
2282
                                            utf8_decode_or_none(result[1][1])),
 
2283
                                           result[2],
 
2284
                                           result[3],
 
2285
                                           result[4],
 
2286
                                           (utf8_decode_or_none(result[5][0]),
 
2287
                                            utf8_decode_or_none(result[5][1])),
 
2288
                                           result[6],
 
2289
                                           result[7],
 
2290
                                          )
2279
2291
                            advance_path = False
2280
2292
                    else:
2281
 
                        result = _process_entry(current_entry, current_path_info)
2282
 
                        if result is not None:
2283
 
                            path_handled = True
2284
 
                            if result is not uninteresting:
2285
 
                                yield result
 
2293
                        for result in _process_entry(current_entry, current_path_info):
 
2294
                            # this check should probably be outside the loop: one
 
2295
                            # 'iterate two trees' api, and then _iter_changes filters
 
2296
                            # unchanged pairs. - RBC 20070226
 
2297
                            if current_entry[1][target_index][0] == 'a':
 
2298
                                advance_path = False
 
2299
                                path_handled = False
 
2300
                            else:
 
2301
                                path_handled = True
 
2302
                            if (include_unchanged
 
2303
                                or result[2]                    # content change
 
2304
                                or result[3][0] != result[3][1] # versioned status
 
2305
                                or result[4][0] != result[4][1] # parent id
 
2306
                                or result[5][0] != result[5][1] # name
 
2307
                                or result[6][0] != result[6][1] # kind
 
2308
                                or result[7][0] != result[7][1] # executable
 
2309
                                ):
 
2310
                                yield (result[0],
 
2311
                                       (utf8_decode_or_none(result[1][0]),
 
2312
                                        utf8_decode_or_none(result[1][1])),
 
2313
                                       result[2],
 
2314
                                       result[3],
 
2315
                                       result[4],
 
2316
                                       (utf8_decode_or_none(result[5][0]),
 
2317
                                        utf8_decode_or_none(result[5][1])),
 
2318
                                       result[6],
 
2319
                                       result[7],
 
2320
                                      )
2286
2321
                    if advance_entry and current_entry is not None:
2287
2322
                        entry_index += 1
2288
2323
                        if entry_index < len(current_block[1]):
2299
2334
                                    stat.S_ISREG(current_path_info[3].st_mode)
2300
2335
                                    and stat.S_IEXEC & current_path_info[3].st_mode)
2301
2336
                                yield (None,
2302
 
                                    (None, utf8_decode(current_path_info[0])[0]),
 
2337
                                    (None, utf8_decode_or_none(current_path_info[0])),
2303
2338
                                    True,
2304
2339
                                    (False, False),
2305
2340
                                    (None, None),
2306
 
                                    (None, utf8_decode(current_path_info[1])[0]),
 
2341
                                    (None, utf8_decode_or_none(current_path_info[1])),
2307
2342
                                    (None, current_path_info[2]),
2308
2343
                                    (None, new_executable))
2309
2344
                            # dont descend into this unversioned path if it is