diff --git a/src/caelestia/subcommands/install.py b/src/caelestia/subcommands/install.py index a8bc830..036a526 100644 --- a/src/caelestia/subcommands/install.py +++ b/src/caelestia/subcommands/install.py @@ -6,7 +6,7 @@ from argparse import Namespace from pathlib import Path from caelestia.utils.dots.deployer import Deployer -from caelestia.utils.dots.manifest import ComponentError, Manifest, ManifestError, expand, expand_dests +from caelestia.utils.dots.manifest import ComponentError, Manifest, ManifestError from caelestia.utils.dots.packages import DEFAULT_AUR_HELPER, PackageInstaller from caelestia.utils.dots.source import DotsSource, SourceError from caelestia.utils.dots.state import DotsState @@ -180,12 +180,12 @@ class Command: log("Installing configs...") deployer = Deployer() for entry in manifest.enabled_entries(): - src = source.working_path(expand(entry.src)) + src = source.working_path(entry.expanded_src()) if not src.exists(): warn(f"missing in source, skipping: {entry.src}") continue - dests = expand_dests(entry.dest) + dests = entry.expanded_dests() if not dests: warn(f"dest glob matched nothing, skipping: {entry.dest}") continue diff --git a/src/caelestia/utils/dots/manifest.py b/src/caelestia/utils/dots/manifest.py index f4acfb5..abf0f40 100644 --- a/src/caelestia/utils/dots/manifest.py +++ b/src/caelestia/utils/dots/manifest.py @@ -25,36 +25,38 @@ class ComponentError(Exception): """Raised when component flags are invalid or contradictory.""" -def expand(text: str) -> Path: +def _expand(text: str) -> Path: """Expand $VAR/${VAR} env vars (with XDG defaults) and ~ in a path.""" env = {**_XDG_DEFAULTS, **os.environ} return Path(Template(text).safe_substitute(env)).expanduser() -def expand_dests(dest: str) -> list[Path]: - """Expand globs within a dest path. - - Globs from the start until the segment with the last glob so subdirs are - created if they didn't exist previously. - """ - - expanded = expand(dest) - if not _GLOB_MAGIC.search(str(expanded)): - return [expanded] - - parts = expanded.parts - glob_idx = max(i for i, part in enumerate(parts) if _GLOB_MAGIC.search(part)) - pattern = str(Path(*parts[: glob_idx + 1])) - tail = parts[glob_idx + 1 :] - return [Path(match, *tail) for match in sorted(glob.glob(pattern))] - - @dataclass(frozen=True) class ManifestEntry: src: str dest: str + def expanded_src(self) -> Path: + return _expand(self.src) + + def expanded_dests(self) -> list[Path]: + """The dest path with globs expanded. + + Globs from the start until the segment with the last glob so subdirs are + created if they didn't exist previously. + """ + + expanded = _expand(self.dest) + if not _GLOB_MAGIC.search(str(expanded)): + return [expanded] + + parts = expanded.parts + glob_idx = max(i for i, part in enumerate(parts) if _GLOB_MAGIC.search(part)) + pattern = str(Path(*parts[: glob_idx + 1])) + tail = parts[glob_idx + 1 :] + return [Path(match, *tail) for match in sorted(glob.glob(pattern))] + @dataclass(frozen=True) class ManifestComponent: