diff --git a/cmdeploy/src/cmdeploy/tests/test_util.py b/cmdeploy/src/cmdeploy/tests/test_util.py
new file mode 100644
index 00000000..486186c7
--- /dev/null
+++ b/cmdeploy/src/cmdeploy/tests/test_util.py
@@ -0,0 +1,54 @@
+
+from cmdeploy.util import collapse, get_git_hash, get_version_string, shell
+
+
+def test_collapse():
+ text = """
+ line 1
+ line 2
+ """
+ assert collapse(text) == "line 1 line 2"
+ assert collapse(" single line ") == "single line"
+
+
+def test_git_helpers_no_git(tmp_path):
+ # Not a git repo
+ assert get_git_hash(root=tmp_path) is None
+ assert get_version_string(root=tmp_path) == "unknown"
+
+
+def test_git_helpers_empty_repo(tmp_path):
+ shell("git init", cwd=tmp_path, check=True)
+ # No commits yet
+ assert get_git_hash(root=tmp_path) is None
+ assert get_version_string(root=tmp_path) == "unknown"
+
+
+def test_git_helpers_with_commits_and_diffs(tmp_path):
+ shell("git init", cwd=tmp_path, check=True)
+ shell("git config user.email you@example.com", cwd=tmp_path, check=True)
+ shell("git config user.name 'Your Name'", cwd=tmp_path, check=True)
+
+ # First commit
+ path = tmp_path / "file.txt"
+ path.write_text("content")
+ shell("git add file.txt", cwd=tmp_path, check=True)
+ shell("git commit -m initial", cwd=tmp_path, check=True)
+
+ git_hash = get_git_hash(root=tmp_path)
+ assert len(git_hash) >= 7 # usually 40, but git is git
+ assert get_version_string(root=tmp_path) == git_hash
+
+ # Create a diff
+ path.write_text("new content")
+ v = get_version_string(root=tmp_path)
+ assert v.startswith(git_hash + "\n")
+ assert "new content" in v
+ assert not v.endswith("\n")
+
+ # Commit again -> no diff
+ shell("git add file.txt", cwd=tmp_path, check=True)
+ shell("git commit -m second", cwd=tmp_path, check=True)
+ new_hash = get_git_hash(root=tmp_path)
+ assert new_hash != git_hash
+ assert get_version_string(root=tmp_path) == new_hash
diff --git a/cmdeploy/src/cmdeploy/util.py b/cmdeploy/src/cmdeploy/util.py
index 9f2c2da0..ed70236d 100644
--- a/cmdeploy/src/cmdeploy/util.py
+++ b/cmdeploy/src/cmdeploy/util.py
@@ -37,27 +37,31 @@ def shell(cmd, check=False, **kwargs):
return subprocess.run(collapse(cmd), shell=True, text=True, check=check, **kwargs)
-def get_git_hash():
+def get_git_hash(root=None):
"""Return the local HEAD commit hash, or None."""
+ if root is None:
+ root = _project_root()
result = shell(
"git rev-parse HEAD",
- cwd=str(_project_root()),
+ cwd=str(root),
)
if result.returncode == 0:
return result.stdout.strip()
return None
-def get_version_string():
+def get_version_string(root=None):
"""Return ``git_hash\\ngit_diff`` for the local working tree.
Used by :class:`~cmdeploy.deployers.GithashDeployer` to write
``/etc/chatmail-version`` and by ``lxc-status`` to compare
the deployed state against the local checkout.
"""
- git_hash = get_git_hash() or "unknown"
+ if root is None:
+ root = _project_root()
+ git_hash = get_git_hash(root=root) or "unknown"
try:
- git_diff = shell("git diff", cwd=str(_project_root())).stdout.strip()
+ git_diff = shell("git diff", cwd=str(root)).stdout.strip()
except Exception:
git_diff = ""
if git_diff:
diff --git a/doc/source/lxc.rst b/doc/source/lxc.rst
index d80aec2a..f4519aca 100644
--- a/doc/source/lxc.rst
+++ b/doc/source/lxc.rst
@@ -17,12 +17,6 @@ They share the host's kernel but run their own init system
(systemd), package manager, and network stack,
so the cmdeploy deployment scripts work exactly
as they would on a real Debian server or cloud VPS.
-Incus is
-`well supported
-`_
-on Debian, Ubuntu, Arch, Fedora,
-and other major distributions.
-
Prerequisites
-------------
@@ -38,15 +32,8 @@ Incus is in the default repositories::
sudo apt install incus
-**Older Debian / Ubuntu**: Use the
-`Zabbly package repository
-`_::
-
- curl -fsSL https://pkgs.zabbly.com/get/incus-stable | sudo bash
-
-**Arch Linux**::
-
- sudo pacman -S incus
+For other distros like Arch, Fedora etc. please check out
+`Incus support on many linux distros `_.
After installing, initialise and grant yourself access::