def status(self, path=None): """Return status of repository or file. Without file argument: returns status of the repository: :First column: working directory status (D: dirty / space) :Second column: index status (I: index dirty / space) :Third column: presence of untracked files (U: untracked files / space) :None: repository clean With file argument: returns status of this file. Output is equivalent to the first two columns of ``git status --porcelain`` (except for merge statuses as they are not supported by libgit2). """ if path: gitd = git_directory(self.directory) # We need HEAD as without it using fugitive to commit causes the # current file’s status (and only the current file) to not be updated # for some reason I cannot be bothered to figure out. return get_file_status( directory=self.directory, dirstate_file=join(gitd, "index"), file_path=path, ignore_file_name=".gitignore", get_func=self.do_status, create_watcher=self.create_watcher, extra_ignore_files=tuple(join(gitd, x) for x in ("logs/HEAD", "info/exclude")), ) return self.do_status(self.directory, path)
def status(self, path=None): '''Return status of repository or file. Without file argument: returns status of the repository: :First column: working directory status (D: dirty / space) :Second column: index status (I: index dirty / space) :Third column: presence of untracked files (U: untracked files / space) :None: repository clean With file argument: returns status of this file. Output is equivalent to the first two columns of ``git status --porcelain`` (except for merge statuses as they are not supported by libgit2). ''' if path: gitd = git_directory(self.directory) # We need HEAD as without it using fugitive to commit causes the # current file’s status (and only the current file) to not be updated # for some reason I cannot be bothered to figure out. return get_file_status( directory=self.directory, dirstate_file=join(gitd, 'index'), file_path=path, ignore_file_name='.gitignore', get_func=self.do_status, create_watcher=self.create_watcher, extra_ignore_files=tuple( join(gitd, x) for x in ('logs/HEAD', 'info/exclude')), ) return self.do_status(self.directory, path)
def get_config_paths(): """Get configuration paths from environment variables. Uses $XDG_CONFIG_HOME and $XDG_CONFIG_DIRS according to the XDG specification. :return: list of paths """ config_home = os.environ.get("XDG_CONFIG_HOME", os.path.join(os.path.expanduser("~"), ".config")) config_path = join(config_home, "powerline") config_paths = [config_path] config_dirs = os.environ.get("XDG_CONFIG_DIRS", DEFAULT_SYSTEM_CONFIG_DIR) if config_dirs is not None: config_paths[:0] = reversed([join(d, "powerline") for d in config_dirs.split(":")]) plugin_path = join(os.path.realpath(os.path.dirname(__file__)), "config_files") config_paths.insert(0, plugin_path) return config_paths
def get_file_status(directory, dirstate_file, file_path, ignore_file_name, get_func, create_watcher, extra_ignore_files=()): global file_status_cache keypath = file_path if os.path.isabs(file_path) else join(directory, file_path) file_status_cache.update_maps(keypath, directory, dirstate_file, ignore_file_name, extra_ignore_files) with file_status_lock: # Optimize case of keypath not being cached if keypath not in file_status_cache: file_status_cache[keypath] = ans = get_func(directory, file_path) return ans # Check if any relevant files have changed file_changed = file_watcher(create_watcher) changed = False # Check if dirstate has changed try: changed = file_changed(dirstate_file) except OSError as e: if getattr(e, 'errno', None) != errno.ENOENT: raise # The .git index file does not exist for a new git repo return get_func(directory, file_path) if changed: # Remove all cached values for files that depend on this # dirstate_file file_status_cache.invalidate(dirstate_file=dirstate_file) else: # Check if the file itself has changed try: changed ^= file_changed(keypath) except OSError as e: if getattr(e, 'errno', None) != errno.ENOENT: raise # Do not call get_func again for a non-existant file if keypath not in file_status_cache: file_status_cache[keypath] = get_func(directory, file_path) return file_status_cache[keypath] if changed: file_status_cache.pop(keypath, None) else: # Check if one of the ignore files has changed for ignf in file_status_cache.ignore_files(keypath): try: changed ^= file_changed(ignf) except OSError as e: if getattr(e, 'errno', None) != errno.ENOENT: raise if changed: # Invalidate cache for all files that might be affected # by this ignore file file_status_cache.invalidate(ignore_file=ignf) break try: return file_status_cache[keypath] except KeyError: file_status_cache[keypath] = ans = get_func(directory, file_path) return ans
def get_config_paths(): '''Get configuration paths from environment variables. Uses $XDG_CONFIG_HOME and $XDG_CONFIG_DIRS according to the XDG specification. :return: list of paths ''' config_home = os.environ.get('XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config')) config_path = join(config_home, 'powerline') config_paths = [config_path] config_dirs = os.environ.get('XDG_CONFIG_DIRS', DEFAULT_SYSTEM_CONFIG_DIR) if config_dirs is not None: config_paths[:0] = reversed([join(d, 'powerline') for d in config_dirs.split(':')]) plugin_path = join(os.path.realpath(os.path.dirname(__file__)), 'config_files') config_paths.insert(0, plugin_path) return config_paths
def branch(self): config_file = join(self.directory, '.hg', 'branch') return get_branch_name( directory=self.directory, config_file=config_file, get_func=branch_name_from_config_file, create_watcher=self.create_watcher, )
def branch(self): directory = git_directory(self.directory) head = join(directory, "HEAD") return get_branch_name( directory=directory, config_file=head, get_func=branch_name_from_config_file, create_watcher=self.create_watcher, )
def branch(self): directory = git_directory(self.directory) head = join(directory, 'HEAD') return get_branch_name( directory=directory, config_file=head, get_func=branch_name_from_config_file, create_watcher=self.create_watcher, )
def _find_config_files(search_paths, config_file, config_loader=None, loader_callback=None): config_file += ".json" found = False for path in search_paths: config_file_path = join(path, config_file) if os.path.isfile(config_file_path): yield config_file_path found = True elif config_loader: config_loader.register_missing(_config_loader_condition, loader_callback, config_file_path) if not found: raise IOError("Config file not found in search paths ({0}): {1}".format(", ".join(search_paths), config_file))
def find_all_ext_config_files(search_paths, subdir): for config_root in search_paths: top_config_subpath = join(config_root, subdir) if not os.path.isdir(top_config_subpath): if os.path.exists(top_config_subpath): yield { 'error': 'Path {0} is not a directory'.format(top_config_subpath), 'path': top_config_subpath, } continue for ext_name in os.listdir(top_config_subpath): ext_path = os.path.join(top_config_subpath, ext_name) if not os.path.isdir(ext_path): if ext_name.endswith('.json') and os.path.isfile(ext_path): yield updated_with_config({ 'error': False, 'path': ext_path, 'name': ext_name[:-5], 'ext': None, 'type': 'top_' + subdir, }) else: yield { 'error': 'Path {0} is not a directory or configuration file'. format(ext_path), 'path': ext_path, } continue for config_file_name in os.listdir(ext_path): config_file_path = os.path.join(ext_path, config_file_name) if config_file_name.endswith('.json') and os.path.isfile( config_file_path): yield updated_with_config({ 'error': False, 'path': config_file_path, 'name': config_file_name[:-5], 'ext': ext_name, 'type': subdir, }) else: yield { 'error': 'Path {0} is not a configuration file'.format( config_file_path), 'path': config_file_path, }
def update_maps(self, keypath, directory, dirstate_file, ignore_file_name, extra_ignore_files): parent = keypath ignore_files = set() while parent != directory: nparent = os.path.dirname(keypath) if nparent == parent: break parent = nparent ignore_files.add(join(parent, ignore_file_name)) for f in extra_ignore_files: ignore_files.add(f) self.keypath_ignore_map[keypath] = ignore_files for ignf in ignore_files: self.ignore_map[ignf].add(keypath) self.dirstate_map[dirstate_file].add(keypath)
def _find_config_files(search_paths, config_file, config_loader=None, loader_callback=None): config_file += '.json' found = False for path in search_paths: config_file_path = join(path, config_file) if os.path.isfile(config_file_path): yield config_file_path found = True elif config_loader: config_loader.register_missing(_config_loader_condition, loader_callback, config_file_path) if not found: raise IOError('Config file not found in search paths ({0}): {1}'.format( ', '.join(search_paths), config_file ))
def git_directory(directory): path = join(directory, ".git") if os.path.isfile(path): with open(path, "rb") as f: raw = f.read() if not raw.startswith(b"gitdir: "): raise IOError("invalid gitfile format") raw = raw[8:] if raw[-1:] == b"\n": raw = raw[:-1] if not isinstance(path, bytes): raw = raw.decode(get_preferred_file_name_encoding()) if not raw: raise IOError("no path in gitfile") return os.path.abspath(os.path.join(directory, raw)) else: return path
def git_directory(directory): path = join(directory, '.git') if os.path.isfile(path): with open(path, 'rb') as f: raw = f.read() if not raw.startswith(b'gitdir: '): raise IOError('invalid gitfile format') raw = raw[8:] if raw[-1:] == b'\n': raw = raw[:-1] if not isinstance(path, bytes): raw = raw.decode(get_preferred_file_name_encoding()) if not raw: raise IOError('no path in gitfile') return os.path.abspath(os.path.join(directory, raw)) else: return path
def find_all_ext_config_files(search_paths, subdir): for config_root in search_paths: top_config_subpath = join(config_root, subdir) if not os.path.isdir(top_config_subpath): if os.path.exists(top_config_subpath): yield { 'error': 'Path {0} is not a directory'.format(top_config_subpath), 'path': top_config_subpath, } continue for ext_name in os.listdir(top_config_subpath): ext_path = os.path.join(top_config_subpath, ext_name) if not os.path.isdir(ext_path): if ext_name.endswith('.json') and os.path.isfile(ext_path): yield updated_with_config({ 'error': False, 'path': ext_path, 'name': ext_name[:-5], 'ext': None, 'type': 'top_' + subdir, }) else: yield { 'error': 'Path {0} is not a directory or configuration file'.format(ext_path), 'path': ext_path, } continue for config_file_name in os.listdir(ext_path): config_file_path = os.path.join(ext_path, config_file_name) if config_file_name.endswith('.json') and os.path.isfile(config_file_path): yield updated_with_config({ 'error': False, 'path': config_file_path, 'name': config_file_name[:-5], 'ext': ext_name, 'type': subdir, }) else: yield { 'error': 'Path {0} is not a configuration file'.format(config_file_path), 'path': config_file_path, }
def status(self, path=None): '''Return status of repository or file. Without file argument: returns status of the repository: :'D?': dirty (tracked modified files: added, removed, deleted, modified), :'?U': untracked-dirty (added, but not tracked files) :None: clean (status is empty) With file argument: returns status of this file: The status codes are those returned by bzr status -S ''' if path is not None: return get_file_status( directory=self.directory, dirstate_file=join(self.directory, '.bzr', 'checkout', 'dirstate'), file_path=path, ignore_file_name='.bzrignore', get_func=self.do_status, create_watcher=self.create_watcher, ) return self.do_status(self.directory, path)
def status_string(self, path=None): '''Return status of repository or file. Without file argument: returns status of the repository: :'D?': dirty (tracked modified files: added, removed, deleted, modified), :'?U': untracked-dirty (added, but not tracked files) :None: clean (status is empty) With file argument: returns status of this file: The status codes are those returned by bzr status -S ''' if path is not None: return get_file_status( directory=self.directory, dirstate_file=join(self.directory, '.bzr', 'checkout', 'dirstate'), file_path=path, ignore_file_name='.bzrignore', get_func=self.do_status, create_watcher=self.create_watcher, ) return self.do_status(self.directory, path)
def status(self, path=None): '''Return status of repository or file. Without file argument: returns status of the repository: :'D?': dirty (tracked modified files: added, removed, deleted, modified), :'?U': untracked-dirty (added, but not tracked files) :None: clean (status is empty) With file argument: returns status of this file: `M`odified, `A`dded, `R`emoved, `D`eleted (removed from filesystem, but still tracked), `U`nknown, `I`gnored, (None)Clean. ''' if path: return get_file_status( directory=self.directory, dirstate_file=join(self.directory, '.hg', 'dirstate'), file_path=path, ignore_file_name='.hgignore', get_func=self.do_status, create_watcher=self.create_watcher, ) return self.do_status(self.directory, path)
def status_string(self, path=None): '''Return status of repository or file. Without file argument: returns status of the repository: :'D?': dirty (tracked modified files: added, removed, deleted, modified), :'?U': untracked-dirty (added, but not tracked files) :None: clean (status is empty) With file argument: returns status of this file: `M`odified, `A`dded, `R`emoved, `D`eleted (removed from filesystem, but still tracked), `U`nknown, `I`gnored, (None)Clean. ''' if path: return get_file_status( directory=self.directory, dirstate_file=join(self.directory, '.hg', 'dirstate'), file_path=path, ignore_file_name='.hgignore', get_func=self.do_status, create_watcher=self.create_watcher, ) return self.do_status(self.directory, path)
def get_file_status(directory, dirstate_file, file_path, ignore_file_name, get_func, create_watcher, extra_ignore_files=()): global file_status_cache keypath = file_path if os.path.isabs(file_path) else join( directory, file_path) file_status_cache.update_maps(keypath, directory, dirstate_file, ignore_file_name, extra_ignore_files) with file_status_lock: # Optimize case of keypath not being cached if keypath not in file_status_cache: file_status_cache[keypath] = ans = get_func(directory, file_path) return ans # Check if any relevant files have changed file_changed = file_watcher(create_watcher) changed = False # Check if dirstate has changed try: changed = file_changed(dirstate_file) except OSError as e: if getattr(e, 'errno', None) != errno.ENOENT: raise # The .git index file does not exist for a new git repo return get_func(directory, file_path) if changed: # Remove all cached values for files that depend on this # dirstate_file file_status_cache.invalidate(dirstate_file=dirstate_file) else: # Check if the file itself has changed try: changed ^= file_changed(keypath) except OSError as e: if getattr(e, 'errno', None) != errno.ENOENT: raise # Do not call get_func again for a non-existant file if keypath not in file_status_cache: file_status_cache[keypath] = get_func(directory, file_path) return file_status_cache[keypath] if changed: file_status_cache.pop(keypath, None) else: # Check if one of the ignore files has changed for ignf in file_status_cache.ignore_files(keypath): try: changed ^= file_changed(ignf) except OSError as e: if getattr(e, 'errno', None) != errno.ENOENT: raise if changed: # Invalidate cache for all files that might be affected # by this ignore file file_status_cache.invalidate(ignore_file=ignf) break try: return file_status_cache[keypath] except KeyError: file_status_cache[keypath] = ans = get_func(directory, file_path) return ans