Skip to content

Commit

Permalink
FEAT: automatically update Binder configuration (#440)
Browse files Browse the repository at this point in the history
  • Loading branch information
redeboer authored Oct 16, 2024
1 parent 19abc0a commit 6fd698c
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 2 deletions.
7 changes: 5 additions & 2 deletions src/compwa_policy/check_dev_files/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from typing import TYPE_CHECKING, Any

from compwa_policy.check_dev_files import (
binder,
black,
citation,
commitlint,
Expand Down Expand Up @@ -52,9 +53,10 @@
from compwa_policy.utilities.pyproject import PythonVersion


def main(argv: Sequence[str] | None = None) -> int:
def main(argv: Sequence[str] | None = None) -> int: # noqa: PLR0915
parser = _create_argparse()
args = parser.parse_args(argv)
doc_apt_packages = _to_list(args.doc_apt_packages)
environment_variables = _get_environment_variables(args.environment_variables)
is_python_repo = not args.no_python
repo_name, repo_title = _determine_repo_name_and_title(args)
Expand All @@ -80,7 +82,7 @@ def main(argv: Sequence[str] | None = None) -> int:
github_workflows.main,
precommit_config,
allow_deprecated=args.allow_deprecated_workflows,
doc_apt_packages=_to_list(args.doc_apt_packages),
doc_apt_packages=doc_apt_packages,
github_pages=args.github_pages,
keep_pr_linting=args.keep_pr_linting,
no_cd=args.no_cd,
Expand All @@ -94,6 +96,7 @@ def main(argv: Sequence[str] | None = None) -> int:
test_extras=_to_list(args.ci_test_extras),
)
if has_notebooks:
do(binder.main, dev_python_version, doc_apt_packages)
do(jupyter.main, args.no_ruff)
do(nbstripout.main, precommit_config, _to_list(args.allowed_cell_metadata))
do(
Expand Down
99 changes: 99 additions & 0 deletions src/compwa_policy/check_dev_files/binder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"""Add configuration for Binder.
See also https://mybinder.readthedocs.io/en/latest/using/config_files.html.
"""

from __future__ import annotations

import os
from textwrap import dedent
from typing import TYPE_CHECKING

from compwa_policy.errors import PrecommitError
from compwa_policy.utilities import CONFIG_PATH
from compwa_policy.utilities.executor import Executor
from compwa_policy.utilities.match import git_ls_files

if TYPE_CHECKING:
from pathlib import Path

from compwa_policy.utilities.pyproject import PythonVersion


def main(python_version: PythonVersion, apt_packages: list[str]) -> None:
with Executor() as do:
do(_update_apt_txt, apt_packages)
do(_update_post_build)
do(_make_executable, CONFIG_PATH.binder / "postBuild")
do(_update_runtime_txt, python_version)


def _update_apt_txt(apt_packages: list[str]) -> None:
apt_txt = CONFIG_PATH.binder / "apt.txt"
if not apt_packages and apt_txt.exists():
apt_txt.unlink()
msg = f"Removed {apt_txt}, because --doc-apt-packages does not specify any packages."
raise PrecommitError(msg)
apt_packages = sorted(set(apt_packages))
__update_file(
expected_content="\n".join(apt_packages) + "\n",
path=apt_txt,
)


def _update_post_build() -> None:
expected_content = dedent("""
#!/bin/bash
set -ex
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.cargo/env
""").strip()
if "uv.lock" in set(git_ls_files(untracked=True)):
expected_content += dedent(R"""
uv export \
--extra jupyter \
--extra notebooks \
> requirements.txt
uv pip install \
--requirement requirements.txt \
--system
uv cache clean
""")
else:
expected_content += dedent(R"""
uv pip install \
--editable '.[jupyter,notebooks]' \
--no-cache \
--system
""")
__update_file(
expected_content.strip() + "\n",
path=CONFIG_PATH.binder / "postBuild",
)


def _make_executable(path: Path) -> None:
if os.access(path, os.X_OK):
return
msg = f"{path} has been made executable"
path.chmod(0o755)
raise PrecommitError(msg)


def _update_runtime_txt(python_version: PythonVersion) -> None:
__update_file(
expected_content=f"python-{python_version}\n",
path=CONFIG_PATH.binder / "runtime.txt",
)


def __update_file(expected_content: str, path: Path) -> None:
path.parent.mkdir(exist_ok=True)
if path.exists():
with open(path) as stream:
if stream.read() == expected_content:
return
with open(path, "w") as stream:
stream.write(expected_content)
msg = f"Updated {path}"
raise PrecommitError(msg)
1 change: 1 addition & 0 deletions src/compwa_policy/utilities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@


class _ConfigFilePaths(NamedTuple):
binder: Path = Path(".binder")
citation: Path = Path("CITATION.cff")
codecov: Path = Path("codecov.yml")
conda: Path = Path("environment.yml")
Expand Down

0 comments on commit 6fd698c

Please sign in to comment.