473
482
return path_utf8.decode('utf8')
475
484
if not osutils.supports_executable():
477
485
def is_executable(self, file_id, path=None):
486
"""Test if a file is executable or not.
488
Note: The caller is expected to take a read-lock before calling this.
478
490
file_id = osutils.safe_file_id(file_id)
479
491
entry = self._get_entry(file_id=file_id, path=path)
480
492
if entry == (None, None):
482
494
return entry[1][0][3]
485
496
def is_executable(self, file_id, path=None):
497
"""Test if a file is executable or not.
499
Note: The caller is expected to take a read-lock before calling this.
487
502
file_id = osutils.safe_file_id(file_id)
488
503
path = self.id2path(file_id)
1800
1808
NULL_PARENT_DETAILS = dirstate.DirState.NULL_PARENT_DETAILS
1801
1809
# Using a list so that we can access the values and change them in
1802
1810
# nested scope. Each one is [path, file_id, entry]
1803
last_source_parent = [None, None, None]
1804
last_target_parent = [None, None, None]
1811
last_source_parent = [None, None]
1812
last_target_parent = [None, None]
1806
1814
use_filesystem_for_exec = (sys.platform != 'win32')
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()
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.
1808
1826
def _process_entry(entry, path_info):
1809
1827
"""Compare an entry and real disk to generate delta information.
1901
1927
target_exec = False
1903
1929
raise Exception, "unknown kind %s" % path_info[2]
1930
if source_minikind == 'd':
1932
old_path = path = pathjoin(old_dirname, old_basename)
1933
old_dirname_to_file_id[old_path] = file_id
1904
1934
# parent id is the entry for the path in the target tree
1905
1935
if old_dirname == last_source_parent[0]:
1906
1936
source_parent_id = last_source_parent[1]
1908
source_parent_entry = state._get_entry(source_index,
1909
path_utf8=old_dirname)
1910
source_parent_id = source_parent_entry[0][2]
1939
source_parent_id = old_dirname_to_file_id[old_dirname]
1941
source_parent_entry = state._get_entry(source_index,
1942
path_utf8=old_dirname)
1943
source_parent_id = source_parent_entry[0][2]
1911
1944
if source_parent_id == entry[0][2]:
1912
1945
# This is the root, so the parent is None
1913
1946
source_parent_id = None
1915
1948
last_source_parent[0] = old_dirname
1916
1949
last_source_parent[1] = source_parent_id
1917
last_source_parent[2] = source_parent_entry
1918
1950
new_dirname = entry[0][0]
1919
1951
if new_dirname == last_target_parent[0]:
1920
1952
target_parent_id = last_target_parent[1]
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]
1955
target_parent_id = new_dirname_to_file_id[new_dirname]
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]
1930
1965
if target_parent_id == entry[0][2]:
1931
1966
# This is the root, so the parent is None
1932
1967
target_parent_id = None
1934
1969
last_target_parent[0] = new_dirname
1935
1970
last_target_parent[1] = target_parent_id
1936
last_target_parent[2] = target_parent_entry
1938
1972
source_exec = source_details[3]
1939
return ((entry[0][2], (old_path, path), content_change,
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)),)
1973
if (include_unchanged
1975
or source_parent_id != target_parent_id
1976
or old_basename != entry[0][1]
1977
or source_exec != target_exec
1979
if old_path is None:
1980
old_path = path = pathjoin(old_dirname, old_basename)
1981
old_path_u = utf8_decode(old_path)[0]
1984
old_path_u = utf8_decode(old_path)[0]
1985
if old_path == path:
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),
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))
1999
return uninteresting
1945
2000
elif source_minikind in 'a' and target_minikind in 'fdlt':
1946
2001
# looks like a new file
1947
2002
if path_info is not None:
1980
2037
parent_id = state._get_entry(source_index, path_utf8=entry[0][0])[0][2]
1981
2038
if parent_id == entry[0][2]:
1982
2039
parent_id = None
1983
return ((entry[0][2], (old_path, None), True,
1986
(entry[0][1], None),
1987
(_minikind_to_kind[source_minikind], None),
1988
(source_details[3], None)),)
2040
return (entry[0][2],
2041
(utf8_decode(old_path)[0], None),
2045
(utf8_decode(entry[0][1])[0], None),
2046
(_minikind_to_kind[source_minikind], None),
2047
(source_details[3], None))
1989
2048
elif source_minikind in 'fdlt' and target_minikind in 'r':
1990
2049
# a rename; could be a true rename, or a rename inherited from
1991
2050
# a renamed parent. TODO: handle this efficiently. Its not
2040
2099
path_handled = False
2041
2100
for entry in root_entries:
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
2101
result = _process_entry(entry, root_dir_info)
2102
if result is not None:
2046
2103
path_handled = True
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
2056
(utf8_decode_or_none(result[1][0]),
2057
utf8_decode_or_none(result[1][1])),
2061
(utf8_decode_or_none(result[5][0]),
2062
utf8_decode_or_none(result[5][1])),
2104
if result is not uninteresting:
2066
2106
if want_unversioned and not path_handled and root_dir_info:
2067
2107
new_executable = bool(
2068
2108
stat.S_ISREG(root_dir_info[3].st_mode)
2145
2185
stat.S_ISREG(current_path_info[3].st_mode)
2146
2186
and stat.S_IEXEC & current_path_info[3].st_mode)
2148
(None, utf8_decode_or_none(current_path_info[0])),
2188
(None, utf8_decode(current_path_info[0])[0]),
2150
2190
(False, False),
2152
(None, utf8_decode_or_none(current_path_info[1])),
2192
(None, utf8_decode(current_path_info[1])[0]),
2153
2193
(None, current_path_info[2]),
2154
2194
(None, new_executable))
2155
# dont descend into this unversioned path if it is
2157
if current_path_info[2] in ('directory',
2159
del current_dir_info[1][path_index]
2195
# dont descend into this unversioned path if it is
2197
if current_path_info[2] in ('directory',
2199
del current_dir_info[1][path_index]
2163
2203
# This dir info has been handled, go to the next
2176
2216
for current_entry in current_block[1]:
2177
2217
# entry referring to file not present on disk.
2178
2218
# advance the entry only, after processing.
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
2192
(utf8_decode_or_none(result[1][0]),
2193
utf8_decode_or_none(result[1][1])),
2197
(utf8_decode_or_none(result[5][0]),
2198
utf8_decode_or_none(result[5][1])),
2219
result = _process_entry(current_entry, None)
2220
if result is not None:
2221
if result is not uninteresting:
2202
2223
block_index +=1
2203
2224
if (block_index < len(state._dirblocks) and
2204
2225
osutils.is_inside(current_root,
2234
2255
elif current_path_info is None:
2235
2256
# no path is fine: the per entry code will handle it.
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
2249
(utf8_decode_or_none(result[1][0]),
2250
utf8_decode_or_none(result[1][1])),
2254
(utf8_decode_or_none(result[5][0]),
2255
utf8_decode_or_none(result[5][1])),
2259
elif current_entry[0][1] != current_path_info[1]:
2260
if current_path_info[1] < current_entry[0][1]:
2257
result = _process_entry(current_entry, current_path_info)
2258
if result is not None:
2259
if result is not uninteresting:
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('/'):
2261
2269
# extra file on disk: pass for now, but only
2262
2270
# increment the path, not the entry
2263
2271
advance_entry = False
2265
2273
# entry referring to file not present on disk.
2266
2274
# advance the entry only, after processing.
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
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
2281
(utf8_decode_or_none(result[1][0]),
2282
utf8_decode_or_none(result[1][1])),
2286
(utf8_decode_or_none(result[5][0]),
2287
utf8_decode_or_none(result[5][1])),
2275
result = _process_entry(current_entry, None)
2276
if result is not None:
2277
if result is not uninteresting:
2291
2279
advance_path = False
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
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
2311
(utf8_decode_or_none(result[1][0]),
2312
utf8_decode_or_none(result[1][1])),
2316
(utf8_decode_or_none(result[5][0]),
2317
utf8_decode_or_none(result[5][1])),
2281
result = _process_entry(current_entry, current_path_info)
2282
if result is not None:
2284
if result is not uninteresting:
2321
2286
if advance_entry and current_entry is not None:
2322
2287
entry_index += 1
2323
2288
if entry_index < len(current_block[1]):