dotfiles Module¶
Install and manage dotfiles by creating symlinks from a dotfiles repository to the home directory, with support for hostname-specific overrides.
Import¶
Directory Structure¶
The dotfiles module expects a specific directory structure:
~/dotfiles/
├── common/ # Files for all hosts
│ ├── .bashrc
│ ├── .vimrc
│ └── .config/
│ └── nvim/
│ └── init.lua
├── hosts/ # Host-specific overrides
│ ├── laptop/
│ │ └── .bashrc # Overrides common/.bashrc on 'laptop'
│ └── server/
│ └── .config/
│ └── nvim/
│ └── init.lua
common/contains files installed on all hostshosts/<hostname>/contains host-specific overrides that take precedence- Nested directories (e.g.,
.config/nvim/) are fully supported
Functions¶
install¶
Install dotfiles by creating symlinks.
dotfiles.install(
dotfiles_dir="~/dotfiles",
target_dir=None, # Default: $HOME
host=None, # Default: current hostname
backup=True, # Backup existing files
force=False, # Replace symlinks pointing elsewhere
sudo=False,
)
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
dotfiles_dir |
str/Path | required | Path to dotfiles repository |
target_dir |
str/Path | $HOME |
Where to create symlinks |
host |
str | current hostname | Hostname for overrides |
backup |
bool | True |
Backup existing files before replacing |
force |
bool | False |
Replace symlinks pointing elsewhere |
sudo |
bool | False |
Use sudo for privileged locations |
Returns: ChangeList with installation changes.
Behavior:
- Creates symlinks for each file in
common/ - Applies host-specific overrides from
hosts/<hostname>/ - Creates parent directories as needed
- Existing regular files are backed up and replaced
- Existing correct symlinks are skipped (idempotent)
- Existing symlinks pointing elsewhere are skipped unless
force=True
uninstall¶
Remove dotfile symlinks that point to the dotfiles repository.
Parameters: Same as install().
Returns: ChangeList with removal changes.
Note: Only removes symlinks pointing to files in your dotfiles repository. Regular files and symlinks pointing elsewhere are left untouched.
list_dotfiles¶
List all dotfiles that would be installed.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
dotfiles_dir |
str/Path | required | Path to dotfiles repository |
host |
str | current hostname | Hostname for overrides |
Returns: Dict[Path, Path] mapping relative target paths to absolute source paths.
status¶
Get the current status of all dotfiles.
Returns: List[DotfileStatus] with status for each dotfile.
Each DotfileStatus has:
source— Source file in dotfiles repotarget— Target path in home directorystate— Current state (see below)needs_action— Whether installation is needed
Change Types¶
The module defines these change types:
DotfileLinked— Symlink createdDotfileBackedUp— Existing file backed upDotfileSkipped— File skipped (with reason)DotfileUnlinked— Symlink removed
DotfileState Enum¶
| State | Description |
|---|---|
MISSING |
Target doesn't exist |
CORRECT_LINK |
Symlink points to our source |
WRONG_LINK |
Symlink points elsewhere |
REGULAR_FILE |
Regular file exists |
DIRECTORY |
Directory exists (not a symlink) |
Skipped Files¶
By default, these files are skipped:
.git/directory and all contentsREADME.md,README,LICENSE,LICENSE.md.gitignore,.gitmodules- Files starting with
.dotfiles(config files for the dotfiles repo itself)
Examples¶
Basic Installation¶
Preview Changes¶
from fscm.modules import dotfiles
# List what would be installed
for target, source in dotfiles.list_dotfiles("~/dotfiles").items():
print(f"{target} -> {source}")
# Check status
for s in dotfiles.status("~/dotfiles"):
print(f"{s.target}: {s.state.value}")
Force Replace Existing Symlinks¶
from fscm.modules import dotfiles
# Replace even symlinks pointing elsewhere
dotfiles.install("~/dotfiles", force=True)
Install for Different Host¶
from fscm.modules import dotfiles
# Install using laptop-specific overrides
dotfiles.install("~/dotfiles", host="laptop")
Install to Custom Location¶
from fscm.modules import dotfiles
# Install to a different target directory
dotfiles.install(
"~/dotfiles",
target_dir="/home/deploy",
sudo=True,
)
Uninstall¶
Complete Example¶
#!/usr/bin/env python3
"""Set up dotfiles on a new machine."""
from fscm.modules import dotfiles
def main():
# Check what needs to be done
statuses = dotfiles.status("~/dotfiles")
needs_install = [s for s in statuses if s.needs_action]
if not needs_install:
print("All dotfiles already installed!")
return
print(f"Installing {len(needs_install)} dotfiles...")
# Install with backup
changes = dotfiles.install("~/dotfiles", backup=True)
# Report what was done
for change in changes:
print(f" {change.msg.format(**change.__dict__)}")
if __name__ == "__main__":
main()