xdg-config-stow

Crates.ioxdg-config-stow
lib.rsxdg-config-stow
version0.1.6
created_at2026-01-24 19:12:03.677158+00
updated_at2026-01-24 23:54:56.501477+00
descriptionXDG-centric GNU stow replacement for dotfile management
homepagehttps://github.com/josefaidt/xdg-config-stow
repositoryhttps://github.com/josefaidt/xdg-config-stow
max_upload_size
id2067282
size90,291
josef (josefaidt)

documentation

README

xdg-config-stow

An XDG-centric GNU stow replacement for managing dotfiles, written in Rust.

Features

  • Smart symlinking of dotfiles from a .config/ directory to XDG_CONFIG_HOME (or $HOME/.config)
  • Support for .stowignore files using gitignore-style patterns
  • Easy removal of stowed packages with the --rm flag
  • Safe operation - verifies symlinks before removal

Installation

Install from crates.io:

cargo install xdg-config-stow

Or build from source:

cargo build --release
# Binary will be in target/release/xdg-config-stow

Usage

Run xdg-config-stow from your dotfiles repository root (the directory containing .config/).

Stow a package

Link all files from .config/fish to $HOME/.config/fish:

xdg-config-stow fish

Remove a stowed package

Remove symlinks for a previously stowed package:

xdg-config-stow --rm fish

Dry run mode

Preview what changes would be made without actually making them. Output uses colored diff-like syntax with + for additions and - for removals:

# See what would be stowed
xdg-config-stow --dry-run fish
# Output:
# DRY RUN: No changes will be made
#
# + config.fish -> /path/to/dotfiles/.config/fish/config.fish
# + functions/ -> /path/to/dotfiles/.config/fish/functions

# See what would be removed
xdg-config-stow --rm --dry-run fish
# Output:
# DRY RUN: No changes will be made
#
# - config.fish
# - functions/

Ignoring files

Create a .stowignore file inside your package directory (e.g., .config/fish/.stowignore) using gitignore syntax:

# Ignore completions directory
completions/

# Ignore specific files
fish_variables

Note: If you add a .stowignore file after initially stowing a package, simply re-run the stow command to automatically update the symlinks:

xdg-config-stow fish  # Automatically migrates and respects new ignore rules

Example Directory Structure

my-dotfiles-repo/
  .config/
    fish/
      config.fish
      functions/
      .stowignore
    nvim/
      init.lua
      lua/
  README.md
  setup.sh

How it works

  1. Detects the .config/ directory in your current working directory
  2. Resolves the target directory using XDG_CONFIG_HOME or falls back to $HOME/.config
  3. Creates symlinks for all files in the specified package
  4. Respects .stowignore files for excluding specific paths
  5. Safely verifies symlink targets when removing packages

Requirements

  • Rust 1.85 or later (for building)
  • Unix-like operating system (Linux, macOS, BSD)
  • Write access to XDG_CONFIG_HOME or $HOME/.config

Development

Running Tests

The project includes comprehensive unit and integration tests:

# Run all tests
cargo test

# Run with output
cargo test -- --nocapture

# Run specific test
cargo test test_stow_single_file

See TESTS.md for detailed test coverage information.

Test Coverage

  • 23 total tests covering:
    • Core stowing/unstowing functionality
    • .stowignore pattern matching
    • Error handling and edge cases
    • XDG_CONFIG_HOME resolution
    • Complex directory structures
    • Automatic migration safety (6 dedicated safety tests)

Contributing

Contributions are welcome! Before submitting a pull request:

  1. Ensure your code is properly formatted: cargo fmt
  2. Check for linting issues: cargo clippy -- -D warnings
  3. Run all tests: cargo test

Git Hooks (Optional)

To automatically run these checks before every commit, you can set up git hooks:

./scripts/setup-hooks.sh

This will install a pre-commit hook that runs formatting checks, clippy, and tests before allowing commits. You can bypass the hook when needed with git commit --no-verify.

License

MIT

Commit count: 13

cargo fmt