diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..33f1a3b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab +indent_size = 4 + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..31534d2 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,24 @@ +version: 2 +updates: + # Enable version updates for npm dependencies + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "monthly" + open-pull-requests-limit: 5 + labels: + - "dependencies" + commit-message: + prefix: "npm" + include: "scope" + + # Enable version updates for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + labels: + - "dependencies" + - "github-actions" + commit-message: + prefix: "ci" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..643e99d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: CI + +on: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: ".node-version" + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Check formatting + run: npm run lint diff --git a/.gitignore b/.gitignore index 0db01f5..6631ad1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ git/gitconfig.local.symlink *.local local/config.json local/automount.sh -.env \ No newline at end of file +.env + +# Node.js +node_modules/ diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..a45fd52 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +24 diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..bf617b6 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "useTabs": true, + "plugins": ["prettier-plugin-sh"] +} diff --git a/AGENTS.md b/AGENTS.md index b8e644f..4004f0a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,20 +27,20 @@ Understanding these patterns is critical for working efficiently in this project #### Within Topic Directories - **`*.zsh`**: Shell scripts that get automatically sourced into the zsh environment - - Recommended prefixes: `env.zsh` (environment variables), `path.zsh` (PATH modifications), `alias.zsh` (command aliases), `hook.zsh` (shell hooks) - - Example: `git/alias.zsh`, `python/env.zsh` + - Recommended prefixes: `env.zsh` (environment variables), `path.zsh` (PATH modifications), `alias.zsh` (command aliases), `hook.zsh` (shell hooks) + - Example: `git/alias.zsh`, `python/env.zsh` - **`*.symlink`**: Files that get automatically symlinked to `$HOME` (without the `.symlink` extension) - - Example: `git/gitconfig.symlink` ’ `~/.gitconfig` - - Example: `zsh/zshrc.symlink` ’ `~/.zshrc` + - Example: `git/gitconfig.symlink` � `~/.gitconfig` + - Example: `zsh/zshrc.symlink` � `~/.zshrc` - **`preinstall.sh`**: Scripts executed during bootstrap BEFORE Homebrew runs - - Use for setup that must happen before package installation - - Example: `homebrew/preinstall.sh` (installs Homebrew itself) + - Use for setup that must happen before package installation + - Example: `homebrew/preinstall.sh` (installs Homebrew itself) - **`install.sh`**: Scripts executed during bootstrap AFTER Homebrew runs - - Use for post-installation configuration and setup - - Example: `macos/install.sh` (installs macOS applications) + - Use for post-installation configuration and setup + - Example: `macos/install.sh` (installs macOS applications) #### Root Directory Special Files @@ -80,6 +80,7 @@ Understanding the execution order is important for making modifications: ### Adding Homebrew Packages Edit `Brewfile` in the root directory. Use these formats: + - `brew "package-name"` for command-line tools - `cask "app-name"` for GUI applications - `mas "App Name", id: 123456` for Mac App Store applications @@ -163,6 +164,7 @@ When making changes, always update documentation: ## Testing Changes To test changes without affecting the user's system: + 1. Review what symlinks will be created 2. Check what Homebrew packages will be installed 3. Consider running individual `install.sh` scripts rather than full bootstrap diff --git a/README.md b/README.md index aef4eeb..c786731 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,9 @@ source .env From here you may want to take a moment to review the dotfiles: -* Applications in the `Brewfile` that are no longer relevant? -* Applications in `macos/install.sh` that you don't use any more? -* Go through the `macos/set-defaults.sh` to see if you still like all of those settings. +- Applications in the `Brewfile` that are no longer relevant? +- Applications in `macos/install.sh` that you don't use any more? +- Go through the `macos/set-defaults.sh` to see if you still like all of those settings. ### Step 3: Intall the dotfiles @@ -59,7 +59,7 @@ You can re-run `./bootstrap.sh` whenever you feel inspired. ### Step 4: Setting MacOS Defaults (Optional) -I suppose every step is optional, but this one really is. You can set up a series of MacOS defaults by running: +I suppose every step is optional, but this one really is. You can set up a series of MacOS defaults by running: ``` cd ~/.dotfiles/macos && ./set-defaults.sh @@ -69,8 +69,8 @@ cd ~/.dotfiles/macos && ./set-defaults.sh 1. Register the shiny new SSH key that the script generated in appropriate places - - GitHub - - Any necessary servers +- GitHub +- Any necessary servers 2. Install your GPG key: @@ -91,13 +91,13 @@ rm private.key ### Organizaztion -Each folder is intended to cover an area of functionality of your computer (as Zach Holman said: topics). As you find new topics of functionality in your computing life you should just toss in a new root directory. +Each folder is intended to cover an area of functionality of your computer (as Zach Holman said: topics). As you find new topics of functionality in your computing life you should just toss in a new root directory. ### Special Topic Files There are a few special files which exist in the root directory have a few special files. -- **topic/\*.zsh**: Any files ending in `.zsh` get sourced into your environment. (Recommended prefixes: env, path, alias, hook) +- **topic/\*.zsh**: Any files ending in `.zsh` get sourced into your environment. (Recommended prefixes: env, path, alias, hook) - **topic/\*.symlink**: Any file ending in `*.symlink` gets symlinked into your `$HOME` (with `.symlink` removed). - **topic/preinstall.sh**: Any file named `preinstall.sh` is executed as part of `bootstrap.sh` but BEFORE brew is invoked. - **topic/install.sh**: Any file named `install.sh` is executed as part of `bootstrap.sh`. diff --git a/android/path.zsh b/android/path.zsh index 3a67653..443449c 100644 --- a/android/path.zsh +++ b/android/path.zsh @@ -3,4 +3,4 @@ export ANDROID_HOME=$HOME/Library/Android/sdk export PATH=$PATH:$ANDROID_HOME/emulator export PATH=$PATH:$ANDROID_HOME/tools export PATH=$PATH:$ANDROID_HOME/tools/bin -export PATH=$PATH:$ANDROID_HOME/platform-tools \ No newline at end of file +export PATH=$PATH:$ANDROID_HOME/platform-tools diff --git a/bootstrap.sh b/bootstrap.sh index 70d8293..df738c4 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -3,88 +3,82 @@ # bootstrap installs things. set +e -info () { - printf "\r [ \033[00;34m..\033[0m ] $1\n" +info() { + printf "\r [ \033[00;34m..\033[0m ] $1\n" } -user () { - printf "\r [ \033[0;33m??\033[0m ] $1\n" +user() { + printf "\r [ \033[0;33m??\033[0m ] $1\n" } -success () { - printf "\r\033[2K [ \033[00;32mOK\033[0m ] $1\n" +success() { + printf "\r\033[2K [ \033[00;32mOK\033[0m ] $1\n" } -fail () { - printf "\r\033[2K [\033[0;31mFAIL\033[0m] $1\n" - echo '' - exit +fail() { + printf "\r\033[2K [\033[0;31mFAIL\033[0m] $1\n" + echo '' + exit } -setup_gitconfig () { - if ! [ -f git/gitconfig.local.symlink ] - then - info 'Setup gitconfig' - - git_credential='cache' - if [ "$(uname -s)" == "Darwin" ] - then - git_credential='osxkeychain' - fi - - user ' - What is your github author name?' - read -e git_authorname - user ' - What is your github author email?' - read -e git_authoremail - user ' - What is your GPG signing key ID? (Find with: gpg --list-secret-keys --keyid-format LONG)' - read -e git_signingkey - - touch git/gitconfig.local.symlink - sed -e "s/AUTHOR_NAME/$git_authorname/g" -e "s/AUTHOR_EMAIL/$git_authoremail/g" -e "s/GIT_CREDENTIAL_HELPER/$git_credential/g" -e "s/GPG_SIGNING_KEY/$git_signingkey/g" git/gitconfig.local.symlink.example > git/gitconfig.local.symlink - - success 'gitconfig' - fi +setup_gitconfig() { + if ! [ -f git/gitconfig.local.symlink ]; then + info 'Setup gitconfig' + + git_credential='cache' + if [ "$(uname -s)" == "Darwin" ]; then + git_credential='osxkeychain' + fi + + user ' - What is your github author name?' + read -e git_authorname + user ' - What is your github author email?' + read -e git_authoremail + user ' - What is your GPG signing key ID? (Find with: gpg --list-secret-keys --keyid-format LONG)' + read -e git_signingkey + + touch git/gitconfig.local.symlink + sed -e "s/AUTHOR_NAME/$git_authorname/g" -e "s/AUTHOR_EMAIL/$git_authoremail/g" -e "s/GIT_CREDENTIAL_HELPER/$git_credential/g" -e "s/GPG_SIGNING_KEY/$git_signingkey/g" git/gitconfig.local.symlink.example > git/gitconfig.local.symlink + + success 'gitconfig' + fi } -install_dotfiles () { - info 'Installing dotfiles (symlinks)' +install_dotfiles() { + info 'Installing dotfiles (symlinks)' - local overwrite_all=false backup_all=false skip_all=false + local overwrite_all=false backup_all=false skip_all=false - for src in $(find -H ~/.dotfiles -maxdepth 2 -name '*.symlink' -not -path '*.git*') - do - echo "linking $src" - dst="$HOME/.$(basename "${src%.*}")" - if [ $(readlink $dst) ] - then - rm -fr "$dst" - fi + for src in $(find -H ~/.dotfiles -maxdepth 2 -name '*.symlink' -not -path '*.git*'); do + echo "linking $src" + dst="$HOME/.$(basename "${src%.*}")" + if [ $(readlink $dst) ]; then + rm -fr "$dst" + fi - ln -s "$src" "$dst" - done + ln -s "$src" "$dst" + done } -setup_clone () { - # Note: This function is not currently called by bootstrap - # Users should manually clone the repo first following the README instructions - cd ~/ - git clone $DOTFILES_REPO_URL .dotfiles - cd .dotfiles +setup_clone() { + # Note: This function is not currently called by bootstrap + # Users should manually clone the repo first following the README instructions + cd ~/ + git clone $DOTFILES_REPO_URL .dotfiles + cd .dotfiles } setup_gitconfig install_dotfiles # Run the pre-installers -find . -name preinstall.sh | while read installer ; do sh -c "${installer}" ; done +find . -name preinstall.sh | while read installer; do sh -c "${installer}"; done # Run Homebrew through the Brewfile info "› brew bundle" brew bundle # find the installers and run them iteratively -find . -name install.sh | while read installer ; do sh -c "${installer}" ; done +find . -name install.sh | while read installer; do sh -c "${installer}"; done success 'All installed!' - - diff --git a/docker/install.sh b/docker/install.sh index 2d68b00..986d3dd 100755 --- a/docker/install.sh +++ b/docker/install.sh @@ -11,4 +11,4 @@ minikube addons enable ingress # Tell Docker CLI to talk to minikube's VM eval $(minikube docker-env) # Set up the custom host -echo "`minikube ip` docker.local" | sudo tee -a /etc/hosts > /dev/null +echo "$(minikube ip) docker.local" | sudo tee -a /etc/hosts > /dev/null diff --git a/google/env.zsh b/google/env.zsh index 7c63a93..63cff98 100644 --- a/google/env.zsh +++ b/google/env.zsh @@ -1,9 +1,9 @@ # Add Google Cloud if [[ $(uname -m) == 'arm64' ]]; then - source /opt/homebrew/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.zsh.inc - source /opt/homebrew/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/completion.zsh.inc + source /opt/homebrew/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.zsh.inc + source /opt/homebrew/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/completion.zsh.inc else - source /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.zsh.inc - source /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/completion.zsh.inc -fi \ No newline at end of file + source /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.zsh.inc + source /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/completion.zsh.inc +fi diff --git a/gpg/install.sh b/gpg/install.sh index 38214b3..f496f41 100755 --- a/gpg/install.sh +++ b/gpg/install.sh @@ -1,4 +1,4 @@ echo "setting up gpg" mkdir ~/.gnupg ln -s ~/.dotfiles/gpg/gpg-agent.conf ~/.gnupg/gpg-agent.conf -gpgconf --kill gpg-agent \ No newline at end of file +gpgconf --kill gpg-agent diff --git a/homebrew/preinstall.sh b/homebrew/preinstall.sh index 25ae3ae..2030247 100755 --- a/homebrew/preinstall.sh +++ b/homebrew/preinstall.sh @@ -6,15 +6,14 @@ # using Homebrew. # Check for Homebrew -if test ! $(which brew) -then - echo "Installing Homebrew" +if test ! $(which brew); then + echo "Installing Homebrew" - # Install the correct homebrew for each OS type - NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - echo >> $HOME/.zprofile - echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> $HOME/.zprofile - eval "$(/opt/homebrew/bin/brew shellenv)" + # Install the correct homebrew for each OS type + NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + echo >> $HOME/.zprofile + echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> $HOME/.zprofile + eval "$(/opt/homebrew/bin/brew shellenv)" fi exit 0 diff --git a/iterm/README.md b/iterm/README.md index 5341a8d..d268cae 100644 --- a/iterm/README.md +++ b/iterm/README.md @@ -10,6 +10,7 @@ Instead of tracking the entire `com.googlecode.iterm2.plist` file (which changes 2. **Settings Script** (`settings.sh`) - Global behavior settings applied via `defaults write` This approach provides: + - ✅ Clean git history (no noise from window resizing, etc.) - ✅ Easy-to-review configuration changes - ✅ Device-specific customization support @@ -18,7 +19,9 @@ This approach provides: ## Files ### `profiles/Default.json` + Dynamic Profile configuration in JSON format. This defines: + - Terminal type and character encoding - Font settings (bold, italic, ligatures) - Scrollback behavior @@ -29,7 +32,9 @@ Dynamic Profile configuration in JSON format. This defines: **Note:** Colors and fonts can be added here. See [iTerm2 Dynamic Profiles Documentation](https://iterm2.com/documentation-dynamic-profiles.html) for all available options. ### `settings.sh` + Global iTerm2 settings applied via `defaults write` commands. This includes: + - Quit behavior (prompt settings) - Appearance preferences - Window behavior @@ -39,7 +44,9 @@ Global iTerm2 settings applied via `defaults write` commands. This includes: Many settings are commented out by default. Uncomment the ones you want to apply. ### `install.sh` + Installation script that: + 1. Disables the old plist sync folder approach 2. Symlinks Dynamic Profiles to the correct location 3. Applies global settings via `settings.sh` @@ -47,7 +54,9 @@ Installation script that: ## Usage ### Initial Setup + Run the install script (typically called by `bootstrap.sh`): + ```bash cd ~/.dotfiles/iterm && ./install.sh ``` @@ -57,24 +66,27 @@ cd ~/.dotfiles/iterm && ./install.sh ### Customizing Settings #### To modify profile settings (colors, fonts, etc.): + 1. Edit `profiles/Default.json` 2. Restart iTerm2 or reload profiles (Preferences > Profiles > Other Actions > Reload All Dynamic Profiles) #### To modify global behavior: + 1. Edit `settings.sh` 2. Run `~/.dotfiles/iterm/settings.sh` 3. Restart iTerm2 if needed #### Device-specific settings: + You can add device-specific logic in `settings.sh` using the `$DEVICE_NAME` variable from your `.env` file: ```bash if [ "$DEVICE_NAME" = "MyLaptop" ]; then - # Smaller font for laptop screen - defaults write com.googlecode.iterm2 "NormalFont" -string "Monaco 12" + # Smaller font for laptop screen + defaults write com.googlecode.iterm2 "NormalFont" -string "Monaco 12" elif [ "$DEVICE_NAME" = "MyDesktop" ]; then - # Larger font for desktop monitors - defaults write com.googlecode.iterm2 "NormalFont" -string "Monaco 16" + # Larger font for desktop monitors + defaults write com.googlecode.iterm2 "NormalFont" -string "Monaco 16" fi ``` @@ -83,6 +95,7 @@ fi To find the correct key names for settings you want to configure: ### Method 1: Dump all preferences + ```bash defaults read com.googlecode.iterm2 > /tmp/before.txt # Change setting in iTerm2 UI @@ -91,6 +104,7 @@ diff /tmp/before.txt /tmp/after.txt ``` ### Method 2: Monitor changes in real-time + ```bash defaults read com.googlecode.iterm2 | tee /tmp/iterm-prefs.txt # Change setting in UI @@ -98,6 +112,7 @@ defaults read com.googlecode.iterm2 | diff /tmp/iterm-prefs.txt - ``` ### Method 3: Check specific key + ```bash defaults read com.googlecode.iterm2 "KeyNameHere" ``` @@ -111,12 +126,14 @@ The old plist-based configuration was backed up to `local/com.googlecode.iterm2. This setup replaced the old "preference sync folder" approach which tracked the entire plist file. Benefits of the new approach: **Old approach:** + - ⌠Constant git noise from window resizing, position changes - ⌠Merge conflicts when syncing across machines - ⌠Hard to review meaningful changes - ⌠Binary plist format difficult to read **New approach:** + - ✅ Only meaningful settings tracked - ✅ JSON format (easy to read/review) - ✅ Declarative settings via scripts @@ -132,15 +149,18 @@ This setup replaced the old "preference sync folder" approach which tracked the ## Troubleshooting ### Changes not appearing + - Make sure you've restarted iTerm2 - Check that Dynamic Profiles are enabled: Preferences > General > Preferences > "Load preferences from custom folder" should be **OFF** - Verify the symlink exists: `ls -la ~/Library/Application\ Support/iTerm2/DynamicProfiles/` ### Profile not showing up + - Go to Preferences > Profiles > Other Actions > Reload All Dynamic Profiles - The "Default" profile from Dynamic Profiles should appear in the list ### Settings reverting + - Some settings require iTerm2 to be completely quit and restarted - Some settings may conflict with existing user preferences - Check `defaults read com.googlecode.iterm2` to see actual values diff --git a/iterm/install.sh b/iterm/install.sh index 6f0eac3..ed4be26 100755 --- a/iterm/install.sh +++ b/iterm/install.sh @@ -12,11 +12,11 @@ set -e info() { - printf "\r [ \033[00;34m..\033[0m ] $1\n" + printf "\r [ \033[00;34m..\033[0m ] $1\n" } success() { - printf "\r\033[2K [ \033[00;32mOK\033[0m ] $1\n" + printf "\r\033[2K [ \033[00;32mOK\033[0m ] $1\n" } printf "\e[32mConfiguring iTerm2\e[0m\n" @@ -37,7 +37,7 @@ mkdir -p ~/Library/Application\ Support/iTerm2/DynamicProfiles/ # Symlink our dotfiles profiles if [ -L ~/Library/Application\ Support/iTerm2/DynamicProfiles/dotfiles-profiles.json ]; then - rm ~/Library/Application\ Support/iTerm2/DynamicProfiles/dotfiles-profiles.json + rm ~/Library/Application\ Support/iTerm2/DynamicProfiles/dotfiles-profiles.json fi ln -s ~/.dotfiles/iterm/profiles/Default.json ~/Library/Application\ Support/iTerm2/DynamicProfiles/dotfiles-profiles.json @@ -56,4 +56,3 @@ chmod +x ~/.dotfiles/iterm/settings.sh printf "\e[32miTerm2 configuration complete!\e[0m\n" printf "\e[33mâš ï¸ You MUST restart iTerm2 for changes to take effect\e[0m\n" printf "\e[33mâš ï¸ After restarting, you may need to select the 'Default' profile in Preferences > Profiles\e[0m\n" - diff --git a/iterm/profiles/Default.json b/iterm/profiles/Default.json index ef666c9..37e5f6f 100644 --- a/iterm/profiles/Default.json +++ b/iterm/profiles/Default.json @@ -1,57 +1,57 @@ { - "Profiles": [ - { - "Name": "Default", - "Guid": "dotfiles-default-profile", - "Dynamic Profile Parent Name": "Default", + "Profiles": [ + { + "Name": "Default", + "Guid": "dotfiles-default-profile", + "Dynamic Profile Parent Name": "Default", - "Working Directory": "~", - "Custom Directory": "Recycle", + "Working Directory": "~", + "Custom Directory": "Recycle", - "Terminal Type": "xterm-256color", + "Terminal Type": "xterm-256color", - "Use Bold Font": true, - "Use Bright Bold": true, - "Use Italic Font": true, + "Use Bold Font": true, + "Use Bright Bold": true, + "Use Italic Font": true, - "ASCII Anti Aliased": true, - "ASCII Ligatures": false, + "ASCII Anti Aliased": true, + "ASCII Ligatures": false, - "Scrollback Lines": 10000, - "Unlimited Scrollback": false, + "Scrollback Lines": 10000, + "Unlimited Scrollback": false, - "Silence Bell": false, - "Visual Bell": true, + "Silence Bell": false, + "Visual Bell": true, - "Close Sessions On End": true, + "Close Sessions On End": true, - "Sync Title": false, - "Badge Text": "", + "Sync Title": false, + "Badge Text": "", - "Use Custom Window Title": false, - "Custom Window Title": "", + "Use Custom Window Title": false, + "Custom Window Title": "", - "Application Keypad Allowed": false, - "Place Prompt at First Column": true, + "Application Keypad Allowed": false, + "Place Prompt at First Column": true, - "Show Mark Indicators": true, + "Show Mark Indicators": true, - "Triggers": [], + "Triggers": [], - "Smart Selection Rules": [ - { - "notes": "URL", - "precision": "very_low", - "regex": "https?://[a-zA-Z0-9_\\-.~:/?#\\[\\]@!$&'()*+,;=%]+", - "actions": [ - { - "title": "Open URL", - "action": 1, - "parameter": "" - } - ] - } - ] - } - ] + "Smart Selection Rules": [ + { + "notes": "URL", + "precision": "very_low", + "regex": "https?://[a-zA-Z0-9_\\-.~:/?#\\[\\]@!$&'()*+,;=%]+", + "actions": [ + { + "title": "Open URL", + "action": 1, + "parameter": "" + } + ] + } + ] + } + ] } diff --git a/iterm/settings.sh b/iterm/settings.sh index 68e1041..e515904 100755 --- a/iterm/settings.sh +++ b/iterm/settings.sh @@ -11,11 +11,11 @@ set -e info() { - printf "\r [ \033[00;34m..\033[0m ] $1\n" + printf "\r [ \033[00;34m..\033[0m ] $1\n" } success() { - printf "\r\033[2K [ \033[00;32mOK\033[0m ] $1\n" + printf "\r\033[2K [ \033[00;32mOK\033[0m ] $1\n" } info "Applying iTerm2 global settings..." diff --git a/java/install.sh b/java/install.sh index df95016..0ac22a2 100755 --- a/java/install.sh +++ b/java/install.sh @@ -1,4 +1,4 @@ echo "Setting up jenv" -for d in /Library/Java/JavaVirtualMachines/*jdk*/ ; do - jenv add $d/Contents/Home/ -done \ No newline at end of file +for d in /Library/Java/JavaVirtualMachines/*jdk*/; do + jenv add $d/Contents/Home/ +done diff --git a/local/README.md b/local/README.md index d89e2f1..a246b28 100644 --- a/local/README.md +++ b/local/README.md @@ -1,4 +1,5 @@ # The "local" directory + This directory contains local (e.g. not-checked-in) files that are generated by other pieces of the dotfiles. It also contains a config file that the user should populate before running the dotfiles. diff --git a/local/config.json.example b/local/config.json.example index 54e2169..a4d6313 100644 --- a/local/config.json.example +++ b/local/config.json.example @@ -1,10 +1,10 @@ { - "smbNetworkMounts": [ - { - "mountName": "", - "serverPath": "", - "username": "", - "password": "" - } - ] + "smbNetworkMounts": [ + { + "mountName": "", + "serverPath": "", + "username": "", + "password": "" + } + ] } diff --git a/macos/install.sh b/macos/install.sh index e09d8d7..76521fc 100755 --- a/macos/install.sh +++ b/macos/install.sh @@ -8,15 +8,15 @@ sudo softwareupdate -i -a # To look up the install ID go to the store and "copy link" # and pull it from the URL -mas install 411643860 # DaisyDisk (4.4) +mas install 411643860 # DaisyDisk (4.4) mas install 1303222628 # Paprika Recipe Manager 3 (3.2.3) -mas install 904280696 # Things3 (3.4.1) +mas install 904280696 # Things3 (3.4.1) mas install 1289583905 # Pixelmator Pro -mas install 992076693 # MindNode (2.5.7) -mas install 880001334 # Reeder (3.1.2) +mas install 992076693 # MindNode (2.5.7) +mas install 880001334 # Reeder (3.1.2) mas install 1091189122 # Bear (1.4.3) -mas install 409183694 # Keynote (8.1) -mas install 497799835 # XCode (9.4.1) +mas install 409183694 # Keynote (8.1) +mas install 497799835 # XCode (9.4.1) ############# ## Set some defaults @@ -174,7 +174,7 @@ sudo launchctl load ~/Library/LaunchAgents/dotfiles.macos.launch.plist # sudo chmod 644 /etc/auto_master # sudo chmod 644 /etc/auto_smb -{ set +x; } 2>/dev/null +{ set +x; } 2> /dev/null printf "\e[32mMacOS settings updated.\e[0m\n" printf "\e[33m(You may need to restart for all settings to take effect)\e[0m\n" diff --git a/macos/preinstall.sh b/macos/preinstall.sh index bbe63af..7a75a33 100755 --- a/macos/preinstall.sh +++ b/macos/preinstall.sh @@ -1,5 +1,4 @@ # Install Rosetta on M1 macs if [[ $(uname -m) == 'arm64' ]]; then - softwareupdate --install-rosetta + softwareupdate --install-rosetta fi - diff --git a/macos/scripts/generateAutoMountScript.js b/macos/scripts/generateAutoMountScript.js index fd3a394..227fcad 100644 --- a/macos/scripts/generateAutoMountScript.js +++ b/macos/scripts/generateAutoMountScript.js @@ -5,10 +5,10 @@ https://apple.stackexchange.com/questions/325686/how-to-add-startup-program-using-terminal */ -var fs = require('fs'); +var fs = require("fs"); function containsLine(filePath, line) { - const contents = fs.readFileSync(filePath, 'utf8'); + const contents = fs.readFileSync(filePath, "utf8"); return contents.includes(line); } @@ -16,29 +16,25 @@ const dotfilesConfigLocation = `${process.env.HOME}/.dotfiles/local/config.json` const autoMountScriptLocation = `${process.env.HOME}/.dotfiles/local/autoMount.sh`; const mountRoot = `${process.env.HOME}/Volumes`; -fs.openSync(autoMountScriptLocation, 'w'); -fs.chmodSync(autoMountScriptLocation, '755'); +fs.openSync(autoMountScriptLocation, "w"); +fs.chmodSync(autoMountScriptLocation, "755"); try { - var config = JSON.parse(fs.readFileSync(dotfilesConfigLocation, 'utf8')); + var config = JSON.parse(fs.readFileSync(dotfilesConfigLocation, "utf8")); var smbNetworkMounts = config.smbNetworkMounts; - smbNetworkMounts.forEach(networkMount => { - const mountPath = `${mountRoot}/${networkMount.mountName}` - const { - username, - password, - serverPath, - } = networkMount + smbNetworkMounts.forEach((networkMount) => { + const mountPath = `${mountRoot}/${networkMount.mountName}`; + const { username, password, serverPath } = networkMount; if (!fs.existsSync(mountPath)) { - fs.mkdirSync(mountPath, { recursive: true }) + fs.mkdirSync(mountPath, { recursive: true }); } - const mountCommand = `mount -t smbfs "//${username}:${password}@${serverPath}" ${mountPath}` - if(!containsLine(autoMountScriptLocation, mountCommand)) { + const mountCommand = `mount -t smbfs "//${username}:${password}@${serverPath}" ${mountPath}`; + if (!containsLine(autoMountScriptLocation, mountCommand)) { fs.appendFileSync(autoMountScriptLocation, `${mountCommand}\n`); } - }) + }); } catch (e) { - console.log("Couldn't generate the autoMount script") - console.log(e) + console.log("Couldn't generate the autoMount script"); + console.log(e); } diff --git a/macos/set-defaults.sh b/macos/set-defaults.sh index e7df4f6..974e636 100755 --- a/macos/set-defaults.sh +++ b/macos/set-defaults.sh @@ -10,7 +10,11 @@ osascript -e 'tell application "System Preferences" to quit' sudo -v # Keep-alive: update existing `sudo` time stamp until `.macos` has finished -while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null & +while true; do + sudo -n true + sleep 60 + kill -0 "$$" || exit +done 2> /dev/null & ############################################################################### # General UI/UX # @@ -606,7 +610,7 @@ sudo mdutil -E / > /dev/null defaults write com.apple.terminal StringEncodings -array 4 # Use a modified version of the Solarized Dark theme by default in Terminal.app -osascript <=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-sh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-sh/-/prettier-plugin-sh-0.14.0.tgz", + "integrity": "sha512-hfXulj5+zEl/ulrO5kMuuTPKmXvOg0bnLHY1hKFNN/N+/903iZbNp8NyZBTsgI8dtkSgFfAEIQq0IQTyP1ZVFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mvdan-sh": "^0.10.1", + "sh-syntax": "^0.4.1" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + }, + "peerDependencies": { + "prettier": "^3.0.3" + } + }, + "node_modules/sh-syntax": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/sh-syntax/-/sh-syntax-0.4.2.tgz", + "integrity": "sha512-/l2UZ5fhGZLVZa16XQM9/Vq/hezGGbdHeVEA01uWjOL1+7Ek/gt6FquW0iKKws4a9AYPYvlz6RyVvjh3JxOteg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..6fa473f --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "dotfiles", + "version": "1.0.0", + "description": "Dotfiles for provisioning macOS development environments", + "private": true, + "scripts": { + "format": "prettier --write .", + "lint": "prettier --check ." + }, + "devDependencies": { + "prettier": "^3.4.2", + "prettier-plugin-sh": "^0.14.0" + }, + "keywords": [ + "dotfiles", + "macos", + "provisioning" + ], + "author": "Daniel Schultz ", + "license": "MIT" +} diff --git a/python/README.md b/python/README.md index c247f10..3d0e37f 100644 --- a/python/README.md +++ b/python/README.md @@ -11,4 +11,4 @@ The dotfile bootstrap will install the latest version of Python (3.x) at the poi You can specify a version of python to use in a given directory by populating `.python-version` -pipenv is installed via homebrew. \ No newline at end of file +pipenv is installed via homebrew. diff --git a/python/env.zsh b/python/env.zsh index be8d76c..16b4ffe 100644 --- a/python/env.zsh +++ b/python/env.zsh @@ -1,6 +1,6 @@ # Set up python path -if command -v pyenv 1>/dev/null 2>&1; then - eval "$(pyenv init -)" +if command -v pyenv 1> /dev/null 2>&1; then + eval "$(pyenv init -)" fi # This relies on pyenv init to function, so it doesn't go in a separate path.zsh file diff --git a/python/hook.zsh b/python/hook.zsh index 511134b..3866ea3 100644 --- a/python/hook.zsh +++ b/python/hook.zsh @@ -1,23 +1,23 @@ get_installed_python_version() { - local query=$1 - pyenv versions 2> /dev/null \ - | grep -E "(^\*?\s*$query\.)|(^\*?\s*$query)" \ - | sed 's/^\s\+//' \ - | sed 's/(.*)//' \ - | sed 's/\*//' \ - | sort -V \ - | tail -1 \ - | xargs + local query=$1 + pyenv versions 2> /dev/null \ + | grep -E "(^\*?\s*$query\.)|(^\*?\s*$query)" \ + | sed 's/^\s\+//' \ + | sed 's/(.*)//' \ + | sed 's/\*//' \ + | sort -V \ + | tail -1 \ + | xargs } get_latest_available_python_version() { - local query=$1 - pyenv install --list \ - | grep -vE "(^Available versions:|-src|dev|rc|alpha|beta|(a|b)[0-9]+)" \ - | grep -E "(^\s*$query\.)|(^\s*$query$)" \ - | sed 's/^\s\+//' \ - | tail -1 \ - | xargs + local query=$1 + pyenv install --list \ + | grep -vE "(^Available versions:|-src|dev|rc|alpha|beta|(a|b)[0-9]+)" \ + | grep -E "(^\s*$query\.)|(^\s*$query$)" \ + | sed 's/^\s\+//' \ + | tail -1 \ + | xargs } # This hook relies on the install-latest pyenv plugin: @@ -37,30 +37,30 @@ autoload_python_version() { return fi - local python_version="$(pyenv version-name)" - local python_version_path=".python-version" - if [ -f "$python_version_path" ]; then - local pyenv_target_version=$(cat "${python_version_path}") - local pyenv_installed_target_version=$(get_installed_python_version $pyenv_target_version) - local pyenv_latest_available_target_version=$(get_latest_available_python_version $pyenv_target_version) - if [ -z "$pyenv_installed_target_version" ]; then - echo "\e[32mAutomatically installing the latest version of Python $pyenv_target_version\e[0m" - pyenv install-latest "$pyenv_target_version" - pyenv_installed_target_version=$(get_installed_python_version $pyenv_target_version) - pip install -U pipenv - fi - if [ -z "$pyenv_installed_target_version" ]; then - echo "\e[91mCould not install Python $pyenv_latest_available_target_version." - elif [ "$pyenv_target_version" != "$pyenv_installed_target_version" ]; then - echo "\e[91mCorrecting your .python-version from $pyenv_target_version to $pyenv_installed_target_version (it must match an installed version)\e[0m" - if [ "$pyenv_installed_target_version" != "$pyenv_latest_available_target_version" ]; then - echo "\e[33mIf you wanted the latest Python $pyenv_target_version type:\e[0m pyenv install $pyenv_latest_available_target_version" - else - echo "\e[33mPython $pyenv_installed_target_version is the latest version of Python $pyenv_target_version available\e[0m" - fi - pyenv local "$(get_installed_python_version $pyenv_target_version)" 2> /dev/null - fi - fi + local python_version="$(pyenv version-name)" + local python_version_path=".python-version" + if [ -f "$python_version_path" ]; then + local pyenv_target_version=$(cat "${python_version_path}") + local pyenv_installed_target_version=$(get_installed_python_version $pyenv_target_version) + local pyenv_latest_available_target_version=$(get_latest_available_python_version $pyenv_target_version) + if [ -z "$pyenv_installed_target_version" ]; then + echo "\e[32mAutomatically installing the latest version of Python $pyenv_target_version\e[0m" + pyenv install-latest "$pyenv_target_version" + pyenv_installed_target_version=$(get_installed_python_version $pyenv_target_version) + pip install -U pipenv + fi + if [ -z "$pyenv_installed_target_version" ]; then + echo "\e[91mCould not install Python $pyenv_latest_available_target_version." + elif [ "$pyenv_target_version" != "$pyenv_installed_target_version" ]; then + echo "\e[91mCorrecting your .python-version from $pyenv_target_version to $pyenv_installed_target_version (it must match an installed version)\e[0m" + if [ "$pyenv_installed_target_version" != "$pyenv_latest_available_target_version" ]; then + echo "\e[33mIf you wanted the latest Python $pyenv_target_version type:\e[0m pyenv install $pyenv_latest_available_target_version" + else + echo "\e[33mPython $pyenv_installed_target_version is the latest version of Python $pyenv_target_version available\e[0m" + fi + pyenv local "$(get_installed_python_version $pyenv_target_version)" 2> /dev/null + fi + fi } add-zsh-hook chpwd autoload_python_version autoload_python_version diff --git a/python/pyenv-install-latest/bin/pyenv-install-latest b/python/pyenv-install-latest/bin/pyenv-install-latest index f85e6fe..7ab593a 100755 --- a/python/pyenv-install-latest/bin/pyenv-install-latest +++ b/python/pyenv-install-latest/bin/pyenv-install-latest @@ -9,49 +9,56 @@ DEFAULT_QUERY="[0-9]" # Provide pyenv completions if [ "$1" = "--complete" ]; then - pyenv install --complete - exit + pyenv install --complete + exit fi get_version() { - local query=$1 - [[ -z $query ]] && query=$DEFAULT_QUERY - pyenv install --list \ - | grep -vE "(^Available versions:|-src|dev|rc|alpha|beta|(a|b)[0-9]+)" \ - | grep -E "(^\s*$query\.)|(^\s*$query$)" \ - | sed 's/^\s\+//' \ - | tail -1 \ - | xargs + local query=$1 + [[ -z $query ]] && query=$DEFAULT_QUERY + pyenv install --list \ + | grep -vE "(^Available versions:|-src|dev|rc|alpha|beta|(a|b)[0-9]+)" \ + | grep -E "(^\s*$query\.)|(^\s*$query$)" \ + | sed 's/^\s\+//' \ + | tail -1 \ + | xargs } version() { - echo "pyenv-install-latest ${PYENV_INSTALL_LATEST_VERSION}" + echo "pyenv-install-latest ${PYENV_INSTALL_LATEST_VERSION}" } for arg; do - case "$arg" in - --version|version) - version - exit 0 - ;; - --help|help) - pyenv-help install-latest - exit 0 - ;; - --print) - shift - latest=$(get_version $1) - [[ -z $latest ]] && { echo "Python version is not found." >&2; exit 1; } - echo $latest - exit 0 - ;; - -*) - install_args="$install_args $arg" - shift - esac + case "$arg" in + --version | version) + version + exit 0 + ;; + --help | help) + pyenv-help install-latest + exit 0 + ;; + --print) + shift + latest=$(get_version $1) + [[ -z $latest ]] && { + echo "Python version is not found." >&2 + exit 1 + } + echo $latest + exit 0 + ;; + -*) + install_args="$install_args $arg" + shift + ;; + esac done latest=$(get_version $1) -[[ -z $latest ]] && { echo "Python version is not found." >&2; exit 1; } +[[ -z $latest ]] && { + echo "Python version is not found." >&2 + exit 1 +} echo "Install $latest..." -pyenv install $install_args $latest \ No newline at end of file +pyenv install $install_args $latest diff --git a/rectangle/install.sh b/rectangle/install.sh index 95f0e6e..d90b4ca 100755 --- a/rectangle/install.sh +++ b/rectangle/install.sh @@ -91,5 +91,5 @@ defaults write com.knollsoft.Rectangle bottomLeftNinth -dict-add keyCode -float defaults write com.knollsoft.Rectangle bottomCenterNinth -dict-add keyCode -float 1 modifierFlags -float 655360 defaults write com.knollsoft.Rectangle bottomRightNinth -dict-add keyCode -float 2 modifierFlags -float 655360 -{ set +x; } 2>/dev/null +{ set +x; } 2> /dev/null printf "\e[32mRectangle settings updated.\e[0m\n" diff --git a/ruby/env.zsh b/ruby/env.zsh index dbe4c3b..436d718 100644 --- a/ruby/env.zsh +++ b/ruby/env.zsh @@ -1,2 +1,2 @@ # Activate rbenv -eval "$(rbenv init -)" \ No newline at end of file +eval "$(rbenv init -)" diff --git a/soundsource/install.sh b/soundsource/install.sh index 11cb39f..0827050 100755 --- a/soundsource/install.sh +++ b/soundsource/install.sh @@ -4,7 +4,7 @@ set -x # Enable super volume controls defaults write com.rogueamoeba.soundsource keyboardVolume 1 -{ set +x; } 2>/dev/null +{ set +x; } 2> /dev/null echo "\e[32mYou're going to need to give SoundSource accessibility access to support super volume buttons\e[0m\n" open "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility" diff --git a/ssh/install.sh b/ssh/install.sh index 527db26..6766465 100755 --- a/ssh/install.sh +++ b/ssh/install.sh @@ -2,9 +2,9 @@ SSH_KEY="$HOME/.ssh/id_ed25519" # Check if the key already exists if [ ! -f "$SSH_KEY" ]; then - echo "🛠 SSH key not found. Generating a new one..." - ssh-keygen -t ed25519 -C "$USER_EMAIL" -f "$SSH_KEY" -N "" - echo "✅ SSH key generated at $SSH_KEY" + echo "🛠 SSH key not found. Generating a new one..." + ssh-keygen -t ed25519 -C "$USER_EMAIL" -f "$SSH_KEY" -N "" + echo "✅ SSH key generated at $SSH_KEY" else - echo "🔑 SSH key already exists at $SSH_KEY" -fi \ No newline at end of file + echo "🔑 SSH key already exists at $SSH_KEY" +fi diff --git a/svn/env.zsh b/svn/env.zsh index 2d8ee90..ec76e81 100644 --- a/svn/env.zsh +++ b/svn/env.zsh @@ -1,2 +1,2 @@ # Set the SVN message editor -export SVN_EDITOR="vim" \ No newline at end of file +export SVN_EDITOR="vim" diff --git a/system/env.zsh b/system/env.zsh index dd64c33..5b67f44 100644 --- a/system/env.zsh +++ b/system/env.zsh @@ -1,4 +1,4 @@ -if command -v codium >/dev/null 2>&1; then +if command -v codium > /dev/null 2>&1; then export EDITOR='codium' else export EDITOR='code' @@ -6,11 +6,11 @@ fi # set LIBRARY_PATH so it includes openssl if it exists # (this is required by certain builds, e.g. python's psycopg2) -if [ -d /usr/local/opt/openssl/lib ] ; then - export LIBRARY_PATH="${LIBRARY_PATH}:/usr/local/opt/openssl/lib" +if [ -d /usr/local/opt/openssl/lib ]; then + export LIBRARY_PATH="${LIBRARY_PATH}:/usr/local/opt/openssl/lib" fi # M1 macs put this stuff in a different place; support that if it exists -if [ -d /opt/homebrew/opt/openssl/lib ] ; then - export LIBRARY_PATH="${LIBRARY_PATH}:/opt/homebrew/opt/openssl/lib" +if [ -d /opt/homebrew/opt/openssl/lib ]; then + export LIBRARY_PATH="${LIBRARY_PATH}:/opt/homebrew/opt/openssl/lib" fi diff --git a/system/install.sh b/system/install.sh index b4c2dbd..f715330 100755 --- a/system/install.sh +++ b/system/install.sh @@ -3,4 +3,4 @@ ln -ns ~/.dotfiles/bin $HOME/bin # Open things that need to be opened once in order to boot on load open /Applications/Rectangle.app -open /Applications/SoundSource.app \ No newline at end of file +open /Applications/SoundSource.app diff --git a/system/path.zsh b/system/path.zsh index d1606ec..8182e2b 100644 --- a/system/path.zsh +++ b/system/path.zsh @@ -1 +1 @@ -export PATH="$HOME/bin:$PATH" \ No newline at end of file +export PATH="$HOME/bin:$PATH" diff --git a/thunderbird/README.md b/thunderbird/README.md index 13d7f7c..151479d 100644 --- a/thunderbird/README.md +++ b/thunderbird/README.md @@ -15,18 +15,18 @@ I have no philosophy here yet, but would like to have one some day so I'm includ ## Archive vs Delete -* **Delete** emails that will never need reference in future OR the information could be referenced elsewhere. -* **Archive** emails that might need reference in future. +- **Delete** emails that will never need reference in future OR the information could be referenced elsewhere. +- **Archive** emails that might need reference in future. ### Scenarios -| Scenario | Outcome | -| -------- | ------- | -| Order confirmation | ARCHIVE | -| Shipping update | DELETE | -| Password Reset | DELETE | -| Email from Justin Reese | DELETE WITHOUT READING | -| Political donation email | DELETE AND UNSUBSCRIBE | -| Newsletter | DELETE | -| Listserv email | DELETE IF WEB ARCHIVE EXISTS | -| Watched codebase email | DELETE | +| Scenario | Outcome | +| ------------------------ | ---------------------------- | +| Order confirmation | ARCHIVE | +| Shipping update | DELETE | +| Password Reset | DELETE | +| Email from Justin Reese | DELETE WITHOUT READING | +| Political donation email | DELETE AND UNSUBSCRIBE | +| Newsletter | DELETE | +| Listserv email | DELETE IF WEB ARCHIVE EXISTS | +| Watched codebase email | DELETE |