dotstate

repository·main·Indexed 18 days ago

https://github.com/serkanyersen/dotstate

A modern, secure, and user-friendly dotfile manager built with Rust. DotState simplifies configuration syncing across machines using Git, profiles, and automatic symlink management via an intuitive TUI or CLI. It supports profile inheritance, common files shared across environments, and automated repository management for GitHub or custom Git hosts.

Tokens
25K
Snippets
97
Records
134
Agent score
62%

What's inside dotstate

  1. How DotState manages files and profiles

    main

    DotState uses a specific model to manage configurations across different environments:

    • Storage: Your dotfiles are stored in a Git repository, typically located at ~/.config/dotstate/storage.
    • Symlinks: When you add a file to DotState, the original file is moved to the repository, and a symlink is created at the original location pointing to the file in the repo.
    • Profiles: You can create separate profiles (e.g., work, personal, mac, linux) to manage different sets of configurations.
    • Inheritance: Profiles support inheritance. A child profile can extend a parent profile; child files will override parent files, allowing you to only define the differences.
    • Common Files: Files shared across all profiles are stored in a common section and are linked regardless of which profile is currently active.
    • Syncing: The sync operation automates the Git workflow (commit, pull, and push) to keep your remote repository up to date.
  2. Configure DotState First-time Setup modes

    main

    When running dotstate for the first time, you must choose between two setup modes:

    1. Create for me (GitHub): DotState automatically creates a repository on your GitHub account. This requires a GitHub Personal Access Token and is best for simple, automated setups.
    2. Use my own repository: You provide an existing git repository (GitHub, GitLab, Bitbucket, or any git host). This uses your existing SSH keys or git credentials and does not require a token.
  3. How profiles and common files work in DotState

    main

    DotState uses Profiles to organize dotfiles for different machines or contexts. Files are categorized into two types:

    1. Common Files: Shared across all profiles automatically. These files remain symlinked regardless of which profile is currently active.
    2. Profile-specific Files: Files that belong to a specific profile (or its inheritance chain). These are swapped out when you switch profiles.

    Profile Inheritance

    A profile can inherit from one parent, creating a chain of configuration. When a profile is activated, DotState resolves files using the following priority (highest to lowest):

    1. Child's own files (overrides everything else)
    2. Parent's files
    3. Grandparent's files, etc.
    4. Common files

    Note: Cycles in inheritance are detected and rejected. You cannot delete a profile if other profiles are currently inheriting from it.

    /* Example Inheritance Chain */
    
    base (Parent)
      └── .zshrc, .vimrc, .tmux.conf
    
    work (Inherits base)
      └── .zshrc (overrides base's)
      └── .ssh/config (own)
    
    work-laptop (Inherits work)
      └── .ssh/config (overrides work's)
    
    Result for 'work-laptop':
    - .ssh/config (from work-laptop)
    - .zshrc (from work)
    - .vimrc (from base)
    - .tmux.conf (from base)
  4. Configure GitHub Mode for automatic repository management

    main

    DotState can automatically create and manage a GitHub repository for your dotfiles. This requires a GitHub Personal Access Token.

    Token Types

    • Fine-grained Token (Recommended): Provides granular security.
      • Required Permissions:
        • Administration: Read & write (to create the dotstate-storage repository).
        • Contents: Read & write (to sync dotfiles).
      • Note: Metadata (read-only) is included automatically.
      • Setup Tip: For initial setup, grant access to "All repositories". You can later restrict the token to only the dotstate-storage repository.
    • Classic Token: Requires the repo scope (Full control of private repositories).

    Providing the Token

    1. Environment Variable (Recommended): Use DOTSTATE_GITHUB_TOKEN. This takes precedence over the config file.
    2. Config File: Stored in the config file during first-time setup.
    # For fine-grained tokens
    export DOTSTATE_GITHUB_TOKEN=github_pat_your_token_here
    
    # For classic tokens
    export DOTSTATE_GITHUB_TOKEN=ghp_your_token_here
  5. Switch between profiles

    main

    To switch your current environment, select a profile in the TUI and press Enter.

    DotState performs the following automatically:

    1. Removes symlinks associated with the old profile.
    2. Creates symlinks for the new profile (including all inherited files).
    3. Ensures Common files remain linked.

    If the activation process fails, DotState automatically restores the previous profile to prevent a broken state.

  6. Deploy the DotState website

    main

    The website is configured to avoid automatic deployments on every commit to main to respect versioning. Use one of the following three methods to deploy:

    1. Automatic (via GitHub Releases)

    Create a GitHub Release using a version tag. This triggers the deploy-website.yml workflow.

    2. Manual via Vercel CLI

    Run the production deployment command from within the website directory.

    3. Manual via GitHub Actions

    Trigger the "Deploy Website" workflow manually from the GitHub Actions tab and provide a version tag (e.g., v1.0.0).

    # Manual via Vercel CLI
    cd website
    vercel --prod
    
    # Automatic via Git Tagging
    git tag v1.0.0
    git push origin v1.0.0
  7. Pre-release checklist for DotState

    main

    Before publishing, ensure the following quality and release steps are completed:

    • Update Cargo.toml version and CHANGELOG.md.
    • Run cargo test (full test suite).
    • Run cargo clippy -- -D warnings (linting).
    • Run cargo fmt -- --check (formatting check).
    • Build the release with cargo build --release and test the binary locally.
    • Create and push a git tag (e.g., git tag -a v0.1.0 -m "Release v0.1.0").
  8. Build DotState binaries for macOS and Linux

    main

    Use cargo build --release with specific target flags to generate binaries for different architectures and operating systems. You may need to add these targets via rustup before building.

    # macOS: Apple Silicon
    cargo build --release --target aarch64-apple-darwin
    
    # macOS: Intel
    cargo build --release --target x86_64-apple-darwin
    
    # Linux: x86_64
    cargo build --release --target x86_64-unknown-linux-gnu
    
    # Add targets if missing
    rustup target add aarch64-apple-darwin
    rustup target add x86_64-unknown-linux-gnu
  9. Build and Install DotState from Source

    main

    To build DotState from the source code, ensure you have the prerequisites installed (Rust 1.70+, Cargo, and Git), then follow these steps:

    1. Clone the repository.
    2. Build in release mode.
    3. Install globally (optional) or run the binary directly from the target directory.
    # Clone the repository
    git clone https://github.com/serkanyersen/dotstate.git
    cd dotstate
    
    # Build in release mode
    cargo build --release
    
    # Install globally (installs to ~/.cargo/bin/)
    cargo install --path .
    
    # OR run directly without installing
    ./target/release/dotstate
  10. Publish DotState to crates.io

    main

    To publish the DotState Rust crate to crates.io, you must first have an account and an API token. Use cargo login to authenticate before running the publish command. Note that publishing to crates.io is a permanent action.

    cargo login YOUR_API_TOKEN
    cargo publish
  11. Create new profiles in the TUI

    main

    To create a new profile, open the TUI, navigate to Manage Profiles, and press C. You have three options for creation:

    • Start blank: Creates a completely new, empty setup.
    • Inherit from an existing profile: Creates a live link. The child profile automatically receives all files and packages from the parent. Changes made to the parent will automatically reflect in the child.
    • Copy from an existing profile: Creates a one-time snapshot. The new profile carries over all files and packages from the source, but they become independent; changes to the original profile will NOT affect the copy.