Switch to chezmoi - blitterated/dotfiles GitHub Wiki
I'm currently using Gnu Stow as a dotfile manager. It's good, but it's more of a binary link farm manager than a dotfile manager. The requirement for Perl isn't my cup of tea, either, There's too many good Rust utilities these days.
draw.io diagram of my chezmoi files logical layout.
git statusOn branch main
Your branch is ahead of 'origin/main' by 4 commits.
(use "git push" to publish your local commits)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: nvim/.config/nvim/init.lua
modified: nvim/.config/nvim/lazy-lock.json
modified: zsh/.zshrc
Untracked files:
(use "git add <file>..." to include in what will be committed)
__lib/
nvim/.config/nvim/lua/linenumber-colors.lua
nvim/.config/nvim/lua/plugins/lsp-config.lua
no changes added to commit (use "git add" and/or "git commit -a")
ls -l nvim/.config/nvim/init.lua.rw-r--r--@ 665 blitterated 6 Jun 00:01 nvim/.config/nvim/init.lua
ls -l nvim/.config/nvim/lazy-lock.json.rw-r--r--@ 1.2k blitterated 7 Jun 15:27 nvim/.config/nvim/lazy-lock.json
ls -l nvim/.config/nvim/lua/linenumber-colors.lua.rw-r--r--@ 162 blitterated 5 Jun 23:48 nvim/.config/nvim/lua/linenumber-colors.lua
ls -l nvim/.config/nvim/lua/plugins/lsp-config.lua.rw-r--r--@ 605 blitterated 7 Jun 15:27 nvim/.config/nvim/lua/plugins/lsp-config.lua
ls -l zsh/.zshrc.rw-r--r--@ 3.3k blitterated 10 Jun 00:42 zsh/.zshrc
Here they are in order.
| Date | Time | File |
|---|---|---|
| 06/05/2025 | 23:48 | nvim/.config/nvim/lua/linenumber-colors.lua |
| 06/06/2025 | 00:01 | nvim/.config/nvim/init.lua |
| 06/07/2025 | 15:27 | nvim/.config/nvim/lazy-lock.json |
| 06/07/2025 | 15:27 | nvim/.config/nvim/lua/plugins/lsp-config.lua |
| 06/10/2025 | 00:42 | zsh/.zshrc |
It took a while with Gnu find, so I also tried timing it.
time find $HOME -type l -exec ls -l {} \; | grep '.dotfiles/'lrwxr-xr-x@ 1 blitterated staff 30 May 18 18:32 ./.config/nvim -> ../.dotfiles/nvim/.config/nvim
lrwxr-xr-x@ 1 blitterated staff 43 May 18 18:37 ./.config/starship.toml -> ../.dotfiles/starship/.config/starship.toml
lrwxr-xr-x@ 1 blitterated staff 21 May 18 18:38 ./.gemrc -> .dotfiles/ruby/.gemrc
lrwxr-xr-x@ 1 blitterated staff 25 May 18 18:43 ./.tmux.conf -> .dotfiles/tmux/.tmux.conf
lrwxr-xr-x@ 1 blitterated staff 22 May 18 18:25 ./.bashrc -> .dotfiles/bash/.bashrc
lrwxr-xr-x@ 1 blitterated staff 20 May 18 18:28 ./.zshrc -> .dotfiles/zsh/.zshrc
lrwxr-xr-x@ 1 blitterated staff 34 May 18 22:01 ./.zsh_local -> .dotfiles/zsh_local.mac/.zsh_local
lrwxr-xr-x@ 1 blitterated staff 23 May 18 18:28 ./.zprofile -> .dotfiles/zsh/.zprofile
lrwxr-xr-x@ 1 blitterated staff 36 May 18 21:45 ./.bash_local -> .dotfiles/bash_local.mac/.bash_local
lrwxr-xr-x@ 1 blitterated staff 31 May 18 18:30 ./.gitignore_global -> .dotfiles/git/.gitignore_global
lrwxr-xr-x@ 1 blitterated staff 20 May 18 18:44 ./.vimrc -> .dotfiles/vim/.vimrc
lrwxr-xr-x@ 1 blitterated staff 21 May 18 18:38 ./.pryrc -> .dotfiles/ruby/.pryrc
lrwxr-xr-x@ 1 blitterated staff 28 May 18 18:25 ./.bash_profile -> .dotfiles/bash/.bash_profile
lrwxr-xr-x@ 1 blitterated staff 22 May 18 18:44 ./.psqlrc -> .dotfiles/psql/.psqlrc
lrwxr-xr-x@ 1 blitterated staff 24 May 18 18:30 ./.gitconfig -> .dotfiles/git/.gitconfig
lrwxr-xr-x@ 1 blitterated staff 18 May 18 18:44 ./.bcrc -> .dotfiles/bc/.bcrc
find . -type l -exec ls -l {} \;
35.04s user
84.79s system
41% cpu
4:50.30 total
grep '.dotfiles/'
0.22s user
0.15s system
0% cpu
4:50.30 total
Here's the results in table form
| Type | Link | Target |
|---|---|---|
| File | ~/.bash_local |
~/.dotfiles/bash_local.mac/.bash_local |
| File | ~/.bash_profile |
~/.dotfiles/bash/.bash_profile |
| File | ~/.bashrc |
~/.dotfiles/bash/.bashrc |
| File | ~/.bcrc |
~/.dotfiles/bc/.bcrc |
| Dir | ~/.config/nvim |
~/.dotfiles/nvim/.config/nvim |
| File | ~/.config/starship.toml |
~/.dotfiles/starship/.config/starship.toml |
| File | ~/.gemrc |
~/.dotfiles/ruby/.gemrc |
| File | ~/.gitconfig |
~/.dotfiles/git/.gitconfig |
| File | ~/.gitignore_global |
~/.dotfiles/git/.gitignore_global |
| File | ~/.pryrc |
~/.dotfiles/ruby/.pryrc |
| File | ~/.psqlrc |
~/.dotfiles/psql/.psqlrc |
| File | ~/.tmux.conf |
~/.dotfiles/tmux/.tmux.conf |
| File | ~/.vimrc |
~/.dotfiles/vim/.vimrc |
| File | ~/.zprofile |
~/.dotfiles/zsh/.zprofile |
| File | ~/.zsh_local |
~/.dotfiles/zsh_local.mac/.zsh_local |
| File | ~/.zshrc |
~/.dotfiles/zsh/.zshrc |
dotlinks=( '.bash_local' '.bash_profile' '.bashrc' '.bcrc' '.config/nvim' '.config/starship.toml'
'.gemrc' '.gitconfig' '.gitignore_global' '.pryrc' '.psqlrc' '.tmux.conf' '.vimrc'
'.zprofile' '.zsh_local' '.zshrc' )Try out the array.
echo "${dotlinks[@]}".bash_local .bash_profile .bashrc .bcrc .config/nvim .config/starship.toml .gemrc .gitconfig .gitignore_global .pryrc .psqlrc .tmux.conf .vimrc .zprofile .zsh_local .zshrc
Try out listing the array.
for link in "${dotlinks[@]}"; do echo "\"${link}\""; done".bash_local"
".bash_profile"
".bashrc"
".bcrc"
".config/nvim"
".config/starship.toml"
".gemrc"
".gitconfig"
".gitignore_global"
".pryrc"
".psqlrc"
".tmux.conf"
".vimrc"
".zprofile"
".zsh_local"
".zshrc"
for link in "${dotlinks[@]}"; do
local target=$(readlink "$HOME/$link")
echo "\"~/${link}\" -> "\"${target}\"
done"~/.bash_local" -> ".dotfiles/bash_local.mac/.bash_local"
"~/.bash_profile" -> ".dotfiles/bash/.bash_profile"
"~/.bashrc" -> ".dotfiles/bash/.bashrc"
"~/.bcrc" -> ".dotfiles/bc/.bcrc"
"~/.config/nvim" -> "../.dotfiles/nvim/.config/nvim"
"~/.config/starship.toml" -> "../.dotfiles/starship/.config/starship.toml"
"~/.gemrc" -> ".dotfiles/ruby/.gemrc"
"~/.gitconfig" -> ".dotfiles/git/.gitconfig"
"~/.gitignore_global" -> ".dotfiles/git/.gitignore_global"
"~/.pryrc" -> ".dotfiles/ruby/.pryrc"
"~/.psqlrc" -> ".dotfiles/psql/.psqlrc"
"~/.tmux.conf" -> ".dotfiles/tmux/.tmux.conf"
"~/.vimrc" -> ".dotfiles/vim/.vimrc"
"~/.zprofile" -> ".dotfiles/zsh/.zprofile"
"~/.zsh_local" -> ".dotfiles/zsh_local.mac/.zsh_local"
"~/.zshrc" -> ".dotfiles/zsh/.zshrc"
Looks like the path returned by readLink returns the path relative to the target fromt the soft link file.
Scrape off everything from the start of the target path up to and including .dotfiles/, and then stitch together a full path to the file.
for link in "${dotlinks[@]}"; do
local target="${HOME}/.dotfiles/$(readlink "$HOME/$link" | gsed -E -e "s/^.*?\.dotfiles\///")"
echo "\"~/${link}\" -> "\"${target}\"
done"~/.bash_local" -> "/Users/blitterated/.dotfiles/bash_local.mac/.bash_local"
"~/.bash_profile" -> "/Users/blitterated/.dotfiles/bash/.bash_profile"
"~/.bashrc" -> "/Users/blitterated/.dotfiles/bash/.bashrc"
"~/.bcrc" -> "/Users/blitterated/.dotfiles/bc/.bcrc"
"~/.config/nvim" -> "/Users/blitterated/.dotfiles/nvim/.config/nvim"
"~/.config/starship.toml" -> "/Users/blitterated/.dotfiles/starship/.config/starship.toml"
"~/.gemrc" -> "/Users/blitterated/.dotfiles/ruby/.gemrc"
"~/.gitconfig" -> "/Users/blitterated/.dotfiles/git/.gitconfig"
"~/.gitignore_global" -> "/Users/blitterated/.dotfiles/git/.gitignore_global"
"~/.pryrc" -> "/Users/blitterated/.dotfiles/ruby/.pryrc"
"~/.psqlrc" -> "/Users/blitterated/.dotfiles/psql/.psqlrc"
"~/.tmux.conf" -> "/Users/blitterated/.dotfiles/tmux/.tmux.conf"
"~/.vimrc" -> "/Users/blitterated/.dotfiles/vim/.vimrc"
"~/.zprofile" -> "/Users/blitterated/.dotfiles/zsh/.zprofile"
"~/.zsh_local" -> "/Users/blitterated/.dotfiles/zsh_local.mac/.zsh_local"
"~/.zshrc" -> "/Users/blitterated/.dotfiles/zsh/.zshrc"
Dump the above in a Markdown table.
echo '| Source | Target |'
echo '| ------ | ------ |'
for link in "${dotlinks[@]}"; do
local target="${HOME}/.dotfiles/$(readlink "$HOME/$link" | gsed -E -e "s/^.*?\.dotfiles\///")"
echo "| \`~/${link}\` | \`${target}\` |"
done| Source | Target |
|---|---|
~/.bash_local |
/Users/blitterated/.dotfiles/bash_local.mac/.bash_local |
~/.bash_profile |
/Users/blitterated/.dotfiles/bash/.bash_profile |
~/.bashrc |
/Users/blitterated/.dotfiles/bash/.bashrc |
~/.bcrc |
/Users/blitterated/.dotfiles/bc/.bcrc |
~/.config/nvim |
/Users/blitterated/.dotfiles/nvim/.config/nvim |
~/.config/starship.toml |
/Users/blitterated/.dotfiles/starship/.config/starship.toml |
~/.gemrc |
/Users/blitterated/.dotfiles/ruby/.gemrc |
~/.gitconfig |
/Users/blitterated/.dotfiles/git/.gitconfig |
~/.gitignore_global |
/Users/blitterated/.dotfiles/git/.gitignore_global |
~/.pryrc |
/Users/blitterated/.dotfiles/ruby/.pryrc |
~/.psqlrc |
/Users/blitterated/.dotfiles/psql/.psqlrc |
~/.tmux.conf |
/Users/blitterated/.dotfiles/tmux/.tmux.conf |
~/.vimrc |
/Users/blitterated/.dotfiles/vim/.vimrc |
~/.zprofile |
/Users/blitterated/.dotfiles/zsh/.zprofile |
~/.zsh_local |
/Users/blitterated/.dotfiles/zsh_local.mac/.zsh_local |
~/.zshrc |
/Users/blitterated/.dotfiles/zsh/.zshrc |
Switch from using ~ to ${HOME} for the link's full path.
Also, separate the path from the filename.
echo '| Source Path | Source Filename | Target Full Path |'
echo '| ------ | ------ | ------ |'
for link in "${dotlinks[@]}"; do
local source="${HOME}/${link}"
local source_path="$(dirname "${source}")"
local source_filename="$(basename "${source}")"
local target="${HOME}/.dotfiles/$(readlink "$HOME/$link" | gsed -E -e "s/^.*?\.dotfiles\///")"
echo "| \`${source_path}\` | \`${source_filename}\` | \`${target}\` |"
done| Source Path | Source Filename | Target Full Path |
|---|---|---|
/Users/blitterated |
.bash_local |
/Users/blitterated/.dotfiles/bash_local.mac/.bash_local |
/Users/blitterated |
.bash_profile |
/Users/blitterated/.dotfiles/bash/.bash_profile |
/Users/blitterated |
.bashrc |
/Users/blitterated/.dotfiles/bash/.bashrc |
/Users/blitterated |
.bcrc |
/Users/blitterated/.dotfiles/bc/.bcrc |
/Users/blitterated/.config |
nvim |
/Users/blitterated/.dotfiles/nvim/.config/nvim |
/Users/blitterated/.config |
starship.toml |
/Users/blitterated/.dotfiles/starship/.config/starship.toml |
/Users/blitterated |
.gemrc |
/Users/blitterated/.dotfiles/ruby/.gemrc |
/Users/blitterated |
.gitconfig |
/Users/blitterated/.dotfiles/git/.gitconfig |
/Users/blitterated |
.gitignore_global |
/Users/blitterated/.dotfiles/git/.gitignore_global |
/Users/blitterated |
.pryrc |
/Users/blitterated/.dotfiles/ruby/.pryrc |
/Users/blitterated |
.psqlrc |
/Users/blitterated/.dotfiles/psql/.psqlrc |
/Users/blitterated |
.tmux.conf |
/Users/blitterated/.dotfiles/tmux/.tmux.conf |
/Users/blitterated |
.vimrc |
/Users/blitterated/.dotfiles/vim/.vimrc |
/Users/blitterated |
.zprofile |
/Users/blitterated/.dotfiles/zsh/.zprofile |
/Users/blitterated |
.zsh_local |
/Users/blitterated/.dotfiles/zsh_local.mac/.zsh_local |
/Users/blitterated |
.zshrc |
/Users/blitterated/.dotfiles/zsh/.zshrc |
Most of the dotfile links created by stow point at a file. However, Neovim's configuration files are pointed to with a directory link.
Create a test folder for cp tests.
mkdir test_cp && cd $_Test out a recursive copy to a test folder.
cp -r ~/.dotfiles/nvim/.config/nvim .
treenvim
├── init.lua
├── lazy-lock.json
└── lua
├── config
│ └── lazy.lua
├── linenumber-colors.lua
├── plugins
│ ├── catppuccin.lua
│ ├── lsp-config.lua
│ ├── lualine.lua
│ ├── neotree.lua
│ ├── telescope.lua
│ └── treesitter.lua
└── vim-options.lua
Can we use the same cp -r command as above to copy files? This would avoid needing a decision branch in bash.
cp -r ~/.dotfiles/bc/.bcrc .
tree -a.bcrc
nvim
├── init.lua
├── lazy-lock.json
└── lua
├── config
│ └── lazy.lua
├── linenumber-colors.lua
├── plugins
│ ├── catppuccin.lua
│ ├── lsp-config.lua
│ ├── lualine.lua
│ ├── neotree.lua
│ ├── telescope.lua
│ └── treesitter.lua
└── vim-options.lua
echo "| Delete link | Copy dotfiles |"
echo "| ----------- | ------------- |"
for link in "${dotlinks[@]}"; do
local source="${HOME}/${link}"
local source_path="$(dirname "${source}")"
local target="${HOME}/.dotfiles/$(readlink "$HOME/$link" | gsed -E -e "s/^.*?\.dotfiles\///")"
local rm_cmd="rm \"${source}\""
local cp_cmd="cp -r \"${target}\" \"${source_path}\""
echo "| ${rm_cmd} | ${cp_cmd} |"
done| Delete link | Copy dotfiles |
|---|---|
| rm "/Users/blitterated/.bash_local" | cp -r "/Users/blitterated/.dotfiles/bash_local.mac/.bash_local" "/Users/blitterated" |
| rm "/Users/blitterated/.bash_profile" | cp -r "/Users/blitterated/.dotfiles/bash/.bash_profile" "/Users/blitterated" |
| rm "/Users/blitterated/.bashrc" | cp -r "/Users/blitterated/.dotfiles/bash/.bashrc" "/Users/blitterated" |
| rm "/Users/blitterated/.bcrc" | cp -r "/Users/blitterated/.dotfiles/bc/.bcrc" "/Users/blitterated" |
| rm "/Users/blitterated/.config/nvim" | cp -r "/Users/blitterated/.dotfiles/nvim/.config/nvim" "/Users/blitterated/.config" |
| rm "/Users/blitterated/.config/starship.toml" | cp -r "/Users/blitterated/.dotfiles/starship/.config/starship.toml" "/Users/blitterated/.config" |
| rm "/Users/blitterated/.gemrc" | cp -r "/Users/blitterated/.dotfiles/ruby/.gemrc" "/Users/blitterated" |
| rm "/Users/blitterated/.gitconfig" | cp -r "/Users/blitterated/.dotfiles/git/.gitconfig" "/Users/blitterated" |
| rm "/Users/blitterated/.gitignore_global" | cp -r "/Users/blitterated/.dotfiles/git/.gitignore_global" "/Users/blitterated" |
| rm "/Users/blitterated/.pryrc" | cp -r "/Users/blitterated/.dotfiles/ruby/.pryrc" "/Users/blitterated" |
| rm "/Users/blitterated/.psqlrc" | cp -r "/Users/blitterated/.dotfiles/psql/.psqlrc" "/Users/blitterated" |
| rm "/Users/blitterated/.tmux.conf" | cp -r "/Users/blitterated/.dotfiles/tmux/.tmux.conf" "/Users/blitterated" |
| rm "/Users/blitterated/.vimrc" | cp -r "/Users/blitterated/.dotfiles/vim/.vimrc" "/Users/blitterated" |
| rm "/Users/blitterated/.zprofile" | cp -r "/Users/blitterated/.dotfiles/zsh/.zprofile" "/Users/blitterated" |
| rm "/Users/blitterated/.zsh_local" | cp -r "/Users/blitterated/.dotfiles/zsh_local.mac/.zsh_local" "/Users/blitterated" |
| rm "/Users/blitterated/.zshrc" | cp -r "/Users/blitterated/.dotfiles/zsh/.zshrc" "/Users/blitterated" |
Looks good!
dotlinks=( '.bash_local' '.bash_profile' '.bashrc' '.bcrc' '.config/nvim' '.config/starship.toml'
'.gemrc' '.gitconfig' '.gitignore_global' '.pryrc' '.psqlrc' '.tmux.conf' '.vimrc'
'.zprofile' '.zsh_local' '.zshrc' )
ls -la $dotlinks[@]lrwxr-xr-x@ - blitterated 18 May 21:45 .bash_local -> .dotfiles/bash_local.mac/.bash_local
lrwxr-xr-x@ - blitterated 18 May 18:25 .bash_profile -> .dotfiles/bash/.bash_profile
lrwxr-xr-x@ - blitterated 18 May 18:25 .bashrc -> .dotfiles/bash/.bashrc
lrwxr-xr-x@ - blitterated 18 May 18:44 .bcrc -> .dotfiles/bc/.bcrc
lrwxr-xr-x@ - blitterated 18 May 18:38 .gemrc -> .dotfiles/ruby/.gemrc
lrwxr-xr-x@ - blitterated 18 May 18:30 .gitconfig -> .dotfiles/git/.gitconfig
lrwxr-xr-x@ - blitterated 18 May 18:30 .gitignore_global -> .dotfiles/git/.gitignore_global
lrwxr-xr-x@ - blitterated 18 May 18:38 .pryrc -> .dotfiles/ruby/.pryrc
lrwxr-xr-x@ - blitterated 18 May 18:44 .psqlrc -> .dotfiles/psql/.psqlrc
lrwxr-xr-x@ - blitterated 18 May 18:43 .tmux.conf -> .dotfiles/tmux/.tmux.conf
lrwxr-xr-x@ - blitterated 18 May 18:44 .vimrc -> .dotfiles/vim/.vimrc
lrwxr-xr-x@ - blitterated 18 May 18:28 .zprofile -> .dotfiles/zsh/.zprofile
lrwxr-xr-x@ - blitterated 18 May 22:01 .zsh_local -> .dotfiles/zsh_local.mac/.zsh_local
lrwxr-xr-x@ - blitterated 18 May 18:28 .zshrc -> .dotfiles/zsh/.zshrc
lrwxr-xr-x@ - blitterated 18 May 18:37 .config/starship.toml -> ../.dotfiles/starship/.config/starship.toml
.config/nvim:
drwxr-xr-x@ - blitterated 18 May 18:31 ..
drwxr-xr-x@ - blitterated 5 Jun 23:59 lua
lrwxr-xr-x@ - blitterated 18 May 18:32 . -> ../.dotfiles/nvim/.config/nvim
.rw-r--r--@ 665 blitterated 6 Jun 00:01 init.lua
.rw-r--r--@ 1.2k blitterated 7 Jun 15:27 lazy-lock.json
cat << EOF > replace_stow_links.sh
#!/bin/bash
replace_stow_links ()
{
# The dotfile links to be replaced
dotlinks=( '.bash_local' '.bash_profile' '.bashrc' '.bcrc' '.config/nvim' '.config/starship.toml'
'.gemrc' '.gitconfig' '.gitignore_global' '.pryrc' '.psqlrc' '.tmux.conf' '.vimrc'
'.zprofile' '.zsh_local' '.zshrc' )
# Backup directory for current link files
dead_dots="${HOME}/.dead_dots"
mkdir -p "${dead_dots}"
# Iterate dotfile links, backup, and replace them.
for link in "${dotlinks[@]}"; do
local source_link="${HOME}/${link}"
local source_path="$(dirname "${source_link}")"
local target="${HOME}/.dotfiles/$(readlink "$HOME/$link" | gsed -E -e "s/^.*?\.dotfiles\///")"
cp -P "${source_link}" "${dead_dots}"
echo
echo "Replacing \"${source_link}\" with \"${target}\""
rm "${source_link}"
cp -r "${target}" "${source_path}"
done
}
EOF
chmod +x replace_stow_links.sh
./replace_stow_links.shdotlinks=( '.bash_local' '.bash_profile' '.bashrc' '.bcrc' '.config/nvim' '.config/starship.toml'
'.gemrc' '.gitconfig' '.gitignore_global' '.pryrc' '.psqlrc' '.tmux.conf' '.vimrc'
'.zprofile' '.zsh_local' '.zshrc' )
ls -la $dotlinks[@].rw-r--r--@ 1.6k blitterated 6 Jul 17:14 .bash_local
.rw-r--r--@ 76 blitterated 6 Jul 17:14 .bash_profile
.rw-r--r--@ 2.6k blitterated 6 Jul 17:14 .bashrc
.rw-r--r--@ 114 blitterated 6 Jul 17:14 .bcrc
.rw-r--r--@ 51 blitterated 6 Jul 17:14 .gemrc
.rw-r--r--@ 115 blitterated 6 Jul 17:14 .gitconfig
.rw-r--r--@ 24 blitterated 6 Jul 17:14 .gitignore_global
.rw-r--r--@ 66 blitterated 6 Jul 17:14 .pryrc
.rw-r--r--@ 987 blitterated 6 Jul 17:14 .psqlrc
.rw-r--r--@ 1.8k blitterated 6 Jul 17:14 .tmux.conf
.rw-r--r--@ 2.5k blitterated 6 Jul 17:14 .vimrc
.rw-r--r--@ 0 blitterated 6 Jul 17:14 .zprofile
.rw-r--r--@ 2.1k blitterated 6 Jul 17:14 .zsh_local
.rw-r--r--@ 2.2k blitterated 6 Jul 17:14 .zshrc
.rw-r--r--@ 3.8k blitterated 6 Jul 17:14 .config/starship.toml
.config/nvim:
drwxr-xr-x@ - blitterated 6 Jul 17:14 .
drwx------ - blitterated 6 Jul 17:14 ..
drwxr-xr-x@ - blitterated 6 Jul 17:14 lua
.rw-r--r--@ 665 blitterated 6 Jul 17:14 init.lua
.rw-r--r--@ 1.2k blitterated 6 Jul 17:14 lazy-lock.json
Double check ~/.config/nvim
tree -a .config/nvimdrwxr-xr-x@ - blitterated 6 Jul 17:14 .config/nvim
.rw-r--r--@ 665 blitterated 6 Jul 17:14 ├── init.lua
.rw-r--r--@ 1.2k blitterated 6 Jul 17:14 ├── lazy-lock.json
drwxr-xr-x@ - blitterated 6 Jul 17:14 └── lua
drwxr-xr-x@ - blitterated 6 Jul 17:14 ├── config
.rw-r--r--@ 1.3k blitterated 6 Jul 17:14 │ └── lazy.lua
.rw-r--r--@ 162 blitterated 6 Jul 17:14 ├── linenumber-colors.lua
drwxr-xr-x@ - blitterated 6 Jul 17:14 ├── plugins
.rw-r--r--@ 155 blitterated 6 Jul 17:14 │ ├── catppuccin.lua
.rw-r--r--@ 605 blitterated 6 Jul 17:14 │ ├── lsp-config.lua
.rw-r--r--@ 162 blitterated 6 Jul 17:14 │ ├── lualine.lua
.rw-r--r--@ 413 blitterated 6 Jul 17:14 │ ├── neotree.lua
.rw-r--r--@ 303 blitterated 6 Jul 17:14 │ ├── telescope.lua
.rw-r--r--@ 591 blitterated 6 Jul 17:14 │ └── treesitter.lua
.rw-r--r--@ 540 blitterated 6 Jul 17:14 └── vim-options.lua
Looks good!
Tag last commit as "Final Gnu Stow Commit".
git tag -a gnu-stow-final -m "This is the last Gnu Stow commit before the switch to chezmoi."git push --tagschezmoi expects the dotfiles repo to reside at ~/.local/share/chezmoi. Move ~/.dofiles to that location.
mv ~/.dotfiles ~/.local/share
cd ~/.local/share
mv .dotfiles chezmoiThis branch will omit
WAIT!!!! I DON'T WANT AN ORPHAN BRANCH!!!! I want to maintain the history of the files. Shit, this is gonna be a lot more work.
git checkout -b chezmoitree -a -I .git.
├── .gitignore
├── __lib
│ └── source_files.sh
├── bash
│ ├── .bash_profile
│ └── .bashrc
├── bash_local.mac
│ └── .bash_local
├── bc
│ └── .bcrc
├── git
│ ├── .gitconfig
│ └── .gitignore_global
├── nvim
│ └── .config
│ └── nvim
│ ├── init.lua
│ ├── lazy-lock.json
│ └── lua
│ ├── config
│ │ └── lazy.lua
│ ├── linenumber-colors.lua
│ ├── plugins
│ │ ├── catppuccin.lua
│ │ ├── lsp-config.lua
│ │ ├── lualine.lua
│ │ ├── neotree.lua
│ │ ├── telescope.lua
│ │ └── treesitter.lua
│ └── vim-options.lua
├── psql
│ └── .psqlrc
├── README.md
├── ruby
│ ├── .gemrc
│ └── .pryrc
├── starship
│ └── .config
│ └── starship.toml
├── tmux
│ └── .tmux.conf
├── vim
│ └── .vimrc
├── Windows
│ ├── link_powershell_configs.ps1
│ └── PowerShell
│ └── Microsoft.PowerShell_profile.ps1
├── zsh
│ ├── .zprofile
│ └── .zshrc
└── zsh_local.mac
└── .zsh_local
# .gitignore do nothing
# __lib/source_files.sh do nothing
git mv bash/.bash_profile ./dot_bash_profile
git mv bash/.bashrc ./dot_bashrc
rm -rf bash
git mv bash_local.mac/.bash_local ./dot_bash_local
rm -rf bash_local.mac
git mv bc/.bcrc ./dot_bcrc
rm -rf bc
git mv git/.gitconfig ./dot_gitconfig
git mv git/.gitignore_global ./dot_gitignore_global
rm -rf git
git mv nvim/.config ./dot_config
rm -rf nvim
git mv psql/.psqlrc ./dot_psqlrc
rm -rf psql
# README.md do nothing
git mv ruby/.gemrc ./dot_gemrc
git mv ruby/.pryrc ./dot_pryrc
rm -rf ruby
git mv starship/.config/starship.toml ./dot_config/starship.toml
rm -rf starship
git mv tmux/.tmux.conf ./dot_tmux.conf
rm -rf tmux
git mv vim/.vimrc ./dot_vimrc
rm -rf vim
# Windows/link_powershell_configs.ps1 save for later
# Windows/PowerShell/Microsoft.PowerShell_profile.ps1 save for later
git mv zsh/.zprofile ./dot_zprofile
git mv zsh/.zshrc ./dot_zshrc
rm -rf zsh
git mv zsh_local.mac/.zsh_local ./dot_zsh_local
rm -rf zsh_local.mactree -a -I .git.
├── .gitignore
├── __lib
│ └── source_files.sh
├── dot_bash_local
├── dot_bash_profile
├── dot_bashrc
├── dot_bcrc
├── dot_config
│ ├── nvim
│ │ ├── init.lua
│ │ ├── lazy-lock.json
│ │ └── lua
│ │ ├── config
│ │ │ └── lazy.lua
│ │ ├── linenumber-colors.lua
│ │ ├── plugins
│ │ │ ├── catppuccin.lua
│ │ │ ├── lsp-config.lua
│ │ │ ├── lualine.lua
│ │ │ ├── neotree.lua
│ │ │ ├── telescope.lua
│ │ │ └── treesitter.lua
│ │ └── vim-options.lua
│ └── starship.toml
├── dot_gemrc
├── dot_gitconfig
├── dot_gitignore_global
├── dot_pryrc
├── dot_psqlrc
├── dot_tmux.conf
├── dot_vimrc
├── dot_zprofile
├── dot_zsh_local
├── dot_zshrc
├── README.md
└── Windows
├── link_powershell_configs.ps1
└── PowerShell
└── Microsoft.PowerShell_profile.ps1
mkdir ~/.dotbak
cd ~/.dotbak
mkdir ./.config
cp ~/.bash_local .
cp ~/.bash_profile .
cp ~/.bashrc .
cp ~/.bcrc .
cp ~/.gemrc .
cp ~/.gitconfig .
cp ~/.gitignore_global .
cp ~/.pryrc .
cp ~/.psqlrc .
cp ~/.tmux.conf .
cp ~/.vimrc .
cp ~/.zprofile .
cp ~/.zsh_local .
cp ~/.zshrc .
cp -r ~/.config/nvim ./.config
cp ~/.config/starship.toml ./.config
cd -cd ~/.dotbak
cp .bash_local ~
cp .bash_profile ~
cp .bashrc ~
cp .bcrc ~
cp .gemrc ~
cp .gitconfig ~
cp .gitignore_global ~
cp .pryrc ~
cp .psqlrc ~
cp .tmux.conf ~
cp .vimrc ~
cp .zprofile ~
cp .zsh_local ~
cp .zshrc ~
cp -r ~/.config/nvim ~/.config
cp .config/starship.toml ~/.config
cd -Capture a listing of current dotfiles in $HOME for comparison after applying with chezmoi.
I have ls is aliased to eza.
The following eza options are used in the steps below:
| switch | long option | description |
|---|---|---|
-1 |
--oneline |
display one entry per line |
-a |
--all |
show hidden and 'dot' files. Use this twice to also show the '.' and '..' directories |
-l |
--long |
display extended file metadata as a table |
-R |
--recurse |
recurse into directories |
-I GLOBS |
--ignore-glob GLOBS |
glob patterns (pipe-separated) of files to ignore |
-f |
--only-files |
list only files |
-m |
--modified |
use the modified timestamp field |
--absolute |
display entries with their absolute path (on, follow, off) | |
--time-style |
how to format timestamps (default, iso, long-iso, full-iso, relative, or a custom style '+' like '+%Y-%m-%d %H:%M') | |
--icons=WHEN |
cisplay icons next to file names. WHEN = always, automatic (auto), never |
I'm just reusing the dotfile backup dir created above to create this array.
watch_dots=( $(ls -1afR --absolute=on --icons=never ~/.dotbak | grep -Ev "(^$|:)" | gsed -E "s|${HOME}/.dotbak/||") )
echo $watch_dots[@].bash_local
.bash_profile
.bashrc
.bcrc
.gemrc
.gitconfig
.gitignore_global
.pryrc
.psqlrc
.tmux.conf
.vimrc
.zprofile
.zsh_local
.zshrc
.config/starship.toml
.config/nvim/init.lua
.config/nvim/lazy-lock.json
.config/nvim/lua/linenumber-colors.lua
.config/nvim/lua/vim-options.lua
.config/nvim/lua/config/lazy.lua
.config/nvim/lua/plugins/catppuccin.lua
.config/nvim/lua/plugins/lsp-config.lua
.config/nvim/lua/plugins/lualine.lua
.config/nvim/lua/plugins/neotree.lua
.config/nvim/lua/plugins/telescope.lua
.config/nvim/lua/plugins/treesitter.lua
watch_dots=( $(ls -1afR --absolute=on --icons=never $HOME/.dotbak | grep -Ev "(^$|:)" | gsed -E "s|${HOME}/.dotbak/||") )
ls -1aflmR --absolute=on --icons=never --time-style '+%Y-%m-%d %H:%M:%S' $watch_dots[@] | grep '^\.[r-]' | gsed -E "s/\.[rwx-]+?@\s+[0-9.k]+\s${USER}\s//"2025-07-06 17:14:57 /Users/blitterated/.bash_local
2025-07-06 17:14:57 /Users/blitterated/.bash_profile
2025-07-06 17:14:57 /Users/blitterated/.bashrc
2025-07-06 17:14:57 /Users/blitterated/.bcrc
2025-07-06 17:14:57 /Users/blitterated/.gemrc
2025-07-06 17:14:57 /Users/blitterated/.gitconfig
2025-07-06 17:14:57 /Users/blitterated/.gitignore_global
2025-07-06 17:14:57 /Users/blitterated/.pryrc
2025-07-06 17:14:57 /Users/blitterated/.psqlrc
2025-07-06 17:14:57 /Users/blitterated/.tmux.conf
2025-07-06 17:14:57 /Users/blitterated/.vimrc
2025-07-06 17:14:57 /Users/blitterated/.zprofile
2025-07-06 17:14:57 /Users/blitterated/.zsh_local
2025-07-06 17:14:57 /Users/blitterated/.zshrc
2025-07-06 17:14:57 /Users/blitterated/.config/nvim/lua/plugins/catppuccin.lua
2025-07-06 17:14:57 /Users/blitterated/.config/nvim/init.lua
2025-07-06 17:14:57 /Users/blitterated/.config/nvim/lazy-lock.json
2025-07-06 17:14:57 /Users/blitterated/.config/nvim/lua/config/lazy.lua
2025-07-06 17:14:57 /Users/blitterated/.config/nvim/lua/linenumber-colors.lua
2025-07-06 17:14:57 /Users/blitterated/.config/nvim/lua/plugins/lsp-config.lua
2025-07-06 17:14:57 /Users/blitterated/.config/nvim/lua/plugins/lualine.lua
2025-07-06 17:14:57 /Users/blitterated/.config/nvim/lua/plugins/neotree.lua
2025-07-06 17:14:57 /Users/blitterated/.config/starship.toml
2025-07-06 17:14:57 /Users/blitterated/.config/nvim/lua/plugins/telescope.lua
2025-07-06 17:14:57 /Users/blitterated/.config/nvim/lua/plugins/treesitter.lua
2025-07-06 17:14:57 /Users/blitterated/.config/nvim/lua/vim-options.lua
brew install chezmoiThe following files and directories need to be ignored for various reasons.
-
__lib/source_files.sh- intended to be used withstow -
Windows/**/*- temporary while I work out the Mac setup first -
Switch to chezmoi.md- the file you're reading right now
We can use .chezmoiignore to do this.
cat << EOF > .chezmoiignore
README.md # don't need this in $HOME
Switch to chezmoi.md # don't need this in $HOME
Windows/ # ignore Windows folder
Windows/** # ignore the contents of Windows
__lib/ # ignore __lib folder
__lib/** # ignore the contents of __lib
EOFVariables, a.k.a. configuration settings
[edit]
command = "nvim"
[git]
autoCommit = false
autoPush = falseConvert to template.
git mv dot_bashrc dot_bashrc.tmplOpen the file to edit it.
chezmoi edit .bashrcchezmoi: .bashrc: not managed
Uh oh. Time to commit everything and try initializing chezmoi again using a URL.
Backup the current source repo.
mv $HOME/.local/share/chezmoi $HOME/.local/share/chezmoi.oopsInitialize chezmoi with the upstream source repo URL.
chezmoi -v init --branch chezmoi ghblit:blitterated/dotfiles.gitCloning into '/Users/blitterated/.local/share/chezmoi'...
remote: Enumerating objects: 245, done.
remote: Counting objects: 100% (245/245), done.
remote: Compressing objects: 100% (124/124), done.
remote: Total 245 (delta 91), reused 225 (delta 71), pack-reused 0 (from 0)
Receiving objects: 100% (245/245), 44.57 KiB | 1.11 MiB/s, done.
Resolving deltas: 100% (91/91), done.
tree showed that $HOME/.local/share/chezmoi and $HOME/.local/share/chezmoi.oops were the same except for .DS_Store in the latter.
See the Appendix entry for details.
Try to edit .bashrc again.
chezmoi edit .bashrcchezmoi: .bashrc: not managed
AAAAANNNNNNNDDDDDD... I'm an idiot. It works if you're in $HOME or specify $HOME in the command.
chezmoi edit ~/.bashrcUnnecessary rework. Yay. Make sure you specify the path to the target file and not just its name, e.g. ~/.bashrc and not just .bashrc.
Open the file to edit it.
chezmoi edit ~/.bashrcI think chezmoi's mapping from .bashrc to dot_bashrc breaks filetype detection.
Force it with this:
:setf bash
Replace any code loading .bash_local with the following template code:
{{- if eq .chezmoi.os "darwin" -}}
{{- include bash_local/bash_darwin -}}
{{- end -}}
I plan to use bash_local as the folder for bash local machine configs.
The current .bash_local file is specific to a Macbook Pro.
chezmoi cd
mkdir bash_local
git mv dot_bash_local bash_local/bash_darwinchezmoi execute-template < dot_bashrc.tmplchezmoi: template: stdin:105: bad character U+002F '/'
Blerg. Line 105 is this line from the template code added above:
{{- include bash_local/bash_darwin -}}
Turns out it just needed quotes around the file path and it works.
{{- include "bash_local/bash_darwin" -}}
chezmoi apply --dry-run --verboseI forgot to capture the output :'(
Crap, the .chezmoiignore file isn't being respected by chezmoi apply.
Delete the unwanted crap.
rm README.md
rm Switch\ to\ chezmoi.md
rm -rf Windows/
rm -rf __libI removed all the comments and empty lines, and it seems to work now. Here's the contents:
README.md
Switch to chezmoi.md
Windows/
Windows/**
__lib/
__lib/**
BUT, it looks like the bash_local folder and its files need to be ignored.
Update .chezmoiignore with the following:
bash_local/
bash_local/**
Bob's your uncle!
Chages made:
- Created
.chezmoirootfile in repo root whose contents is simply "home". - Created
homedirectory in repo root and moved source directory files except for templates into it. - Created
.chezmoitemplatesin repo root and moved templates into it.
Templating broke after doing the above.
cz execute-template < home/dot_bashrc.tmplchezmoi: template: stdin:10:3: executing "stdin" at <include "shell_common/bash_zsh_common.sh">: error calling include: open /Users/blitterated/.local/share/chezmoi/home/shell_common/bash_zsh_common.sh: no such file or directory
cz execute-template < home/dot_bashrc.tmplchezmoi: template: stdin:10:12: executing "stdin" at <{{template "shell_common/bash_zsh_common.sh"}}>: template "shell_common/bash_zsh_common.sh" not defined
mv .chezmoitemplates/shell_common/bash_zsh_common.sh .chezmoitemplates/bash_zsh_common.sh
cz execute-template < home/dot_bashrc.tmplchezmoi: template: stdin:10:12: executing "stdin" at <{{template "shell_common/bash_zsh_common.sh"}}>: template "shell_common/bash_zsh_common.sh" not defined
mv .chezmoitemplates/bash_zsh_common.sh .chezmoitemplates/shell_common/bash_zsh_common.sh
cz execute-template < home/dot_bashrc.tmplchezmoi: template: stdin:10:3: executing "stdin" at <includeTemplate "shell_common/bash_zsh_common.sh">: error calling includeTemplate: open /Users/blitterated/.local/share/chezmoi/home/shell_common/bash_zsh_common.sh: no such file or directory
mv .chezmoitemplates home/
cz execute-template < home/dot_bashrc.tmplchezmoi: template: stdin:18:5: executing "stdin" at <includeTemplate "machine_local/macOS/bashrc.tmpl">: error calling includeTemplate: machine_local/macOS/bashrc.tmpl:9:3: executing "machine_local/macOS/bashrc.tmpl" at <include "machine_local/macOS/bash_zsh_common.sh">: error calling include: open /Users/blitterated/.local/share/chezmoi/home/machine_local/macOS/bash_zsh_common.sh: no such file or directory
Switched from include action to includeTemplate action in home/.chezmoitemplates/machine_local/macOS/bashrc.tmpl.
cz execute-template < home/dot_bashrc.tmpl# ▄ ▄▖▄▖▖▖▄▖▄▖
# ▙▘▌▌▚ ▙▌▙▘▌
# ▗ ▙▘▛▌▄▌▌▌▌▌▙▖
########################################
# Common bash + zsh config #
########################################
...
GREAT SUCCESS!!!
They were all changes from the include action to the includeTemplate action.
cz applychezmoi: .zshrc: template: dot_zshrc.tmpl:10:3: executing "dot_zshrc.tmpl" at <include "shell_common/bash_zsh_common.sh">: error calling include: open /Users/blitterated/.local/share/chezmoi/home/shell_common/bash_zsh_common.sh: no such file or directory
cz applychezmoi: .zshrc: template: dot_zshrc.tmpl:35:5: executing "dot_zshrc.tmpl" at <includeTemplate "machine_local/macOS/zshrc.tmpl">: error calling includeTemplate: machine_local/macOS/zshrc.tmpl:9:3: executing "machine_local/macOS/zshrc.tmpl" at <include "machine_local/macOS/bash_zsh_common.sh">: error calling include: open /Users/blitterated/.local/share/chezmoi/home/machine_local/macOS/bash_zsh_common.sh: no such file or directory
cz applychezmoi.toml has changed since chezmoi last wrote it? diff/overwrite/all-overwrite/skip/quit
bat home/chezmoi.toml───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ File: home/chezmoi.toml
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 │ [edit]
2 │ command = "nvim"
3 │
4 │ [git]
5 │ autoCommit = false
6 │ autoPush = false
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
cz applydiff --git a/chezmoi.toml b/chezmoi.toml
new file mode 100644
index 0000000000000000000000000000000000000000..6dda1421433b89aa136817e1b4fb4e34b8712656
--- /dev/null
+++ b/chezmoi.toml
@@ -0,0 +1,6 @@
+[edit]
+ command = "nvim"
+
+[git]
+ autoCommit = false
+ autoPush = false
git status didn't see any difference. 🤷
.chezmoitemplates did not get written to ~.
ls ~/.chezmoitemplates"/Users/blitterated/.chezmoitemplates": No such file or directory (os error 2)
GREAT SUCCESS!!!
Full path: ~/.config/karabiner/assets/complex_modifications/mbp_only_complex_mods.json
karabiner_complex_config="~/.config/karabiner/assets/complex_modifications/mbp_only_complex_mods.json"
chezmoi add --template "${karabiner_complex_config}"
chezmoi chattr +template "${karabiner_complex_config}"Trying to add the config with chezmoi add gave the following error:
chezmoi: /Users/blitterated/.local/share/chezmoi: cannot add chezmoi file to chezmoi (/Users/blitterated/.local/share/chezmoi is protected)
Apparently, you have to add each folder in ~/.config manually.
Target file:
karabiner_complex_config="~/.config/karabiner/assets/complex_modifications/mbp_only_complex_mods.json"Grab the dirname and replace ~/.config above with ~/.local/share/chezmoi/home/dot_config/.
orig_cfg_path="$( dirname "${karabiner_complex_config}" )"
dir_in_home="~/.config"
dir_in_chezmoi="~/.local/share/chezmoi/home/dot_config"
sed "s|${dir_in_home}|${dir_in_chezmoi}|g" <<< "${orig_cfg_path}"~/.local/share/chezmoi/home/dot_config/karabiner/assets/complex_modifications
Compare the original directory and the new path for chezmoi's source directory.
original: ~/.config/karabiner/assets/complex_modifications
chezmoi: ~/.local/share/chezmoi/home/dot_config/karabiner/assets/complex_modifications
Create the new path.
new_chezmoi_path=$(sed "s|${dir_in_home}|${dir_in_chezmoi}|g" <<< "${orig_cfg_path}")
mkdir -p "${new_chezmoi_path}"Now add the Karabiner complex config as a template.
chezmoi add --template "${karabiner_complex_config}"
chezmoi chattr +template "${karabiner_complex_config}"Not sure why, but a lot of the directories along the path were marked as private.
ls ~/.local/share/chezmoi/home/dot_config/private_karabiner/private_assets/private_complex_modifications/mbp_only_complex_mods.json.tmpl
Check for ids with system_profiler
system_profiler SPUSBDataTypeFound a 3rd party USB keyboard, but no "Apple Internal Keyboard / Trackpad"
Karabiner reports the following IDs for a 2016 MacBook Pro M1 builtin keyboard:
{
"vendor_id": 1452
},
{
"product_id":835
}system_profiler reports IDs in hexidecimal, so let's convert the above IDs.
printf "0x%X\n" 14520x5AC
printf "0x%X\n" 8350x343
Dump the output of system_profiler to a file.
system_profiler | tee ~/sysprfl.txtThe chezmoi Docs have the following recommendations.
If you're trying to manage configuration differences between machines in a file, use templates.
If you're wanting to exclude entire files or directories for a given machine, use template code inside of .chezmoiignore.
The latter requires using some ugly conditionals. Since we want to ignore files unless they apply to a specific machine, we need to add an entry to .chezmoiignore when running chezmoi on a different machine.
For example:
{{- if ne .chezmoi.os "windows" }}
Documents\WindowsPowerShell # Ignore Windows PowerShell 5 configuration
Documents\PowerShell # Ignore Windows PowerShell 7.5 configuration
{{- end }}
The chezmoi Testing templates docs in the User Guide show a neat way similar to immediate mode for seeing what values are set for keys.
chezmoi execute-template 'hostname: {{ .chezmoi.hostname }}
OS: {{ .chezmoi.os }}
arch: {{ .chezmoi.arch }}'hostname: blitterated
OS: darwin
arch: arm64
We can also dump all of chezmoi's data in JSON format with the following:
chezmoi dataHere's another way of getting hostname, OS, and architecture using jq.
chezmoi data | jq ".chezmoi.hostname,.chezmoi.os,.chezmoi.arch""blitterated"
"darwin"
"arm64"
chezmoi's Variables docs cover available variables and settings,
- ✅ Extract common config from
dot_bashrc.tmplanddot_zshrc.tmpland templatize. - ✅ Test cman function.
- ✅ Add GCP tools to
dot_bashrc.tmplanddot_zshrc.tmpl. - ✅ Have setup for specific utils check for utils' existence first. Print an error if not found.
- ✅ Change
shell_localtomachine_local. - ✅ Move macOS/darwin related config under
machine_local/macOS.
- ✅ Swap out
nvimforvimas editor in~/.pryrc. - ✅ Starship for
bash. - ✅ Move
STM32_PRG_PATHout ofdot_bashrcanddot_zshrc. - ✅ Load hombrew completions for
zshin~/.zsh_local. - Templatize
chezmoi.tomlinto.chezmoi.toml.tmpl.- 20251016: Ugh, can't remember why I wanted to do this now.
- 20251021: I think it may have been these:
- Use
Windows/link_powershell_configs.ps1code during run_once script time to link PowerShell 5 and 7.5 configs to same file. -
work_google_cloud.shis zsh specific. Create one for bash. -
~/.zprofileis empty. Do I need it for anything? - Add rc files for POSIX sh, ash, and dash? Fat chance of that happening, it's goofy af.
-
~/.config/homebrew -
~/.config/karabiner/assets/complex_modifications/mbp_only_complex_mods.json-
vendor_idandproduct_idwill need to be templated and set to mac model specific values.-
Example for 2021 16" MacBook Pro M1 Max:
"vendor_id": 1452 "product_id":835
-
-
-
~/.hammerspoon -
~/.config/ghostty -
~/.config/btop/btop.conf -
~/Library/Application Support/REAPER/*
These dependencies are expected to be installed on the system.
- chezmoi
- homebrew
- git
- figlet
- miniwi font for figlet
- eza
- bc
The Reference docs land you on page that sets up all the sections of the Reference.
However, the User Guide drops you straight into its first section, Command overview.
Converting a dotfile to a template after it's already been added to the source directory breaks its history in Git.
NOTE: This only applies if you've previously added the config file to the source directory, and it has multiple committed changes.
Using chezmoi chattr +template ~/.foobar breaks the history of the original file by deleting it and adding the templated version as a new file to Git.
Here's what the git status looks like:
git status
On branch chezmoi
Your branch is up to date with 'origin/chezmoi'.
Changes not staged for commit:
...
deleted: dot_bashrc
Untracked files:
...
dot_bashrc.tmpl
To preserve the file's history, use git mv instead.
git mv dot_bashrc dot_bashrc.tmpl
git statusOn branch chezmoi
Your branch is up to date with 'origin/chezmoi'.
Changes to be committed:
...
renamed: dot_bashrc -> dot_bashrc.tmpl
Simply specifying the file name to edit only works if you're currently in $HOME. Otherwise, make sure you specify $HOME or ~ in the file path parameter.
This only works in $HOME:
chezmoi edit .bashrcOtherwise you'll get this error:
chezmoi: .bashrc: not managed
This will work from any directory:
chezmoi edit ~/.bashrcSee what happened here. TODO: Recreate this link. It was deleted while cleaning up intra-doc links for GitHubs crappy extended Markdown link support.
chezmoi will examine your pre-existing config file's permissions when you use chezmoi add to add it to the source directory.
The config file's name will be prefaced with some combination of chezmoi's file name prefixes: private_, executable_, and readonly_.
If you add your config file's manually, and you want to maintain the same file permissions, you'll need to add the appropriate chezmoi file permission prefixes to the file's name.
This is the same as using the dot_ prefix for any config file whose name starts with a dot, e.g. .bashrc gets renamed to dot_bashrc in the source directory.
The way chezmoi renames files in the source repo can break Vim's file type detection.
For example, Vim will detect .bashrc as a Bash file, but it fails with dot_bashrc.
It happens with the edit command chezmoi edit ~/.bashrc if you've made the source file a template with the .tmpl extension.
Here's what I got from :ls in Vim while editing .bashrc:
/private/var/folders/s9/84x1rz2j02g5pth66xsm7vv80000gp/T/chezmoi-edit663884950/.bashrc.tmplThe quick fix is to run the following in Vim:
:setf bash
...or chezmoi.toml
Paths to includes and templates must be relative to the top level template when nesting templates, I think.
The grisly details are in the Appendix section below. TODO: Link to "Getting Templates to Work" section in Appendix below.
From chezmoi's intro to templating doc:
chezmoi uses the text/template syntax from Go extended with text template functions from sprig.
template is an existing action in Golang's text/template standard lib. includeTemplate is a function provided by chezmoi. includeTemplate has better context of the source state than template does.
This becomes very clear the first time you need to include a template in another themplate.
It's tricky to figure out what template file your config code lives in when looking at .bashrc or .zshrc.
To make it a little easier, I generated section headers and footers using figlet with the miniwi font.
Figlet is easy to install with homebrew.
brew install figletNext, download the miniwi font and drop it in the figlet font directory found here:
ls $(brew --prefix figlet)/share/figlet/fontsI created a shell function to generate the headers and footers and stuck it in my .bashrc and .zshrc.
# Convenience function for generating rc file
# section headers and footers using figlet.
fighead () {
local header_text="$(echo "$1" | tr '[:lower:]' '[:upper:]')"
echo -e "BEGIN ${header_text}\nEND ${header_text}" | \
figlet -w 200 -f miniwi | \
# Turn each line of header/footer into a shell comment line
while read -r ln; do echo "# ${ln}"; done
}chezmoi cd creates a sub-shell for reasons specified in the docs here.
chezmoi cdspawns a shell because it is not possible for a program to change the working directory of its parent process.
Use this alias in your shell instead:
alias czcd=cd "$(chezmoi source-path)"chezmoi cd
cd ..
git clone git@ghblit:blitterated/dotfiles.wiki.git chezmoi_wiki
cd chezmoi_wiki
git config user.name "blitterated"
git config user.email "[email protected]"Before reinit:
tree -a -I .gitdrwxr-xr-x@ - blitterated 12 Jul 23:29 .
.rw-r--r--@ 539 blitterated 12 Jul 14:01 ├── .chezmoiignore
.rw-r--r--@ 10k blitterated 8 Jul 10:42 ├── .DS_Store
.rw-r--r--@ 19 blitterated 18 May 22:07 ├── .gitignore
drwxr-xr-x@ - blitterated 2 Jul 14:02 ├── __lib
.rw-r--r--@ 1.1k blitterated 2 Jul 14:02 │ └── source_files.sh
.rw-r--r--@ 154 blitterated 12 Jul 01:08 ├── chezmoi.toml
.rw-r--r--@ 1.6k blitterated 9 Jun 18:22 ├── dot_bash_local
.rw-r--r--@ 76 blitterated 18 May 22:07 ├── dot_bash_profile
.rw-r--r--@ 2.6k blitterated 12 Jul 23:28 ├── dot_bashrc.tmpl
.rw-r--r--@ 114 blitterated 18 May 03:05 ├── dot_bcrc
drwxr-xr-x@ - blitterated 7 Jul 22:32 ├── dot_config
drwxr-xr-x@ - blitterated 6 Jun 00:01 │ ├── nvim
.rw-r--r--@ 665 blitterated 6 Jun 00:01 │ │ ├── init.lua
.rw-r--r--@ 1.2k blitterated 7 Jun 15:27 │ │ ├── lazy-lock.json
drwxr-xr-x@ - blitterated 5 Jun 23:59 │ │ └── lua
drwxr-xr-x@ - blitterated 5 Jun 23:59 │ │ ├── config
.rw-r--r--@ 1.3k blitterated 3 Jun 16:52 │ │ │ └── lazy.lua
.rw-r--r--@ 162 blitterated 5 Jun 23:48 │ │ ├── linenumber-colors.lua
drwxr-xr-x@ - blitterated 2 Jul 01:19 │ │ ├── plugins
.rw-r--r--@ 155 blitterated 20 Apr 18:15 │ │ │ ├── catppuccin.lua
.rw-r--r--@ 605 blitterated 7 Jun 15:27 │ │ │ ├── lsp-config.lua
.rw-r--r--@ 162 blitterated 5 Jun 23:03 │ │ │ ├── lualine.lua
.rw-r--r--@ 413 blitterated 4 Jun 13:42 │ │ │ ├── neotree.lua
.rw-r--r--@ 303 blitterated 20 Apr 22:02 │ │ │ ├── telescope.lua
.rw-r--r--@ 591 blitterated 20 Apr 21:53 │ │ │ └── treesitter.lua
.rw-r--r--@ 540 blitterated 3 Jun 17:40 │ │ └── vim-options.lua
.rw-r--r--@ 3.8k blitterated 20 May 23:40 │ └── starship.toml
.rw-r--r--@ 51 blitterated 13 Feb 2024 ├── dot_gemrc
.rw-r--r--@ 115 blitterated 25 Mar 2024 ├── dot_gitconfig
.rw-r--r--@ 24 blitterated 18 May 03:05 ├── dot_gitignore_global
.rw-r--r--@ 66 blitterated 18 May 22:49 ├── dot_pryrc
.rw-r--r--@ 987 blitterated 18 May 03:05 ├── dot_psqlrc
.rw-r--r--@ 1.8k blitterated 18 May 03:05 ├── dot_tmux.conf
.rw-r--r--@ 2.5k blitterated 18 May 03:05 ├── dot_vimrc
.rw-r--r--@ 0 blitterated 30 May 15:33 ├── dot_zprofile
.rw-r--r--@ 2.1k blitterated 9 Jun 18:27 ├── dot_zsh_local
.rw-r--r--@ 2.2k blitterated 2 Jul 01:34 ├── dot_zshrc
.rw-r--r--@ 102 blitterated 18 May 22:07 ├── README.md
.rw-r--r--@ 42k blitterated 12 Jul 23:31 ├── 'Switch to chezmoi.md'
drwxr-xr-x@ - blitterated 30 May 15:34 └── Windows
.rw-r--r--@ 1.4k blitterated 30 May 15:34 ├── link_powershell_configs.ps1
drwxr-xr-x@ - blitterated 30 May 15:34 └── PowerShell
.rw-r--r--@ 5.8k blitterated 30 May 15:34 └── Microsoft.PowerShell_profile.ps1
After reinit:
tree -a -I .gitdrwxr-xr-x@ - blitterated 13 Jul 00:00 .
.rw-r--r--@ 539 blitterated 13 Jul 00:00 ├── .chezmoiignore
.rw-r--r--@ 19 blitterated 13 Jul 00:00 ├── .gitignore
drwxr-xr-x@ - blitterated 13 Jul 00:00 ├── __lib
.rw-r--r--@ 1.1k blitterated 13 Jul 00:00 │ └── source_files.sh
.rw-r--r--@ 154 blitterated 13 Jul 00:00 ├── chezmoi.toml
.rw-r--r--@ 1.6k blitterated 13 Jul 00:00 ├── dot_bash_local
.rw-r--r--@ 76 blitterated 13 Jul 00:00 ├── dot_bash_profile
.rw-r--r--@ 2.6k blitterated 13 Jul 00:00 ├── dot_bashrc.tmpl
.rw-r--r--@ 114 blitterated 13 Jul 00:00 ├── dot_bcrc
drwxr-xr-x@ - blitterated 13 Jul 00:00 ├── dot_config
drwxr-xr-x@ - blitterated 13 Jul 00:00 │ ├── nvim
.rw-r--r--@ 665 blitterated 13 Jul 00:00 │ │ ├── init.lua
.rw-r--r--@ 1.2k blitterated 13 Jul 00:00 │ │ ├── lazy-lock.json
drwxr-xr-x@ - blitterated 13 Jul 00:00 │ │ └── lua
drwxr-xr-x@ - blitterated 13 Jul 00:00 │ │ ├── config
.rw-r--r--@ 1.3k blitterated 13 Jul 00:00 │ │ │ └── lazy.lua
.rw-r--r--@ 162 blitterated 13 Jul 00:00 │ │ ├── linenumber-colors.lua
drwxr-xr-x@ - blitterated 13 Jul 00:00 │ │ ├── plugins
.rw-r--r--@ 155 blitterated 13 Jul 00:00 │ │ │ ├── catppuccin.lua
.rw-r--r--@ 605 blitterated 13 Jul 00:00 │ │ │ ├── lsp-config.lua
.rw-r--r--@ 162 blitterated 13 Jul 00:00 │ │ │ ├── lualine.lua
.rw-r--r--@ 413 blitterated 13 Jul 00:00 │ │ │ ├── neotree.lua
.rw-r--r--@ 303 blitterated 13 Jul 00:00 │ │ │ ├── telescope.lua
.rw-r--r--@ 591 blitterated 13 Jul 00:00 │ │ │ └── treesitter.lua
.rw-r--r--@ 540 blitterated 13 Jul 00:00 │ │ └── vim-options.lua
.rw-r--r--@ 3.8k blitterated 13 Jul 00:00 │ └── starship.toml
.rw-r--r--@ 51 blitterated 13 Jul 00:00 ├── dot_gemrc
.rw-r--r--@ 115 blitterated 13 Jul 00:00 ├── dot_gitconfig
.rw-r--r--@ 24 blitterated 13 Jul 00:00 ├── dot_gitignore_global
.rw-r--r--@ 66 blitterated 13 Jul 00:00 ├── dot_pryrc
.rw-r--r--@ 987 blitterated 13 Jul 00:00 ├── dot_psqlrc
.rw-r--r--@ 1.8k blitterated 13 Jul 00:00 ├── dot_tmux.conf
.rw-r--r--@ 2.5k blitterated 13 Jul 00:00 ├── dot_vimrc
.rw-r--r--@ 0 blitterated 13 Jul 00:00 ├── dot_zprofile
.rw-r--r--@ 2.1k blitterated 13 Jul 00:00 ├── dot_zsh_local
.rw-r--r--@ 2.2k blitterated 13 Jul 00:00 ├── dot_zshrc
.rw-r--r--@ 102 blitterated 13 Jul 00:00 ├── README.md
.rw-r--r--@ 42k blitterated 13 Jul 00:00 ├── 'Switch to chezmoi.md'
drwxr-xr-x@ - blitterated 13 Jul 00:00 └── Windows
.rw-r--r--@ 1.4k blitterated 13 Jul 00:00 ├── link_powershell_configs.ps1
drwxr-xr-x@ - blitterated 13 Jul 00:00 └── PowerShell
.rw-r--r--@ 5.8k blitterated 13 Jul 00:00 └── Microsoft.PowerShell_profile.ps1
They're the same except for .DS_Store.
I'd extracted common shell config code to various template files.
Code common to both .bashrc and .zshrc on all machines was extracted to shell_common/bash_zsh_common.sh.
Mac specific shell config in .bashrc was extracted to shell_local/bash_darwin.sh.tmpl.
Mac specific shell config in .zshrc was extracted to shell_local/zsh_darwin.sh.tmpl.
mkdir shell_common
mv bash_zsh_common.sh shell_common
nvim .chezmoiignore
chezmoi edit ~/.bashrc ~/.zshrc
nvim shell_common/bash_zsh_common.sh
nvim shell_local/*
nvim shell_common/bash_zsh_common.sh
nvim shell_common/bash_zsh_common.sh
nvim shell_common/bash_zsh_common.sh shell_local/bash_darwin shell_local/zsh_darwin
nvim shell_local/bash_darwin shell_local/zsh_darwin shell_local/bash_zsh_common_darwin.sh
cd shell_local
git mv bash_darwin bash_darwin.sh.tmpl
git mv zsh_darwin zsh_darwin.sh.tmpl
nvim bash_darwin.sh.tmpl zsh_darwin.sh.tmpl ../dot_zshrc.tmpl
chezmoi applychezmoi: .bashrc: template: dot_bashrc.tmpl:13:5:
executing "dot_bashrc.tmpl" at <include "shell_local/zsh_darwin">:
error calling include: open /Users/blitterated/.local/share/chezmoi/shell_local/zsh_darwin: no such file or directory
Whoops, forgot to add .sh.tmpl to include "shell_local/zsh_darwin" in dot_zshrc.tmpl.
nvim dot_zshrc.tmpl dot_bashrc.tmpl
chezmoi applydiff --git a/.bashrc b/.bashrc
index 09d966e75d13d6cb7652c22b09fd3c826f5e3f41..3e65225f42730fe164bf8b3ca12b499b03f9a6c2 100644
...
diff --git a/.zshrc b/.zshrc
index c70b2328b096dcaeb5c56cbf4dc54b973017c17b..3ea5bf71e70671ca71a5061fdad187c1807e8de8 100644
It rendered correctly, but include just copies file contents. I got the raw contents of the template files with the template code instead of the executed template results. I changed from calling include to calling template.
nvim dot_zshrc.tmpl dot_bashrc.tmpl
chezmoi applychezmoi: .bashrc: template: dot_bashrc.tmpl:18:14:
executing "dot_bashrc.tmpl" at <{{template "shell_local/bash_darwin.sh.tmpl"}}>:
template "shell_local/bash_darwin.sh.tmpl" not defined
I checked that the template files were in the right location, and they were. So I applied the changes again.
nvim dot_zshrc.tmpl dot_bashrc.tmpl
chezmoi applychezmoi: .bashrc: template: dot_bashrc.tmpl:18:14:
executing "dot_bashrc.tmpl" at <{{template "./bash_darwin.sh.tmpl"}}>:
template "./bash_darwin.sh.tmpl" not defined
Same issue. I followed some documentation and moved the template files to the .chezmoitemplates directory in the root of the dotfiles repo directory. The tree results show that the template files were moved out of the directory.
cd shell_local
mkdir .chezmoitemplates
mv *.sh.tmpl .chezmoitemplates
tree.
├── bash_zsh_common_darwin.sh
├── README.md
└── work_google_cloud.sh
Here's the tree listing for the .chezmoitemplates directory.
t -a.
├── .chezmoitemplates
│ ├── bash_darwin.sh.tmpl
│ └── zsh_darwin.sh.tmpl
├── bash_zsh_common_darwin.sh
├── README.md
└── work_google_cloud.sh
Like a dumbass, I used mv to move files instead of git mv. I fixed that up to retain git history, and applied the changes again.
nvim ../shell_common/bash_zsh_common.sh
mv .chezmoitemplates/*.sh.tmpl .
git mv *.sh.tmpl .chezmoitemplates
cd .chezmoitemplates
nvim *
cd ..
cd ..
nvim dot_bashrc.tmpl dot_zshrc.tmpl
chezmoi applychezmoi: .bashrc: template: dot_bashrc.tmpl:18:14:
executing "dot_bashrc.tmpl" at <{{template "bash_darwin.sh.tmpl"}}>:
template "bash_darwin.sh.tmpl" not defined
I wound up moving the templates into a shell_local directory in chezmoitemplates.
nvim dot_bashrc.tmpl dot_zshrc.tmpl
chezmoi applychezmoi: .bashrc: template: dot_bashrc.tmpl:18:14:
executing "dot_bashrc.tmpl" at <{{template "shell_local/bash_darwin.sh.tmpl"}}>:
template "shell_local/bash_darwin.sh.tmpl" not defined
Some fiddling with file paths and a retry.
nvim dot_bashrc.tmpl dot_zshrc.tmpl
chezmoi applychezmoi: .bashrc: template: dot_bashrc.tmpl:18:14:
executing "dot_bashrc.tmpl" at <{{template "./shell_local/bash_darwin.sh.tmpl"}}>:
template "./shell_local/bash_darwin.sh.tmpl" not defined
Applying with -v didn't give any extra information.
chezmoi apply -vchezmoi: .bashrc: template: dot_bashrc.tmpl:18:14:
executing "dot_bashrc.tmpl" at <{{template "./shell_local/bash_darwin.sh.tmpl"}}>:
template "./shell_local/bash_darwin.sh.tmpl" not defined
I found out that template comes with Go's text/template library, but chezmoi has its own call called includeTemplate so I gave that a try.
This comment on a chezmoi GitHub issue pointed me in that direction.
nvim dot_bashrc.tmpl dot_zshrc.tmpl
chezmoi apply -vchezmoi: .bashrc: template: dot_bashrc.tmpl:18:5:
executing "dot_bashrc.tmpl" at <includeTemplate "./shell_local/bash_darwin.sh.tmpl">:
error calling includeTemplate: open /Users/blitterated/.local/share/chezmoi/shell_local/bash_darwin.sh.tmpl:
no such file or directory
Next, I moved the *.sh.tmpl out of .chezmoitemplates/ back to the root shell_local directory.
cd shell_local
mv .chezmoitemplates/*.sh.tmpl .
chezmoi applychezmoi: .bashrc: template: dot_bashrc.tmpl:18:5:
executing "dot_bashrc.tmpl" at <includeTemplate "./shell_local/bash_darwin.sh.tmpl">:
error calling includeTemplate: ./shell_local/bash_darwin.sh.tmpl:9:3:
executing "./shell_local/bash_darwin.sh.tmpl" at <include "./bash_zsh_common_darwin.sh">:
error calling include: open /Users/blitterated/.local/share/chezmoi/bash_zsh_common_darwin.sh:
no such file or directory
I patched up file paths I missed in the templates, and it finally worked!
nvim *.sh.tmpl
chezmoi apply -vdiff --git a/.bashrc b/.bashrc
index 3e65225f42730fe164bf8b3ca12b499b03f9a6c2..c2a3c347119bf65f1203baae17eb118bc24e1130 100644
--- a/.bashrc
+++ b/.bashrc
@@ -32,8 +32,8 @@
...
diff --git a/.zshrc b/.zshrc
index 3ea5bf71e70671ca71a5061fdad187c1807e8de8..f5072e69417a640f1d5824220e635a06a1d8caaf 100644
--- a/.zshrc
+++ b/.zshrc
@@ -32,8 +32,8 @@
...
| Config |
|---|
chezmoi.toml |
.chezmoiignore |
| Templates |
|---|
dot_bashrc.tmpl |
dot_zshrc.tmpl |
machine_local/macOS/bashrc.tmpl |
machine_local/macOS/zshrc.tmpl |
| Dot Files |
|---|
dot_bash_profile |
dot_bcrc |
dot_gemrc |
dot_gitconfig |
dot_gitignore_global |
dot_pryrc |
dot_psqlrc |
dot_tmux.conf |
dot_vimrc |
dot_zprofile |
dot_config/nvim/** |
dot_config/starship.toml |
machine_local/macOS/bash_zsh_common.sh |
machine_local/macOS/STM32CubeProg.sh |
machine_local/macOS/work_google_cloud_zsh.sh |
shell_common/bash_zsh_common.sh |
Windows/PowerShell/Microsoft.PowerShell_profile.ps1 |
| Worry About These Later | Description |
|---|---|
README.md |
dotfile repo README. |
__lib/source_files.sh |
A shell script that sources all scriptsin a given directory when sourced itself. |
machine_local/README.md |
Description of what files go in the machine_local directory. |
Windows/link_powershell_configs.ps1 |
Windows configs. Currently incorrectly pathed for chezmoi. |
Get a list of system_profiler's available DataTypes.
system_profiler -listDataTypesAvailable Datatypes:
SPParallelATADataType
SPUniversalAccessDataType
SPSecureElementDataType
SPApplicationsDataType
SPAudioDataType
SPBluetoothDataType
SPCameraDataType
SPCardReaderDataType
SPiBridgeDataType
SPDeveloperToolsDataType
SPDiagnosticsDataType
SPDisabledSoftwareDataType
SPDiscBurningDataType
SPEthernetDataType
SPExtensionsDataType
SPFibreChannelDataType
SPFireWireDataType
SPFirewallDataType
SPFontsDataType
SPFrameworksDataType
SPDisplaysDataType
SPHardwareDataType
SPInstallHistoryDataType
SPInternationalDataType
SPLegacySoftwareDataType
SPNetworkLocationDataType
SPLogsDataType
SPManagedClientDataType
SPMemoryDataType
SPNVMeDataType
SPNetworkDataType
SPPCIDataType
SPParallelSCSIDataType
SPPowerDataType
SPPrefPaneDataType
SPPrintersSoftwareDataType
SPPrintersDataType
SPConfigurationProfileDataType
SPRawCameraDataType
SPSASDataType
SPSerialATADataType
SPSPIDataType
SPSmartCardsDataType
SPSoftwareDataType
SPStartupItemDataType
SPStorageDataType
SPSyncServicesDataType
SPThunderboltDataType
SPUSBDataType
SPNetworkVolumeDataType
SPAirPortDataType
Dump the output of all available DataTypes into one file.
system_profiler SPParallelATADataType SPUniversalAccessDataType SPSecureElementDataType SPApplicationsDataType SPAudioDataType SPBluetoothDataType SPCameraDataType SPCardReaderDataType SPiBridgeDataType SPDeveloperToolsDataType SPDiagnosticsDataType SPDisabledSoftwareDataType SPDiscBurningDataType SPEthernetDataType SPExtensionsDataType SPFibreChannelDataType SPFireWireDataType SPFirewallDataType SPFontsDataType SPFrameworksDataType SPDisplaysDataType SPHardwareDataType SPInstallHistoryDataType SPInternationalDataType SPLegacySoftwareDataType SPNetworkLocationDataType SPLogsDataType SPManagedClientDataType SPMemoryDataType SPNVMeDataType SPNetworkDataType SPPCIDataType SPParallelSCSIDataType SPPowerDataType SPPrefPaneDataType SPPrintersSoftwareDataType SPPrintersDataType SPConfigurationProfileDataType SPRawCameraDataType SPSASDataType SPSerialATADataType SPSPIDataType SPSmartCardsDataType SPSoftwareDataType SPStartupItemDataType SPStorageDataType SPSyncServicesDataType SPThunderboltDataType SPUSBDataType SPNetworkVolumeDataType SPAirPortDataType | tee ~/system_profiler_all_datatypes.txtSee if there are any hits.
ggrep -P "0x5AC" system_profiler_all_datatypes.txt
ggrep -P "0x343" system_profiler_all_datatypes.txt There are, but it's difficult to determine for which DataTypes.
Write the output of each DataType into its own file.
sp_out=( $(system_profiler -listDataTypes) )
sp_datatypes=("${sp_out[@]:2}")
idx=0
for dt in "${sp_datatypes[@]}"; do
echo "${idx}: ${dt}"
system_profiler $dt | tee "${dt}.txt"
((idx=idx+1))
doneUse rg to find matches.
rg -i "0x5AC" *.txt
rg -i "0x343" *.txtThey're in SPLogsDataType.txt. That's not very useful. It's a dump of a dump of something else.
May need to live with manually updating mbp_only_complex_mods.json for Karabiner.
Quick experiment with splitting and iterating a path in shell script.
This was a waste of time, because I'd completely blocked out mkdir -p from my mind.
karabiner_complex_config_path="~/.config/karabiner/assets/complex_modifications"Path splitting in bash:
IFS='/' read -ra cfg_paths <<< "${karabiner_complex_config_path}"Path splitting in zsh:
cfg_paths=( ${(@s:/:)karabiner_complex_config_path} )idx=0
dir_path=""
for dir in "${cfg_paths[@]}"; do
((idx=idx+1))
$dir_path="${dir_path}/${dir}"
$local:dir_exists=[ -d "${dir_path}" ] && "already exists" || "is creatable"
echo "${idx}: ${dir_path} ${dir_exists}"
done...and then I remembered mkdir -p
~fin.
cd "$(chezmoi source-path)"Run the following in irb or pry to see what permissions chezmoi apply generates.
def make_chezmoi_file_permission_test_files()
(1..3).sum([]) do |n|
#["executable", "private", "readonly"]
#["private", "readonly", "executable"]
["private", "readonly", "executable", "dot"]
.combination(n)
.to_a
end.each.with_index do |ary, idx|
#test_fname = "dot_#{ary.join("_")}_test#{"%02i" % idx}"
#test_fname = "#{ary.join("_")}_dot_test#{"%02i" % idx}"
test_fname = "#{ary.join("_")}_test#{"%02i" % idx}"
#test_fname = "#{ary.reverse.join("_")}_test#{"%02i" % idx}"
File.open(test_fname, "w") { |f| f.write(test_fname) }
end
puts "Test files written to current directory: \"#{Dir.pwd}\"\n\n"
end
make_chezmoi_file_permission_test_fileschezmoi apply
ls -l .*_test??.rw-r--r--@ 38 blitterated 23 Oct 01:10 .executable_private_readonly_test06
.rw-r--r--@ 29 blitterated 23 Oct 01:10 .executable_private_test03
.rw-r--r--@ 30 blitterated 23 Oct 01:10 .executable_readonly_test04
.rw-r--r--@ 21 blitterated 23 Oct 01:10 .executable_test00
.rw-r--r--@ 27 blitterated 23 Oct 01:10 .private_readonly_test05
.rw-r--r--@ 18 blitterated 23 Oct 01:10 .private_test01
.rw-r--r--@ 19 blitterated 23 Oct 01:10 .readonly_test02
WTF?!?!
Maybe it's because the dot_ prefix needs to be last, not first.
Altered make_chezmoi_file_permission_test_files() to move it to the last prefix spot, and reran the test.
test_fname = "#{ary.join("_")}_dot_test#{"%02i" % idx}".rwxr-xr-x@ 21 peteyoung 23 Oct 14:24 .test00
.rw-------@ 18 peteyoung 23 Oct 14:24 .test01
.r--r--r--@ 19 peteyoung 23 Oct 14:24 .test02
.r--------@ 27 peteyoung 23 Oct 14:24 .test05
.rwxr-xr-x@ 29 peteyoung 23 Oct 14:24 private_dot_test03
.rwxr-xr-x@ 38 peteyoung 23 Oct 14:24 private_readonly_dot_test06
.rwxr-xr-x@ 30 peteyoung 23 Oct 14:24 readonly_dot_test04
03, 04, and 06 are not being processed correctly.
Tried it without the dot_ prefix beingin the mix.
test_fname = "#{ary.join("_")}_test#{"%02i" % idx}".rwxr-xr-x@ 34 peteyoung 23 Oct 17:46 private_readonly_test06
.rwxr-xr-x@ 25 peteyoung 23 Oct 17:46 private_test03
.rwxr-xr-x@ 26 peteyoung 23 Oct 17:46 readonly_test04
.rwxr-xr-x@ 17 peteyoung 23 Oct 17:46 test00
.rw-------@ 14 peteyoung 23 Oct 17:46 test01
.r--r--r--@ 15 peteyoung 23 Oct 17:46 test02
.r--------@ 23 peteyoung 23 Oct 17:46 test05
03, 04, and 06 are still not being processed correctly.
Maybe it's the order of the prefixes? I tried reversing the list of prefixes to see if changing prefix' order made a difference.
test_fname = "#{ary.reverse.join("_")}_test#{"%02i" % idx}".r--r--r--@ 34 peteyoung 23 Oct 18:05 private_executable_test06
.r--r--r--@ 23 peteyoung 23 Oct 18:05 private_test05
.rwxr-xr-x@ 17 peteyoung 23 Oct 18:05 test00
.rw-------@ 14 peteyoung 23 Oct 18:05 test01
.r--r--r--@ 15 peteyoung 23 Oct 18:05 test02
.rwx------@ 25 peteyoung 23 Oct 18:05 test03
.r-xr-xr-x@ 26 peteyoung 23 Oct 18:05 test04
Interestingly, we got 03 and 04, but lost 05. Let's compare the original source files with the last batch.
| Generated Source Files | Generated Configs | Reverse Generated Configs | Reverse Generated Source Files |
|---|---|---|---|
| executable_test00 | test00 | test00 | executable_test00 |
| private_test01 | test01 | test01 | private_test01 |
| readonly_test02 | test02 | test02 | readonly_test02 |
| executable_private_test03 | private_test03 | test03 | private_executable_test03 |
| executable_readonly_test04 | readonly_test04 | test04 | readonly_executable_test04 |
| private_readonly_test05 | test05 | private_test05 | readonly_private_test05 |
| executable_private_readonly_test06 | private_readonly_test06 | private_executable_test06 | readonly_private_executable_test06 |
Looking at 03 and 04, it appears private_ and readonly need to go before executable_.
And looking at 05, it appears that private_ needs to go before readonly.
And don't forget, all the above need to go before dot_.
Let's try what we've discovered with the source attributes.
["private", "readonly", "executable"]
...
test_fname = "#{ary.join("_")}_test#{"%02i" % idx}".rw-------@ 14 peteyoung 24 Oct 00:29 test00
.r--r--r--@ 15 peteyoung 24 Oct 00:29 test01
.rwxr-xr-x@ 17 peteyoung 24 Oct 00:29 test02
.r--------@ 23 peteyoung 24 Oct 00:29 test03
.rwx------@ 25 peteyoung 24 Oct 00:29 test04
.r-xr-xr-x@ 26 peteyoung 24 Oct 00:29 test05
.r-x------@ 34 peteyoung 24 Oct 00:29 test06
That looks good! Let's check the contents of the files.
for i in {0..6}; do echo "test0${i}: $(cat test0${i})"; donetest00: private_test00
test01: readonly_test01
test02: executable_test02
test03: private_readonly_test03
test04: private_executable_test04
test05: readonly_executable_test05
test06: private_readonly_executable_test06
Hell Yeah!
Now for one last test that adds the dot_ prefix back into the mix
["private", "readonly", "executable", "dot"]Then list and somewhat sort the files.
ls -1 (.|)test?? | sort.test03
.test06
.test08
.test09
.test11
.test12
.test13
test00
test01
test02
test04
test05
test07
test10
That looks promising. Let's try using ruby with a regex to list and sort the files.
Here's a monster one-liner for the shell.
ruby -e 'Dir.glob("{*,.*}").select { |file| file =~ /\.?test\d{2}/ }.sort_by { |fn| fn.match(/\.?test(\d{2})/)[1].to_i }.each { |fn| puts "#{File.stat(fn).mode.to_s(8)[-3..-1].ljust(6)}#{fn.ljust(10)}#{File.read(fn)}" }'- or -
Run this in pry.
rgx = /\.?test(\d{2})/
Dir.glob("{*,.*}")
.select { |fn| fn =~ rgx }
.sort_by { |fn| fn.match(rgx)[1].to_i }
.each do |fn|
mode = File.stat(fn).mode.to_s(8)[-3..-1]
srcf = File.read(fn)
puts "#{mode.ljust(6)}#{fn.ljust(10)}#{srcf}"
end
nil600 test00 private_test00
444 test01 readonly_test01
755 test02 executable_test02
644 .test03 dot_test03
400 test04 private_readonly_test04
700 test05 private_executable_test05
600 .test06 private_dot_test06
555 test07 readonly_executable_test07
444 .test08 readonly_dot_test08
755 .test09 executable_dot_test09
500 test10 private_readonly_executable_test10
400 .test11 private_readonly_dot_test11
700 .test12 private_executable_dot_test12
555 .test13 readonly_executable_dot_test13
HELL YEAH!!!
rm ~/.*_test??cd "$(chezmoi source-path)"
rm ./dot_*_test??| chezmoi Source Attribute | $HOME |
|||||
|---|---|---|---|---|---|---|
| Private | Readonly | Executable | Long Mode | Mode | File Name | Source File Name |
| X | rwxr-xr-x |
755 | .test00 |
executable_dot_test00 |
||
| X | rw------- |
600 | .test01 |
private_dot_test01 |
||
| X | r--r--r-- |
444 | .test02 |
readonly_dot_test02 |
||
| X | X |
rwxr-xr-x(rwx------)
|
755 (700) |
private_dot_test03(.test03)
|
executable_private_dot_test03 |
|
| X | X |
rwxr-xr-x(r-xr-xr-x)
|
755 (555) |
readonly_dot_test04(.test04)
|
executable_readonly_dot_test04 |
|
| X | X | r-------- |
400 | .test05 |
private_readonly_dot_test05 |
|
| X | X | X |
rwxr-xr-x(r-x------)
|
755 (500) |
private_readonly_dot_test06(.test06)
|
executable_private_readonly_dot_test06 |
| chezmoi Source Attribute | $HOME |
||||||
|---|---|---|---|---|---|---|---|
| Private | Readonly | Executable | Dotfile | Long Mode | Mode | File Name | Source File Name |
| X | rw------- |
600 | test00 |
private_test00 |
|||
| X | r--r--r-- |
444 | test01 |
readonly_test01 |
|||
| X | rwxr-xr-x |
755 | test02 |
executable_test02 |
|||
| X | rw-r--r-- |
644 | .test03 |
dot_test03 |
|||
| X | X | r-------- |
400 | test04 |
private_readonly_test04 |
||
| X | X | rwx------ |
700 | test05 |
private_executable_test05 |
||
| X | X | rw------- |
600 | .test06 |
private_dot_test06 |
||
| X | X | r-xr-xr-x |
555 | test07 |
readonly_executable_test07 |
||
| X | X | r--r--r-- |
444 | .test08 |
readonly_dot_test08 |
||
| X | X | rwxr-xr-x |
755 | .test09 |
executable_dot_test09 |
||
| X | X | X | r-x------ |
500 | test10 |
private_readonly_executable_test10 |
|
| X | X | X | r-------- |
400 | .test11 |
private_readonly_dot_test11 |
|
| X | X | X | rwx------ |
700 | .test12 |
private_executable_dot_test12 |
|
| X | X | X | r-xr-xr-x |
555 | .test13 |
readonly_executable_dot_test13 |
|
Here's the Ruby script for generating table rows above from source directory filenames.
SourceAttrs = [ "private_", "readonly_", "executable_", "dot_" ].freeze
LongForms = { 0 => "---", 4 => "r--", 5 => "r-x", 6 => "rw-", 7 => "rwx" }.freeze
def filter_and_sort(files)
rgx = /\.?test(\d{2})/
files.select { |fn| fn =~ rgx }.sort_by { |fn| fn.match(rgx)[1].to_i }
end
def make_chezmoi_source_attribute_table_rows(files)
filter_and_sort(files).each do |fname|
src_fname = File.read(fname) # test file's contents are its source file name.
mode = File.stat(fname).mode.to_s(8)[-3..-1]
perms = mode.chars.map { |n| LongForms[n.to_i] }.join
sa_cells = SourceAttrs.map do |sa_prefix|
if src_fname.include?(sa_prefix)
"<td><strong>X</strong></td>" else
"<td> </td>" end
end
ind = ' ' * 2
tbl_cells = (sa_cells + [
"<td><code>#{perms}</code></td>",
"<td>#{mode}</td>",
"<td><code>#{fname}</code></td>",
"<td><code>#{src_fname}</code></td>"
]).join("\n#{ind*3}")
puts [
"#{ind*2}<tr>",
"#{ind}#{tbl_cells}",
"</tr>"
].join("\n#{ind*2}")
end
end
make_chezmoi_source_attribute_table_rows Dir.glob("{*,.*}")- chezmoi Documentation
- Video
- Chezmoi
- Gnu Stow
- dotfiles