Source code for punctual.package

from colorama import Fore, Style
import json
import os
from subprocess import run

from .utils import use_dir, root_package_dir, join, logs, log
from .link import Link


[docs]class Package: """ An object representing a dotfile package. :param package_name: The directory name of the package to load :param force: Whether or not to force installation """ def __init__(self, package_name, force=False): self.package_dir = join(root_package_dir, package_name) self.package_name = package_name self.name = os.path.basename(package_name) self.force = force package_config = {} with use_dir(self.package_dir): with open('config.json', 'r') as f: package_config = json.load(f) self.include_hidden = package_config.get('includeHidden', False) self.links = [ Link(src, dest) for src, dest in package_config.get('links', {}).items() ] self._autolink(package_config) self.sub_packages = [ Package(join(package_name, sub_package_name), force=force) for sub_package_name in package_config.get('packages', []) ] self._autodiscover_packages(package_config) self.hooks = { 'pre_install': log(f'Initiating install of {self.name}'), 'post_install': logs(f'Installed {self.name}'), 'pre_delete': log(f'Initiating deletion of {self.name}'), 'post_delete': logs(f'Deleted {self.name}'), } self.hooks.update(package_config.get('hooks', {})) self.force = package_config.get('force', force) def _call_hook(self, name): hook = self.hooks[name] if callable(hook): hook() elif isinstance(hook, str): run(hook, shell=True) def _in_existing_links(self, name): existing_links = set([l.src for l in self.links]) return name in existing_links def _autodiscover_packages(self, package_config): if not package_config.get('autodiscover', False): return def _is_sub_package(f): if not f.is_dir(): return False if f.name.startswith('.') and not self.include_hidden: return False if self._in_existing_links(f.name): return False with use_dir(f.name): return 'config.json' in [g.name for g in os.scandir()] sub_packages = [ Package(join(self.package_name, f.name), force=self.force) for f in os.scandir() if _is_sub_package(f) ] self.sub_packages += sub_packages def _autolink(self, package_config): if not package_config.get('autolink', False): return links = [ Link(f.name, join(os.path.expanduser('~/'), f.name)) for f in os.scandir() if f.name != 'config.json' and not self._in_existing_links(f.name) ] self.links += links @property def installed(self): return all([link.exists for link in self.links]) @property def status_text(self): if self.installed: return f'{Fore.GREEN}{Style.BRIGHT}installed{Style.RESET_ALL}' return f'{Fore.RED}{Style.BRIGHT}not installed{Style.RESET_ALL}'
[docs] def install(self): """ Installs the package, top level links, and sub packages. """ with use_dir(self.package_dir): self._call_hook('pre_install') for link in self.links: link.install(force=self.force) for sub_package in self.sub_packages: sub_package.install() self._call_hook('post_install')
[docs] def delete(self): """ Deletes the package, top level links, and sub packages. """ with use_dir(self.package_dir): self._call_hook('pre_delete') for link in self.links: link.delete() for sub_package in self.sub_packages: sub_package.delete() self._call_hook('post_delete')