Make CommandsCache play well with Windows

This commit is contained in:
Burak Yigit Kaya 2016-06-24 01:00:42 +03:00
parent e2dece482c
commit ce93945de3
2 changed files with 30 additions and 18 deletions

View file

@ -823,31 +823,27 @@ def _yield_executables(directory, name):
def locate_binary(name):
"""Locates an executable on the file system."""
cc = builtins.__xonsh_commands_cache__
if ON_WINDOWS:
# Windows users expect to be able to execute files in the same
# directory without `./`
cwd = _get_cwd()
if os.path.isfile(name):
return os.path.abspath(os.path.relpath(name, cwd))
exts = builtins.__xonsh_env__['PATHEXT']
for ext in exts:
namext = name + ext
if os.path.isfile(namext):
return os.path.abspath(os.path.relpath(namext, cwd))
elif os.path.isfile(name) and name != os.path.basename(name):
return name
cc = builtins.__xonsh_commands_cache__
if ON_WINDOWS:
upname = name.upper()
if upname in cc:
return cc.lazyget(upname)[0]
for ext in exts:
upnamext = upname + ext
if cc.lazyin(upnamext):
return cc.lazyget(upnamext)[0]
elif name in cc:
if name in cc:
# can be lazy here since we know name is already available
return cc.lazyget(name)[0]
elif os.path.isfile(name) and name != os.path.basename(name):
return name
def get_git_branch():
@ -1037,7 +1033,7 @@ def dirty_working_directory(cwd=None):
def branch_color():
"""Return red if the current branch is dirty, yellow if the dirtiness can
not be determined, and green if it clean. Thes are bold, intesnse colors
not be determined, and green if it clean. These are bold, intense colors
for the foreground.
"""
dwd = dirty_working_directory()

View file

@ -1564,8 +1564,18 @@ class CommandsCache(abc.Mapping):
self._alias_checksum = None
self._path_mtime = -1
def __get_possible_names(self, key):
if ON_WINDOWS:
return {
name + ext
for ext in ([''] + builtins.__xonsh_env__['PATHEXT'])
for name in (key, key.upper())
}
else:
return { key, }
def __contains__(self, key):
return key in self.all_commands
return bool(self.__get_possible_names(key) & self.all_commands.keys())
def __iter__(self):
return iter(self.all_commands)
@ -1574,7 +1584,8 @@ class CommandsCache(abc.Mapping):
return len(self.all_commands)
def __getitem__(self, key):
return self.all_commands[key]
possibilities = self.__get_possible_names(key)
return self.all_commands[next(possibilities & self.all_commands.keys())]
@property
def all_commands(self):
@ -1599,6 +1610,7 @@ class CommandsCache(abc.Mapping):
self._path_mtime = max_mtime
if cache_valid:
return self._cmds_cache
allcmds = {}
for path in reversed(paths):
# iterate backwards so that entries at the front of PATH overwrite
@ -1606,6 +1618,7 @@ class CommandsCache(abc.Mapping):
for cmd in executables_in(path):
key = cmd.upper() if ON_WINDOWS else cmd
allcmds[key] = (os.path.join(path, cmd), cmd in alss)
only_alias = (None, True)
for cmd in alss:
if cmd not in allcmds:
@ -1613,12 +1626,13 @@ class CommandsCache(abc.Mapping):
self._cmds_cache = allcmds
return allcmds
def lazyin(self, value):
def lazyin(self, key):
"""Checks if the value is in the current cache without the potential to
update the cache. It just says whether the value is known *now*. This
may not reflect precisely what is on the $PATH.
"""
return value in self._cmds_cache
return bool(self.__get_possible_names(key) & self._cmds_cache.keys())
def lazyiter(self):
"""Returns an iterator over the current cache contents without the
@ -1636,7 +1650,9 @@ class CommandsCache(abc.Mapping):
def lazyget(self, key, default=None):
"""A lazy value getter."""
return self._cmds_cache.get(key, default)
possibilities = self.__get_possible_names(key)
matches = possibilities & self._cmds_cache.keys()
return self._cmds_cache[matches.pop()] if matches else default
WINDOWS_DRIVE_MATCHER = LazyObject(lambda: re.compile(r'^\w:'),