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

1"""The Git LFS tasks: lfs.mk, as tasks. 

2 

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. 

6 

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``. 

11 

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. 

18 

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. 

24 

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""" 

28 

29from __future__ import annotations 

30 

31import sys 

32 

33from ..config import Config 

34from ..spec import Failed, Guard, have, task 

35from ..uv import tool 

36 

37SECTION = "Git LFS" 

38 

39INSTALL_URL = "https://github.com/git-lfs/git-lfs#installing" 

40 

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.""" 

47 

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.""" 

51 

52 

53def install_hint() -> str: 

54 """Return the platform's install command, for the message a missing binary produces. 

55 

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}") 

60 

61 

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. 

65 

66 Args: 

67 cfg: The resolved config. 

68 

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) 

78 

79 

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. 

83 

84 Args: 

85 cfg: The resolved config. 

86 """ 

87 tool("git", "lfs", "pull", cwd=cfg.root) 

88 

89 

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. 

93 

94 Args: 

95 cfg: The resolved config. 

96 """ 

97 tool("git", "lfs", "track", cwd=cfg.root) 

98 

99 

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. 

103 

104 Args: 

105 cfg: The resolved config. 

106 """ 

107 tool("git", "lfs", "status", cwd=cfg.root)