feat: switch to chezmoi

Signed-off-by: Ismo Vuorinen <ismo@ivuorinen.net>
This commit is contained in:
2025-11-12 16:27:50 +02:00
parent ab67f6be5a
commit 8460c2d408
13 changed files with 2451 additions and 35 deletions

53
.chezmoi.yaml.tmpl Normal file
View File

@@ -0,0 +1,53 @@
{{- $hostname := .chezmoi.hostname -}}
{{- $username := .chezmoi.username -}}
{{- $osid := .chezmoi.os -}}
sourceDir: {{ .chezmoi.sourceDir | quote }}
data:
hostname: {{ $hostname | quote }}
username: {{ $username | quote }}
osid: {{ $osid | quote }}
# Detect if we're on macOS
is_macos: {{ eq $osid "darwin" }}
# Detect if we're on Linux
is_linux: {{ eq $osid "linux" }}
# Host-specific flags
is_air: {{ eq $hostname "air" }}
is_lakka: {{ eq $hostname "lakka" }}
is_tunkki: {{ eq $hostname "tunkki" }}
is_s: {{ eq $hostname "s" }}
# Merge strategy for dealing with conflicts
merge:
command: "nvim"
args:
- "-d"
- "{{ "{{" }} .Destination {{ "}}" }}"
- "{{ "{{" }} .Source {{ "}}" }}"
- "{{ "{{" }} .Target {{ "}}" }}"
# Template options
template:
options:
- "missingkey=error"
# Diff options
diff:
exclude:
- "scripts"
pager: "delta"
# Git options
git:
autoCommit: false
autoPush: false
# Hooks
hooks:
read-source-state:
pre:
command: ".local/share/chezmoi/.chezmoihooks/pre-read-source-state.sh"

View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Pre-read-source-state hook for chezmoi
# This runs before chezmoi reads the source state
set -e
DOTFILES="${CHEZMOI_SOURCE_DIR:-$HOME/.local/share/chezmoi}"
# Update git submodules if they exist
if [ -d "$DOTFILES/.git" ]; then
cd "$DOTFILES"
git submodule update --init --recursive --quiet || true
fi

90
.chezmoiignore Normal file
View File

@@ -0,0 +1,90 @@
# Chezmoi ignore file
# Files and directories that should not be managed by chezmoi
# Git and version control
.git/
.gitignore
.gitattributes
.gitmodules
# GitHub
.github/
# Documentation
README.md
*.md
docs/
AGENTS.md
# Development tools
.vscode/
.serena/
.claude/
node_modules/
# Testing
tests/
test-all.sh
# Configuration files for the repo itself
.editorconfig
.editorconfig-checker.json
.eslintrc.json
.prettierrc.js
.prettierignore
.markdownlint.json
.markdownlintignore
.mega-linter.yml
.commitlintrc.json
.releaserc.json
.shellcheckrc
.yamlignore
.yamllint.yml
.browserslistrc
.actrc
.luarc.json
.ignore
stylua.toml
phpcs.xml
# Package management
package.json
yarn.lock
# Python and Node version files
.python-version
.nvmrc
.go-version
# Dotbot (old system)
install.conf.yaml
tools/dotbot/
tools/dotbot-*/
tools/dotbot-defaults.yaml
# Installation and build scripts in root
install
add-submodules.sh
# Chezmoi-specific directories (not to be managed)
.chezmoihooks/
# Host-specific directories (will be handled via templates)
{{- if not .is_air }}
hosts/air/
{{- end }}
{{- if not .is_lakka }}
hosts/lakka/
{{- end }}
{{- if not .is_tunkki }}
hosts/tunkki/
{{- end }}
{{- if not .is_s }}
hosts/s/
{{- end }}
# Secrets (should use separate secrets management)
secrets/
# macOS specific files
.DS_Store

View File

