1263
1227
@needs_tree_write_lock
1264
1228
def _write_inventory(self, inv):
1265
1229
"""Write inventory as the current inventory."""
1267
raise AssertionError("attempting to write an inventory when the "
1268
"dirstate is dirty will lose pending changes")
1269
had_inventory = self._inventory is not None
1270
# Setting self._inventory = None forces the dirstate to regenerate the
1271
# working inventory. We do this because self.inventory may be inv, or
1272
# may have been modified, and either case would prevent a clean delta
1274
self._inventory = None
1276
delta = inv._make_delta(self.inventory)
1278
self.apply_inventory_delta(delta)
1230
assert not self._dirty, ("attempting to write an inventory when the "
1231
"dirstate is dirty will cause data loss")
1232
self.current_dirstate().set_state_from_inventory(inv)
1233
self._make_dirty(reset_inventory=False)
1234
if self._inventory is not None:
1280
1235
self._inventory = inv
1284
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1286
def __init__(self, tree):
1289
def sha1(self, abspath):
1290
"""See dirstate.SHA1Provider.sha1()."""
1291
filters = self.tree._content_filter_stack(
1292
self.tree.relpath(osutils.safe_unicode(abspath)))
1293
return internal_size_sha_file_byname(abspath, filters)[1]
1295
def stat_and_sha1(self, abspath):
1296
"""See dirstate.SHA1Provider.stat_and_sha1()."""
1297
filters = self.tree._content_filter_stack(
1298
self.tree.relpath(osutils.safe_unicode(abspath)))
1299
file_obj = file(abspath, 'rb', 65000)
1301
statvalue = os.fstat(file_obj.fileno())
1303
file_obj = filtered_input_file(file_obj, filters)
1304
sha1 = osutils.size_sha_file(file_obj)[1]
1307
return statvalue, sha1
1310
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1311
"""Dirstate working tree that supports content filtering.
1313
The dirstate holds the hash and size of the canonical form of the file,
1314
and most methods must return that.
1317
def _file_content_summary(self, path, stat_result):
1318
# This is to support the somewhat obsolete path_content_summary method
1319
# with content filtering: see
1320
# <https://bugs.edge.launchpad.net/bzr/+bug/415508>.
1322
# If the dirstate cache is up to date and knows the hash and size,
1324
# Otherwise if there are no content filters, return the on-disk size
1325
# and leave the hash blank.
1326
# Otherwise, read and filter the on-disk file and use its size and
1329
# The dirstate doesn't store the size of the canonical form so we
1330
# can't trust it for content-filtered trees. We just return None.
1331
dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1332
executable = self._is_executable_from_path_and_stat(path, stat_result)
1333
return ('file', None, executable, dirstate_sha1)
1336
class WorkingTree4(DirStateWorkingTree):
1337
"""This is the Format 4 working tree.
1339
This differs from WorkingTree3 by:
1340
- Having a consolidated internal dirstate, stored in a
1341
randomly-accessible sorted file on disk.
1342
- Not having a regular inventory attribute. One can be synthesized
1343
on demand but this is expensive and should be avoided.
1345
This is new in bzr 0.15.
1349
class WorkingTree5(ContentFilteringDirStateWorkingTree):
1350
"""This is the Format 5 working tree.
1352
This differs from WorkingTree4 by:
1353
- Supporting content filtering.
1355
This is new in bzr 1.11.
1359
class WorkingTree6(ContentFilteringDirStateWorkingTree):
1360
"""This is the Format 6 working tree.
1362
This differs from WorkingTree5 by:
1363
- Supporting a current view that may mask the set of files in a tree
1364
impacted by most user operations.
1366
This is new in bzr 1.14.
1369
def _make_views(self):
1370
return views.PathBasedViews(self)
1373
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1239
class WorkingTreeFormat4(WorkingTreeFormat3):
1240
"""The first consolidated dirstate working tree format.
1243
- exists within a metadir controlling .bzr
1244
- includes an explicit version marker for the workingtree control
1245
files, separate from the BzrDir format
1246
- modifies the hash cache format
1247
- is new in bzr 0.15
1248
- uses a LockDir to guard access to it.
1251
upgrade_recommended = False
1253
def get_format_string(self):
1254
"""See WorkingTreeFormat.get_format_string()."""
1255
return "Bazaar Working Tree Format 4 (bzr 0.15)\n"
1257
def get_format_description(self):
1258
"""See WorkingTreeFormat.get_format_description()."""
1259
return "Working tree format 4"
1375
1261
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1376
1262
accelerator_tree=None, hardlink=False):
2080
1835
if not found_versioned:
2081
1836
# none of the indexes was not 'absent' at all ids for this
2083
not_versioned.append(path)
2084
if len(not_versioned) > 0:
2085
raise errors.PathsNotVersionedError(not_versioned)
1838
all_versioned = False
1840
if not all_versioned:
1841
raise errors.PathsNotVersionedError(specific_files)
2086
1842
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2087
search_specific_files = osutils.minimum_path_selection(specific_files)
1843
search_specific_files = set()
1844
for path in specific_files:
1845
other_specific_files = specific_files.difference(set([path]))
1846
if not osutils.is_inside_any(other_specific_files, path):
1847
# this is a top level path, we must check it.
1848
search_specific_files.add(path)
1850
# compare source_index and target_index at or under each element of search_specific_files.
1851
# follow the following comparison table. Note that we only want to do diff operations when
1852
# the target is fdl because thats when the walkdirs logic will have exposed the pathinfo
1856
# Source | Target | disk | action
1857
# r | fdlt | | add source to search, add id path move and perform
1858
# | | | diff check on source-target
1859
# r | fdlt | a | dangling file that was present in the basis.
1861
# r | a | | add source to search
1863
# r | r | | this path is present in a non-examined tree, skip.
1864
# r | r | a | this path is present in a non-examined tree, skip.
1865
# a | fdlt | | add new id
1866
# a | fdlt | a | dangling locally added file, skip
1867
# a | a | | not present in either tree, skip
1868
# a | a | a | not present in any tree, skip
1869
# a | r | | not present in either tree at this path, skip as it
1870
# | | | may not be selected by the users list of paths.
1871
# a | r | a | not present in either tree at this path, skip as it
1872
# | | | may not be selected by the users list of paths.
1873
# fdlt | fdlt | | content in both: diff them
1874
# fdlt | fdlt | a | deleted locally, but not unversioned - show as deleted ?
1875
# fdlt | a | | unversioned: output deleted id for now
1876
# fdlt | a | a | unversioned and deleted: output deleted id
1877
# fdlt | r | | relocated in this tree, so add target to search.
1878
# | | | Dont diff, we will see an r,fd; pair when we reach
1879
# | | | this id at the other path.
1880
# fdlt | r | a | relocated in this tree, so add target to search.
1881
# | | | Dont diff, we will see an r,fd; pair when we reach
1882
# | | | this id at the other path.
1884
# for all search_indexs in each path at or under each element of
1885
# search_specific_files, if the detail is relocated: add the id, and add the
1886
# relocated path as one to search if its not searched already. If the
1887
# detail is not relocated, add the id.
1888
searched_specific_files = set()
1889
NULL_PARENT_DETAILS = dirstate.DirState.NULL_PARENT_DETAILS
1890
# Using a list so that we can access the values and change them in
1891
# nested scope. Each one is [path, file_id, entry]
1892
last_source_parent = [None, None]
1893
last_target_parent = [None, None]
2089
1895
use_filesystem_for_exec = (sys.platform != 'win32')
2090
iter_changes = self.target._iter_changes(include_unchanged,
2091
use_filesystem_for_exec, search_specific_files, state,
2092
source_index, target_index, want_unversioned, self.target)
2093
return iter_changes.iter_changes()
1897
# Just a sentry, so that _process_entry can say that this
1898
# record is handled, but isn't interesting to process (unchanged)
1899
uninteresting = object()
1902
old_dirname_to_file_id = {}
1903
new_dirname_to_file_id = {}
1904
# TODO: jam 20070516 - Avoid the _get_entry lookup overhead by
1905
# keeping a cache of directories that we have seen.
1907
def _process_entry(entry, path_info):
1908
"""Compare an entry and real disk to generate delta information.
1910
:param path_info: top_relpath, basename, kind, lstat, abspath for
1911
the path of entry. If None, then the path is considered absent.
1912
(Perhaps we should pass in a concrete entry for this ?)
1913
Basename is returned as a utf8 string because we expect this
1914
tuple will be ignored, and don't want to take the time to
1916
:return: None if these don't match
1917
A tuple of information about the change, or
1918
the object 'uninteresting' if these match, but are
1919
basically identical.
1921
if source_index is None:
1922
source_details = NULL_PARENT_DETAILS
1924
source_details = entry[1][source_index]
1925
target_details = entry[1][target_index]
1926
target_minikind = target_details[0]
1927
if path_info is not None and target_minikind in 'fdlt':
1928
assert target_index == 0
1929
link_or_sha1 = state.update_entry(entry, abspath=path_info[4],
1930
stat_value=path_info[3])
1931
# The entry may have been modified by update_entry
1932
target_details = entry[1][target_index]
1933
target_minikind = target_details[0]
1936
file_id = entry[0][2]
1937
source_minikind = source_details[0]
1938
if source_minikind in 'fdltr' and target_minikind in 'fdlt':
1939
# claimed content in both: diff
1940
# r | fdlt | | add source to search, add id path move and perform
1941
# | | | diff check on source-target
1942
# r | fdlt | a | dangling file that was present in the basis.
1944
if source_minikind in 'r':
1945
# add the source to the search path to find any children it
1946
# has. TODO ? : only add if it is a container ?
1947
if not osutils.is_inside_any(searched_specific_files,
1949
search_specific_files.add(source_details[1])
1950
# generate the old path; this is needed for stating later
1952
old_path = source_details[1]
1953
old_dirname, old_basename = os.path.split(old_path)
1954
path = pathjoin(entry[0][0], entry[0][1])
1955
old_entry = state._get_entry(source_index,
1957
# update the source details variable to be the real
1959
if old_entry == (None, None):
1960
raise errors.CorruptDirstate(state._filename,
1961
"entry '%s/%s' is considered renamed from %r"
1962
" but source does not exist\n"
1963
"entry: %s" % (entry[0][0], entry[0][1], old_path, entry))
1964
source_details = old_entry[1][source_index]
1965
source_minikind = source_details[0]
1967
old_dirname = entry[0][0]
1968
old_basename = entry[0][1]
1969
old_path = path = None
1970
if path_info is None:
1971
# the file is missing on disk, show as removed.
1972
content_change = True
1976
# source and target are both versioned and disk file is present.
1977
target_kind = path_info[2]
1978
if target_kind == 'directory':
1980
old_path = path = pathjoin(old_dirname, old_basename)
1981
new_dirname_to_file_id[path] = file_id
1982
if source_minikind != 'd':
1983
content_change = True
1985
# directories have no fingerprint
1986
content_change = False
1988
elif target_kind == 'file':
1989
if source_minikind != 'f':
1990
content_change = True
1992
# We could check the size, but we already have the
1994
content_change = (link_or_sha1 != source_details[1])
1995
# Target details is updated at update_entry time
1996
if use_filesystem_for_exec:
1997
# We don't need S_ISREG here, because we are sure
1998
# we are dealing with a file.
1999
target_exec = bool(stat.S_IEXEC & path_info[3].st_mode)
2001
target_exec = target_details[3]
2002
elif target_kind == 'symlink':
2003
if source_minikind != 'l':
2004
content_change = True
2006
content_change = (link_or_sha1 != source_details[1])
2008
elif target_kind == 'tree-reference':
2009
if source_minikind != 't':
2010
content_change = True
2012
content_change = False
2015
raise Exception, "unknown kind %s" % path_info[2]
2016
if source_minikind == 'd':
2018
old_path = path = pathjoin(old_dirname, old_basename)
2019
old_dirname_to_file_id[old_path] = file_id
2020
# parent id is the entry for the path in the target tree
2021
if old_dirname == last_source_parent[0]:
2022
source_parent_id = last_source_parent[1]
2025
source_parent_id = old_dirname_to_file_id[old_dirname]
2027
source_parent_entry = state._get_entry(source_index,
2028
path_utf8=old_dirname)
2029
source_parent_id = source_parent_entry[0][2]
2030
if source_parent_id == entry[0][2]:
2031
# This is the root, so the parent is None
2032
source_parent_id = None
2034
last_source_parent[0] = old_dirname
2035
last_source_parent[1] = source_parent_id
2036
new_dirname = entry[0][0]
2037
if new_dirname == last_target_parent[0]:
2038
target_parent_id = last_target_parent[1]
2041
target_parent_id = new_dirname_to_file_id[new_dirname]
2043
# TODO: We don't always need to do the lookup, because the
2044
# parent entry will be the same as the source entry.
2045
target_parent_entry = state._get_entry(target_index,
2046
path_utf8=new_dirname)
2047
assert target_parent_entry != (None, None), (
2048
"Could not find target parent in wt: %s\nparent of: %s"
2049
% (new_dirname, entry))
2050
target_parent_id = target_parent_entry[0][2]
2051
if target_parent_id == entry[0][2]:
2052
# This is the root, so the parent is None
2053
target_parent_id = None
2055
last_target_parent[0] = new_dirname
2056
last_target_parent[1] = target_parent_id
2058
source_exec = source_details[3]
2059
if (include_unchanged
2061
or source_parent_id != target_parent_id
2062
or old_basename != entry[0][1]
2063
or source_exec != target_exec
2065
if old_path is None:
2066
old_path = path = pathjoin(old_dirname, old_basename)
2067
old_path_u = utf8_decode(old_path)[0]
2070
old_path_u = utf8_decode(old_path)[0]
2071
if old_path == path:
2074
path_u = utf8_decode(path)[0]
2075
source_kind = _minikind_to_kind[source_minikind]
2076
return (entry[0][2],
2077
(old_path_u, path_u),
2080
(source_parent_id, target_parent_id),
2081
(utf8_decode(old_basename)[0], utf8_decode(entry[0][1])[0]),
2082
(source_kind, target_kind),
2083
(source_exec, target_exec))
2085
return uninteresting
2086
elif source_minikind in 'a' and target_minikind in 'fdlt':
2087
# looks like a new file
2088
if path_info is not None:
2089
path = pathjoin(entry[0][0], entry[0][1])
2090
# parent id is the entry for the path in the target tree
2091
# TODO: these are the same for an entire directory: cache em.
2092
parent_id = state._get_entry(target_index,
2093
path_utf8=entry[0][0])[0][2]
2094
if parent_id == entry[0][2]:
2096
if use_filesystem_for_exec:
2097
# We need S_ISREG here, because we aren't sure if this
2100
stat.S_ISREG(path_info[3].st_mode)
2101
and stat.S_IEXEC & path_info[3].st_mode)
2103
target_exec = target_details[3]
2104
return (entry[0][2],
2105
(None, utf8_decode(path)[0]),
2109
(None, utf8_decode(entry[0][1])[0]),
2110
(None, path_info[2]),
2111
(None, target_exec))
2113
# but its not on disk: we deliberately treat this as just
2114
# never-present. (Why ?! - RBC 20070224)
2116
elif source_minikind in 'fdlt' and target_minikind in 'a':
2117
# unversioned, possibly, or possibly not deleted: we dont care.
2118
# if its still on disk, *and* theres no other entry at this
2119
# path [we dont know this in this routine at the moment -
2120
# perhaps we should change this - then it would be an unknown.
2121
old_path = pathjoin(entry[0][0], entry[0][1])
2122
# parent id is the entry for the path in the target tree
2123
parent_id = state._get_entry(source_index, path_utf8=entry[0][0])[0][2]
2124
if parent_id == entry[0][2]:
2126
return (entry[0][2],
2127
(utf8_decode(old_path)[0], None),
2131
(utf8_decode(entry[0][1])[0], None),
2132
(_minikind_to_kind[source_minikind], None),
2133
(source_details[3], None))
2134
elif source_minikind in 'fdlt' and target_minikind in 'r':
2135
# a rename; could be a true rename, or a rename inherited from
2136
# a renamed parent. TODO: handle this efficiently. Its not
2137
# common case to rename dirs though, so a correct but slow
2138
# implementation will do.
2139
if not osutils.is_inside_any(searched_specific_files, target_details[1]):
2140
search_specific_files.add(target_details[1])
2141
elif source_minikind in 'ra' and target_minikind in 'ra':
2142
# neither of the selected trees contain this file,
2143
# so skip over it. This is not currently directly tested, but
2144
# is indirectly via test_too_much.TestCommands.test_conflicts.
2147
raise AssertionError("don't know how to compare "
2148
"source_minikind=%r, target_minikind=%r"
2149
% (source_minikind, target_minikind))
2150
## import pdb;pdb.set_trace()
2153
while search_specific_files:
2154
# TODO: the pending list should be lexically sorted? the
2155
# interface doesn't require it.
2156
current_root = search_specific_files.pop()
2157
current_root_unicode = current_root.decode('utf8')
2158
searched_specific_files.add(current_root)
2159
# process the entries for this containing directory: the rest will be
2160
# found by their parents recursively.
2161
root_entries = _entries_for_path(current_root)
2162
root_abspath = self.target.abspath(current_root_unicode)
2164
root_stat = os.lstat(root_abspath)
2166
if e.errno == errno.ENOENT:
2167
# the path does not exist: let _process_entry know that.
2168
root_dir_info = None
2170
# some other random error: hand it up.
2173
root_dir_info = ('', current_root,
2174
osutils.file_kind_from_stat_mode(root_stat.st_mode), root_stat,
2176
if root_dir_info[2] == 'directory':
2177
if self.target._directory_is_tree_reference(
2178
current_root.decode('utf8')):
2179
root_dir_info = root_dir_info[:2] + \
2180
('tree-reference',) + root_dir_info[3:]
2182
if not root_entries and not root_dir_info:
2183
# this specified path is not present at all, skip it.
2185
path_handled = False
2186
for entry in root_entries:
2187
result = _process_entry(entry, root_dir_info)
2188
if result is not None:
2190
if result is not uninteresting:
2192
if want_unversioned and not path_handled and root_dir_info:
2193
new_executable = bool(
2194
stat.S_ISREG(root_dir_info[3].st_mode)
2195
and stat.S_IEXEC & root_dir_info[3].st_mode)
2197
(None, current_root_unicode),
2201
(None, splitpath(current_root_unicode)[-1]),
2202
(None, root_dir_info[2]),
2203
(None, new_executable)
2205
initial_key = (current_root, '', '')
2206
block_index, _ = state._find_block_index_from_key(initial_key)
2207
if block_index == 0:
2208
# we have processed the total root already, but because the
2209
# initial key matched it we should skip it here.
2211
if root_dir_info and root_dir_info[2] == 'tree-reference':
2212
current_dir_info = None
2214
dir_iterator = osutils._walkdirs_utf8(root_abspath, prefix=current_root)
2216
current_dir_info = dir_iterator.next()
2218
# on win32, python2.4 has e.errno == ERROR_DIRECTORY, but
2219
# python 2.5 has e.errno == EINVAL,
2220
# and e.winerror == ERROR_DIRECTORY
2221
e_winerror = getattr(e, 'winerror', None)
2222
win_errors = (ERROR_DIRECTORY, ERROR_PATH_NOT_FOUND)
2223
# there may be directories in the inventory even though
2224
# this path is not a file on disk: so mark it as end of
2226
if e.errno in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
2227
current_dir_info = None
2228
elif (sys.platform == 'win32'
2229
and (e.errno in win_errors
2230
or e_winerror in win_errors)):
2231
current_dir_info = None
2235
if current_dir_info[0][0] == '':
2236
# remove .bzr from iteration
2237
bzr_index = bisect_left(current_dir_info[1], ('.bzr',))
2238
assert current_dir_info[1][bzr_index][0] == '.bzr'
2239
del current_dir_info[1][bzr_index]
2240
# walk until both the directory listing and the versioned metadata
2242
if (block_index < len(state._dirblocks) and
2243
osutils.is_inside(current_root, state._dirblocks[block_index][0])):
2244
current_block = state._dirblocks[block_index]
2246
current_block = None
2247
while (current_dir_info is not None or
2248
current_block is not None):
2249
if (current_dir_info and current_block
2250
and current_dir_info[0][0] != current_block[0]):
2251
if cmp_by_dirs(current_dir_info[0][0], current_block[0]) < 0:
2252
# filesystem data refers to paths not covered by the dirblock.
2253
# this has two possibilities:
2254
# A) it is versioned but empty, so there is no block for it
2255
# B) it is not versioned.
2257
# if (A) then we need to recurse into it to check for
2258
# new unknown files or directories.
2259
# if (B) then we should ignore it, because we don't
2260
# recurse into unknown directories.
2262
while path_index < len(current_dir_info[1]):
2263
current_path_info = current_dir_info[1][path_index]
2264
if want_unversioned:
2265
if current_path_info[2] == 'directory':
2266
if self.target._directory_is_tree_reference(
2267
current_path_info[0].decode('utf8')):
2268
current_path_info = current_path_info[:2] + \
2269
('tree-reference',) + current_path_info[3:]
2270
new_executable = bool(
2271
stat.S_ISREG(current_path_info[3].st_mode)
2272
and stat.S_IEXEC & current_path_info[3].st_mode)
2274
(None, utf8_decode(current_path_info[0])[0]),
2278
(None, utf8_decode(current_path_info[1])[0]),
2279
(None, current_path_info[2]),
2280
(None, new_executable))
2281
# dont descend into this unversioned path if it is
2283
if current_path_info[2] in ('directory',
2285
del current_dir_info[1][path_index]
2289
# This dir info has been handled, go to the next
2291
current_dir_info = dir_iterator.next()
2292
except StopIteration:
2293
current_dir_info = None
2295
# We have a dirblock entry for this location, but there
2296
# is no filesystem path for this. This is most likely
2297
# because a directory was removed from the disk.
2298
# We don't have to report the missing directory,
2299
# because that should have already been handled, but we
2300
# need to handle all of the files that are contained
2302
for current_entry in current_block[1]:
2303
# entry referring to file not present on disk.
2304
# advance the entry only, after processing.
2305
result = _process_entry(current_entry, None)
2306
if result is not None:
2307
if result is not uninteresting:
2310
if (block_index < len(state._dirblocks) and
2311
osutils.is_inside(current_root,
2312
state._dirblocks[block_index][0])):
2313
current_block = state._dirblocks[block_index]
2315
current_block = None
2318
if current_block and entry_index < len(current_block[1]):
2319
current_entry = current_block[1][entry_index]
2321
current_entry = None
2322
advance_entry = True
2324
if current_dir_info and path_index < len(current_dir_info[1]):
2325
current_path_info = current_dir_info[1][path_index]
2326
if current_path_info[2] == 'directory':
2327
if self.target._directory_is_tree_reference(
2328
current_path_info[0].decode('utf8')):
2329
current_path_info = current_path_info[:2] + \
2330
('tree-reference',) + current_path_info[3:]
2332
current_path_info = None
2334
path_handled = False
2335
while (current_entry is not None or
2336
current_path_info is not None):
2337
if current_entry is None:
2338
# the check for path_handled when the path is adnvaced
2339
# will yield this path if needed.
2341
elif current_path_info is None:
2342
# no path is fine: the per entry code will handle it.
2343
result = _process_entry(current_entry, current_path_info)
2344
if result is not None:
2345
if result is not uninteresting:
2347
elif (current_entry[0][1] != current_path_info[1]
2348
or current_entry[1][target_index][0] in 'ar'):
2349
# The current path on disk doesn't match the dirblock
2350
# record. Either the dirblock is marked as absent, or
2351
# the file on disk is not present at all in the
2352
# dirblock. Either way, report about the dirblock
2353
# entry, and let other code handle the filesystem one.
2355
# Compare the basename for these files to determine
2357
if current_path_info[1] < current_entry[0][1]:
2358
# extra file on disk: pass for now, but only
2359
# increment the path, not the entry
2360
advance_entry = False
2362
# entry referring to file not present on disk.
2363
# advance the entry only, after processing.
2364
result = _process_entry(current_entry, None)
2365
if result is not None:
2366
if result is not uninteresting:
2368
advance_path = False
2370
result = _process_entry(current_entry, current_path_info)
2371
if result is not None:
2373
if result is not uninteresting:
2375
if advance_entry and current_entry is not None:
2377
if entry_index < len(current_block[1]):
2378
current_entry = current_block[1][entry_index]
2380
current_entry = None
2382
advance_entry = True # reset the advance flaga
2383
if advance_path and current_path_info is not None:
2384
if not path_handled:
2385
# unversioned in all regards
2386
if want_unversioned:
2387
new_executable = bool(
2388
stat.S_ISREG(current_path_info[3].st_mode)
2389
and stat.S_IEXEC & current_path_info[3].st_mode)
2391
(None, utf8_decode(current_path_info[0])[0]),
2395
(None, utf8_decode(current_path_info[1])[0]),
2396
(None, current_path_info[2]),
2397
(None, new_executable))
2398
# dont descend into this unversioned path if it is
2400
if current_path_info[2] in ('directory'):
2401
del current_dir_info[1][path_index]
2403
# dont descend the disk iterator into any tree
2405
if current_path_info[2] == 'tree-reference':
2406
del current_dir_info[1][path_index]
2409
if path_index < len(current_dir_info[1]):
2410
current_path_info = current_dir_info[1][path_index]
2411
if current_path_info[2] == 'directory':
2412
if self.target._directory_is_tree_reference(
2413
current_path_info[0].decode('utf8')):
2414
current_path_info = current_path_info[:2] + \
2415
('tree-reference',) + current_path_info[3:]
2417
current_path_info = None
2418
path_handled = False
2420
advance_path = True # reset the advance flagg.
2421
if current_block is not None:
2423
if (block_index < len(state._dirblocks) and
2424
osutils.is_inside(current_root, state._dirblocks[block_index][0])):
2425
current_block = state._dirblocks[block_index]
2427
current_block = None
2428
if current_dir_info is not None:
2430
current_dir_info = dir_iterator.next()
2431
except StopIteration:
2432
current_dir_info = None
2096
2436
def is_compatible(source, target):
2097
2437
# the target must be a dirstate working tree
2098
if not isinstance(target, DirStateWorkingTree):
2438
if not isinstance(target, WorkingTree4):
2100
# the source must be a revtree or dirstate rev tree.
2440
# the source must be a revtreee or dirstate rev tree.
2101
2441
if not isinstance(source,
2102
2442
(revisiontree.RevisionTree, DirStateRevisionTree)):
2104
2444
# the source revid must be in the target dirstate
2105
if not (source._revision_id == _mod_revision.NULL_REVISION or
2445
if not (source._revision_id == NULL_REVISION or
2106
2446
source._revision_id in target.get_parent_ids()):
2107
# TODO: what about ghosts? it may well need to
2447
# TODO: what about ghosts? it may well need to
2108
2448
# check for them explicitly.