Coverage for src/rhiza_task/tasks/lfs.py: 100%
28 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 04:13 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 04:13 +0000
1"""The Git LFS tasks: lfs.mk, as tasks.
3Three of the four are one git subcommand each. The fourth, ``lfs-install``, is 50 lines of
4platform shell and is **deliberately not ported as written** -- what it did and what it is
5now differ, so the change is stated here rather than discovered.
7lfs.mk's ``lfs-install`` has two branches. On Linux it runs ``apt-get install git-lfs``,
8with ``sudo`` when not root. On macOS it queries the GitHub releases API for the newest
9git-lfs, downloads the architecture-matched zip into ``.local/tmp``, extracts the binary
10into ``.local/bin``, and runs ``PATH=$PWD/.local/bin:$PATH git-lfs install``.
12The macOS branch does not leave a working installation. ``.local/bin`` is not on PATH
13after the recipe exits, and every other target in the fragment -- and every ``git lfs``
14anywhere else -- invokes the bare command, so ``make lfs-install && make lfs-pull``
15fails on a machine that had no git-lfs. The one thing the branch achieves that survives is
16the ``git lfs install`` at the end, which writes the filter and hook configuration into
17the repository.
19So this task does that part, and *reports* how to install the binary rather than
20downloading one. Two reasons beyond the broken branch: a task runner provisioned by
21``uvx`` should not be shelling out to ``sudo apt-get`` as a side effect of a target
22someone typed, and pinning a download URL to a release-API shape is a maintenance
23liability for something ``brew``/``apt``/``winget`` all do properly.
25Consumers who relied on the apt branch need one line of their own -- in CI, the
26``setup-git-lfs`` action or the distribution's package; locally, their package manager.
27"""
29from __future__ import annotations
31import sys
33from ..config import Config
34from ..spec import Failed, Guard, have, task
35from ..uv import tool
37SECTION = "Git LFS"
39INSTALL_URL = "https://github.com/git-lfs/git-lfs#installing"
41INSTALL_HINTS = {
42 "darwin": "brew install git-lfs",
43 "linux": "sudo apt-get install git-lfs (or your distribution's package)",
44 "win32": "winget install GitHub.GitLFS",
45}
46"""How to get the binary, by :data:`sys.platform`. Reported, never run."""
48HAVE_LFS = Guard(tool="git-lfs", reason=f"git-lfs not found; see {INSTALL_URL}")
49"""``git lfs <cmd>`` needs the ``git-lfs`` binary on PATH; git reports it as an unknown
50command otherwise, which is a confusing way to learn that a tool is missing."""
53def install_hint() -> str:
54 """Return the platform's install command, for the message a missing binary produces.
56 Returns:
57 A command to run, or the project's install page when the platform is unknown.
58 """
59 return INSTALL_HINTS.get(sys.platform, f"see {INSTALL_URL}")
62@task("lfs-install", "configure git-lfs for this repository", section=SECTION)
63def lfs_install(cfg: Config) -> None:
64 """Run ``git lfs install``, writing this repository's filter and hook configuration.
66 Args:
67 cfg: The resolved config.
69 Raises:
70 Failed: When the git-lfs binary is absent. A failure rather than a skip, unlike
71 every other tool guard in this module's siblings: installing is the one thing
72 this task exists to do, so it has nothing left to report success about.
73 """
74 if not have("git-lfs"):
75 print(f"[ERROR] git-lfs not found. Install it with:\n {install_hint()}")
76 raise Failed(1, "git-lfs is not installed")
77 tool("git", "lfs", "install", cwd=cfg.root)
80@task("lfs-pull", "download the LFS files for the current branch", section=SECTION, guards=(HAVE_LFS,))
81def lfs_pull(cfg: Config) -> None:
82 """Fetch and check out the LFS objects the working tree points at.
84 Args:
85 cfg: The resolved config.
86 """
87 tool("git", "lfs", "pull", cwd=cfg.root)
90@task("lfs-track", "list the patterns tracked by git-lfs", section=SECTION, guards=(HAVE_LFS,))
91def lfs_track(cfg: Config) -> None:
92 """Show the ``.gitattributes`` patterns routed through LFS.
94 Args:
95 cfg: The resolved config.
96 """
97 tool("git", "lfs", "track", cwd=cfg.root)
100@task("lfs-status", "show the status of LFS files", section=SECTION, guards=(HAVE_LFS,))
101def lfs_status(cfg: Config) -> None:
102 """Show which LFS files are modified, staged, or not yet pushed.
104 Args:
105 cfg: The resolved config.
106 """
107 tool("git", "lfs", "status", cwd=cfg.root)