240 # much faster than os.path.join() |
240 # much faster than os.path.join() |
241 # it's safe because f is always a relative path |
241 # it's safe because f is always a relative path |
242 return self._rootdir + f |
242 return self._rootdir + f |
243 |
243 |
244 def flagfunc(self, buildfallback): |
244 def flagfunc(self, buildfallback): |
245 if not (self._checklink and self._checkexec): |
245 """build a callable that returns flags associated with a filename |
246 fallback = buildfallback() |
246 |
247 |
247 The information is extracted from three possible layers: |
248 def check_both(x): |
248 1. the file system if it supports the information |
249 """This platform supports symlinks and exec permissions""" |
249 2. the "fallback" information stored in the dirstate if any |
|
250 3. a more expensive mechanism inferring the flags from the parents. |
|
251 """ |
|
252 |
|
253 # small hack to cache the result of buildfallback() |
|
254 fallback_func = [] |
|
255 |
|
256 def get_flags(x): |
|
257 entry = None |
|
258 fallback_value = None |
250 try: |
259 try: |
251 st = os.lstat(self._join(x)) |
260 st = os.lstat(self._join(x)) |
|
261 except OSError: |
|
262 return b'' |
|
263 |
|
264 if self._checklink: |
252 if util.statislink(st): |
265 if util.statislink(st): |
253 return b'l' |
266 return b'l' |
|
267 else: |
|
268 entry = self.get_entry(x) |
|
269 if entry.has_fallback_symlink: |
|
270 if entry.fallback_symlink: |
|
271 return b'l' |
|
272 else: |
|
273 if not fallback_func: |
|
274 fallback_func.append(buildfallback()) |
|
275 fallback_value = fallback_func[0](x) |
|
276 if b'l' in fallback_value: |
|
277 return b'l' |
|
278 |
|
279 if self._checkexec: |
254 if util.statisexec(st): |
280 if util.statisexec(st): |
255 return b'x' |
281 return b'x' |
256 except OSError: |
282 else: |
257 pass |
283 if entry is None: |
|
284 entry = self.get_entry(x) |
|
285 if entry.has_fallback_exec: |
|
286 if entry.fallback_exec: |
|
287 return b'x' |
|
288 else: |
|
289 if fallback_value is None: |
|
290 if not fallback_func: |
|
291 fallback_func.append(buildfallback()) |
|
292 fallback_value = fallback_func[0](x) |
|
293 if b'x' in fallback_value: |
|
294 return b'x' |
258 return b'' |
295 return b'' |
259 |
296 |
260 def check_link(x): |
297 return get_flags |
261 """This platform only supports symlinks""" |
|
262 if os.path.islink(self._join(x)): |
|
263 return b'l' |
|
264 entry = self.get_entry(x) |
|
265 if entry.has_fallback_exec: |
|
266 if entry.fallback_exec: |
|
267 return b'x' |
|
268 elif b'x' in fallback(x): |
|
269 return b'x' |
|
270 return b'' |
|
271 |
|
272 def check_exec(x): |
|
273 """This platform only supports exec permissions""" |
|
274 if b'l' in fallback(x): |
|
275 return b'l' |
|
276 entry = self.get_entry(x) |
|
277 if entry.has_fallback_symlink: |
|
278 if entry.fallback_symlink: |
|
279 return b'l' |
|
280 if util.isexec(self._join(x)): |
|
281 return b'x' |
|
282 return b'' |
|
283 |
|
284 def check_fallback(x): |
|
285 """This platform supports neither symlinks nor exec permissions, so |
|
286 check the fallback in the dirstate if it exists, otherwise figure it |
|
287 out the more expensive way from the parents.""" |
|
288 entry = self.get_entry(x) |
|
289 if entry.has_fallback_symlink: |
|
290 if entry.fallback_symlink: |
|
291 return b'l' |
|
292 if entry.has_fallback_exec: |
|
293 if entry.fallback_exec: |
|
294 return b'x' |
|
295 elif entry.has_fallback_symlink: |
|
296 return b'' |
|
297 return fallback(x) |
|
298 |
|
299 if self._checklink and self._checkexec: |
|
300 return check_both |
|
301 elif self._checklink: |
|
302 return check_link |
|
303 elif self._checkexec: |
|
304 return check_exec |
|
305 else: |
|
306 return check_fallback |
|
307 |
298 |
308 @propertycache |
299 @propertycache |
309 def _cwd(self): |
300 def _cwd(self): |
310 # internal config: ui.forcecwd |
301 # internal config: ui.forcecwd |
311 forcecwd = self._ui.config(b'ui', b'forcecwd') |
302 forcecwd = self._ui.config(b'ui', b'forcecwd') |