1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
"""Pin the packages the dotfiles assume are present.
Three packages are not optional extras: something the dotfiles ship depends
on each one, and when the package is missing the dependent silently does the
wrong thing rather than failing.
- libreoffice-fresh :: common/.config/mimeapps.list maps presentations,
documents and spreadsheets to libreoffice-impress/-writer/-calc. With the
package absent those .desktop files don't exist, so xdg-mime falls through
to the next application claiming the type — on a machine with the winvm
dotfiles that is powerpoint.desktop, which boots a Windows VM to open a
deck (2026-09-18).
- imv :: gui-open --image execs imv, and without it every agent-side image
render fails with "required application is unavailable" (2026-09-18).
- git-lfs :: a repo tracking globs in LFS fails every checkout and merge
with "smudge filter lfs failed" (2026-09-20).
All three were installed before the 2026-08-13 rebuild and absent after it,
which is the regression this pins: they are dependencies of shipped defaults,
so the installer has to declare them rather than leave them to whatever a
machine happens to carry.
Method mirrors test_required_software: sed-extract supplemental_software from
the real `archsetup`, stub pacman_install as a recorder, run it, and assert
against what it actually invoked. Running the function beats matching its
source text, because the property under test is "every machine installs this"
and only a run resolves the conditionals that could make that false. The
function is run once per desktop environment for the same reason.
Run from repo root:
python3 -m unittest tests.installer-steps.test_dotfiles_dependency_packages
"""
import os
import subprocess
import textwrap
import unittest
REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
ARCHSETUP = os.path.join(REPO_ROOT, "archsetup")
DEPENDENCY_PACKAGES = ("libreoffice-fresh", "imv", "git-lfs")
# Every desktop environment the installer branches on inside this function.
DESKTOP_ENVS = ("dwm", "hyprland")
def declared_packages(desktop_env):
"""Return (exit_code, [pacman package, ...]) for one desktop environment.
Everything the function calls besides pacman_install is stubbed to a no-op,
so the run records package declarations and nothing else. aur_install is
deliberately separate: these three are pacman packages, and folding the two
recorders together would let an AUR declaration satisfy the pin.
"""
script = textwrap.dedent(f"""\
desktop_env={desktop_env}
display() {{ :; }}
aur_install() {{ :; }}
mask_fwupd_passim() {{ :; }}
run_task() {{ :; }}
error_warn() {{ :; }}
pacman_install() {{ echo "$1"; }}
source <(sed -n '/^supplemental_software() {{/,/^}}/p' "{ARCHSETUP}")
supplemental_software
""")
result = subprocess.run(
["bash", "-c", script], capture_output=True, text=True, timeout=30,
)
return result.returncode, result.stdout.split()
class DotfilesDependencyPackages(unittest.TestCase):
# ------------------------------------------------------------ normal ----
def test_each_dependency_package_is_installed(self):
rc, pkgs = declared_packages("hyprland")
self.assertEqual(rc, 0)
for package in DEPENDENCY_PACKAGES:
with self.subTest(package=package):
self.assertIn(
package, pkgs,
f"{package} is a dependency of a shipped dotfiles default "
"and must be declared",
)
# ---------------------------------------------------------- boundary ----
def test_each_is_declared_exactly_once(self):
# A second declaration is dead weight and drifts out of sync with the
# first when one of them is edited.
rc, pkgs = declared_packages("hyprland")
self.assertEqual(rc, 0)
for package in DEPENDENCY_PACKAGES:
with self.subTest(package=package):
self.assertEqual(pkgs.count(package), 1)
# ------------------------------------------------------------- error ----
def test_none_is_gated_behind_a_desktop_environment(self):
# The dotfiles defaults that need these apply on every DE, so a
# declaration reachable under only one of them would leave the same
# hole on the other.
for env in DESKTOP_ENVS:
rc, pkgs = declared_packages(env)
self.assertEqual(rc, 0)
for package in DEPENDENCY_PACKAGES:
with self.subTest(desktop_env=env, package=package):
self.assertIn(package, pkgs)
def test_harness_observes_desktop_environment_gating(self):
# The control for the test above: ranger IS gated to dwm on purpose, so
# if this run can't see that, the DE-independence assertion is vacuous
# and would pass against a gated package too.
_, dwm = declared_packages("dwm")
_, hyprland = declared_packages("hyprland")
self.assertIn("ranger", dwm)
self.assertNotIn("ranger", hyprland)
if __name__ == "__main__":
unittest.main()
|