From 96ca478d31819a1f4ef08fd958e3cf42cade5118 Mon Sep 17 00:00:00 2001 From: Filipe Fortes Date: Tue, 30 Jan 2024 09:36:06 -0500 Subject: [PATCH] Mac: WIP initial working version --- .github/workflows/mac-os.yml | 13 ++ README.md | 13 +- scripts/brew-packages | 42 +++++++ scripts/create_local_profile | 11 +- scripts/setup_mac | 117 ++++++++++++++++++ .../.config/alacritty/alacritty.toml | 9 ++ stowed-files/bash/.bashrc | 41 +++--- stowed-files/bash/.local/bin/fd_with_git | 11 +- stowed-files/bash/.profile | 3 + 9 files changed, 232 insertions(+), 28 deletions(-) create mode 100644 .github/workflows/mac-os.yml create mode 100644 scripts/brew-packages create mode 100755 scripts/setup_mac create mode 100644 stowed-files/alacritty/.config/alacritty/alacritty.toml diff --git a/.github/workflows/mac-os.yml b/.github/workflows/mac-os.yml new file mode 100644 index 00000000..44847002 --- /dev/null +++ b/.github/workflows/mac-os.yml @@ -0,0 +1,13 @@ +name: MacOS +on: [push] + +jobs: + build: + runs-on: macos-14 + + steps: + - uses: actions/checkout@v4 + + - name: Setup machine + run: bash ./scripts/setup_mac + diff --git a/README.md b/README.md index 392250f8..74c7a0b6 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,11 @@ Graphical sections are Linux-only, and use: * foot * Firefox +On MacOS, use: + +* Alacritty +* Rectangle + ## Letting me own your machine ```sh @@ -204,7 +209,13 @@ The Bullseye to Bookworm upgrade requires a few manual steps that I'm too lazy t ### Mac -- Not fully functional, see `mac-setup` branch for current status +Still a work in progress, but kinda works + +- [ ] May want to install command line tools manually in order to get `git`: `xcode-select --install` +- [ ] Set `terminal.app` profile, send option as meta key +- [ ] `terminal.app` sucks with colors, so once installs happen, switch to Alacritty and pin it in the dock +- [ ] Music scripts depend on `playerctl`, which requires `dbus` which does not exist on Mac. Will need to switch to scripting `cmus` directly perhaps? +- [ ] Figure out how to get [M1 CI running](https://github.blog/changelog/2024-01-30-github-actions-introducing-the-new-m1-macos-runner-available-to-open-source/) to check builds ## Known Issues diff --git a/scripts/brew-packages b/scripts/brew-packages new file mode 100644 index 00000000..49675a36 --- /dev/null +++ b/scripts/brew-packages @@ -0,0 +1,42 @@ +1password-cli +alacritty +bash +bash-completion@2 +bat +oven-sh/bun/bun +chafa +cmus +deno +docker +duf +MisterTea/et/et +eza +fd +firefox +fnm +fzf +git +git-crypt +git-extras +git-lfs +helix +htop +hugo +jq +keychain +mpv +ncdu +neovim +pipx +rclone +rectangle +ripgrep +sad +shellcheck +speedtest-cli +stow +tmux +visual-studio-code +wget +yt-dlp +zoxide diff --git a/scripts/create_local_profile b/scripts/create_local_profile index 244f43fe..5afb24ce 100755 --- a/scripts/create_local_profile +++ b/scripts/create_local_profile @@ -9,17 +9,19 @@ IFS=$'\n\t' main() { local is_crostini=$([[ -f /etc/apt/sources.list.d/cros.list ]] && printf 1) + local is_mac=$([[ ${OSTYPE:-} == 'darwin'* ]] && printf 1) local is_docker=$([[ -f /.dockerenv ]] && printf 1) local is_wsl=$([[ -d /run/WSL ]] && printf 1) # Default to headless in Crostini / Docker / WSL, even though GUI might be # possible, can always be overridden - local is_headless=$([[ -n "${is_crostini}${is_docker}${is_wsl}" || \ + local is_headless=$([[ -n "${is_crostini}${is_docker}${is_mac}${is_wsl}" || \ -z "${WAYLAND_DISPLAY:-}" ]] && printf 1) cat < /dev/null + fi + + # Only change shell if running interactively, otherwise fails in CI which + # can't do the required auth + if [[ -t 1 ]] ; then + echo "Changing shell to bash ($homebrew_bash_path)" + chsh -s "${homebrew_bash_path}" + fi + fi +} + +install_command_line_tools() { + if ! xcode-select -p > /dev/null 2>&1; then + echo "Installing command line tools" + xcode-select --install + fi +} + +install_homebrew() { + if [[ ! -x "${brew_prefix}/bin/brew" ]]; then + echo "Installing Homebrew" + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + fi + + if [[ ! -f "$HOME/.profile.brew" ]]; then + echo "Exporting brew shellenv" + "${brew_prefix}/bin/brew" shellenv > "$HOME/.profile.brew" + fi + + # Ensure `brew` in path for rest of script + # shellcheck source=/dev/null + . "$HOME/.profile.brew" +} + +install_homebrew_packages() { + echo "Installing homebrew packages" + # Use full path just in case `brew` not in path during initial setup + grep -v "^#" "${dotfiles_root}/scripts/brew-packages" | \ + xargs "${brew_prefix}/bin/brew" install --quiet +} + +main() { + if ! uname -s | grep -q Darwin; then + >&2 echo "Only works on Mac!" + exit 1 + fi + + # Make sure to load `command_exists` helper + # shellcheck source=../stowed-files/bash/.profile + . "${dotfiles_root}/stowed-files/bash/.profile" + + local local_profile_path="$HOME/.profile.local" + + if [[ ! -f "$local_profile_path" ]]; then + echo "Generating $local_profile_path" + "${dotfiles_root}/scripts/create_local_profile" > "$local_profile_path" + fi + + # shellcheck source=/dev/null + . "$local_profile_path" + + install_command_line_tools + install_homebrew + install_homebrew_packages + + # Remove default files before stowing, otherwise stow fails + "${dotfiles_root}/scripts/remove_default_dotfiles" + "${dotfiles_root}/scripts/stow" + + setup_shell + + "${dotfiles_root}/scripts/lock_local_files" + + # Non-brew package managers + "${dotfiles_root}/scripts/install_node_packages" + "${dotfiles_root}/scripts/install_python_packages" + + "${dotfiles_root}/scripts/generate_completions" + + # TODO: Neovim plugin install? + + echo "Setup complete!" +} + +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + if [[ "${BASH_VERSINFO:-0}" -ge 4 ]]; then + main "${@}" + else + # Ancient Mac Bash version does not support `@` + main + fi +fi diff --git a/stowed-files/alacritty/.config/alacritty/alacritty.toml b/stowed-files/alacritty/.config/alacritty/alacritty.toml new file mode 100644 index 00000000..81288f94 --- /dev/null +++ b/stowed-files/alacritty/.config/alacritty/alacritty.toml @@ -0,0 +1,9 @@ +[env] +# tmux uses `$SHELL` which isn't set by `chsh` on MacOS +SHELL = "/opt/homebrew/bin/bash" +[shell] +# Only used on MacOS, so this path is OK +program = "/opt/homebrew/bin/bash" +args = ["--login"] +[window] +option_as_alt = "OnlyLeft" diff --git a/stowed-files/bash/.bashrc b/stowed-files/bash/.bashrc index c5cf85d2..4688c7de 100644 --- a/stowed-files/bash/.bashrc +++ b/stowed-files/bash/.bashrc @@ -42,40 +42,40 @@ if [[ -z "${COLORTERM:-}" ]] && [[ "$TERM" =~ "256color" ]]; then fi # Bash Options {{{ -# cd without typing cd -shopt -qs autocd +# cd without typing cd (unsupported in Mac version) +shopt -qs autocd 2> /dev/null || true # Auto-correct directory typos shopt -qs cdspell # Check hash before executing shopt -qs checkhash -# Check for stopped jobs before exiting -shopt -qs checkjobs +# Check for stopped jobs before exiting (unsupported in Mac version) +shopt -qs checkjobs 2> /dev/null || true # Check window size after each command, and update $LINES and $COLUMNS -shopt -s checkwinsize +shopt -qs checkwinsize # Save all lines of multiline commands -shopt -s cmdhist -# Expand directory names when doing file completion -shopt -qs direxpand -# Fix typos for directories in completion -shopt -qs dirspell +shopt -qs cmdhist +# Expand directory names when doing file completion (unsupported in Mac version) +shopt -qs direxpand 2> /dev/null || true +# Fix typos for directories in completion (unsupported in Mac version) +shopt -qs dirspell 2> /dev/null || true # Include filenames that begin with '.' in filename expansion shopt -qs dotglob # Extended pattern matching shopt -qs extglob # Allow escape sequencing within ${parameter} expansions shopt -qs extquote -# Support ** for expansion -shopt -qs globstar +# Support ** for expansion (unsupported in Mac version) +shopt -qs globstar 2> /dev/null || true # Append to history list. Allow editing of history substitution in readline shopt -qs histappend histreedit histverify # Do hostname completion on words that contain @ shopt -qs hostcomplete # Don't search path for completions when on an empty line -shopt -s no_empty_cmd_completion +shopt -qs no_empty_cmd_completion # Case insensitive glob matching and case statements -shopt -s nocaseglob nocasematch +shopt -qs nocaseglob nocasematch # Expand aliases in order to find completions -shopt -s progcomp_alias +shopt -qs progcomp_alias # }}} # shellcheck disable=SC2034 @@ -127,7 +127,7 @@ PS1="$BASE_PROMPT ""\${HAS_JOBS:+$JOB_COUNT}" git_prompt_location="/etc/bash_completion.d/git-prompt" if [ ! -r "${git_prompt_location}" ]; then # Homebrew - git_prompt_location="/usr/local/etc/bash_completion.d/git-prompt.sh" + git_prompt_location="/opt/homebrew/etc/bash_completion.d/git-prompt.sh" fi if [ -r "${git_prompt_location}" ]; then @@ -215,7 +215,7 @@ export MOZ_ENABLE_WAYLAND=1 # FZF keybindings (Debian) source_if_exists "/usr/share/doc/fzf/examples/key-bindings.bash" # FZF keybindings (Homebrew) -source_if_exists "/usr/local/opt/fzf/shell/key-bindings.bash" +source_if_exists "/opt/homebrew/opt/fzf/shell/key-bindings.bash" if command_exists fnm; then eval "$(fnm env)" @@ -226,8 +226,11 @@ export ET_NO_TELEMETRY=1 # Load system bash completion source_if_exists "/etc/bash_completion" -# Load homebrew bash completion -source_if_exists "/usr/local/etc/bash_completion" +# Load Homebrew bash completion, see https://docs.brew.sh/Shell-Completion +source_if_exists "/opt/homebrew/etc/profile.d/bash_completion.sh" +source_if_exists "/opt/homebrew/etc/bash_completion.d" +source_if_exists "/opt/homebrew/share/bash-completion/bash_completion" + # Load local bash completion source_if_exists "$HOME/.local/completion.d" diff --git a/stowed-files/bash/.local/bin/fd_with_git b/stowed-files/bash/.local/bin/fd_with_git index 61981b67..e79c410c 100755 --- a/stowed-files/bash/.local/bin/fd_with_git +++ b/stowed-files/bash/.local/bin/fd_with_git @@ -1,11 +1,10 @@ #!/usr/bin/env sh -FD_COMMAND="fd" -if ! command -v "${FD_COMMAND}" > /dev/null; then +fd_command="fd" +if ! command -v "${fd_command}" > /dev/null; then # Debian uses `fdfind` - FD_COMMAND="fdfind" + fd_command="fdfind" fi -export FD_COMMAND if [ "$#" -eq 0 ]; then # Default to matching all files @@ -14,7 +13,7 @@ fi if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then git_root=$(git rev-parse --show-cdup) - "${FD_COMMAND}" --type file --follow --hidden --relative-path "$@" "${git_root:-.}" + "${fd_command}" --type file --follow --hidden --relative-path "$@" "${git_root:-.}" else - "${FD_COMMAND}" --type file --follow --relative-path "$@" + "${fd_command}" --type file --follow --relative-path "$@" fi diff --git a/stowed-files/bash/.profile b/stowed-files/bash/.profile index 3ab0c618..bb7090e6 100644 --- a/stowed-files/bash/.profile +++ b/stowed-files/bash/.profile @@ -49,6 +49,9 @@ if [[ -n ${VISUAL:-} ]]; then export EDITOR VISUAL fi +# Homebrew paths, etc +source_if_exists "$HOME/.profile.brew" + # Locally-installed packages belong in path add_to_path "$HOME/.local/bin"