mirror of
https://github.com/nikdoof/dotfiles.git
synced 2026-01-29 18:38:15 +00:00
[bin] Simplify stowage
This commit is contained in:
@@ -34,96 +34,50 @@ import shutil
|
|||||||
import sys
|
import sys
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import IO, List
|
from typing import List
|
||||||
|
|
||||||
|
from _colorize import ANSIColors, can_colorize # ty: ignore[unresolved-import]
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Colours(object):
|
# Make use of Python internal _colorize module for ANSI colors
|
||||||
"""ANSI color codes for terminal output"""
|
# this will break, but we want keep to zero depdencies for the script.
|
||||||
|
def get_color(name: str):
|
||||||
# Reset
|
"""Get a color code by name from the Python stdlib."""
|
||||||
RESET = "\033[0m"
|
if not can_colorize():
|
||||||
|
return ""
|
||||||
# Regular colors
|
return getattr(ANSIColors, name.replace(" ", "_").upper(), "")
|
||||||
BLACK = "\033[30m"
|
|
||||||
RED = "\033[31m"
|
|
||||||
GREEN = "\033[32m"
|
|
||||||
YELLOW = "\033[33m"
|
|
||||||
BLUE = "\033[34m"
|
|
||||||
MAGENTA = "\033[35m"
|
|
||||||
CYAN = "\033[36m"
|
|
||||||
WHITE = "\033[37m"
|
|
||||||
|
|
||||||
# Copied from _colorize in Python stdlib
|
|
||||||
def can_colorize(*, file: IO[str] | IO[bytes] | None = None) -> bool:
|
|
||||||
def _safe_getenv(k: str, fallback: str | None = None) -> str | None:
|
|
||||||
try:
|
|
||||||
return os.environ.get(k, fallback)
|
|
||||||
except Exception:
|
|
||||||
return fallback
|
|
||||||
|
|
||||||
if file is None:
|
|
||||||
file = sys.stdout
|
|
||||||
|
|
||||||
if not sys.flags.ignore_environment:
|
|
||||||
if _safe_getenv("PYTHON_COLORS") == "0":
|
|
||||||
return False
|
|
||||||
if _safe_getenv("PYTHON_COLORS") == "1":
|
|
||||||
return True
|
|
||||||
if _safe_getenv("NO_COLOR"):
|
|
||||||
return False
|
|
||||||
if _safe_getenv("FORCE_COLOR"):
|
|
||||||
return True
|
|
||||||
if _safe_getenv("TERM") == "dumb":
|
|
||||||
return False
|
|
||||||
|
|
||||||
if not hasattr(file, "fileno"):
|
|
||||||
return False
|
|
||||||
|
|
||||||
if sys.platform == "win32":
|
|
||||||
try:
|
|
||||||
import nt
|
|
||||||
|
|
||||||
if not nt._supports_virtual_terminal():
|
|
||||||
return False
|
|
||||||
except (ImportError, AttributeError):
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
|
||||||
return os.isatty(file.fileno())
|
|
||||||
except OSError:
|
|
||||||
return hasattr(file, "isatty") and file.isatty()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def by_name(name):
|
|
||||||
if not Colours.can_colorize():
|
|
||||||
return ""
|
|
||||||
return getattr(Colours, name.upper(), "")
|
|
||||||
|
|
||||||
|
|
||||||
# Colours to use for each action
|
# Colours to use for each action
|
||||||
ACTION_COLOURS = {
|
ACTION_COLORS = {
|
||||||
"LINK": "GREEN",
|
"LINK": "GREEN",
|
||||||
"UNLINK": "RED",
|
"UNLINK": "RED",
|
||||||
"DIR": "GREEN",
|
"DIR": "GREEN",
|
||||||
"RMDIR": "RED",
|
"RMDIR": "RED",
|
||||||
"SKIP": "YELLOW",
|
"SKIP": "INTENSE_BLACK",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def print_action(action: str, msg: str) -> None:
|
def print_action(action: str, msg: str) -> None:
|
||||||
"""Print an action message."""
|
"""Print an action message."""
|
||||||
colour = ""
|
colour, reset = "", ""
|
||||||
if action in ACTION_COLOURS:
|
if action in ACTION_COLORS:
|
||||||
colour = Colours.by_name(ACTION_COLOURS[action])
|
colour = get_color(ACTION_COLORS[action])
|
||||||
print(f"{colour}{action}{Colours.by_name('RESET')} {msg}")
|
reset = get_color("RESET")
|
||||||
|
print(f"{colour}{action}{reset} {msg}")
|
||||||
|
|
||||||
|
|
||||||
def add_file_to_package(
|
def add_file_to_package(
|
||||||
file_path: Path, package_name: str, args: argparse.Namespace
|
file_path: Path, package_name: str, args: argparse.Namespace
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Add a file to a package by moving it and creating a symlink."""
|
"""Add a file to a package by moving it and creating a symlink."""
|
||||||
|
|
||||||
|
if package_name not in get_packages(args.repository):
|
||||||
|
logger.error("no such package: %s", package_name)
|
||||||
|
return False
|
||||||
|
|
||||||
target = args.target.resolve()
|
target = args.target.resolve()
|
||||||
package = Path(args.repository, package_name).resolve()
|
package = Path(args.repository, package_name).resolve()
|
||||||
|
|
||||||
@@ -168,12 +122,13 @@ def install_package(
|
|||||||
package: str, args: argparse.Namespace, is_excluded: Callable[[str], bool]
|
package: str, args: argparse.Namespace, is_excluded: Callable[[str], bool]
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Install a package by creating symlinks from repository to target."""
|
"""Install a package by creating symlinks from repository to target."""
|
||||||
package_dir = args.repository / package
|
|
||||||
if not package_dir.is_dir():
|
if package not in get_packages(args.repository):
|
||||||
logger.warning("no such package: %s; skipping", package)
|
logger.error("no such package: %s", package)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Walk the package
|
# Walk the package
|
||||||
|
package_dir = args.repository / package
|
||||||
for root, _, files in os.walk(package_dir, followlinks=True):
|
for root, _, files in os.walk(package_dir, followlinks=True):
|
||||||
root_path = Path(root)
|
root_path = Path(root)
|
||||||
files = [filename for filename in files if not is_excluded(filename)]
|
files = [filename for filename in files if not is_excluded(filename)]
|
||||||
@@ -230,6 +185,10 @@ def uninstall_package(
|
|||||||
"""Uninstalls a package by removing symlinks."""
|
"""Uninstalls a package by removing symlinks."""
|
||||||
dirs: List[Path] = []
|
dirs: List[Path] = []
|
||||||
|
|
||||||
|
if package not in get_packages(args.repository):
|
||||||
|
logger.error("no such package: %s", package)
|
||||||
|
return False
|
||||||
|
|
||||||
package_dir = args.repository / package
|
package_dir = args.repository / package
|
||||||
if not package_dir.is_dir():
|
if not package_dir.is_dir():
|
||||||
logger.warning("no such package: %s; skipping", package)
|
logger.warning("no such package: %s; skipping", package)
|
||||||
@@ -322,6 +281,10 @@ def cleanup_package(package: str, args: argparse.Namespace) -> None:
|
|||||||
- discover the directories used in the package
|
- discover the directories used in the package
|
||||||
- iterate the directories and remove any broken symlinks that point back to the package
|
- iterate the directories and remove any broken symlinks that point back to the package
|
||||||
"""
|
"""
|
||||||
|
if package not in get_packages(args.repository):
|
||||||
|
logger.error("no such package: %s", package)
|
||||||
|
return
|
||||||
|
|
||||||
package_dir = args.repository / package
|
package_dir = args.repository / package
|
||||||
if not package_dir.is_dir():
|
if not package_dir.is_dir():
|
||||||
return
|
return
|
||||||
@@ -461,9 +424,7 @@ def main() -> None:
|
|||||||
if len(packages):
|
if len(packages):
|
||||||
print(f"Packages in repository: {repo_path}")
|
print(f"Packages in repository: {repo_path}")
|
||||||
for package in packages:
|
for package in packages:
|
||||||
print(
|
print(f"{get_color('GREEN')}-{get_color('RESET')} {package}")
|
||||||
f"{Colours.by_name('GREEN')}-{Colours.by_name('RESET')} {package}"
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.info("no packages found in repository")
|
logger.info("no packages found in repository")
|
||||||
|
|||||||
Reference in New Issue
Block a user