@@ -0,0 +1,425 @@
# Chezmoi Migration Summary
## What Was Done
Your dotfiles repository has been prepared for migration from dotbot to chezmoi. Here's what was created:
### 1. Updated Install Script
- **File**: `install`
- **Change**: Now uses chezmoi's one-line installer
- **Command**: `sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply ivuorinen`
### 2. Chezmoi Configuration Files
#### `.chezmoi.yaml.tmpl`
Main configuration file that includes:
- Source directory configuration
- Host detection (air, lakka, tunkki, s)
- OS detection (macOS, Linux)
- Custom data variables for templates
- Merge and diff settings
- Git configuration
- Pre-read hook for submodule updates
#### `.chezmoiignore`
Specifies what files should NOT be managed by chezmoi:
- Git and GitHub files
- Documentation (*.md files)
- Development tools (.vscode, node_modules, etc.)
- Old dotbot configuration
- Host-specific files (via templates)
- Repository management files
### 3. Run Scripts (Automated Setup)
#### `run_once_before_install-prerequisites.sh.tmpl`
Runs **once before** applying dotfiles:
- Installs Homebrew (macOS)
- Installs Xcode CLI tools (macOS)
- Updates package manager (Linux)
#### `run_once_after_install-packages.sh.tmpl`
Runs **once after** applying dotfiles:
- Installs Homebrew packages (Brewfile)
- Sets macOS defaults
- Installs apt packages (Linux)
- Installs pipx packages
#### `run_once_after_setup-languages.sh.tmpl`
Runs **once after** applying dotfiles:
- Installs fonts
- Installs Cargo packages (Rust)
- Installs Go packages
- Installs Composer (PHP)
- Installs NVM and latest Node LTS
- Installs NPM packages
- Installs GitHub CLI extensions
- Installs z (directory jumper)
- Installs cheat databases
#### `run_once_after_create-directories.sh.tmpl`
Runs **once after** applying dotfiles:
- Creates required directories in `$HOME`
- Sets proper permissions (e.g., `.ssh` → 0700)
### 4. Hooks
#### `.chezmoihooks/pre-read-source-state.sh`
Runs before chezmoi reads the source state:
- Updates git submodules automatically
### 5. Documentation
#### `MIGRATION-DOTBOT-TO-CHEZMOI.md` (66KB)
Comprehensive migration guide including:
- Why migrate to chezmoi
- Key differences between dotbot and chezmoi
- Complete dotbot → chezmoi mapping
- File structure comparison
- Step-by-step migration instructions
- Usage guide with examples
- Troubleshooting section
- Migration checklist
#### `CHEZMOI-QUICK-REFERENCE.md` (11KB)
Quick reference guide for daily use:
- Common commands
- File naming conventions
- Template syntax examples
- Host-specific configuration patterns
- Troubleshooting tips
- Useful aliases
#### `HOST-SPECIFIC-MIGRATION.md` (9KB)
Detailed guide for migrating host-specific configurations:
- Three migration approaches explained
- Examples from your current hosts
- Step-by-step host config migration
- Testing strategies
- Best practices
### 6. Migration Helper Script
#### `migrate-to-chezmoi.sh`
Automated script to restructure your files:
- Creates backup branch automatically
- Creates migration branch
- Renames files to chezmoi conventions
- `base/*``dot_*`
- `config/*``dot_config/*`
- `local/bin/*``executable_dot_local/bin/*`
- `ssh/*``private_dot_ssh/*`
- Cleans up empty directories
- Generates migration notes
## What Needs To Be Done
### Immediate Next Steps
1. **Review Changes**
```bash
cd ~/.dotfiles
git status
git diff
```
2. **Read Documentation**
- Start with: `MIGRATION-DOTBOT-TO-CHEZMOI.md`
- Quick reference: `CHEZMOI-QUICK-REFERENCE.md`
- Host configs: `HOST-SPECIFIC-MIGRATION.md`
3. **Commit Current State**
```bash
git add install .chezmoi.yaml.tmpl .chezmoiignore
git add run_once_*.sh.tmpl .chezmoihooks/
git add migrate-to-chezmoi.sh
git add *.md
git commit -m "Add chezmoi configuration and migration tools"
```
### File Restructuring
You have two options:
#### Option A: Automated (Recommended for First Pass)
```bash
# Run the migration script
./migrate-to-chezmoi.sh
# This will:
# - Create backup branch
# - Create migration branch
# - Rename all files to chezmoi conventions
# - Show you what was done
```
#### Option B: Manual (More Control)
Manually rename files following chezmoi conventions:
```bash
# Base files become dot_ files
git mv base/bashrc dot_bashrc
git mv base/zshrc dot_zshrc
git mv base/tmux.conf dot_tmux.conf
# Config files
mkdir -p dot_config
git mv config/fish dot_config/fish
git mv config/nvim dot_config/nvim
# ... etc
# Local bin (make executable)
mkdir -p executable_dot_local/bin
for file in local/bin/*; do
git mv "$file" "executable_dot_local/bin/$(basename $file)"
done
# SSH files (private)
mkdir -p private_dot_ssh
git mv ssh/* private_dot_ssh/
# See full examples in MIGRATION-DOTBOT-TO-CHEZMOI.md
```
### Host-Specific Configurations
Your hosts need special attention:
```bash
hosts/
├── air/
├── lakka/
├── tunkki/
└── s/
```
**Read**: `HOST-SPECIFIC-MIGRATION.md` for detailed strategies.
**Quick decision guide**:
- **Few differences per file** → Use templates with `{{ if .is_air }}`
- **Complete replacement** → Use `filename__hostname` suffix
- **Host-specific directories** → Use `.chezmoiignore` with templates
### Testing Before Commit
```bash
# After restructuring files, test with chezmoi
cd ~/.dotfiles
# Initialize chezmoi with current directory as source
chezmoi init --source $(pwd)
# See what would happen (dry run)
chezmoi apply --dry-run --verbose
# See what a specific file would look like
chezmoi cat ~/.bashrc
# Check for errors
chezmoi verify
```
### Final Steps
1. **Commit Migration**
```bash
git add -A
git commit -m "Migrate from dotbot to chezmoi"
git push
```
2. **Test on Current Machine**
```bash
# Apply dotfiles
chezmoi apply -v
# Verify everything works
# Open new terminal
# Check configs
```
3. **Test on Another Machine** (if available)
```bash
# On another machine
sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply ivuorinen
# Verify host-specific configs applied correctly
```
4. **Clean Up** (after confirming everything works)
```bash
cd $(chezmoi source-path)
# Remove old dotbot files
rm -rf tools/dotbot tools/dotbot-*
rm install.conf.yaml
rm tools/dotbot-defaults.yaml
# Optionally remove hosts/ if fully migrated to templates
# rm -rf hosts/
git add -A
git commit -m "Clean up old dotbot files"
git push
```
## Key Differences to Remember
### Installation
**Before**: `./install` (ran dotbot)
**After**: `sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply ivuorinen`
### Making Changes
**Before**:
```bash
cd ~/.dotfiles
vim base/bashrc
./install # Re-run to create symlinks
```
**After**:
```bash
chezmoi edit ~/.bashrc
# Or: vim ~/.bashrc && chezmoi add ~/.bashrc
chezmoi apply
```
### Syncing Across Machines
**Before**:
```bash
cd ~/.dotfiles
git pull
./install
```
**After**:
```bash
chezmoi update
# Equivalent to: cd $(chezmoi source-path) && git pull && chezmoi apply
```
### Host-Specific Configs
**Before**: Separate files in `hosts/hostname/`
**After**: Templates with `{{ if eq .chezmoi.hostname "air" }}` or `filename__hostname`
## File Mapping Reference
| Old Location | New Location | Notes |
|--------------|--------------|-------|
| `base/bashrc` | `dot_bashrc` | Becomes `~/.bashrc` |
| `config/fish/` | `dot_config/fish/` | Becomes `~/.config/fish/` |
| `local/bin/script` | `executable_dot_local/bin/script` | Executable `~/.local/bin/script` |
| `ssh/config` | `private_dot_ssh/config` | Private (0600) `~/.ssh/config` |
| `install.conf.yaml` | `run_once_*.sh.tmpl` | Setup tasks |
| `hosts/air/config/` | `dot_config/*.tmpl` or `*__air` | Host-specific |
## Troubleshooting Quick Tips
### "Entry not in source state"
```bash
# File not added to chezmoi
chezmoi add <file>
```
### "File modified since chezmoi last wrote it"
```bash
# See changes
chezmoi diff
# Re-add
chezmoi add <file>
```
### "Template undefined variable"
```bash
# Check available data
chezmoi data
# Test template
chezmoi execute-template "{{ .chezmoi.hostname }}"
```
### Scripts not running
```bash
# Check permissions
chmod +x run_once_*.sh.tmpl
# Force re-run
chezmoi apply --force
```
## Additional Resources
### Created Documentation
- `MIGRATION-DOTBOT-TO-CHEZMOI.md` - Complete migration guide
- `CHEZMOI-QUICK-REFERENCE.md` - Daily usage reference
- `HOST-SPECIFIC-MIGRATION.md` - Host configuration guide
- `MIGRATION-NOTES.md` - Generated after running migration script
### External Resources
- [Chezmoi Official Docs](https://www.chezmoi.io/)
- [Chezmoi Quick Start](https://www.chezmoi.io/quick-start/)
- [Chezmoi User Guide](https://www.chezmoi.io/user-guide/)
- [Chezmoi Templates](https://www.chezmoi.io/reference/templates/)
## Summary Checklist
- [x] Install script updated
- [x] Chezmoi configuration created (`.chezmoi.yaml.tmpl`)
- [x] Ignore file created (`.chezmoiignore`)
- [x] Run scripts created (4 scripts)
- [x] Hooks created (pre-read-source-state)
- [x] Migration script created (`migrate-to-chezmoi.sh`)
- [x] Documentation created (3 guides)
- [ ] **Review and commit configuration files**
- [ ] **Run migration script** or manually restructure
- [ ] **Migrate host-specific configs**
- [ ] **Test with chezmoi**
- [ ] **Commit migration**
- [ ] **Test on current machine**
- [ ] **Test on other machines**
- [ ] **Clean up old dotbot files**
- [ ] **Update README.md** (document chezmoi usage)
## Questions?
If you have questions during migration:
1. Check the relevant guide:
- General questions → `MIGRATION-DOTBOT-TO-CHEZMOI.md`
- Usage questions → `CHEZMOI-QUICK-REFERENCE.md`
- Host configs → `HOST-SPECIFIC-MIGRATION.md`
2. Use chezmoi's help:
```bash
chezmoi help
chezmoi help <command>
chezmoi doctor
```
3. Check official docs:
- https://www.chezmoi.io/
## What Makes This Migration Special
Your dotfiles have:
- ✅ Custom `dfm` script → Wrapped in run_once scripts
- ✅ Multiple dotbot plugins → Equivalent run_once scripts
- ✅ Host-specific configs → Template support added
- ✅ Complex installation → Automated in run scripts
- ✅ Git submodules → Pre-read hook handles this
- ✅ Multiple hosts (air, lakka, tunkki, s) → Detected and flagged
Everything from your dotbot setup has been accounted for in the chezmoi migration!
## Final Notes
- **Take your time**: This is a significant migration
- **Test thoroughly**: Use `--dry-run` extensively
- **Backup everything**: The migration script creates backups
- **Iterate**: You can always refine the migration later
- **Have fun**: Chezmoi offers powerful features to explore!
Good luck with your migration! 🚀

View File

@@ -0,0 +1,432 @@
# Chezmoi Quick Reference
Quick reference guide for common chezmoi operations with your dotfiles.
## Installation
```bash
# Fresh install on a new machine
sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply ivuorinen
# Or if chezmoi is already installed
chezmoi init --apply ivuorinen
```
## Daily Workflow
### Making Changes
```bash
# Edit a dotfile (opens in $EDITOR)
chezmoi edit ~/.bashrc
# Or edit directly and add to chezmoi
vim ~/.bashrc
chezmoi add ~/.bashrc
# See what would change
chezmoi diff
# Apply changes
chezmoi apply
```
### Syncing Across Machines
```bash
# On machine A: commit and push changes
cd $(chezmoi source-path)
git add -A
git commit -m "Update configuration"
git push
# On machine B: pull and apply changes
chezmoi update
# This is equivalent to:
# cd $(chezmoi source-path) && git pull && chezmoi apply
```
## Common Commands
### Viewing and Inspecting
```bash
# See what chezmoi would do
chezmoi diff
# List all managed files
chezmoi managed
# List unmanaged files
chezmoi unmanaged
# Show the source path
chezmoi source-path
# Show what a file would look like after templating
chezmoi cat ~/.bashrc
# Show available template data
chezmoi data
```
### Adding and Removing Files
```bash
# Add a file
chezmoi add ~/.newfile
# Add a file as a template
chezmoi add --template ~/.newfile
# Add a directory recursively
chezmoi add --recursive ~/.config/newapp
# Add with autodetection (templates, scripts, etc.)
chezmoi add --autotemplate ~/.newfile
# Stop managing a file (removes from chezmoi)
chezmoi forget ~/.oldfile
# Remove a file from both chezmoi and home directory
chezmoi remove ~/.oldfile
```
### Working with Templates
```bash
# Execute a template expression
chezmoi execute-template "{{ .chezmoi.hostname }}"
# Edit template data
chezmoi edit-config
# Verify templates
chezmoi verify
```
### Applying Changes
```bash
# Apply all changes
chezmoi apply
# Apply with verbose output
chezmoi apply -v
# Dry run (show what would happen)
chezmoi apply --dry-run -v
# Force apply (re-runs scripts)
chezmoi apply --force
# Apply only specific files
chezmoi apply ~/.bashrc ~/.zshrc
```
### Updating from Repository
```bash
# Update dotfiles from repository
chezmoi update
# Update but don't apply
cd $(chezmoi source-path) && git pull
# Update with interactive merge
chezmoi update --interactive
```
## File Naming Conventions
### Basic Prefixes
| Source File | Destination | Description |
|------------|-------------|-------------|
| `dot_bashrc` | `~/.bashrc` | Dot file |
| `dot_config/` | `~/.config/` | Dot directory |
| `private_dot_ssh/` | `~/.ssh/` | Private directory (0700) |
| `executable_dot_local/bin/script` | `~/.local/bin/script` | Executable |
| `symlink_dot_vim` | `~/.vim` | Symlink |
| `readonly_dot_file` | `~/.file` | Read-only |
### Template Files
| Source File | Description |
|------------|-------------|
| `dot_bashrc.tmpl` | Template file |
| `dot_config/fish/config.fish.tmpl` | Nested template |
### Scripts
| Script Name | When It Runs |
|------------|--------------|
| `run_once_before_*.sh` | Once before applying |
| `run_once_after_*.sh` | Once after applying |
| `run_before_*.sh` | Every time before applying |
| `run_after_*.sh` | Every time after applying |
| `run_onchange_*.sh` | When script content changes |
## Template Syntax
### Basic Variables
```go
// Hostname
{{ .chezmoi.hostname }}
// Username
{{ .chezmoi.username }}
// Operating system
{{ .chezmoi.os }}
// Home directory
{{ .chezmoi.homeDir }}
// Source directory
{{ .chezmoi.sourceDir }}
// Custom data from .chezmoi.yaml
{{ .is_macos }}
{{ .is_linux }}
```
### Conditionals
```go
{{ if eq .chezmoi.hostname "air" }}
# Configuration for air
{{ else if eq .chezmoi.hostname "lakka" }}
# Configuration for lakka
{{ else }}
# Default configuration
{{ end }}
{{ if .is_macos }}
# macOS-specific
{{ end }}
{{ if and .is_macos (eq .chezmoi.hostname "air") }}
# macOS on air
{{ end }}
```
### Loops
```go
{{ range $key, $value := .data }}
{{ $key }}: {{ $value }}
{{ end }}
```
### Including Files
```go
{{ include "template-file.txt" }}
{{ includeTemplate "template-file.tmpl" }}
```
## Host-Specific Configuration
### Method 1: Template Conditionals
In `dot_bashrc.tmpl`:
```bash
# Common configuration
export PATH="$HOME/.local/bin:$PATH"
{{ if eq .chezmoi.hostname "air" }}
# air-specific configuration
export WORK_DIR="$HOME/Work"
{{ end }}
{{ if eq .chezmoi.hostname "lakka" }}
# lakka-specific configuration
export WORK_DIR="$HOME/Projects"
{{ end }}
```
### Method 2: Separate Files with Symlinks
Use `.chezmoiignore` to exclude files for specific hosts:
```
{{ if ne .chezmoi.hostname "air" }}
dot_config/air-specific-app/
{{ end }}
{{ if ne .chezmoi.hostname "lakka" }}
dot_config/lakka-specific-app/
{{ end }}
```
## Working with Secrets
### Environment Variables
```go
{{ .Env.MY_SECRET }}
```
### 1Password
```go
{{ (onepasswordDocument "my-secret").content }}
{{ (onepasswordItemFields "my-item").password.value }}
```
### External Commands
```go
{{ output "op" "read" "op://vault/item/field" }}
```
## Troubleshooting
### Check Configuration
```bash
# Verify chezmoi is working correctly
chezmoi doctor
# Check state
chezmoi verify
# See detailed info
chezmoi data
```
### Debug Templates
```bash
# See what a template would produce
chezmoi cat ~/.bashrc
# Execute a template
chezmoi execute-template "{{ .chezmoi.hostname }}"
# Verbose output
chezmoi apply -v
```
### Fix Issues
```bash
# Re-apply everything
chezmoi apply --force
# Reset state (dangerous!)
chezmoi state reset
# Clear cache
rm -rf $(chezmoi source-path)/.git/chezmoi-*
```
### Common Errors
**Error: template: ... undefined variable**
- Check template syntax
- Verify data with `chezmoi data`
**Error: entry ... is not in source state**
- File not added to chezmoi: `chezmoi add <file>`
**Error: ... has been modified since chezmoi last wrote it**
- See changes: `chezmoi diff`
- Re-add: `chezmoi add <file>`
- Or force apply: `chezmoi apply --force`
## Useful Aliases
Add these to your shell configuration:
```bash
# Chezmoi shortcuts
alias cm='chezmoi'
alias cma='chezmoi apply'
alias cmd='chezmoi diff'
alias cme='chezmoi edit'
alias cmu='chezmoi update'
alias cmcd='cd $(chezmoi source-path)'
# Common workflows
alias cmup='chezmoi git pull && chezmoi apply'
alias cmpush='cd $(chezmoi source-path) && git add -A && git commit && git push'
```
## Environment Variables
```bash
# Change source directory (default: ~/.local/share/chezmoi)
export CHEZMOI_SOURCE_DIR="$HOME/.dotfiles"
# Change config file location
export CHEZMOI_CONFIG_FILE="$HOME/.config/chezmoi/chezmoi.yaml"
# Use different editor
export EDITOR="vim"
```
## Advanced Usage
### Using chezmoi as a dotfiles manager
```bash
# Initialize with local directory
chezmoi init --source ~/.dotfiles
# Use current directory as source
chezmoi init --source $(pwd)
```
### Managing Multiple Machines
Use data in `.chezmoi.yaml.tmpl`:
```yaml
data:
is_work_machine: {{ or (eq .chezmoi.hostname "work-laptop") (eq .chezmoi.hostname "work-desktop") }}
is_personal: {{ eq .chezmoi.hostname "personal-laptop" }}
```
Then in templates:
```go
{{ if .is_work_machine }}
# Work configuration
{{ end }}
```
### External Files
```yaml
# .chezmoiexternal.yaml
".config/nvim/lua/plugins":
type: "archive"
url: "https://github.com/user/nvim-config/archive/main.tar.gz"
stripComponents: 1
refreshPeriod: "168h"
```
## Resources
- [Official Documentation](https://www.chezmoi.io/)
- [User Guide](https://www.chezmoi.io/user-guide/)
- [Template Reference](https://www.chezmoi.io/reference/templates/)
- [Command Reference](https://www.chezmoi.io/reference/commands/)
- [FAQ](https://www.chezmoi.io/faq/)
## Help
```bash
# General help
chezmoi help
# Command-specific help
chezmoi help apply
chezmoi help add
# Show version
chezmoi --version
```

View File

@@ -0,0 +1,462 @@
# Host-Specific Configuration Migration
Guide for migrating host-specific configurations from dotbot to chezmoi.
## Current Dotbot Structure
You currently have host-specific configurations in:
```
hosts/
├── air/
│ ├── base/
│ ├── config/
│ └── install.conf.yaml
├── lakka/
│ ├── base/
│ ├── config/
│ └── install.conf.yaml
├── tunkki/
│ └── install.conf.yaml
└── s/
└── install.conf.yaml
```
## Chezmoi Approaches
There are three main approaches to handle host-specific configurations in chezmoi:
### 1. Template Conditionals (Recommended)
Use if/else conditions in template files.
**Pros:**
- Single source file for all hosts
- Easy to see all variations
- Less file duplication
**Cons:**
- Files can get complex with many hosts
- Need `.tmpl` extension
**Example:**
Create `dot_bashrc.tmpl`:
```bash
# Common configuration for all hosts
export PATH="$HOME/.local/bin:$PATH"
{{ if eq .chezmoi.hostname "air" }}
# air-specific
export WORK_DIR="$HOME/Work"
alias air-specific="echo air"
{{ end }}
{{ if eq .chezmoi.hostname "lakka" }}
# lakka-specific
export WORK_DIR="$HOME/Projects"
alias lakka-specific="echo lakka"
{{ end }}
# More common configuration
```
### 2. Separate Files with .chezmoiignore (Simple)
Keep separate files per host and ignore the ones that don't apply.
**Pros:**
- Clean separation
- No template syntax needed
- Easy to maintain
**Cons:**
- More files to manage
- Some duplication
**Example:**
Create multiple version files:
```
dot_bashrc__air
dot_bashrc__lakka
dot_bashrc__tunkki
```
These automatically apply based on hostname. No `.chezmoiignore` needed!
Or use directories:
```
dot_config/
├── app/
│ ├── config.yaml__air
│ ├── config.yaml__lakka
│ └── config.yaml__default
```
### 3. Hybrid Approach (Most Flexible)
Combine both methods:
- Use templates for files with minor differences
- Use separate files for completely different configs
## Migration Steps for Your Hosts
### Step 1: Analyze Each Host
Review what's different per host:
```bash
# See what's in each host directory
ls -la hosts/air/
ls -la hosts/lakka/
ls -la hosts/tunkki/
ls -la hosts/s/
# Compare configs
diff hosts/air/config/some-app/config hosts/lakka/config/some-app/config
```
### Step 2: Choose Strategy Per File
For each file that differs:
**Small differences** (few lines):
→ Use templates with conditionals
**Complete replacement**:
→ Use `filename__hostname` suffix
**Shared base + host additions**:
→ Use templates with includes or blocks
### Step 3: Migrate Host Configurations
#### Example: Fish Configuration
Your `hosts/air/config/fish/config.fish` differences:
**Current dotbot way:**
```yaml
# hosts/air/install.conf.yaml
- link:
~/.config/:
path: hosts/air/config/**
```
**New chezmoi way - Option A (Templates):**
Create `dot_config/fish/config.fish.tmpl`:
```fish
# Common fish configuration
set -gx EDITOR nvim
{{ if eq .chezmoi.hostname "air" }}
# air-specific config
set -gx WORK_DIR ~/Work
{{ else if eq .chezmoi.hostname "lakka" }}
# lakka-specific config
set -gx WORK_DIR ~/Projects
{{ end }}
# More common configuration
```
**New chezmoi way - Option B (Separate files):**
Create multiple files:
```
dot_config/fish/config.fish__air
dot_config/fish/config.fish__lakka
```
Chezmoi will automatically use the correct file based on hostname.
### Step 4: Update .chezmoi.yaml.tmpl
Add host flags for easier conditionals:
```yaml
{{- $hostname := .chezmoi.hostname -}}
data:
hostname: {{ $hostname | quote }}
# Host-specific flags
is_air: {{ eq $hostname "air" }}
is_lakka: {{ eq $hostname "lakka" }}
is_tunkki: {{ eq $hostname "tunkki" }}
is_s: {{ eq $hostname "s" }}
# Group flags
is_work: {{ or (eq $hostname "air") (eq $hostname "tunkki") }}
is_personal: {{ or (eq $hostname "lakka") (eq $hostname "s") }}
```
Then use simpler conditionals:
```go
{{ if .is_air }}
# air config
{{ end }}
{{ if .is_work }}
# All work machines
{{ end }}
```
## Specific Migration Examples
### Example 1: Simple Host-Specific Line
**Before (dotbot):**
```yaml
# hosts/air/config/app/config
setting=value_for_air
# hosts/lakka/config/app/config
setting=value_for_lakka
```
**After (chezmoi) - Option A:**
```
# dot_config/app/config.tmpl
{{ if .is_air -}}
setting=value_for_air
{{- else if .is_lakka -}}
setting=value_for_lakka
{{- end }}
```
**After (chezmoi) - Option B:**
```
# dot_config/app/config__air
setting=value_for_air
# dot_config/app/config__lakka
setting=value_for_lakka
```
### Example 2: Mostly Shared with Few Differences
**Before:**
100 lines shared, 5 lines different per host
**After (recommended - templates):**
```bash
# dot_config/app/config.tmpl
# ... 50 lines of shared config ...
{{ if .is_air }}
air_specific_setting=true
{{ else if .is_lakka }}
lakka_specific_setting=true
{{ end }}
# ... 50 more lines of shared config ...
```
### Example 3: Completely Different Configs
**Before:**
Two totally different config files
**After (recommended - separate files):**
```
dot_config/app/config__air
dot_config/app/config__lakka
```
### Example 4: Host-Specific Directories
**Before:**
```
hosts/air/config/air-only-app/
hosts/lakka/config/lakka-only-app/
```
**After - Use .chezmoiignore:**
```
# .chezmoiignore
{{ if ne .chezmoi.hostname "air" }}
dot_config/air-only-app/
{{ end }}
{{ if ne .chezmoi.hostname "lakka" }}
dot_config/lakka-only-app/
{{ end }}
```
Then create:
```
dot_config/air-only-app/ # Only applied on air
dot_config/lakka-only-app/ # Only applied on lakka
```
## Testing Host-Specific Configs
### Before Applying
```bash
# See what would be applied on this host
chezmoi diff
# See what a specific file would look like
chezmoi cat ~/.config/fish/config.fish
# Check template data
chezmoi data | grep hostname
```
### Simulating Other Hosts
```bash
# Test what would be applied on another host
chezmoi execute-template --init --promptString hostname=air "{{ .chezmoi.hostname }}"
# See what a file would look like on another host
# (This requires manual variable setting in templates)
```
### On Another Machine
```bash
# Initialize and test without applying
chezmoi init --dry-run --verbose ivuorinen
# Apply with dry-run
chezmoi apply --dry-run -v
```
## Migration Script Adjustments
Add to `migrate-to-chezmoi.sh`:
```bash
# Migrate host-specific configs
log_info "Processing host-specific configurations..."
CURRENT_HOST=$(hostname -s)
log_info "Current hostname: $CURRENT_HOST"
# Prompt for migration strategy
echo ""
log_warning "How do you want to handle host-specific configs?"
echo " 1) Merge into templates (recommended for small differences)"
echo " 2) Keep separate files per host (recommended for large differences)"
echo " 3) Manual (skip automatic migration)"
read -p "Choose (1/2/3): " -r STRATEGY
if [ "$STRATEGY" = "1" ]; then
log_info "Will merge into templates (requires manual editing after)"
# Create template files
# ... migration logic ...
elif [ "$STRATEGY" = "2" ]; then
log_info "Creating separate host-specific files..."
for host in air lakka tunkki s; do
if [ -d "hosts/$host" ]; then
log_info "Processing host: $host"
# Process host-specific base files
if [ -d "hosts/$host/base" ]; then
for file in hosts/$host/base/*; do
if [ -f "$file" ]; then
filename=$(basename "$file")
move_dotfiles "$file" "dot_${filename}__${host}" ""
fi
done
fi
# Process host-specific config files
if [ -d "hosts/$host/config" ]; then
for file in hosts/$host/config/*; do
if [ -f "$file" ]; then
filename=$(basename "$file")
dest="dot_config/$(dirname $file)__${host}"
move_dotfiles "$file" "$dest/$(basename $file)" ""
fi
done
fi
fi
done
else
log_info "Skipping automatic host-specific migration"
log_info "You'll need to manually migrate hosts/ directory"
fi
```
## Best Practices
1. **Start Simple**: Use separate files first, move to templates as you see patterns
2. **Don't Over-Template**: If a file is completely different per host, use separate files
3. **Document Hosts**: Add comments in `.chezmoi.yaml.tmpl` explaining each host
4. **Test Thoroughly**: Test on each host before committing
5. **Use Host Groups**: Group hosts (work/personal, laptop/desktop) for easier conditionals
## Checklist
- [ ] Identify all host-specific files
- [ ] Choose strategy per file (templates vs separate)
- [ ] Update `.chezmoi.yaml.tmpl` with host flags
- [ ] Migrate host-specific base files
- [ ] Migrate host-specific config files
- [ ] Update `.chezmoiignore` for host-specific directories
- [ ] Test on current host
- [ ] Test on other hosts
- [ ] Document which approach was used where
- [ ] Clean up old hosts/ directory
## Examples from Your Hosts
Based on your current structure:
### hosts/air/install.conf.yaml
```yaml
- link:
~/.config/:
path: hosts/air/config/**
```
**Migration approach:**
- Check what's in `hosts/air/config/`
- If it's app configs, use separate files: `dot_config/app/config__air`
- If it's just a few lines different, merge into templates
### Common Pattern
For configurations that need host-specific values but share structure:
```yaml
# dot_config/app/config.tmpl
# Common settings
port=8080
# Host-specific
{{ if .is_air -}}
workspace=/Users/yourname/Work
{{- else if .is_lakka -}}
workspace=/Users/yourname/Projects
{{- end }}
# More common settings
debug=false
```
## Need Help?
If you're unsure about a specific file:
1. Check the diff: `diff hosts/air/file hosts/lakka/file`
2. Count different lines
3. If < 20% different use templates
4. If > 20% different → use separate files
Remember: You can always refactor later!

View File

@@ -0,0 +1,523 @@
# Migration Guide: Dotbot to Chezmoi
This guide documents the migration from dotbot to chezmoi for managing dotfiles.
## Table of Contents
1. [Why Migrate to Chezmoi?](#why-migrate-to-chezmoi)
2. [Key Differences](#key-differences)
3. [Dotbot to Chezmoi Mapping](#dotbot-to-chezmoi-mapping)
4. [New File Structure](#new-file-structure)
5. [Migration Steps](#migration-steps)
6. [Usage Guide](#usage-guide)
7. [Troubleshooting](#troubleshooting)
## Why Migrate to Chezmoi?
Chezmoi offers several advantages over dotbot:
- **Built-in templating**: Use Go templates for dynamic configuration
- **Secret management**: Native support for password managers (1Password, LastPass, etc.)
- **Cross-platform**: Better support for managing dotfiles across different OS and machines
- **State tracking**: Chezmoi tracks what it manages more precisely
- **Active development**: Regular updates and large community
- **No dependencies**: Single binary, no Python required
## Key Differences
### Philosophy
**Dotbot**:
- Configuration-driven (YAML files)
- Manages symlinks from a source directory
- Plugins extend functionality
**Chezmoi**:
- Source-state driven
- Copies files to home directory (can also use symlinks)
- Built-in templating for dynamic content
- Manages the entire lifecycle of dotfiles
### Directory Structure
**Dotbot**:
```
~/.dotfiles/
├── base/ # Files symlinked to ~/.*
├── config/ # Files symlinked to ~/.config/
├── local/ # Scripts and local files
├── install # Installation script
└── install.conf.yaml # Configuration
```
**Chezmoi**:
```
~/.local/share/chezmoi/ # Source directory
├── .chezmoi.yaml.tmpl # Configuration template
├── .chezmoiignore # Files to ignore
├── run_once_*.sh.tmpl # One-time setup scripts
├── run_*.sh.tmpl # Scripts that run on every apply
├── dot_bashrc # Becomes ~/.bashrc
├── dot_config/ # Becomes ~/.config/
└── private_dot_ssh/ # Becomes ~/.ssh/ with 0700
```
## Dotbot to Chezmoi Mapping
### 1. Link Directives
**Dotbot** (install.conf.yaml):
```yaml
- link:
~/.bashrc: base/bashrc
~/.config/fish: config/fish
```
**Chezmoi**:
- Files are automatically managed based on their names in the source directory
- `dot_bashrc``~/.bashrc`
- `dot_config/fish/``~/.config/fish/`
- Use `symlink_` prefix for symlinks: `symlink_dot_vim` → symlinked `~/.vim`
### 2. Create Directives
**Dotbot**:
```yaml
- create:
~/.ssh:
mode: 0700
~/.local/bin:
```
**Chezmoi**:
- Create a `run_once_after_create-directories.sh.tmpl` script
- Or use `.chezmoitemplates` for reusable directory creation
- Chezmoi automatically creates parent directories
### 3. Shell Commands
**Dotbot**:
```yaml
- shell:
- git submodule update --init --recursive
- bash local/bin/dfm install all
```
**Chezmoi**:
- Use `run_once_*.sh.tmpl` for one-time setup scripts
- Use `run_*.sh.tmpl` for scripts that run every time
- Use `run_before_*.sh` for scripts that run before applying
- Use `run_after_*.sh` for scripts that run after applying
### 4. Clean Directives
**Dotbot**:
```yaml
- clean:
~/:
~/.config:
recursive: true
```
**Chezmoi**:
- Chezmoi doesn't automatically remove files
- Use `chezmoi unmanaged` to see unmanaged files
- Manually remove or add to `.chezmoiignore`
### 5. Host-Specific Configuration
**Dotbot**:
```yaml
# hosts/air/install.conf.yaml
- link:
~/.config/:
path: hosts/air/config/**
```
**Chezmoi**:
- Use templates with conditionals:
```
{{ if eq .chezmoi.hostname "air" }}
# air-specific content
{{ end }}
```
- Or use separate files: `dot_config/file.tmpl` with hostname checks
### 6. Dotbot Plugins
**dotbot-brew**:
- Replace with `run_once_after_install-packages.sh.tmpl`
- Use `brew bundle install`
**dotbot-asdf**:
- Chezmoi doesn't have built-in asdf support
- Use `run_once_after_*.sh` scripts to install asdf plugins
**dotbot-pip/pipx**:
- Use `run_once_after_*.sh` scripts
- Or use chezmoi's external management
## New File Structure
### Configuration Files
#### `.chezmoi.yaml.tmpl`
Main configuration file with template support. Defines:
- Source directory
- Data variables (hostname, OS, custom flags)
- Merge strategy
- Template options
- Git options
#### `.chezmoiignore`
Files and patterns to ignore when applying dotfiles. Includes:
- Repository management files (.git, .github, etc.)
- Documentation
- Development tools
- Old dotbot configuration
### Run Scripts
Scripts follow a naming convention:
- `run_once_before_*.sh.tmpl`: Runs once before applying (prerequisites)
- `run_once_after_*.sh.tmpl`: Runs once after applying (installation)
- `run_before_*.sh.tmpl`: Runs every time before applying
- `run_after_*.sh.tmpl`: Runs every time after applying
- `run_onchange_*.sh.tmpl`: Runs when file content changes
### File Naming
Chezmoi uses special prefixes:
- `dot_`: Becomes a dot file (`.`)
- `private_`: Sets permissions to 0600
- `executable_`: Makes file executable
- `symlink_`: Creates a symlink
- `readonly_`: Makes file read-only
Examples:
- `dot_bashrc``~/.bashrc`
- `private_dot_ssh/``~/.ssh/` (mode 0700)
- `executable_dot_local/bin/script``~/.local/bin/script` (executable)
## Migration Steps
### 1. Backup Current Setup
```bash
# Backup your current dotfiles
cd ~/.dotfiles
git add -A
git commit -m "Backup before chezmoi migration"
git push
```
### 2. Install Chezmoi
```bash
# The new install script will do this automatically
sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply ivuorinen
```
### 3. Initialize Chezmoi with Existing Dotfiles
```bash
# If you want to test before full migration
chezmoi init --apply ivuorinen
# Or initialize without applying
chezmoi init ivuorinen
```
### 4. Restructure Files (Manual Step)
You'll need to rename files to follow chezmoi conventions:
```bash
cd ~/.local/share/chezmoi
# Rename base files
mv base/bashrc dot_bashrc
mv base/zshrc dot_zshrc
mv base/tmux.conf dot_tmux.conf
# Move config files
mkdir -p dot_config
mv config/* dot_config/
# Move local/bin files
mkdir -p dot_local/bin
for file in local/bin/*; do
mv "$file" "executable_dot_local/bin/$(basename "$file")"
done
# Move SSH files with proper permissions
mkdir -p private_dot_ssh
mv ssh/* private_dot_ssh/
```
### 5. Convert Host-Specific Configurations
For files that differ between hosts, use templates:
```bash
# Instead of hosts/air/config/fish/config.fish
# Create: dot_config/fish/config.fish.tmpl
{{ if eq .chezmoi.hostname "air" }}
# air-specific configuration
{{ else if eq .chezmoi.hostname "lakka" }}
# lakka-specific configuration
{{ end }}
```
### 6. Test the Migration
```bash
# See what changes chezmoi would make
chezmoi diff
# Apply changes
chezmoi apply
# Verify everything works
chezmoi verify
```
### 7. Clean Up Old Files
```bash
# Remove dotbot directories (after confirming everything works)
cd ~/.local/share/chezmoi
rm -rf tools/dotbot tools/dotbot-*
rm install.conf.yaml
rm -rf hosts/ # If fully migrated to templates
```
## Usage Guide
### Basic Commands
```bash
# Initialize chezmoi with your dotfiles
chezmoi init ivuorinen
# See what changes would be made
chezmoi diff
# Apply dotfiles
chezmoi apply
# Apply with verbose output
chezmoi apply -v
# Edit a file managed by chezmoi
chezmoi edit ~/.bashrc
# Add a new file to chezmoi
chezmoi add ~/.newfile
# Update dotfiles from source
chezmoi update
# See what files are managed
chezmoi managed
# See what files are unmanaged
chezmoi unmanaged
# Re-run scripts
chezmoi apply --force
# Check for issues
chezmoi doctor
```
### Working with Templates
```bash
# Execute a template
chezmoi execute-template "{{ .chezmoi.hostname }}"
# See the data available in templates
chezmoi data
# Edit template data
chezmoi edit-config
```
### Managing Secrets
```bash
# Use with 1Password
chezmoi secret keychain
# Template with 1Password
{{ (index (onepasswordDocument "my-secret") 0).content }}
# Use with environment variables
{{ .Env.MY_SECRET }}
```
### Updating Dotfiles
```bash
# Edit source file
chezmoi edit ~/.bashrc
# Or edit directly and add
vi ~/.bashrc
chezmoi add ~/.bashrc
# Commit changes
cd $(chezmoi source-path)
git add -A
git commit -m "Update bashrc"
git push
# On another machine
chezmoi update
```
## Troubleshooting
### Common Issues
#### 1. File Permissions
**Problem**: Files have wrong permissions after applying.
**Solution**: Use prefixes:
```bash
# For 0600 permissions
chezmoi add --template private_dot_ssh/config
# For 0700 directories
mkdir -p private_dot_ssh
```
#### 2. Symlinks Not Working
**Problem**: Chezmoi copies files instead of symlinking.
**Solution**: Use `symlink_` prefix:
```bash
chezmoi add --symlink ~/.vim
# This creates symlink_dot_vim in the source directory
```
#### 3. Templates Not Rendering
**Problem**: Template syntax is showing literally in files.
**Solution**:
- Ensure file has `.tmpl` extension
- Check template syntax
- Verify data with `chezmoi data`
#### 4. Scripts Not Running
**Problem**: `run_once_` scripts not executing.
**Solution**:
- Check script permissions: `chmod +x run_once_*.sh.tmpl`
- Run with force: `chezmoi apply --force`
- Check script order (before/after)
#### 5. Host-Specific Files Not Applying
**Problem**: Wrong host configuration applied.
**Solution**:
- Check hostname: `chezmoi data | grep hostname`
- Verify template conditionals
- Use `.chezmoiignore` for host-specific exclusions
### Debugging
```bash
# Verbose output
chezmoi apply -v
# Very verbose output
chezmoi apply -vv
# Dry run to see what would happen
chezmoi apply --dry-run -v
# Check configuration
chezmoi doctor
# Verify state
chezmoi verify
# See source directory
chezmoi source-path
# See what would be applied to a specific file
chezmoi cat ~/.bashrc
```
### Migration Checklist
- [ ] Backup current dotfiles
- [ ] Install chezmoi
- [ ] Create `.chezmoi.yaml.tmpl`
- [ ] Create `.chezmoiignore`
- [ ] Rename files with proper prefixes
- [ ] Convert host-specific configs to templates
- [ ] Create `run_once_before` scripts
- [ ] Create `run_once_after` scripts
- [ ] Test with `chezmoi diff`
- [ ] Apply with `chezmoi apply`
- [ ] Verify everything works
- [ ] Update documentation
- [ ] Clean up old dotbot files
- [ ] Update README.md
- [ ] Test on another machine
## Additional Resources
- [Chezmoi Documentation](https://www.chezmoi.io/)
- [Chezmoi Quick Start](https://www.chezmoi.io/quick-start/)
- [Chezmoi User Guide](https://www.chezmoi.io/user-guide/)
- [Chezmoi Template Reference](https://www.chezmoi.io/reference/templates/)
- [Example Dotfiles Using Chezmoi](https://github.com/topics/chezmoi)
## Notes
### What Stays the Same
- Your actual dotfile contents
- Directory structure in home directory
- Git workflow for managing dotfiles
- The `dfm` script functionality (wrapped in run_once scripts)
### What Changes
- Installation method (new `install` script)
- Source directory location (`~/.local/share/chezmoi` by default)
- Configuration method (templates instead of YAML)
- File naming (special prefixes)
- No more symlinks by default (unless specified)
### Benefits of Migration
1. **Simplicity**: Single binary, no dependencies
2. **Templating**: Dynamic content based on hostname, OS, etc.
3. **Secrets**: Built-in support for password managers
4. **State Management**: Better tracking of what's managed
5. **Cross-platform**: Excellent support for different OSes
6. **Documentation**: Extensive docs and examples
7. **Community**: Active development and support
## Post-Migration
After successful migration:
1. Update your README to reflect chezmoi usage
2. Archive dotbot configuration for reference
3. Document any custom scripts or workflows
4. Test on all your machines
5. Share your experience!

37
install
View File

@@ -1,38 +1,5 @@
#!/usr/bin/env bash
set -e
CONFIG="install.conf.yaml"
DOTBOT_DIR="tools/dotbot"
DOTBOT_BIN="bin/dotbot"
BASEDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DOTBOT_BIN_PATH="${BASEDIR}/${DOTBOT_DIR}/${DOTBOT_BIN}"
DOTBOT_HOST="$(hostname -s)"
cd "${BASEDIR}"
git -C "${DOTBOT_DIR}" submodule sync --quiet --recursive
git submodule update --init --recursive "${DOTBOT_DIR}"
"${DOTBOT_BIN_PATH}" \
-d "${BASEDIR}" \
--plugin-dir=tools/dotbot-asdf \
--plugin-dir=tools/dotbot-brew \
--plugin-dir=tools/dotbot-include \
--plugin-dir=tools/dotbot-pip \
-c "${CONFIG}" \
"${@}"
if [ "${DOTBOT_HOST}" != "" ]; then
DOTBOT_HOST_CONFIG="${BASEDIR}/hosts/${DOTBOT_HOST}/${CONFIG}"
echo "-> Trying if host config can be found: ${DOTBOT_HOST_CONFIG}"
[ -r "$DOTBOT_HOST_CONFIG" ] && [ -f "$DOTBOT_HOST_CONFIG" ] &&
echo "(!) Found $DOTBOT_HOST_CONFIG" &&
"$DOTBOT_BIN_PATH" \
-d "$BASEDIR" \
--plugin-dir=tools/dotbot-asdf \
--plugin-dir=tools/dotbot-brew \
--plugin-dir=tools/dotbot-include \
--plugin-dir=tools/dotbot-pip \
-c "$DOTBOT_HOST_CONFIG" \
"${@}"
fi
# Install and apply chezmoi
sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply ivuorinen

260
migrate-to-chezmoi.sh Executable file
View File

@@ -0,0 +1,260 @@
#!/usr/bin/env bash
# Migration helper script: Dotbot to Chezmoi
# This script helps restructure files from dotbot format to chezmoi format
#
# IMPORTANT: Review changes carefully before running!
# It's recommended to run this in a new git branch
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log_info() {
echo -e "${BLUE}${NC} $1"
}
log_success() {
echo -e "${GREEN}${NC} $1"
}
log_warning() {
echo -e "${YELLOW}${NC} $1"
}
log_error() {
echo -e "${RED}${NC} $1"
}
# Check if we're in a git repository
if [ ! -d .git ]; then
log_error "Not a git repository. Please run from your dotfiles directory."
exit 1
fi
# Confirm with user
log_warning "This script will restructure your dotfiles for chezmoi."
log_warning "It's STRONGLY recommended to:"
log_warning " 1. Commit all current changes"
log_warning " 2. Create a new branch for migration"
log_warning " 3. Review all changes before merging"
echo ""
read -p "Do you want to continue? (yes/no): " -r
echo
if [[ ! $REPLY =~ ^[Yy][Ee][Ss]$ ]]; then
log_info "Migration cancelled."
exit 0
fi
# Create backup branch
log_info "Creating backup branch..."
BACKUP_BRANCH="backup-before-chezmoi-$(date +%Y%m%d-%H%M%S)"
git branch "$BACKUP_BRANCH"
log_success "Created backup branch: $BACKUP_BRANCH"
# Create migration branch
log_info "Creating migration branch..."
MIGRATION_BRANCH="migrate-to-chezmoi"
git checkout -b "$MIGRATION_BRANCH" 2>/dev/null || git checkout "$MIGRATION_BRANCH"
log_success "Switched to migration branch: $MIGRATION_BRANCH"
# Function to move and rename files
move_dotfiles() {
local src=$1
local dest=$2
local prefix=$3
if [ -f "$src" ]; then
mkdir -p "$(dirname "$dest")"
log_info "Moving: $src$dest"
git mv "$src" "$dest" 2>/dev/null || mv "$src" "$dest"
fi
}
# Migrate base files (these become dot_ files)
log_info "Migrating base files..."
if [ -d base ]; then
for file in base/*; do
if [ -f "$file" ]; then
filename=$(basename "$file")
# Skip certain files
if [[ "$filename" =~ \.(md|MD)$ ]]; then
continue
fi
move_dotfiles "$file" "dot_${filename}" ""
fi
done
log_success "Base files migrated"
fi
# Migrate config directory
log_info "Migrating config directory..."
if [ -d config ]; then
# Create dot_config if it doesn't exist
mkdir -p dot_config
for item in config/*; do
if [ -e "$item" ]; then
basename_item=$(basename "$item")
# Skip certain directories
if [[ "$basename_item" == "homebrew" ]] || [[ "$basename_item" == "shared.sh" ]]; then
log_info "Keeping $item in place (referenced by scripts)"
continue
fi
log_info "Moving: $item → dot_config/$basename_item"
git mv "$item" "dot_config/$basename_item" 2>/dev/null || mv "$item" "dot_config/$basename_item"
fi
done
log_success "Config files migrated"
fi
# Migrate local/bin with executable prefix
log_info "Migrating local/bin scripts..."
if [ -d local/bin ]; then
mkdir -p executable_dot_local/bin
for script in local/bin/*; do
if [ -f "$script" ]; then
basename_script=$(basename "$script")
log_info "Moving: $script → executable_dot_local/bin/$basename_script"
git mv "$script" "executable_dot_local/bin/$basename_script" 2>/dev/null || \
mv "$script" "executable_dot_local/bin/$basename_script"
fi
done
log_success "Local bin scripts migrated"
fi
# Migrate local/share
log_info "Migrating local/share..."
if [ -d local/share ]; then
mkdir -p dot_local/share
for item in local/share/*; do
if [ -e "$item" ]; then
basename_item=$(basename "$item")
log_info "Moving: $item → dot_local/share/$basename_item"
git mv "$item" "dot_local/share/$basename_item" 2>/dev/null || \
mv "$item" "dot_local/share/$basename_item"
fi
done
log_success "Local share migrated"
fi
# Migrate local/man
log_info "Migrating local/man..."
if [ -d local/man ]; then
mkdir -p dot_local/man
for item in local/man/*; do
if [ -e "$item" ]; then
basename_item=$(basename "$item")
log_info "Moving: $item → dot_local/man/$basename_item"
git mv "$item" "dot_local/man/$basename_item" 2>/dev/null || \
mv "$item" "dot_local/man/$basename_item"
fi
done
log_success "Local man pages migrated"
fi
# Migrate SSH files with private prefix
log_info "Migrating SSH files..."
if [ -d ssh ]; then
mkdir -p private_dot_ssh
for item in ssh/*; do
if [ -f "$item" ]; then
basename_item=$(basename "$item")
log_info "Moving: $item → private_dot_ssh/$basename_item"
git mv "$item" "private_dot_ssh/$basename_item" 2>/dev/null || \
mv "$item" "private_dot_ssh/$basename_item"
fi
done
log_success "SSH files migrated"
fi
# Clean up empty directories
log_info "Cleaning up empty directories..."
find . -type d -empty -delete 2>/dev/null || true
log_success "Empty directories removed"
# Create README for old structure
log_info "Creating migration notes..."
cat > MIGRATION-NOTES.md << 'EOF'
# Migration Notes
This repository has been migrated from dotbot to chezmoi.
## Old Structure (Dotbot)
```
~/.dotfiles/
├── base/ # Files symlinked to ~/.*
├── config/ # Files symlinked to ~/.config/
├── local/ # Scripts and local files
├── ssh/ # SSH configuration
├── install # Dotbot installation script
└── install.conf.yaml # Dotbot configuration
```
## New Structure (Chezmoi)
```
~/.dotfiles/ (or ~/.local/share/chezmoi)
├── dot_* # Files that become ~/.*
├── dot_config/ # Files that become ~/.config/
├── executable_dot_local/ # Executable scripts
├── private_dot_ssh/ # SSH files with 0700 permissions
├── run_once_*.sh.tmpl # One-time setup scripts
├── .chezmoi.yaml.tmpl # Chezmoi configuration
└── .chezmoiignore # Files to ignore
```
## File Naming Conventions
- `dot_bashrc``~/.bashrc`
- `dot_config/fish/``~/.config/fish/`
- `private_dot_ssh/``~/.ssh/` (mode 0700)
- `executable_dot_local/bin/script``~/.local/bin/script` (executable)
- `symlink_dot_vim``~/.vim` (symlink)
## Next Steps
1. Review the migration with: `git diff`
2. Test with chezmoi: `chezmoi init --dry-run --verbose $(pwd)`
3. Apply if everything looks good: `chezmoi init --apply $(pwd)`
4. Read the full migration guide: `MIGRATION-DOTBOT-TO-CHEZMOI.md`
## Backup
A backup branch was created: `$BACKUP_BRANCH`
You can switch back with: `git checkout $BACKUP_BRANCH`
EOF
log_success "Migration notes created: MIGRATION-NOTES.md"
# Show summary
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
log_success "Migration complete!"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
log_info "Summary:"
echo " • Backup branch: $BACKUP_BRANCH"
echo " • Migration branch: $MIGRATION_BRANCH"
echo ""
log_info "Next steps:"
echo " 1. Review changes: git status && git diff"
echo " 2. Test with chezmoi: chezmoi init --dry-run --verbose \$(pwd)"
echo " 3. Read migration guide: cat MIGRATION-DOTBOT-TO-CHEZMOI.md"
echo " 4. Commit changes: git add -A && git commit -m 'Migrate to chezmoi'"
echo ""
log_warning "IMPORTANT: Review all changes before committing!"
log_warning "Test thoroughly before applying to your home directory!"
echo ""

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# run_once_after script to create required directories
# This runs once after applying dotfiles
set -e
echo "→ Creating required directories..."
# Create directories with proper permissions
mkdir -p "$HOME/.cache"
mkdir -p "$HOME/.cache/git"
mkdir -p "$HOME/.config"
mkdir -p "$HOME/.local"
mkdir -p "$HOME/.local/bin"
mkdir -p "$HOME/.local/run"
mkdir -p "$HOME/.local/share"
mkdir -p "$HOME/.local/state"
mkdir -p "$HOME/.local/state/tmux"
mkdir -p "$HOME/.local/state/zsh"
mkdir -p "$HOME/Code"
# Create directories with restricted permissions
mkdir -p "$HOME/.local/share/gnupg"
chmod 0700 "$HOME/.local/share/gnupg"
mkdir -p "$HOME/.ssh"
chmod 0700 "$HOME/.ssh"
mkdir -p "$HOME/.ssh/local.d"
chmod 0700 "$HOME/.ssh/local.d"
echo "✓ Directories created!"

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# run_once_after script to install packages
# This runs once after applying dotfiles
set -e
DOTFILES="{{ .chezmoi.sourceDir }}"
export DOTFILES
# Source shared configuration
if [ -f "$DOTFILES/config/shared.sh" ]; then
source "$DOTFILES/config/shared.sh"
fi
# Source message helper if available
if [ -f "$DOTFILES/local/bin/msgr" ]; then
source "$DOTFILES/local/bin/msgr"
fi
echo "→ Installing packages..."
{{- if .is_macos }}
# Install Homebrew packages
if [ -f "$DOTFILES/config/homebrew/Brewfile" ]; then
echo "→ Installing Homebrew packages..."
brew bundle install --file="$DOTFILES/config/homebrew/Brewfile" --no-lock || true
fi
# Setup macOS defaults
if [ -f "$DOTFILES/scripts/install-macos-defaults.sh" ]; then
echo "→ Setting up macOS defaults..."
bash "$DOTFILES/scripts/install-macos-defaults.sh" || true
fi
{{- end }}
{{- if .is_linux }}
# Install apt packages if on Debian/Ubuntu
if command -v apt &> /dev/null && [ -f "$DOTFILES/tools/apt.txt" ]; then
echo "→ Installing apt packages..."
sudo apt install -y $(grep -vE '^\s*#' "$DOTFILES/tools/apt.txt" | sed -e 's/#.*//' | tr '\n' ' ') || true
fi
{{- end }}
# Install pipx packages
if command -v pipx &> /dev/null && [ -f "$DOTFILES/tools/requirements-pipx.txt" ]; then
echo "→ Installing pipx packages..."
while IFS= read -r package; do
[ -z "$package" ] || pipx install "$package" || true
done < "$DOTFILES/tools/requirements-pipx.txt"
fi
echo "✓ Packages installed!"

View File

@@ -0,0 +1,76 @@
#!/usr/bin/env bash
# run_once_after script to setup programming languages and tools
# This runs once after applying dotfiles
set -e
DOTFILES="{{ .chezmoi.sourceDir }}"
export DOTFILES
echo "→ Setting up programming languages and tools..."
# Install fonts
if [ -f "$DOTFILES/scripts/install-fonts.sh" ]; then
echo "→ Installing fonts..."
bash "$DOTFILES/scripts/install-fonts.sh" || true
fi
# Install Cargo packages
if command -v cargo &> /dev/null && [ -f "$DOTFILES/scripts/install-cargo-packages.sh" ]; then
echo "→ Installing Cargo packages..."
bash "$DOTFILES/scripts/install-cargo-packages.sh" || true
fi
# Install Go packages
if command -v go &> /dev/null && [ -f "$DOTFILES/scripts/install-go-packages.sh" ]; then
echo "→ Installing Go packages..."
bash "$DOTFILES/scripts/install-go-packages.sh" || true
fi
# Install Composer
if [ -f "$DOTFILES/scripts/install-composer.sh" ]; then
echo "→ Installing Composer..."
bash "$DOTFILES/scripts/install-composer.sh" || true
fi
# Install NVM
if [ ! -d "$HOME/.nvm" ] && command -v curl &> /dev/null; then
echo "→ Installing NVM..."
NVM_VERSION=$(curl -s https://api.github.com/repos/nvm-sh/nvm/releases/latest | grep -o '"tag_name": "[^"]*' | cut -d'"' -f4)
PROFILE=/dev/null bash -c "curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh | bash" || true
fi
# Install latest Node LTS
if [ -s "$HOME/.nvm/nvm.sh" ]; then
echo "→ Installing latest Node LTS..."
source "$HOME/.nvm/nvm.sh"
nvm install --lts --latest-npm --default || true
fi
# Install NPM packages
if command -v npm &> /dev/null && [ -f "$DOTFILES/scripts/install-npm-packages.sh" ]; then
echo "→ Installing NPM packages..."
bash "$DOTFILES/scripts/install-npm-packages.sh" || true
fi
# Install GitHub CLI extensions
if command -v gh &> /dev/null && [ -f "$DOTFILES/scripts/install-gh-extensions.sh" ]; then
echo "→ Installing GitHub CLI extensions..."
bash "$DOTFILES/scripts/install-gh-extensions.sh" || true
fi
# Install z
if [ -f "$DOTFILES/scripts/install-z.sh" ]; then
echo "→ Installing z..."
bash "$DOTFILES/scripts/install-z.sh" || true
fi
# Install cheat databases
for database in "$DOTFILES"/scripts/install-cheat-*; do
if [ -f "$database" ]; then
echo "→ Installing $(basename "$database")..."
bash "$database" || true
fi
done
echo "✓ Programming languages and tools setup complete!"

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# run_once_before script to install prerequisites
# This runs once before applying dotfiles
set -e
echo "→ Installing prerequisites..."
{{- if .is_macos }}
# Install Homebrew if not present
if ! command -v brew &> /dev/null; then
echo "→ Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
# Install Xcode CLI tools if needed
if ! xcode-select -p &> /dev/null; then
echo "→ Installing Xcode Command Line Tools..."
xcode-select --install || true
fi
{{- end }}
{{- if .is_linux }}
# Update package manager
if command -v apt &> /dev/null; then
echo "→ Updating apt..."
sudo apt update
fi
{{- end }}
echo "✓ Prerequisites installed!"