96
96
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
99
# This is the Windows equivalent of ENOTDIR
100
# It is defined in pywin32.winerror, but we don't want a strong dependency for
101
# just an error code.
102
ERROR_DIRECTORY = 267
99
105
class WorkingTree4(WorkingTree3):
100
106
"""This is the Format 4 working tree.
353
359
inv_entry = factory[kind](file_id, name_unicode,
354
360
parent_ie.file_id)
355
361
if kind == 'file':
362
# This is only needed on win32, where this is the only way
363
# we know the executable bit.
364
inv_entry.executable = executable
356
365
# not strictly needed: working tree
357
#entry.executable = executable
358
#entry.text_size = size
359
#entry.text_sha1 = sha1
366
#inv_entry.text_size = size
367
#inv_entry.text_sha1 = sha1
361
368
elif kind == 'directory':
362
369
# add this entry to the parent map.
363
370
parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
364
371
elif kind == 'tree-reference':
365
assert self._repo_supports_tree_reference
372
assert self._repo_supports_tree_reference, \
373
"repository of %r " \
374
"doesn't support tree references " \
375
"required by entry %r" \
366
377
inv_entry.reference_revision = link_or_sha1 or None
368
assert 'unknown kind'
378
elif kind != 'symlink':
379
raise AssertionError("unknown kind %r" % kind)
369
380
# These checks cost us around 40ms on a 55k entry tree
370
381
assert file_id not in inv_byid, ('file_id %s already in'
371
382
' inventory as %s' % (file_id, inv_byid[file_id]))
460
471
path_utf8 = osutils.pathjoin(entry[0][0], entry[0][1])
461
472
return path_utf8.decode('utf8')
474
if not osutils.supports_executable():
476
def is_executable(self, file_id, path=None):
477
file_id = osutils.safe_file_id(file_id)
478
entry = self._get_entry(file_id=file_id, path=path)
479
if entry == (None, None):
481
return entry[1][0][3]
484
def is_executable(self, file_id, path=None):
486
file_id = osutils.safe_file_id(file_id)
487
path = self.id2path(file_id)
488
mode = os.lstat(self.abspath(path)).st_mode
489
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
464
492
def __iter__(self):
465
493
"""Iterate through file_ids for this tree.
1141
1169
entry_index = 0
1142
1170
while entry_index < len(block[1]):
1143
1171
# Mark this file id as having been removed
1144
ids_to_unversion.discard(block[1][entry_index][0][2])
1145
if not state._make_absent(block[1][entry_index]):
1172
entry = block[1][entry_index]
1173
ids_to_unversion.discard(entry[0][2])
1174
if (entry[1][0][0] == 'a'
1175
or not state._make_absent(entry)):
1146
1176
entry_index += 1
1147
1177
# go to the next block. (At the moment we dont delete empty
1400
1430
parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1401
1431
elif kind == 'symlink':
1402
1432
inv_entry.executable = False
1403
inv_entry.text_size = size
1433
inv_entry.text_size = None
1404
1434
inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1405
1435
elif kind == 'tree-reference':
1406
1436
inv_entry.reference_revision = fingerprint or None
1621
1651
output. An unversioned file is defined as one with (False, False)
1622
1652
for the versioned pair.
1624
utf8_decode = cache_utf8._utf8_decode_with_None
1654
utf8_decode_or_none = cache_utf8._utf8_decode_with_None
1625
1655
_minikind_to_kind = dirstate.DirState._minikind_to_kind
1626
1656
# NB: show_status depends on being able to pass in non-versioned files
1627
1657
# and report them as unknown
1961
1991
# TODO: the pending list should be lexically sorted? the
1962
1992
# interface doesn't require it.
1963
1993
current_root = search_specific_files.pop()
1994
current_root_unicode = current_root.decode('utf8')
1964
1995
searched_specific_files.add(current_root)
1965
1996
# process the entries for this containing directory: the rest will be
1966
1997
# found by their parents recursively.
1967
1998
root_entries = _entries_for_path(current_root)
1968
root_abspath = self.target.abspath(current_root)
1999
root_abspath = self.target.abspath(current_root_unicode)
1970
2001
root_stat = os.lstat(root_abspath)
1971
2002
except OSError, e:
2003
2034
or result[6][0] != result[6][1] # kind
2004
2035
or result[7][0] != result[7][1] # executable
2006
result = (result[0],
2007
((utf8_decode(result[1][0])[0]),
2008
utf8_decode(result[1][1])[0]),) + result[2:]
2010
if want_unversioned and not path_handled:
2038
(utf8_decode_or_none(result[1][0]),
2039
utf8_decode_or_none(result[1][1])),
2043
(utf8_decode_or_none(result[5][0]),
2044
utf8_decode_or_none(result[5][1])),
2048
if want_unversioned and not path_handled and root_dir_info:
2011
2049
new_executable = bool(
2012
2050
stat.S_ISREG(root_dir_info[3].st_mode)
2013
2051
and stat.S_IEXEC & root_dir_info[3].st_mode)
2014
yield (None, (None, current_root), True, (False, False),
2016
(None, splitpath(current_root)[-1]),
2017
(None, root_dir_info[2]), (None, new_executable))
2053
(None, current_root_unicode),
2057
(None, splitpath(current_root_unicode)[-1]),
2058
(None, root_dir_info[2]),
2059
(None, new_executable)
2018
2061
initial_key = (current_root, '', '')
2019
2062
block_index, _ = state._find_block_index_from_key(initial_key)
2020
2063
if block_index == 0:
2029
2072
current_dir_info = dir_iterator.next()
2030
2073
except OSError, e:
2031
if e.errno in (errno.ENOENT, errno.ENOTDIR):
2032
# there may be directories in the inventory even though
2033
# this path is not a file on disk: so mark it as end of
2074
# on win32, python2.4 has e.errno == ERROR_DIRECTORY, but
2075
# python 2.5 has e.errno == EINVAL,
2076
# and e.winerror == ERROR_DIRECTORY
2077
e_winerror = getattr(e, 'winerror', None)
2078
# there may be directories in the inventory even though
2079
# this path is not a file on disk: so mark it as end of
2081
if e.errno in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
2082
current_dir_info = None
2083
elif (sys.platform == 'win32'
2084
and ERROR_DIRECTORY in (e.errno, e_winerror)):
2035
2085
current_dir_info = None
2089
2139
or result[6][0] != result[6][1] # kind
2090
2140
or result[7][0] != result[7][1] # executable
2092
result = (result[0],
2093
((utf8_decode(result[1][0])[0]),
2094
utf8_decode(result[1][1])[0]),) + result[2:]
2143
(utf8_decode_or_none(result[1][0]),
2144
utf8_decode_or_none(result[1][1])),
2148
(utf8_decode_or_none(result[5][0]),
2149
utf8_decode_or_none(result[5][1])),
2096
2153
block_index +=1
2097
2154
if (block_index < len(state._dirblocks) and
2098
2155
osutils.is_inside(current_root,
2139
2196
or result[6][0] != result[6][1] # kind
2140
2197
or result[7][0] != result[7][1] # executable
2142
result = (result[0],
2143
((utf8_decode(result[1][0])[0]),
2144
utf8_decode(result[1][1])[0]),) + result[2:]
2200
(utf8_decode_or_none(result[1][0]),
2201
utf8_decode_or_none(result[1][1])),
2205
(utf8_decode_or_none(result[5][0]),
2206
utf8_decode_or_none(result[5][1])),
2146
2210
elif current_entry[0][1] != current_path_info[1]:
2147
2211
if current_path_info[1] < current_entry[0][1]:
2148
2212
# extra file on disk: pass for now, but only
2164
2228
or result[6][0] != result[6][1] # kind
2165
2229
or result[7][0] != result[7][1] # executable
2167
result = (result[0],
2168
((utf8_decode(result[1][0])[0]),
2169
utf8_decode(result[1][1])[0]),) + result[2:]
2232
(utf8_decode_or_none(result[1][0]),
2233
utf8_decode_or_none(result[1][1])),
2237
(utf8_decode_or_none(result[5][0]),
2238
utf8_decode_or_none(result[5][1])),
2171
2242
advance_path = False
2173
2244
for result in _process_entry(current_entry, current_path_info):
2183
2254
or result[6][0] != result[6][1] # kind
2184
2255
or result[7][0] != result[7][1] # executable
2186
result = (result[0],
2187
((utf8_decode(result[1][0])[0]),
2188
utf8_decode(result[1][1])[0]),) + result[2:]
2258
(utf8_decode_or_none(result[1][0]),
2259
utf8_decode_or_none(result[1][1])),
2263
(utf8_decode_or_none(result[5][0]),
2264
utf8_decode_or_none(result[5][1])),
2190
2268
if advance_entry and current_entry is not None:
2191
2269
entry_index += 1
2192
2270
if entry_index < len(current_block[1]):
2203
2281
stat.S_ISREG(current_path_info[3].st_mode)
2204
2282
and stat.S_IEXEC & current_path_info[3].st_mode)
2205
2283
if want_unversioned:
2206
yield (None, (None, current_path_info[0]),
2285
(None, utf8_decode_or_none(current_path_info[0])),
2208
2287
(False, False),
2210
(None, current_path_info[1]),
2289
(None, utf8_decode_or_none(current_path_info[1])),
2211
2290
(None, current_path_info[2]),
2212
2291
(None, new_executable))
2213
2292
# dont descend into this unversioned path if it is