# -*- coding: utf-8 -*- # # Copyright (C) 2011-2018 Ben Kurtovic # Released under the terms of the MIT License. See LICENSE for details. from __future__ import print_function from glob import glob import os from colorama import Fore, Style from gitup.migrate import run_migrations __all__ = ["get_default_config_path", "get_bookmarks", "add_bookmarks", "delete_bookmarks", "list_bookmarks", "clean_bookmarks"] YELLOW = Fore.YELLOW + Style.BRIGHT RED = Fore.RED + Style.BRIGHT INDENT1 = " " * 3 def _ensure_dirs(path): """Ensure the directories within the given pathname exist.""" dirname = os.path.dirname(path) if dirname and not os.path.exists(dirname): # Race condition, meh... os.makedirs(dirname) def _load_config_file(config_path=None): """Read the config file and return a list of bookmarks.""" run_migrations() cfg_path = config_path or get_default_config_path() try: with open(cfg_path, "rb") as config_file: paths = config_file.read().split(b"\n") except IOError: return [] paths = [path.decode("utf8").strip() for path in paths] return [path for path in paths if path] def _save_config_file(bookmarks, config_path=None): """Save the bookmarks list to the given config file.""" run_migrations() cfg_path = config_path or get_default_config_path() _ensure_dirs(cfg_path) dump = b"\n".join(path.encode("utf8") for path in bookmarks) with open(cfg_path, "wb") as config_file: config_file.write(dump) def _normalize_path(path): """Normalize the given path.""" if path.startswith("~"): return os.path.normcase(os.path.normpath(path)) return os.path.normcase(os.path.abspath(path)) def get_default_config_path(): """Return the default path to the configuration file.""" xdg_cfg = os.environ.get("XDG_CONFIG_HOME") or os.path.join("~", ".config") return os.path.join(os.path.expanduser(xdg_cfg), "gitup", "bookmarks") def get_bookmarks(config_path=None): """Get a list of all bookmarks, or an empty list if there are none.""" return _load_config_file(config_path) def add_bookmarks(paths, config_path=None): """Add a list of paths as bookmarks to the config file.""" config = _load_config_file(config_path) paths = [_normalize_path(path) for path in paths] added, exists = [], [] for path in paths: if path in config: exists.append(path) else: config.append(path) added.append(path) _save_config_file(config, config_path) if added: print(YELLOW + "Added bookmarks:") for path in added: print(INDENT1, path) if exists: print(RED + "Already bookmarked:") for path in exists: print(INDENT1, path) def delete_bookmarks(paths, config_path=None): """Remove a list of paths from the bookmark config file.""" config = _load_config_file(config_path) paths = [_normalize_path(path) for path in paths] deleted, notmarked = [], [] if config: for path in paths: if path in config: config.remove(path) deleted.append(path) else: notmarked.append(path) _save_config_file(config, config_path) else: notmarked = paths if deleted: print(YELLOW + "Deleted bookmarks:") for path in deleted: print(INDENT1, path) if notmarked: print(RED + "Not bookmarked:") for path in notmarked: print(INDENT1, path) def list_bookmarks(config_path=None): """Print all of our current bookmarks.""" bookmarks = _load_config_file(config_path) if bookmarks: print(YELLOW + "Current bookmarks:") for bookmark_path in bookmarks: print(INDENT1, bookmark_path) else: print("You have no bookmarks to display.") def clean_bookmarks(config_path=None): """Delete any bookmarks that don't exist.""" bookmarks = _load_config_file(config_path) if not bookmarks: print("You have no bookmarks to clean up.") return delete = [path for path in bookmarks if not (os.path.isdir(path) or glob(os.path.expanduser(path)))] if not delete: print("All of your bookmarks are valid.") return bookmarks = [path for path in bookmarks if path not in delete] _save_config_file(bookmarks, config_path) print(YELLOW + "Deleted bookmarks:") for path in delete: print(INDENT1, path)