diff --git a/pkgs/applications/editors/emacs/elisp-packages/update-from-overlay.py b/pkgs/applications/editors/emacs/elisp-packages/update-from-overlay.py index 3dc35bfa8583..e4860da7c683 100755 --- a/pkgs/applications/editors/emacs/elisp-packages/update-from-overlay.py +++ b/pkgs/applications/editors/emacs/elisp-packages/update-from-overlay.py @@ -2,6 +2,7 @@ #! nix-shell -i python3 -p nix git # linter: ruff check update-from-overlay.py +# formatter: ruff format update-from-overlay.py import argparse import contextlib @@ -15,63 +16,69 @@ import subprocess import sys import urllib.request + @dataclasses.dataclass class EmacsOverlay: - git_url : str = 'https://github.com/nix-community/emacs-overlay' - raw_url : str = 'https://raw.githubusercontent.com/nix-community/emacs-overlay' + git_url: str = "https://github.com/nix-community/emacs-overlay" + raw_url: str = "https://raw.githubusercontent.com/nix-community/emacs-overlay" # The field declaration here is a hack around the error: # ValueError: mutable default for field elisp_packages_set is not allowed: use default_factory # See more at https://peps.python.org/pep-0557/#mutable-default-values - elisp_packages_set : dict[str, dict] = dataclasses.field(default_factory = lambda: { - 'elpa': { - 'location': 'repos/elpa', - 'basename': 'elpa-generated.nix', - 'nix_attrs': ['elpaPackages'] - }, - 'elpa-devel': { - 'location': 'repos/elpa', - 'basename': 'elpa-devel-generated.nix', - 'nix_attrs': ['elpaDevelPackages'] - }, - 'melpa': { - 'location': 'repos/melpa', - 'basename': 'recipes-archive-melpa.json', - 'nix_attrs': ['melpaPackages', - 'melpaStablePackages'] - }, - 'nongnu': { - 'location': 'repos/nongnu', - 'basename': 'nongnu-generated.nix', - 'nix_attrs': ['nongnuPackages'] - }, - 'nongnu-devel': { - 'location': 'repos/nongnu', - 'basename': 'nongnu-devel-generated.nix', - 'nix_attrs': ['nongnuDevelPackages'] - }, - }) + elisp_packages_set: dict[str, dict] = dataclasses.field( + default_factory=lambda: { + "elpa": { + "location": "repos/elpa", + "basename": "elpa-generated.nix", + "nix_attrs": ["elpaPackages"], + }, + "elpa-devel": { + "location": "repos/elpa", + "basename": "elpa-devel-generated.nix", + "nix_attrs": ["elpaDevelPackages"], + }, + "melpa": { + "location": "repos/melpa", + "basename": "recipes-archive-melpa.json", + "nix_attrs": ["melpaPackages", "melpaStablePackages"], + }, + "nongnu": { + "location": "repos/nongnu", + "basename": "nongnu-generated.nix", + "nix_attrs": ["nongnuPackages"], + }, + "nongnu-devel": { + "location": "repos/nongnu", + "basename": "nongnu-devel-generated.nix", + "nix_attrs": ["nongnuDevelPackages"], + }, + } + ) - def master_sha (self) -> str: - '''Return the SHA of current master tip.''' - cmdline = ['git', 'ls-remote', '--branches', self.git_url, 'refs/heads/master'] - result = subprocess.run(cmdline, capture_output = True, text = True) + def master_sha(self) -> str: + """Return the SHA of current master tip.""" + cmdline = ["git", "ls-remote", "--branches", self.git_url, "refs/heads/master"] + result = subprocess.run(cmdline, capture_output=True, text=True) return result.stdout.split()[0] + @dataclasses.dataclass class HereDirectory: - path : pathlib.Path = pathlib.Path('.').resolve() + path: pathlib.Path = pathlib.Path(".").resolve() def git_root(self) -> pathlib.Path: - '''Returns the root directory of Git repository.''' - cmdline = ['git', 'rev-parse', '--show-toplevel'] - result = subprocess.run(cmdline, capture_output = True, text = True) + """Returns the root directory of Git repository.""" + cmdline = ["git", "rev-parse", "--show-toplevel"] + result = subprocess.run(cmdline, capture_output=True, text=True) return pathlib.Path(result.stdout.rstrip()).resolve() -def main (emacs_overlay : EmacsOverlay, - here_directory : HereDirectory, - argument_parser : argparse.ArgumentParser) -> None: - '''The entry point.''' + +def main( + emacs_overlay: EmacsOverlay, + here_directory: HereDirectory, + argument_parser: argparse.ArgumentParser, +) -> None: + """The entry point.""" args = argument_parser.parse_args() @@ -81,67 +88,80 @@ def main (emacs_overlay : EmacsOverlay, sha = args.commit match args.loglevel.lower(): - case 'debug': + case "debug": loglevel = logging.DEBUG - case 'info': + case "info": loglevel = logging.INFO case _: loglevel = logging.INFO - logger = get_logger(loglevel = loglevel) + logger = get_logger(loglevel=loglevel) - datestring = datetime.datetime.today().strftime('%Y-%m-%d') + datestring = datetime.datetime.today().strftime("%Y-%m-%d") # The loops are decoupled because each phase interferes with the next ones; # e.g. it is pretty possible that an Elisp package updated in fetch_fileset # breaks the check because of another Elisp package. for name in emacs_overlay.elisp_packages_set: - fetch_fileset(name, sha, - emacs_overlay = emacs_overlay, - here_directory = here_directory, - logger = logger) + fetch_fileset( + name, + sha, + emacs_overlay=emacs_overlay, + here_directory=here_directory, + logger=logger, + ) for name in emacs_overlay.elisp_packages_set: - check_fileset(name, - emacs_overlay = emacs_overlay, - here_directory = here_directory, - logger = logger) + check_fileset( + name, + emacs_overlay=emacs_overlay, + here_directory=here_directory, + logger=logger, + ) for name in emacs_overlay.elisp_packages_set: - commit_fileset(name, sha, datestring = datestring, - emacs_overlay = emacs_overlay, - here_directory = here_directory, - logger = logger) + commit_fileset( + name, + sha, + datestring=datestring, + emacs_overlay=emacs_overlay, + here_directory=here_directory, + logger=logger, + ) + def get_argument_parser() -> argparse.ArgumentParser: - '''Return a getopt-style parser for command-line arguments.''' + """Return a getopt-style parser for command-line arguments.""" parser = argparse.ArgumentParser( - description = 'Fetch and commit Elisp package sets from nix-community/emacs-overlay', + description="Fetch and commit Elisp package sets from nix-community/emacs-overlay", ) parser.add_argument( - '--commit', - help = 'Commit to be fetched, in SHA format. If not specified, retrieve the master tip.', - default = None + "--commit", + help="Commit to be fetched, in SHA format. If not specified, retrieve the master tip.", + default=None, ) parser.add_argument( - '--loglevel', - help = 'Level of noisiness of logging messages. Values currently supported: INFO (default), DEBUG.', - default = 'InFo' + "--loglevel", + help="Level of noisiness of logging messages. Values currently supported: INFO (default), DEBUG.", + default="InFo", ) return parser -def get_logger (loglevel: int) -> logging.Logger: - '''Return a basic logging facility to emit messages over console (stdout).''' - logger = logging.getLogger('update-from-overlay') + +def get_logger(loglevel: int) -> logging.Logger: + """Return a basic logging facility to emit messages over console (stdout).""" + logger = logging.getLogger("update-from-overlay") # Set the lowest level here, so that it does not clobber the one provided by # the function argument logger.setLevel(logging.DEBUG) - console_formatter = logging.Formatter(fmt='%(asctime)s - %(levelname)s - %(funcName)s - %(message)s', - datefmt='[%Y-%m-%d %H:%M:%S]') + console_formatter = logging.Formatter( + fmt="%(asctime)s - %(levelname)s - %(funcName)s - %(message)s", + datefmt="[%Y-%m-%d %H:%M:%S]", + ) - console_handler = logging.StreamHandler(stream = sys.stdout) + console_handler = logging.StreamHandler(stream=sys.stdout) console_handler.setLevel(loglevel) console_handler.setFormatter(console_formatter) @@ -149,108 +169,130 @@ def get_logger (loglevel: int) -> logging.Logger: return logger -def fetch_fileset (name: str, sha: str, - emacs_overlay : EmacsOverlay, - here_directory : HereDirectory, - logger : logging.Logger) -> None: - '''Fetch a fileset from emacs overlay. + +def fetch_fileset( + name: str, + sha: str, + emacs_overlay: EmacsOverlay, + here_directory: HereDirectory, + logger: logging.Logger, +) -> None: + """Fetch a fileset from emacs overlay. Arguments: name -- The name of fileset. sha -- The commit SHA of emacs-overlay from which the files are retrieved. - ''' - logger.debug('BEGIN') + """ + logger.debug("BEGIN") - location = emacs_overlay.elisp_packages_set[name]['location'] - basename = emacs_overlay.elisp_packages_set[name]['basename'] - url = f'{emacs_overlay.raw_url}/{sha}/{location}/{basename}' + location = emacs_overlay.elisp_packages_set[name]["location"] + basename = emacs_overlay.elisp_packages_set[name]["basename"] + url = f"{emacs_overlay.raw_url}/{sha}/{location}/{basename}" destination = pathlib.Path(here_directory.path, basename).resolve() - logger.debug(f'Getting {url}') + logger.debug(f"Getting {url}") - with urllib.request.urlopen (url) as input_stream, open(destination, 'wb') as output_file: - logger.info(f'Installing {destination}') + with ( + urllib.request.urlopen(url) as input_stream, + open(destination, "wb") as output_file, + ): + logger.info(f"Installing {destination}") shutil.copyfileobj(input_stream, output_file) - logger.debug('END') + logger.debug("END") -def check_fileset (name: str, - emacs_overlay : EmacsOverlay, - here_directory : HereDirectory, - logger : logging.Logger) -> None: - '''Smoke-test the fileset. + +def check_fileset( + name: str, + emacs_overlay: EmacsOverlay, + here_directory: HereDirectory, + logger: logging.Logger, +) -> None: + """Smoke-test the fileset. Arguments: name -- The name of fileset. - ''' - logger.debug('BEGIN') + """ + logger.debug("BEGIN") - for nix_attr in emacs_overlay.elisp_packages_set[name]['nix_attrs']: - - cmdline = ['nix-instantiate', '--show-trace', here_directory.git_root(), - '-A', f'emacsPackages.{nix_attr}'] + for nix_attr in emacs_overlay.elisp_packages_set[name]["nix_attrs"]: + cmdline = [ + "nix-instantiate", + "--show-trace", + here_directory.git_root(), + "-A", + f"emacsPackages.{nix_attr}", + ] environment = os.environ - environment['NIXPKGS_ALLOW_BROKEN'] = '1' + environment["NIXPKGS_ALLOW_BROKEN"] = "1" - logger.info(f'Testing {nix_attr}') + logger.info(f"Testing {nix_attr}") # TODO: capture the output (to put it in the logfile). - result = subprocess.run(cmdline, capture_output = True, text = True) - logger.debug(f''' + result = subprocess.run(cmdline, capture_output=True, text=True) + logger.debug(f""" Shell Command: {result.args} Output: -{result.stdout}''') +{result.stdout}""") - logger.debug('END') + logger.debug("END") -def commit_fileset (name: str, sha: str, datestring : str | None, - emacs_overlay : EmacsOverlay, - here_directory : HereDirectory, - logger : logging.Logger) -> None: - '''Commit the fileset. + +def commit_fileset( + name: str, + sha: str, + datestring: str | None, + emacs_overlay: EmacsOverlay, + here_directory: HereDirectory, + logger: logging.Logger, +) -> None: + """Commit the fileset. Arguments: name -- The name of fileset. sha -- The commit SHA of emacs-overlay from which the files are retrieved. datestring -- The date to be written on commit message. If None, use the current time. - ''' - logger.debug('BEGIN') + """ + logger.debug("BEGIN") - nix_attrs = emacs_overlay.elisp_packages_set[name]['nix_attrs'] - basename = emacs_overlay.elisp_packages_set[name]['basename'] + nix_attrs = emacs_overlay.elisp_packages_set[name]["nix_attrs"] + basename = emacs_overlay.elisp_packages_set[name]["basename"] if datestring is None: - datestring = datetime.datetime.today().strftime('%Y-%m-%d') - logger.debug(f'Date string not provided, using {datestring}') + datestring = datetime.datetime.today().strftime("%Y-%m-%d") + logger.debug(f"Date string not provided, using {datestring}") else: - logger.debug(f'Date string was provided: {datestring}') + logger.debug(f"Date string was provided: {datestring}") - cmdline_verify = ['git', 'diff', '--exit-code', '--quiet', '--', basename] + cmdline_verify = ["git", "diff", "--exit-code", "--quiet", "--", basename] result_verify = subprocess.run(cmdline_verify) if result_verify.returncode != 0: - attrs = ', '.join(nix_attrs) - commit_message = f'''{attrs}: Updated at {datestring} (from emacs-overlay) + attrs = ", ".join(nix_attrs) + commit_message = f"""{attrs}: Updated at {datestring} (from emacs-overlay) emacs-overlay commit: {sha} -''' - cmdline_commit = ['git', 'commit', '--message', commit_message, '--', basename] - result_commit = subprocess.run(cmdline_commit, capture_output = True, text = True) - logger.info(f'File {basename} committed') - logger.debug(f''' +""" + cmdline_commit = ["git", "commit", "--message", commit_message, "--", basename] + result_commit = subprocess.run(cmdline_commit, capture_output=True, text=True) + logger.info(f"File {basename} committed") + logger.debug(f""" Shell Command: {result_commit.args} Output: -{result_commit.stdout}''') +{result_commit.stdout}""") else: - logger.info(f'File {basename} not modified, skipping') + logger.info(f"File {basename} not modified, skipping") - logger.debug('END') + logger.debug("END") -if __name__ == '__main__': + +if __name__ == "__main__": emacs_overlay = EmacsOverlay() here_directory = HereDirectory() argument_parser = get_argument_parser() with contextlib.chdir(here_directory.path): - main(emacs_overlay = emacs_overlay, - here_directory = here_directory, - argument_parser = argument_parser) + main( + emacs_overlay=emacs_overlay, + here_directory=here_directory, + argument_parser=argument_parser, + )