Skip to content

chezmoi

chezmoi_add(path)

Start tracking a new file: copies it into the repo's chezmoi source dir.

Source code in src/personal_os_setup/tasks/system/chezmoi.py
def chezmoi_add(path: Path) -> TaskResult:
    """Start tracking a new file: copies it into the repo's chezmoi source dir."""
    chezmoi_path = _chezmoi_path()
    if chezmoi_path is None:
        return TaskResult(ok=False, summary="chezmoi not found on PATH")

    argv = [chezmoi_path, "--source", str(chezmoi_source_dir()), "add", "-v", str(path)]
    res = run(argv, check=False)
    details = (res.stdout + "\n" + res.stderr).strip()
    if res.returncode == 0:
        return TaskResult(
            ok=True,
            summary=f"chezmoi add: ok ({path} is now tracked in the repo)",
            details=details,
        )
    return TaskResult(ok=False, summary="chezmoi add: failed", details=details)

chezmoi_apply(targets=None)

Apply the selected dotfile(s) to the home directory without refreshing git-repo externals.

Source code in src/personal_os_setup/tasks/system/chezmoi.py
def chezmoi_apply(targets: list[Path] | None = None) -> TaskResult:
    """Apply the selected dotfile(s) to the home directory without refreshing git-repo externals."""
    chezmoi_path = _chezmoi_path()
    if chezmoi_path is None:
        return TaskResult(ok=False, summary="chezmoi not found on PATH")

    backed_up = _backup_before_overwrite(targets or [])

    argv = [
        chezmoi_path,
        "--source",
        str(chezmoi_source_dir()),
        "apply",
        "-v",
        "--force",
        "--parent-dirs",
        "--refresh-externals=never",
    ]
    argv.extend(str(t) for t in targets or [])
    res = run(argv, check=False)
    details = (res.stdout + "\n" + res.stderr).strip()
    if backed_up:
        backup_note = "Backed up before applying:\n" + "\n".join(str(p) for p in backed_up)
        details = f"{backup_note}\n\n{details}".strip()
    if res.returncode == 0:
        return TaskResult(ok=True, summary="chezmoi apply: ok", details=details)
    return TaskResult(ok=False, summary="chezmoi apply: failed", details=details)

chezmoi_clean_backups()

Delete every "__backup" copy sitting next to a managed file.

Only names that match a currently managed file are removed, so an unrelated file that happens to contain "_backup" is never touched. The live (managed) files are not modified.

Source code in src/personal_os_setup/tasks/system/chezmoi.py
def chezmoi_clean_backups() -> TaskResult:
    """Delete every "<name>_<timestamp>_backup<suffix>" copy sitting next to a managed file.

    Only names that match a currently managed file are removed, so an unrelated file that
    happens to contain "_backup" is never touched. The live (managed) files are not modified.
    """
    managed = chezmoi_managed_paths()
    if not managed:
        return TaskResult(ok=False, summary="chezmoi clean backups: no managed files found")

    patterns_by_dir: dict[Path, list[re.Pattern[str]]] = {}
    for path in managed:
        patterns_by_dir.setdefault(path.parent, []).append(_backup_name_pattern(path))

    removed: list[Path] = []
    failed: list[str] = []
    for directory, patterns in sorted(patterns_by_dir.items()):
        if not directory.is_dir():
            continue
        for candidate in sorted(directory.iterdir()):
            if not candidate.is_file() or not any(p.match(candidate.name) for p in patterns):
                continue
            try:
                candidate.unlink()
            except OSError as e:
                failed.append(f"{candidate}: {e}")
            else:
                removed.append(candidate)

    details = "\n".join([*(str(p) for p in removed), *(f"FAILED {f}" for f in failed)])
    if failed:
        return TaskResult(
            ok=False,
            summary=f"chezmoi clean backups: removed {len(removed)}, {len(failed)} failed",
            details=details,
        )
    return TaskResult(
        ok=True, summary=f"chezmoi clean backups: removed {len(removed)} file(s)", details=details
    )

chezmoi_forget(targets)

Stop tracking the given files: removes them from the repo's chezmoi source dir.

Leaves the live file on disk untouched -- only the repo's copy is removed.

Source code in src/personal_os_setup/tasks/system/chezmoi.py
def chezmoi_forget(targets: list[Path]) -> TaskResult:
    """Stop tracking the given files: removes them from the repo's chezmoi source dir.

    Leaves the live file on disk untouched -- only the repo's copy is removed.
    """
    chezmoi_path = _chezmoi_path()
    if chezmoi_path is None:
        return TaskResult(ok=False, summary="chezmoi not found on PATH")
    if not targets:
        return TaskResult(ok=False, summary="chezmoi forget: no targets given")

    argv = [
        chezmoi_path,
        "--source",
        str(chezmoi_source_dir()),
        "--force",
        "forget",
        *(str(t) for t in targets),
    ]
    res = run(argv, check=False)
    details = (res.stdout + "\n" + res.stderr).strip()
    if res.returncode == 0:
        return TaskResult(ok=True, summary="chezmoi forget: ok", details=details)
    return TaskResult(ok=False, summary="chezmoi forget: failed", details=details)

chezmoi_managed_paths()

List the destination paths chezmoi currently manages from this repo's source dir.

Includes regular files, scripts (e.g. run_onchange_*), and symlinks (symlink_*).

Returns an empty list if chezmoi isn't installed or the command fails, so callers (e.g. populating a UI selection list) can degrade gracefully instead of raising.

Source code in src/personal_os_setup/tasks/system/chezmoi.py
def chezmoi_managed_paths() -> list[Path]:
    """List the destination paths chezmoi currently manages from this repo's source dir.

    Includes regular files, scripts (e.g. `run_onchange_*`), and symlinks (`symlink_*`).

    Returns an empty list if chezmoi isn't installed or the command fails, so callers
    (e.g. populating a UI selection list) can degrade gracefully instead of raising.
    """
    chezmoi_path = _chezmoi_path()
    if chezmoi_path is None:
        return []

    res = run(
        [
            chezmoi_path,
            "--source",
            str(chezmoi_source_dir()),
            "managed",
            "--include=files,scripts,symlinks",
            "--path-style=absolute",
        ],
        check=False,
    )
    if res.returncode != 0:
        return []
    return sorted(Path(line) for line in res.stdout.splitlines() if line.strip())

chezmoi_refresh_zsh_externals()

Force-refresh oh-my-zsh, its custom plugins, and its theme from upstream.

https://www.chezmoi.io/user-guide/include-files-from-elsewhere/

Source code in src/personal_os_setup/tasks/system/chezmoi.py
def chezmoi_refresh_zsh_externals() -> TaskResult:
    """Force-refresh oh-my-zsh, its custom plugins, and its theme from upstream.

    https://www.chezmoi.io/user-guide/include-files-from-elsewhere/
    """
    chezmoi_path = _chezmoi_path()
    if chezmoi_path is None:
        return TaskResult(ok=False, summary="chezmoi not found on PATH")

    argv = [
        chezmoi_path,
        "--source",
        str(chezmoi_source_dir()),
        "apply",
        "-v",
        "--force",
        "--refresh-externals=always",
        str(Path.home() / ".oh-my-zsh"),
    ]
    res = run(argv, check=False)
    details = (res.stdout + "\n" + res.stderr).strip()
    if res.returncode == 0:
        return TaskResult(ok=True, summary="chezmoi: sync zsh plugins/theme: ok", details=details)
    return TaskResult(ok=False, summary="chezmoi: sync zsh plugins/theme: failed", details=details)