diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 404b2d5b..39988cff 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,8 +14,14 @@ # [[file:../../workstation.org::*Github Actions CI][Github Actions CI:1]] name: CI +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + on: + pull_request: push: + branches: main schedule: - cron: '0 0 * * *' # every day at midnight @@ -24,17 +30,20 @@ jobs: strategy: matrix: os: + # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories - macos-13 # x86 - macos-latest # aarch - ubuntu-latest runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 - - - name: Run a one-line script - env: - BW_CLIENTID: ${{ secrets.BW_CLIENTID }} - BW_CLIENTSECRET: ${{ secrets.BW_CLIENTSECRET }} - WS_BW_MASTER_PASS: ${{ secrets.WS_BW_MASTER_PASS }} - run: ./test/ci.sh + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + # ref: ${{ github.sha }} + - run: ./test/ci.sh + env: + WORKSTATION_VERSION: ${{ github.event.pull_request.head.sha }} + BW_CLIENTID: ${{ secrets.BW_CLIENTID }} + BW_CLIENTSECRET: ${{ secrets.BW_CLIENTSECRET }} + WS_BW_MASTER_PASS: ${{ secrets.WS_BW_MASTER_PASS }} # Github Actions CI:1 ends here diff --git a/.github/workflows/ws_tool.yaml b/.github/workflows/ws_tool.yaml new file mode 100644 index 00000000..c5bb7792 --- /dev/null +++ b/.github/workflows/ws_tool.yaml @@ -0,0 +1,59 @@ +name: WS Tool + +on: + pull_request: + push: + branches: main + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + strategy: + matrix: + os: + # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories + - macos-13 # x86 + - macos-latest # aarch + - ubuntu-latest + permissions: + id-token: write + contents: read + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + ref: ${{ github.event.pull_request.head.ref }} + - run: ws_tool/test/bats/bin/bats ws_tool/test + env: + WORKSTATION_VERSION: ${{ github.event.pull_request.head.sha }} + BW_CLIENTID: ${{ secrets.BW_CLIENTID }} + BW_CLIENTSECRET: ${{ secrets.BW_CLIENTSECRET }} + WS_BW_MASTER_PASS: ${{ secrets.WS_BW_MASTER_PASS }} + + full-setup: + strategy: + matrix: + os: + # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories + - macos-13 # x86 + - macos-latest # aarch + - ubuntu-latest + permissions: + id-token: write + contents: read + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + ref: ${{ github.event.pull_request.head.sha }} + - run: bash ws_tool/test/ci_full_setup.bash + env: + WORKSTATION_VERSION: ${{ github.event.pull_request.head.sha }} + BW_CLIENTID: ${{ secrets.BW_CLIENTID }} + BW_CLIENTSECRET: ${{ secrets.BW_CLIENTSECRET }} + WS_BW_MASTER_PASS: ${{ secrets.WS_BW_MASTER_PASS }} diff --git a/.gitmodules b/.gitmodules index b7efcb44..50ca3ae1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ [submodule "test/bats"] - path = test/bats + path = ws_tool/test/bats url = https://github.com/bats-core/bats-core.git [submodule "test/test_helper/bats-support"] - path = test/test_helper/bats-support + path = ws_tool/test/test_helper/bats-support url = https://github.com/bats-core/bats-support.git [submodule "test/test_helper/bats-assert"] - path = test/test_helper/bats-assert + path = ws_tool/test/test_helper/bats-assert url = https://github.com/bats-core/bats-assert.git diff --git a/bin/cron-5.sh b/bin/cron-5.sh index 70a52a2a..f1cbf02f 100755 --- a/bin/cron-5.sh +++ b/bin/cron-5.sh @@ -15,9 +15,13 @@ main() { # env echo "updating EF" - ~/workstation/bin/update-ef-on-server.sh + # TODO this maybe could be better + # script to generate this file with pointers to specific workstation dirs + # perhaps have $HOME/.config/workstation/ standard location as well/instead? + source $HOME/workstation/hosts/current/zshrc.sh + $HOME/workstation/bin/update-ef-on-server.sh echo "FINISHED $(date)" } -main >> ~/workstation/var/log/cron 2>&1 +main >> $HOME/workstation/var/log/cron 2>&1 diff --git a/bin/disable-passwordless-sudo.sh b/bin/disable-passwordless-sudo.sh deleted file mode 100755 index 1e7d4211..00000000 --- a/bin/disable-passwordless-sudo.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -# [[file:../workstation.org::*Passwordless sudo][Passwordless sudo:2]] -set -euo pipefail - -rm /etc/sudoers.d/me-passwordless-sudo -# Passwordless sudo:2 ends here diff --git a/bin/enable-passwordless-sudo.sh b/bin/enable-passwordless-sudo.sh deleted file mode 100755 index f0a4bcca..00000000 --- a/bin/enable-passwordless-sudo.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash -# Passwordless sudo -# Occasionally, sudo is extremely annoying. Having to type "sudo" in the middle of a nix-darwin rebuild really interrupts the flow. So here are a couple of scripts -# to toggle passwordless sudo. - -# [[file:../workstation.org::*Passwordless sudo][Passwordless sudo:1]] -set -eo pipefail - -if [[ -z "$SUDO_USER" ]]; then - echo ERROR: run as sudo - exit 1 -fi - -TEMPFILE=$(mktemp) - -cat > $TEMPFILE < '; + echo ' - enable/disable passwordless sudo'; + echo ' must be run with sudo.'; + exit 1 +} + +mk_sudoer_file(){ + local modifier="$1" file + file="$(mktemp -d "${TMPDIR:-/tmp}/sudoerd-file.XXXXXXXXX")/file" + + cat > $file <<-EOF + $SUDO_USER ALL=(ALL) ${modifier}ALL +EOF + visudo -c "$file" > /dev/null + echo "$file"; +} + +no_pw() { + put_sudo_file 'NOPASSWD: ' +} + +yes_pw() { + put_sudo_file '' +} + +put_sudo_file() { + local param="$1" + local tmpfile + tmpfile="$(mk_sudoer_file "$param")" + + mv "$tmpfile" "$sudo_file" +} + + +if (( $# != 1 )) || [[ -z "${SUDO_USER:-}" ]]; then + usage +fi + +case "$1" in + (--pw) yes_pw;; + (--no-pw) no_pw;; + (*) usage;; +esac diff --git a/bin/tangle.sh b/bin/tangle.sh index 71f3bd73..3ec1a8cd 100755 --- a/bin/tangle.sh +++ b/bin/tangle.sh @@ -5,6 +5,6 @@ # [[file:../workstation.org::*Makefile][Makefile:2]] -source ~/workstation/lib/shell/foundation.sh +source ${WORKSTATION_DIR}/lib/shell/foundation.sh $WORKSTATION_EMACS_CONFIG_DIR/bin/doomscript lib/emacs/tangle-file.el # Makefile:2 ends here diff --git a/bin/workstation-doctor.sh b/bin/workstation-doctor.sh new file mode 100644 index 00000000..aaa1c768 --- /dev/null +++ b/bin/workstation-doctor.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +# TODO idea for basic workstation sanity checking framework +# can KISS instead of making things too complicated + + +# check settings for current workstation, are +# workstation_name and workstation_dir set? is link at hosts/current? +# is there anything else that needs to be done? can I move anything from test script to here, and also +# invoke this script within the test scripty? +# +# check emacs works +# check secrets setup +# - use a dummy secrete + some sha for checking w.r.t real secrets setup correctly +# - check workstation origin for newer version? +# - see other notes about what to do here, have thought about doing this a million times +# - check somehow if pending migration to run? +# - check if nix stuff needs to be rebuilt? +# - maybe keep some of this stuff in ~/.config +# +# +# +# see here for more ideas https://unix.stackexchange.com/questions/312988/understanding-home-configuration-file-locations-config-and-local-sha#313001 +# +# can replace var directory +# +# add standard sanity checking in front of all workstaiton scripts, and have standard bypass +# infra if I want to run script anyway. +# TODO run git diff in ~ and $WORKSTATION_DIR to check for any stray changes. +# TODO someday run reddup also +# TODO someday have this script run automatically and have action items output in +# notable spots (bitbar, shell input notice) diff --git a/bootstrap-workstation.sh b/bootstrap-workstation.sh index 6d6bd16e..d202215c 100755 --- a/bootstrap-workstation.sh +++ b/bootstrap-workstation.sh @@ -26,7 +26,7 @@ fi # When the CI process starts, we start out with a check out of the code for this # commit in a directory on the CI machine. However, this is not how workstation runs: # - part of the job of workstation is getting its own code from the server -# - workstation expects the code to be in a specific directory, that is, ~/workstation +# - workstation expects the code to be in a specific directory, that is, $HOME/workstation # Because of this (and possibly other reasons that escape me now), even though the # source code of the current commit is checked out on the CI machine already, # the CI process re-downloads the code (via this script). The specific SHA to get @@ -42,8 +42,8 @@ else fi # [[file:../../workstation.org::workstation_foundation][workstation_foundation]] -export WORKSTATION_DIR="$HOME/workstation" -export WORKSTATION_EMACS_CONFIG_DIR=~/.config/emacs +export WORKSTATION_DIR="${WORKSTATION_DIR:-$HOME/workstation}" +export WORKSTATION_EMACS_CONFIG_DIR=$HOME/.config/emacs export WORKSTATION_GIT_ORIGIN='git@github.com:joelmccracken/workstation.git' export WORKSTATION_GIT_ORIGIN_PUB='https://github.com/joelmccracken/workstation.git' export WORKSTATION_HOST_CURRENT_SETTINGS_DIR=$WORKSTATION_DIR/hosts/current @@ -216,48 +216,28 @@ is_git_repo_cloned_at $WORKSTATION_DIR $WORKSTATION_GIT_ORIGIN || { } # at this point, this is hardly necessary; however, the gitignore file is handy # i may explore getting rid of this repo entirely and just having a fresh -# repo without any origin in ~ +# repo without any origin in $HOME info ensuring dotfiles repo is checked out DOTFILES_ORIGIN='git@github.com:joelmccracken/dotfiles.git' -is_git_repo_cloned_at ~ "$DOTFILES_ORIGIN" || - polite-git-checkout ~ 'https://github.com/joelmccracken/dotfiles.git' \ +is_git_repo_cloned_at $HOME "$DOTFILES_ORIGIN" || + polite-git-checkout $HOME 'https://github.com/joelmccracken/dotfiles.git' \ "$DOTFILES_ORIGIN" info finished ensuring dotfiles repo is checked out -# each workstaion host I use has different settings needs. -# For example, my remote cloud hosted server has a different setup than -# my mac laptop, which has a different set up from my work computer. -# the way I have these settings specified is by having a directory in my home -# directory which has all of the needed files I would need for such differences. -# there are different directories for each host I maintain, but on a given host, -# one of those directories are symlinked into 'current' host, which other things -# can then refer to - -export WORKSTATION_HOST_SETTINGS_SRC_DIR=$WORKSTATION_DIR/hosts/$WORKSTATION_NAME - -info setting current host settings directory... -info workstation host settings directory: $WORKSTATION_HOST_SETTINGS_SRC_DIR - -if [ -d $WORKSTATION_HOST_SETTINGS_SRC_DIR ]; then - info setting current host directory to $WORKSTATION_HOST_SETTINGS_SRC_DIR; - ln -s $WORKSTATION_HOST_SETTINGS_SRC_DIR $WORKSTATION_HOST_CURRENT_SETTINGS_DIR; -else - echo ERROR $WORKSTATION_HOST_SETTINGS_SRC_DIR does not exist, must exit - exit 5 -fi +${WORKSTATION_DIR}/lib/shell/setup/link-host-dir.sh "$WORKSTATION_NAME" info ensuring nix is installed -~/workstation/lib/shell/setup/ensure_nix_installed.sh +${WORKSTATION_DIR}/lib/shell/setup/ensure_nix_installed.sh info finished ensuring nix is installed info setting up nix.conf -~/workstation/lib/shell/setup/install_system_nix_conf.sh +${WORKSTATION_DIR}/lib/shell/setup/install_system_nix_conf.sh info restarting nix daemon -~/workstation/lib/shell/setup/restart_nix_daemon.sh +${WORKSTATION_DIR}/lib/shell/setup/restart_nix_daemon.sh info nix daemon restarted NIX_DAEMON_PATH='/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' @@ -266,37 +246,36 @@ source "$NIX_DAEMON_PATH"; set -u -is_mac && { - info installing darwin-nix - ~/workstation/lib/shell/setup/install_nix_darwin.sh - info finished installing darwin-nix -} +# is_mac && { +# info installing darwin-nix +# ${WORKSTATION_DIR}/lib/shell/setup/install_nix_darwin.sh +# info finished installing darwin-nix +# } -~/workstation/lib/shell/setup/install_home_manager.sh +${WORKSTATION_DIR}/lib/shell/setup/install_home_manager.sh -~/workstation/lib/shell/setup/home-manager-flake-switch.sh +${WORKSTATION_DIR}/lib/shell/setup/home-manager-flake-switch.sh set +u # evaluating this with set -u will cause an unbound variable error source $HOME/.nix-profile/etc/profile.d/hm-session-vars.sh set -u -~/workstation/lib/shell/setup/install_doom_emacs_no_nix.sh +${WORKSTATION_DIR}/lib/shell/setup/install_doom_emacs_no_nix.sh info linking dotfiles that should be symlinked -bash ~/workstation/lib/shell/setup/link-dotfiles.sh -f -c +bash ${WORKSTATION_DIR}/lib/shell/setup/link-dotfiles.sh -f -c info finished linking dotfiles info "building the 'ws' script" -~/workstation/lib/shell/setup/build_ws_tool.sh +${WORKSTATION_DIR}/lib/shell/setup/build_ws_tool.sh info "running the 'ws install' process" -~/workstation/lib/shell/setup/ws_install.sh +${WORKSTATION_DIR}/lib/shell/setup/ws_install.sh info "'ws install' process completed" -info linking dotfiles that should be symlinked -bash ~/workstation/lib/shell/setup/link-dotfiles.sh -f -c -info finished linking dotfiles -bash ~/workstation/lib/shell/setup/initial_bitwarden_sync.sh +echo "initial bitwarden sync" +bash ${WORKSTATION_DIR}/lib/shell/setup/initial_bitwarden_sync.sh +echo "initial bitwarden sync done" cat <<-EOF Success! However, there are some remaining manual set up steps required. @@ -309,7 +288,7 @@ manually: - icloud - slack - spotify -- install haskell language server in ~/bin (or somwewhere else?) for hls +- install haskell language server in $HOME/bin (or somwewhere else?) for hls These are the settings I use for slack: - accessibility then at bottom changbe up arrow to move focus to last message diff --git a/dotfiles/config/doom/config.el b/dotfiles/config/doom/config.el index 2107fc81..212238c9 100644 --- a/dotfiles/config/doom/config.el +++ b/dotfiles/config/doom/config.el @@ -35,11 +35,24 @@ ;; change `org-directory'. It must be set before org loads! (setq workstation-config-path - (concat "~/workstation/hosts/current/config.el")) + (concat (or (getenv "WORKSTATION_DIR") + "~/workstation") + "/hosts/current/config.el")) (when (file-exists-p workstation-config-path) (load workstation-config-path)) +(defun jnm/ef-ssh-belthronding () + "open EF via ssh on belthronding" + (interactive) + (find-file "/ssh:joel@belthronding.wildkraken.monster:~/EF/")) + +(map! "C-c e" #'jnm/ef-ssh-belthronding) +(map! "C-c d" #'org-timestamp-inactive) + +;; (map! :leader "SPC" +;; :n "SPC SPC e" #'jnm/ef-ssh-belthronding) + (after! +popup ;; added here to change the behavior of *info* buffers (set :quit to nil) (set-popup-rules! diff --git a/dotfiles/config/doom/init.el b/dotfiles/config/doom/init.el index 74b37626..060fcc95 100644 --- a/dotfiles/config/doom/init.el +++ b/dotfiles/config/doom/init.el @@ -78,7 +78,7 @@ vc ; version-control and Emacs, sitting in a tree :term - ;;eshell ; the elisp shell that works everywhere + eshell ; the elisp shell that works everywhere ;;shell ; simple shell REPL for Emacs ;;term ; basic terminal emulator for Emacs vterm ; the best terminal emulation in Emacs @@ -98,6 +98,7 @@ ;;editorconfig ; let someone else argue about tabs vs spaces ;;ein ; tame Jupyter notebooks with emacs (eval +overlay) ; run code, run (also, repls) + ;;gist ; interacting with github gists lookup ; navigate your code and its documentation lsp ; M-x vscode magit ; a git porcelain for Emacs @@ -112,7 +113,8 @@ ;;upload ; map local to remote projects via ssh/ftp :os - (:if (featurep :system 'macos) macos) ; improve compatibility with macOS + ;; (:if (featurep :system 'macos) macos) ; improve compatibility with macOS + (:if IS-MAC macos) ; improve compatibility with macOS ;;tty ; improve the terminal Emacs experience :lang diff --git a/dotfiles/zshrc b/dotfiles/zshrc index d8dd1e21..85c66e5c 100644 --- a/dotfiles/zshrc +++ b/dotfiles/zshrc @@ -4,9 +4,11 @@ sourceIfExists () { fi } -sourceIfExists ~/workstation/lib/shell/settings.sh -sourceIfExists ~/workstation/lib/shell/paths.sh -sourceIfExists ~/workstation/hosts/current/zshrc.sh +export WORKSTATION_DIR="${WORKSTATION_DIR:-~/workstation}" + +sourceIfExists ${WORKSTATION_DIR}/lib/shell/settings.sh +sourceIfExists ${WORKSTATION_DIR}/lib/shell/paths.sh +sourceIfExists ${WORKSTATION_DIR}/hosts/current/zshrc.sh export EDITOR=emacsclient export GIT_EDITOR=$EDITOR @@ -40,3 +42,5 @@ sourceIfExists /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh sourceIfExists ~/.nix-profile/etc/profile.d/hm-session-vars.sh sourceIfExists ~/workstation/lib/shell/funcs.sh sourceIfExists ~/.ghcup/env + +sourceIfExists ${WORKSTATION_DIR}/lib/shell/funcs.sh diff --git a/flake.nix b/flake.nix index 1ea8ac27..6a6abb4e 100644 --- a/flake.nix +++ b/flake.nix @@ -55,7 +55,7 @@ pkgs.git pkgs.ripgrep pkgs.jq - pkgs.jl + # pkgs.jl pkgs.fd pkgs.ispell newer-pkgs.bitwarden-cli diff --git a/hosts/aeglos/README.md b/hosts/aeglos/README.md new file mode 100644 index 00000000..88afd400 --- /dev/null +++ b/hosts/aeglos/README.md @@ -0,0 +1,2 @@ +my main personal workstation + * [ ] diff --git a/hosts/aeglos/zshrc.sh b/hosts/aeglos/zshrc.sh index e2e1fce2..94083b32 100755 --- a/hosts/aeglos/zshrc.sh +++ b/hosts/aeglos/zshrc.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash # [[file:../../workstation.org::*aeglos/][aeglos/:2]] -source ~/workstation/hosts/aeglos/settings.sh +source ${WORKSTATION_DIR}/hosts/aeglos/settings.sh # aeglos/:2 ends here diff --git a/hosts/angrist/README.md b/hosts/angrist/README.md new file mode 100644 index 00000000..41673c8b --- /dev/null +++ b/hosts/angrist/README.md @@ -0,0 +1,4 @@ +my work-workstation + + + diff --git a/hosts/angrist/config.el b/hosts/angrist/config.el new file mode 100644 index 00000000..703417e0 --- /dev/null +++ b/hosts/angrist/config.el @@ -0,0 +1,2 @@ +(after! org + (setq org-directory "~/freckle/notes/")) diff --git a/hosts/angrist/settings.sh b/hosts/angrist/settings.sh new file mode 100644 index 00000000..c97a0f49 --- /dev/null +++ b/hosts/angrist/settings.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +export WORKSTATION_NAME=angrist diff --git a/hosts/angrist/zshrc.sh b/hosts/angrist/zshrc.sh new file mode 100644 index 00000000..9ccbccde --- /dev/null +++ b/hosts/angrist/zshrc.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env zsh + +source ${WORKSTATION_DIR}/hosts/angrist/settings.sh diff --git a/hosts/glamdring/zshrc.sh b/hosts/glamdring/zshrc.sh index 5bbe3ab2..ec66ac21 100755 --- a/hosts/glamdring/zshrc.sh +++ b/hosts/glamdring/zshrc.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash # [[file:../../workstation.org::*glamdring/][glamdring/:3]] -source ~/workstation/hosts/glamdring/settings.sh +source ${WORKSTATION_DIR}/hosts/glamdring/settings.sh # glamdring/:3 ends here diff --git a/lib/shell/foundation.sh b/lib/shell/foundation.sh index 03d254b6..d3850bb4 100644 --- a/lib/shell/foundation.sh +++ b/lib/shell/foundation.sh @@ -3,8 +3,8 @@ # #+name: workstation_foundation # [[file:../../workstation.org::workstation_foundation][workstation_foundation]] -export WORKSTATION_DIR="$HOME/workstation" -export WORKSTATION_EMACS_CONFIG_DIR=~/.config/emacs +export WORKSTATION_DIR="${WORKSTATION_DIR:-$HOME/workstation}" +export WORKSTATION_EMACS_CONFIG_DIR=$HOME/.config/emacs export WORKSTATION_GIT_ORIGIN='git@github.com:joelmccracken/workstation.git' export WORKSTATION_GIT_ORIGIN_PUB='https://github.com/joelmccracken/workstation.git' export WORKSTATION_HOST_CURRENT_SETTINGS_DIR=$WORKSTATION_DIR/hosts/current diff --git a/lib/shell/setup/build_ws_tool.sh b/lib/shell/setup/build_ws_tool.sh index 4a7066c6..ef07d668 100755 --- a/lib/shell/setup/build_ws_tool.sh +++ b/lib/shell/setup/build_ws_tool.sh @@ -2,6 +2,6 @@ # Build WS tool # [[file:../../../workstation.org::*Build WS tool][Build WS tool:1]] -cd ~/workstation/wshs +cd ${WORKSTATION_DIR}/wshs nix build --no-link -L .#"wshs:exe:bww" .#"wshs:exe:ws" # Build WS tool:1 ends here diff --git a/lib/shell/setup/ensure_nix_installed.sh b/lib/shell/setup/ensure_nix_installed.sh index e49567d2..bfd9b3ff 100755 --- a/lib/shell/setup/ensure_nix_installed.sh +++ b/lib/shell/setup/ensure_nix_installed.sh @@ -2,8 +2,8 @@ # Install Nix # [[file:../../../workstation.org::*Install Nix][Install Nix:1]] -source ~/workstation/lib/shell/setup/workstation_setup_versions.sh -source ~/workstation/lib/shell/funcs.sh +source ${WORKSTATION_DIR}/lib/shell/setup/workstation_setup_versions.sh +source ${WORKSTATION_DIR}/lib/shell/funcs.sh if which nix > /dev/null; then info "nix exists in path, not installing" diff --git a/lib/shell/setup/home-manager-flake-switch.sh b/lib/shell/setup/home-manager-flake-switch.sh index 5d7da1cb..d706036f 100755 --- a/lib/shell/setup/home-manager-flake-switch.sh +++ b/lib/shell/setup/home-manager-flake-switch.sh @@ -11,7 +11,7 @@ # [[file:../../../workstation.org::*flake-world equivalent to 'home-manager switch'][flake-world equivalent to 'home-manager switch':1]] set -u # error in case WORKSTATION_NAME is not set -nix build --no-link ~/workstation/#homeConfigurations.${WORKSTATION_NAME}.$(whoami).activationPackage --show-trace +nix build --no-link ${WORKSTATION_DIR}/#homeConfigurations.${WORKSTATION_NAME}.$(whoami).activationPackage --show-trace -"$(nix path-info ~/workstation/#homeConfigurations.${WORKSTATION_NAME}.$(whoami).activationPackage)"/activate --show-trace +"$(nix path-info ${WORKSTATION_DIR}/#homeConfigurations.${WORKSTATION_NAME}.$(whoami).activationPackage)"/activate --show-trace # flake-world equivalent to 'home-manager switch':1 ends here diff --git a/lib/shell/setup/initial_bitwarden_sync.sh b/lib/shell/setup/initial_bitwarden_sync.sh index 08dcb10c..26667fa2 100755 --- a/lib/shell/setup/initial_bitwarden_sync.sh +++ b/lib/shell/setup/initial_bitwarden_sync.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # [[file:../../../workstation.org::*Initial Bitwarden Sync][Initial Bitwarden Sync:2]] -source ~/workstation/lib/shell/funcs.sh +source ${WORKSTATION_DIR}/lib/shell/funcs.sh # The initial BitWarden Sync process. Requires wshs/bww executable to @@ -17,7 +17,7 @@ function initial_bitwarden_sync() { if [ ! -d ~/secrets ]; then mkdir ~/secrets; fi - cd ~/workstation/wshs + cd ${WORKSTATION_DIR}/wshs # overwriting anything that was previously in the file echo "${WS_BW_MASTER_PASS}" > ~/secrets/bw_pass bw login --apikey diff --git a/lib/shell/setup/install_doom_emacs_no_nix.sh b/lib/shell/setup/install_doom_emacs_no_nix.sh index ec2629c9..fe59e98d 100755 --- a/lib/shell/setup/install_doom_emacs_no_nix.sh +++ b/lib/shell/setup/install_doom_emacs_no_nix.sh @@ -2,7 +2,7 @@ # Install doom emacs without nix # [[file:../../../workstation.org::*Install doom emacs without nix][Install doom emacs without nix:1]] -source ~/workstation/lib/shell/foundation.sh +source ${WORKSTATION_DIR}/lib/shell/foundation.sh { cd $WORKSTATION_EMACS_CONFIG_DIR diff --git a/lib/shell/setup/install_home_manager.sh b/lib/shell/setup/install_home_manager.sh index 05e286cb..b5de1033 100755 --- a/lib/shell/setup/install_home_manager.sh +++ b/lib/shell/setup/install_home_manager.sh @@ -4,5 +4,5 @@ # [[file:../../../workstation.org::*Install home manager][Install home manager:1]] export HOME_MANAGER_BACKUP_EXT=old -nix run home-manager/$WORKSTATION_HOME_MANAGER_VERSION -- init ~/workstation +nix run home-manager/$WORKSTATION_HOME_MANAGER_VERSION -- init $HOME/workstation # Install home manager:1 ends here diff --git a/lib/shell/setup/install_nix_darwin.sh b/lib/shell/setup/install_nix_darwin.sh index 9b2821b4..1d0d6a90 100755 --- a/lib/shell/setup/install_nix_darwin.sh +++ b/lib/shell/setup/install_nix_darwin.sh @@ -2,12 +2,12 @@ # Install nix-darwin # [[file:../../../workstation.org::*Install nix-darwin][Install nix-darwin:1]] -source ~/workstation/lib/shell/foundation.sh -source ~/workstation/lib/shell/setup/workstation_setup_versions.sh +source ${WORKSTATION_DIR}/lib/shell/foundation.sh +source ${WORKSTATION_DIR}/lib/shell/setup/workstation_setup_versions.sh cd $WORKSTATION_DIR nix-build https://github.com/LnL7/nix-darwin/archive/${WORKSTATION_NIX_DARWIN_VERSION}.tar.gz -A installer ./result/bin/darwin-installer -source ~/workstation/lib/shell/setup/nix-darwin-rebuild-flake.sh +source ${WORKSTATION_DIR}/lib/shell/setup/nix-darwin-rebuild-flake.sh # Install nix-darwin:1 ends here diff --git a/lib/shell/setup/link-dotfiles.sh b/lib/shell/setup/link-dotfiles.sh index 8df48a4e..876c5746 100755 --- a/lib/shell/setup/link-dotfiles.sh +++ b/lib/shell/setup/link-dotfiles.sh @@ -2,7 +2,7 @@ # Linking dotfiles # [[file:../../../workstation.org::*Linking dotfiles][Linking dotfiles:1]] -source ~/workstation/lib/shell/funcs.sh +source ${WORKSTATION_DIR}/lib/shell/funcs.sh export FORCE=false; export VERBOSE=false; @@ -31,10 +31,9 @@ function check () { fi } - function ln_helper() { dest=~/$2$1 - src=~/workstation/dotfiles/$1 + src=${WORKSTATION_DIR}/dotfiles/$1 curr=$(readlink -f "$dest") if [ -L "$dest" ] && [ "$curr" = "$src" ]; then @@ -59,9 +58,9 @@ function ln_norm() { } function ln_dotfile_n() { - src=~/workstation/dotfiles/$1 + src=${WORKSTATION_DIR}/dotfiles/$1 dest=~/.$1 - destdir=$(dirname $dest) + destdir=$(dirname "$dest") if [ ! -d $destdir ]; then mkdir -p $destdir diff --git a/lib/shell/setup/link-host-dir.sh b/lib/shell/setup/link-host-dir.sh new file mode 100755 index 00000000..4a4764d6 --- /dev/null +++ b/lib/shell/setup/link-host-dir.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# setting directories for current host +# Each workstaion host I use has different settings needs. My remote cloud hosted +# server has a different setup than my mac laptop, which has a different set up +# from my work computer. The way I have these settings specified is by having a +# directory in my home directory which has all of the needed files to +# specify such differences. There are different directories for each host I +# maintain, but on a specific, individual host, one of those directories are symlinked +# into the 'current' (src_text{~/workstation/hosts/current/}) +# directory, and various workstation components are programmed to look +# in this location for their code/settings as appropriate. + + +# [[file:../../../workstation.org::*setting directories for current host][setting directories for current host:1]] +set -e + +usage() { + cat <<-EOF +usage: $0 + +Sets up expected link in a 'current' directory, based upon the WORKSTATION_NAME +provided as argument. Environment variable WORKSTATION_DIR is must also be set so +script can put link within. +EOF +} + +if [ "$#" -ne 1 ]; then + echo "Error: Wrong number of arguments" + usage + exit 55 +fi + +if [ "${WORKSTATION_DIR:-}" = "" ]; then + echo "Error: environment variable WORKSTATION_DIR unset" + usage + exit 56 +fi + +source ${WORKSTATION_DIR}/lib/shell/foundation.sh +source ${WORKSTATION_DIR}/lib/shell/funcs.sh + +WORKSTATION_NAME="$1" + +export WORKSTATION_HOST_CURRENT_SETTINGS_DIR=$WORKSTATION_DIR/hosts/current +export WORKSTATION_HOST_SETTINGS_SRC_DIR=$WORKSTATION_DIR/hosts/$WORKSTATION_NAME + +info setting current host settings directory +info workstation host settings directory: $WORKSTATION_HOST_SETTINGS_SRC_DIR + +if [ -d "$WORKSTATION_HOST_CURRENT_SETTINGS_DIR" ]; then + info "$WORKSTATION_HOST_CURRENT_SETTINGS_DIR" already exists, not changing. \ + If this is incorrect, run rm "$WORKSTATION_HOST_CURRENT_SETTINGS_DIR" \ + and then rerun this script + exit 120 +fi + +if [ -d $WORKSTATION_HOST_SETTINGS_SRC_DIR ]; then + info setting current host directory to $WORKSTATION_HOST_SETTINGS_SRC_DIR; + ln -s $WORKSTATION_HOST_SETTINGS_SRC_DIR $WORKSTATION_HOST_CURRENT_SETTINGS_DIR; +else + echo ERROR $WORKSTATION_HOST_SETTINGS_SRC_DIR does not exist, cannot link + exit 5 +fi +# setting directories for current host:1 ends here diff --git a/lib/shell/setup/restart_nix_daemon.sh b/lib/shell/setup/restart_nix_daemon.sh index dce70cc3..7246e674 100755 --- a/lib/shell/setup/restart_nix_daemon.sh +++ b/lib/shell/setup/restart_nix_daemon.sh @@ -4,7 +4,7 @@ # file. # [[file:../../../workstation.org::*restart nix daemons][restart nix daemons:1]] -source ~/workstation/lib/shell/funcs.sh +source ${WORKSTATION_DIR}/lib/shell/funcs.sh function restart_nix_daemon_linux() { sudo systemctl restart nix-daemon.service; } diff --git a/lib/shell/setup/ws_install.sh b/lib/shell/setup/ws_install.sh index 395d2217..feefdd45 100755 --- a/lib/shell/setup/ws_install.sh +++ b/lib/shell/setup/ws_install.sh @@ -2,6 +2,6 @@ # Run WS install # [[file:../../../workstation.org::*Run WS install][Run WS install:1]] -cd ~/workstation/wshs +cd ${WORKSTATION_DIR}/wshs $(nix path-info .#"wshs:exe:ws")/bin/ws install -m "$WORKSTATION_NAME"; # Run WS install:1 ends here diff --git a/test/ci.sh b/test/ci.sh index f392f9bf..a0d79a4e 100755 --- a/test/ci.sh +++ b/test/ci.sh @@ -10,12 +10,12 @@ set -xeuo pipefail # env # are there environment variables where I can get the commit sha? -cd ~ +cd $HOME -if [ "$GITHUB_SHA" == "" ]; then +if [ "$WORKSTATION_VERSION" == "" ]; then WORKSTATION_BOOTSTRAP_COMMIT=master else - WORKSTATION_BOOTSTRAP_COMMIT="$GITHUB_SHA" + WORKSTATION_BOOTSTRAP_COMMIT="$WORKSTATION_VERSION" fi curl https://raw.githubusercontent.com/joelmccracken/workstation/$WORKSTATION_BOOTSTRAP_COMMIT/bootstrap-workstation.sh > bootstrap-workstation.sh @@ -33,5 +33,18 @@ fi echo INSTALL PROCESS COMPLETE, TESTING -bash ~/workstation/test/test.sh + +pwd +sleep 10 +ls -lah +sleep 10 +ls -lah $HOME +sleep 10 +env +sleep 10 +ls -lah $HOME/workstation/ +sleep 10 +export WORKSTATION_DIR=$HOME/workstation +bash $HOME/workstation/test/test.sh + # The environment setup script:1 ends here diff --git a/test/test.bats b/test/test.bats deleted file mode 100644 index 87b67e06..00000000 --- a/test/test.bats +++ /dev/null @@ -1,23 +0,0 @@ -setup (){ - load 'test_helper/bats-support/load' - load 'test_helper/bats-assert/load' - - # get the containing directory of this file - # use $BATS_TEST_FILENAME instead of ${BASH_SOURCE[0]} or $0, - # as those will point to the bats executable's location or the preprocessed file respectively - DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" - # make executables in src/ visible to PATH - PATH="$DIR/..:$PATH" -} - -@test "supports help flag" { - run ws -h - assert_output --partial 'ws usage:' -} - - - -@test "supports help flag" { - run ws -h - assert_output --partial 'ws usage:' -} diff --git a/test/test.sh b/test/test.sh index 53fa9500..2afbc0ad 100755 --- a/test/test.sh +++ b/test/test.sh @@ -15,7 +15,7 @@ set +u source $HOME/.nix-profile/etc/profile.d/hm-session-vars.sh set -u -source ~/workstation/lib/shell/foundation.sh +source ${WORKSTATION_DIR}/lib/shell/foundation.sh function find_emacs_init() { init_file=""; @@ -35,12 +35,11 @@ function find_emacs_init() { emacs_init="$(find_emacs_init)" - function assert_input() { local label=$1 local expected=$2 local actual - read actual + read -r actual if [[ "$expected" == "$actual" ]]; then echo "$label is correct" @@ -52,7 +51,7 @@ function assert_input() { echo "RUNNING TESTS" -EMACS_PATH=~/.nix-profile/bin/emacs +EMACS_PATH=$HOME/.nix-profile/bin/emacs # emacs if [ -x "$EMACS_PATH" ]; then echo found emacs @@ -62,7 +61,7 @@ else fi $EMACS_PATH -Q --batch --eval '(progn (princ emacs-version) (terpri))' | { - read actual + read -r actual if [[ "$actual" == "27.1" || "$actual" == "27.2" || "$actual" == "28.1" || "$actual" == "28.2" ]]; then echo "emacs version is correct" else @@ -72,7 +71,7 @@ $EMACS_PATH -Q --batch --eval '(progn (princ emacs-version) (terpri))' | { } $EMACS_PATH -l "$emacs_init" --batch --eval '(progn (princ doom-version) (terpri))' | { - read actual; + read -r actual; if [[ "$actual" == "21.12.0-alpha" || "$actual" == "3.0.0-dev" || "$actual" == "3.0.0-pre" ]]; then echo "doom version is correct" else @@ -88,9 +87,9 @@ else exit 1 fi -if [ -f ~/secrets/test_secret ]; then +if [ -f $HOME/secrets/test_secret ]; then echo "test secret file sucessfully synced" - cat ~/secrets/test_secret + cat $HOME/secrets/test_secret else echo "error: test secret file was missing" fi diff --git a/workstation.org b/workstation.org index 828f841d..ffc4baf1 100644 --- a/workstation.org +++ b/workstation.org @@ -108,7 +108,7 @@ tangle: Which requires a shell script: #+begin_src sh :shebang "#!/usr/bin/env bash" :tangle ./bin/tangle.sh -source ~/workstation/lib/shell/foundation.sh +source ${WORKSTATION_DIR}/lib/shell/foundation.sh $WORKSTATION_EMACS_CONFIG_DIR/bin/doomscript lib/emacs/tangle-file.el #+end_src @@ -281,6 +281,11 @@ is_git_repo_cloned_at $WORKSTATION_DIR $WORKSTATION_GIT_ORIGIN || { } #+end_src *** check out the dotfiles repository +TODO this should probably change, it would almost certainly be better to set +this up somewhow without some other repo. I could likely achieve the same +outcome by just creating a git repo in ~ without any origin, and then figuring +out + #+begin_src shell :noweb yes # at this point, this is hardly necessary; however, the gitignore file is handy # i may explore getting rid of this repo entirely and just having a fresh @@ -297,42 +302,21 @@ info finished ensuring dotfiles repo is checked out #+end_src *** set up host specific settings #+begin_src shell :noweb yes -# each workstaion host I use has different settings needs. -# For example, my remote cloud hosted server has a different setup than -# my mac laptop, which has a different set up from my work computer. -# the way I have these settings specified is by having a directory in my home -# directory which has all of the needed files I would need for such differences. -# there are different directories for each host I maintain, but on a given host, -# one of those directories are symlinked into 'current' host, which other things -# can then refer to - -export WORKSTATION_HOST_SETTINGS_SRC_DIR=$WORKSTATION_DIR/hosts/$WORKSTATION_NAME - -info setting current host settings directory... -info workstation host settings directory: $WORKSTATION_HOST_SETTINGS_SRC_DIR - -if [ -d $WORKSTATION_HOST_SETTINGS_SRC_DIR ]; then - info setting current host directory to $WORKSTATION_HOST_SETTINGS_SRC_DIR; - ln -s $WORKSTATION_HOST_SETTINGS_SRC_DIR $WORKSTATION_HOST_CURRENT_SETTINGS_DIR; -else - echo ERROR $WORKSTATION_HOST_SETTINGS_SRC_DIR does not exist, must exit - exit 5 -fi +${WORKSTATION_DIR}/lib/shell/setup/link-host-dir.sh "$WORKSTATION_NAME" #+end_src - *** set up nix #+begin_src shell :noweb yes info ensuring nix is installed -~/workstation/lib/shell/setup/ensure_nix_installed.sh +${WORKSTATION_DIR}/lib/shell/setup/ensure_nix_installed.sh info finished ensuring nix is installed info setting up nix.conf -~/workstation/lib/shell/setup/install_system_nix_conf.sh +${WORKSTATION_DIR}/lib/shell/setup/install_system_nix_conf.sh info restarting nix daemon -~/workstation/lib/shell/setup/restart_nix_daemon.sh +${WORKSTATION_DIR}/lib/shell/setup/restart_nix_daemon.sh info nix daemon restarted NIX_DAEMON_PATH='/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' @@ -346,7 +330,7 @@ set -u is_mac && { info installing darwin-nix - ~/workstation/lib/shell/setup/install_nix_darwin.sh + ${WORKSTATION_DIR}/lib/shell/setup/install_nix_darwin.sh info finished installing darwin-nix } @@ -354,9 +338,9 @@ is_mac && { *** install home manager #+begin_src shell :noweb yes -~/workstation/lib/shell/setup/install_home_manager.sh +${WORKSTATION_DIR}/lib/shell/setup/install_home_manager.sh -~/workstation/lib/shell/setup/home-manager-flake-switch.sh +${WORKSTATION_DIR}/lib/shell/setup/home-manager-flake-switch.sh set +u # evaluating this with set -u will cause an unbound variable error @@ -370,7 +354,7 @@ much to get into here), the project nix-doom-emacs doesn't work for my purposes, and so while emacs itself is installed via nix, doom does its own package management. #+begin_src shell :noweb yes -~/workstation/lib/shell/setup/install_doom_emacs_no_nix.sh +${WORKSTATION_DIR}/lib/shell/setup/install_doom_emacs_no_nix.sh #+end_src *** link dotfiles into place Note: this must be before wshs is run otherwise when ~ws~ runs ~brew bundle~, it @@ -378,28 +362,28 @@ will fail. #+begin_src shell :noweb yes info linking dotfiles that should be symlinked -bash ~/workstation/lib/shell/setup/link-dotfiles.sh -f -c +bash ${WORKSTATION_DIR}/lib/shell/setup/link-dotfiles.sh -f -c info finished linking dotfiles #+end_src *** set up 'ws' workstation tool #+begin_src shell :noweb yes info "building the 'ws' script" -~/workstation/lib/shell/setup/build_ws_tool.sh +${WORKSTATION_DIR}/lib/shell/setup/build_ws_tool.sh info "running the 'ws install' process" -~/workstation/lib/shell/setup/ws_install.sh +${WORKSTATION_DIR}/lib/shell/setup/ws_install.sh info "'ws install' process completed" #+end_src *** link dotfiles into place #+begin_src shell :noweb yes info linking dotfiles that should be symlinked -bash ~/workstation/lib/shell/setup/link-dotfiles.sh -f -c +bash ${WORKSTATION_DIR}/lib/shell/setup/link-dotfiles.sh -f -c info finished linking dotfiles #+end_src *** set up workstation secrets #+begin_src shell :noweb yes -bash ~/workstation/lib/shell/setup/initial_bitwarden_sync.sh +bash ${WORKSTATION_DIR}/lib/shell/setup/initial_bitwarden_sync.sh #+end_src *** output final manual setup notes #+begin_src shell :noweb yes @@ -571,7 +555,7 @@ emit_nix_conf_content | \ Sometimes we need to restart the nix daemons, e.g. after editing the nix config file. #+begin_src sh :tangle ./lib/shell/setup/restart_nix_daemon.sh :shebang "#!/usr/bin/env bash" :noweb yes -source ~/workstation/lib/shell/funcs.sh +source ${WORKSTATION_DIR}/lib/shell/funcs.sh function restart_nix_daemon_linux() { sudo systemctl restart nix-daemon.service; } @@ -588,8 +572,8 @@ if is_linux; then restart_nix_daemon_linux; fi #+end_src *** Install Nix #+begin_src sh :tangle ./lib/shell/setup/ensure_nix_installed.sh :shebang "#!/usr/bin/env bash" :noweb yes -source ~/workstation/lib/shell/setup/workstation_setup_versions.sh -source ~/workstation/lib/shell/funcs.sh +source ${WORKSTATION_DIR}/lib/shell/setup/workstation_setup_versions.sh +source ${WORKSTATION_DIR}/lib/shell/funcs.sh if which nix > /dev/null; then info "nix exists in path, not installing" @@ -601,7 +585,7 @@ fi #+end_src *** Install doom emacs without nix #+begin_src sh :tangle ./lib/shell/setup/install_doom_emacs_no_nix.sh :shebang "#!/usr/bin/env bash" :noweb yes -source ~/workstation/lib/shell/foundation.sh +source ${WORKSTATION_DIR}/lib/shell/foundation.sh { cd $WORKSTATION_EMACS_CONFIG_DIR @@ -622,25 +606,25 @@ source ~/workstation/lib/shell/foundation.sh *** Build WS tool #+begin_src sh :tangle ./lib/shell/setup/build_ws_tool.sh :shebang "#!/usr/bin/env bash" :noweb yes -cd ~/workstation/wshs +cd ${WORKSTATION_DIR}/wshs nix build --no-link -L .#"wshs:exe:bww" .#"wshs:exe:ws" #+end_src *** Run WS install #+begin_src sh :tangle ./lib/shell/setup/ws_install.sh :shebang "#!/usr/bin/env bash" :noweb yes -cd ~/workstation/wshs +cd ${WORKSTATION_DIR}/wshs $(nix path-info .#"wshs:exe:ws")/bin/ws install -m "$WORKSTATION_NAME"; #+end_src *** Install nix-darwin #+begin_src sh :tangle ./lib/shell/setup/install_nix_darwin.sh :shebang "#!/usr/bin/env bash" :noweb yes -source ~/workstation/lib/shell/foundation.sh -source ~/workstation/lib/shell/setup/workstation_setup_versions.sh +source ${WORKSTATION_DIR}/lib/shell/foundation.sh +source ${WORKSTATION_DIR}/lib/shell/setup/workstation_setup_versions.sh cd $WORKSTATION_DIR nix-build https://github.com/LnL7/nix-darwin/archive/${WORKSTATION_NIX_DARWIN_VERSION}.tar.gz -A installer ./result/bin/darwin-installer -source ~/workstation/lib/shell/setup/nix-darwin-rebuild-flake.sh +source ${WORKSTATION_DIR}/lib/shell/setup/nix-darwin-rebuild-flake.sh #+end_src *** Install home manager @@ -668,7 +652,7 @@ function initial_bitwarden_sync() { if [ ! -d ~/secrets ]; then mkdir ~/secrets; fi - cd ~/workstation/wshs + cd ${WORKSTATION_DIR}/wshs # overwriting anything that was previously in the file echo "${WS_BW_MASTER_PASS}" > ~/secrets/bw_pass bw login --apikey @@ -683,15 +667,79 @@ function initial_bitwarden_sync() { #+end_src #+begin_src sh :tangle ./lib/shell/setup/initial_bitwarden_sync.sh :shebang "#!/usr/bin/env bash" :noweb yes -source ~/workstation/lib/shell/funcs.sh +source ${WORKSTATION_DIR}/lib/shell/funcs.sh «initial_bitwarden_sync_function» initial_bitwarden_sync #+end_src +*** setting directories for current host +Each workstaion host I use has different settings needs. My remote cloud hosted +server has a different setup than my mac laptop, which has a different set up +from my work computer. The way I have these settings specified is by having a +directory in my home directory which has all of the needed files to +specify such differences. There are different directories for each host I +maintain, but on a specific, individual host, one of those directories are symlinked +into the 'current' (src_text{~/workstation/hosts/current/}) +directory, and various workstation components are programmed to look +in this location for their code/settings as appropriate. + +#+begin_src sh :tangle ./lib/shell/setup/link-host-dir.sh :shebang "#!/usr/bin/env bash" :noweb yes +set -e + +usage() { + cat <<-EOF +usage: $0 + +Sets up expected link in a 'current' directory, based upon the WORKSTATION_NAME +provided as argument. Environment variable WORKSTATION_DIR is must also be set so +script can put link within. +EOF +} + +if [ "$#" -ne 1 ]; then + echo "Error: Wrong number of arguments" + usage + exit 55 +fi + +if [ "${WORKSTATION_DIR:-}" = "" ]; then + echo "Error: environment variable WORKSTATION_DIR unset" + usage + exit 56 +fi + +source ${WORKSTATION_DIR}/lib/shell/foundation.sh +source ${WORKSTATION_DIR}/lib/shell/funcs.sh + +WORKSTATION_NAME="$1" + +export WORKSTATION_HOST_CURRENT_SETTINGS_DIR=$WORKSTATION_DIR/hosts/current +export WORKSTATION_HOST_SETTINGS_SRC_DIR=$WORKSTATION_DIR/hosts/$WORKSTATION_NAME + +info setting current host settings directory +info workstation host settings directory: $WORKSTATION_HOST_SETTINGS_SRC_DIR + +if [ -d "$WORKSTATION_HOST_CURRENT_SETTINGS_DIR" ]; then + info "$WORKSTATION_HOST_CURRENT_SETTINGS_DIR" already exists, not changing. \ + If this is incorrect, run rm "$WORKSTATION_HOST_CURRENT_SETTINGS_DIR" \ + and then rerun this script + exit 120 +fi + +if [ -d $WORKSTATION_HOST_SETTINGS_SRC_DIR ]; then + info setting current host directory to $WORKSTATION_HOST_SETTINGS_SRC_DIR; + ln -s $WORKSTATION_HOST_SETTINGS_SRC_DIR $WORKSTATION_HOST_CURRENT_SETTINGS_DIR; +else + echo ERROR $WORKSTATION_HOST_SETTINGS_SRC_DIR does not exist, cannot link + exit 5 +fi +#+end_src + + *** Linking dotfiles #+begin_src sh :tangle ./lib/shell/setup/link-dotfiles.sh :shebang "#!/usr/bin/env bash" :noweb yes -source ~/workstation/lib/shell/funcs.sh +source ${WORKSTATION_DIR}/lib/shell/funcs.sh export FORCE=false; export VERBOSE=false; @@ -723,7 +771,7 @@ function check () { function ln_helper() { dest=~/$2$1 - src=~/workstation/dotfiles/$1 + src=${WORKSTATION_DIR}/dotfiles/$1 curr=$(readlink -f "$dest") if [ -L "$dest" ] && [ "$curr" = "$src" ]; then @@ -748,10 +796,9 @@ function ln_norm() { } function ln_dotfile_n() { - src=~/workstation/dotfiles/$1 + src=${WORKSTATION_DIR}/dotfiles/$1 dest=~/.$1 - destdir=$(dirname $dest) - + destdir=$(dirname "$dest") if [ ! -d $destdir ]; then mkdir -p $destdir fi @@ -811,9 +858,9 @@ machines have the same home manager configurations. #+begin_src sh :shebang "#!/usr/bin/env bash" :tangle ./lib/shell/setup/home-manager-flake-switch.sh :noweb yes set -u # error in case WORKSTATION_NAME is not set -nix build --no-link ~/workstation/#homeConfigurations.${WORKSTATION_NAME}.$(whoami).activationPackage --show-trace +nix build --no-link ${WORKSTATION_DIR}/#homeConfigurations.${WORKSTATION_NAME}.$(whoami).activationPackage --show-trace -"$(nix path-info ~/workstation/#homeConfigurations.${WORKSTATION_NAME}.$(whoami).activationPackage)"/activate --show-trace +"$(nix path-info ${WORKSTATION_DIR}/#homeConfigurations.${WORKSTATION_NAME}.$(whoami).activationPackage)"/activate --show-trace #+end_src ** Nix darwin @@ -878,37 +925,12 @@ I need to have a process to check that system is OK. ** Passwordless sudo Occasionally, sudo is extremely annoying. Having to type "sudo" in the middle of a nix-darwin rebuild really interrupts the flow. So here are a couple of scripts to toggle passwordless sudo. -#+begin_src sh :tangle ./bin/enable-passwordless-sudo.sh :shebang "#!/usr/bin/env bash" -set -eo pipefail - -if [[ -z "$SUDO_USER" ]]; then - echo ERROR: run as sudo - exit 1 -fi - -TEMPFILE=$(mktemp) - -cat > $TEMPFILE <&2 -} - -usage_and_quit() { - print_usage - exit "$1" -} - -print_usage() { - echo "ws usage:" - echo " global flags:" - echo " -v | --verbose : be verbose (i.e. set -x)" - echo " -h | --help : display this message" - echo - echo " commands:" - echo " bootstrap : run the bootstrap process" - echo " flags: " - echo " -n NAME | --name NAME : workstation name to use" - echo " help : display this message" -} - -print_workstation_names() { - echo "Possible workstation names are:" - echo " - glamdring (primary laptop)" - echo " - belthronding (cloud VM)" - echo " - aeglos (work computer)" -} - - - -process_cli_args() { - for i in "$@"; do - case $i in - -v|--verbose) - WS_VERBOSE=true - shift; - ;; - -n|--name) - WORKSTATION_NAME_ARG="$2"; - shift; shift; - ;; - -h|--help|help) - usage_and_quit 0; - ;; - -*|--*) - echo "Unknown option $i" - exit 1 - ;; - bootstrap) - WS_COMMAND="$1"; - WORKSTATION_NAME="$2"; - shift; shift; - ;; - doctor) - WS_COMMAND="$1" - esac - done - - if [[ "$WS_VERBOSE" == "true" ]]; then - set -x; - fi -} - -bootstrap_command_setup() { - if [[ -f "$WORKSTATION_SETTINGS_FILE" ]] ; then - info "settings file exists, loading it"; - source "$WORKSTATION_SETTINGS_FILE"; - - if [ -z "$WORKSTATION_NAME" ]; then - echo "settings file loaded, but WORKSTATION_NAME not set." - fi - - if [[ -z "$WORKSTATION_NAME" && -z "$WORKSTATION_NAME_ARG" ]]; then - echo "workstation name unset in settings file and not provided as argument." - echo "must provide -n or --name with workstation name." - print_workstation_names - usage_and_quit 1 - fi - else - echo "settings file does not exist" - if [[ -z "$WORKSTATION_NAME" && -z "$WORKSTATION_NAME_ARG" ]]; then - echo "workstation name is unset." - echo "must provide -n or --name with workstation name." - print_workstation_names - usage_and_quit 1 - fi - fi -} - - -props_ws_settings_file_check() { - if [[ -f "$WORKSTATION_SETTINGS_FILE" ]] ; then - echo "settings file exists"; - echo "no settings file found (expected at $WORKSTATION_SETTINGS_FILE)" 2>&1 - fi -} - - -boostrap_command() { - echo BOOTSTRAP HERE: -} - - - - - - - - -process_cli_args "$@" - -case "$WS_COMMAND" in - bootstrap) bootstrap_command;; - doctor) doctor_command;; - *) error "unknown command $WS_COMMAND; how did we get here?" -esac - - - - - -# # Script should be passed a single argument, which is name of this workstation. - -# # When using script to set up a workstation, the "name" of the workstation should -# # be provided as the first argument. This is used to pick which settings should be -# # applied to this machine. -# if [ -z "${1+x}" ]; then -# echo WORKSTATION_NAME must be provided as first argument -# exit 2 -# else -# export WORKSTATION_NAME="$1" -# fi - -# # This argument generally should not be used by the user, but it is needed for -# # the CI process. -# # When the CI process starts, we start out with a check out of the code for this -# # commit in a directory on the CI machine. However, this is not how workstation runs: -# # - part of the job of workstation is getting its own code from the server -# # - workstation expects the code to be in a specific directory, that is, ~/workstation -# # Because of this (and possibly other reasons that escape me now), even though the -# # source code of the current commit is checked out on the CI machine already, -# # the CI process re-downloads the code (via this script). The specific SHA to get -# # is passed via the argument below. However, if actually being used by a user, -# # generally user will always want to use the most up to date content of the master -# # branch, so this can be ignored. -# # I think probably this sha should just be passed in as an environment variable -# # instead of a CLI argument, as that seems a bit less confusing to me. -# if [ -z "${2+x}" ]; then -# export WORKSTATION_BOOTSTRAP_COMMIT=origin/master -# else -# export WORKSTATION_BOOTSTRAP_COMMIT="$2" -# fi -# # [[file:../../workstation.org::workstation_foundation][workstation_foundation]] - -# export WORKSTATION_DIR="$HOME/workstation" -# export WORKSTATION_EMACS_CONFIG_DIR=~/.config/emacs -# export WORKSTATION_GIT_ORIGIN='git@github.com:joelmccracken/workstation.git' -# export WORKSTATION_GIT_ORIGIN_PUB='https://github.com/joelmccracken/workstation.git' -# export WORKSTATION_HOST_CURRENT_SETTINGS_DIR=$WORKSTATION_DIR/hosts/current - -# sourceIfExists () { -# if [ -f "$1" ]; then -# source "$1" -# fi -# } - -# if [ -z "${WORKSTATION_NAME+x}" ] ; then -# sourceIfExists "$WORKSTATION_HOST_CURRENT_SETTINGS_DIR/settings.sh" -# fi - - -# if [ -z "${WORKSTATION_NAME+x}" ] ; then -# echo WARNING: no environment variable WORKSTATION_NAME provided. -# echo This variable should be exported by a script at: -# echo $WORKSTATION_DIR/hosts/current/settings.sh -# echo see workstation.org for more information -# else -# export WORKSTATION_HOST_SETTINGS_SRC_DIR=$WORKSTATION_DIR/hosts/$WORKSTATION_NAME -# fi -# # workstation_foundation ends here -# # These are the various versions of things that should be installed. Keeping them -# # in one place like this make them easier to keep track of. -# # [[file:../../../workstation.org::workstation_setup_versions][workstation_setup_versions]] -# export WORKSTATION_NIX_PM_VERSION=nix-2.11.1 -# export WORKSTATION_NIX_DARWIN_VERSION=f6648ca0698d1611d7eadfa72b122252b833f86c -# export WORKSTATION_HOME_MANAGER_VERSION=0f4e5b4999fd6a42ece5da8a3a2439a50e48e486 -# # workstation_setup_versions ends here -# # hereafter, we use many helper functions. Here they are defined up front, -# # as some of them are used throughout the other code. - -# # [[file:workstation.org::is_mac_function][is_mac_function]] -# function is_mac() { -# [[ "$(uname)" == 'Darwin' ]] -# } -# # is_mac_function ends here - -# # [[file:workstation.org::is_linux_function][is_linux_function]] -# function is_linux() { -# [[ "$(uname)" == 'Linux' ]] -# } -# # is_linux_function ends here - -# # [[file:workstation.org::info_function][info_function]] -# function info() { -# echo "INFO ========= $(date) $@" -# } -# # info_function ends here - -# # [[file:workstation.org::polite_git_checkout_function][polite_git_checkout_function]] -# function polite-git-checkout () { -# DIR=$1 -# REPO=$2 -# ORIGIN=$3 - -# cd $DIR -# git init -# git remote add origin $REPO -# git fetch - -# # wont work (it will have already been deleted from the index) -# git reset --mixed origin/master -# # This formulation of the checkout command seems to work most reliably -# git status -s | grep -E '^ D' | sed -E 's/^ D //' | xargs -n 1 -- git checkout -# # fixing; used public to start, but want to be able to push -# git remote set-url origin $ORIGIN -# } -# # polite_git_checkout_function ends here - -# # [[file:workstation.org::mv_dated_backup_function][mv_dated_backup_function]] -# function mv_dated_backup() { -# local THEDIR="$1" -# if test -e "$THEDIR"; then -# mv "$THEDIR" "${THEDIR}-$(date +"%s")" -# fi -# } -# # mv_dated_backup_function ends here - -# # [[file:workstation.org::is_git_repo_cloned_at_function][is_git_repo_cloned_at_function]] -# function is_git_repo_cloned_at(){ -# cd $1 && [[ "$(git remote get-url origin)" == "$2" ]] -# } -# # is_git_repo_cloned_at_function ends here - -# # [[file:workstation.org::clone_repo_and_checkout_at_function][clone_repo_and_checkout_at_function]] -# function clone_repo_and_checkout_at() { -# mv_dated_backup $1 -# info cloning repo into $1 -# git clone $2 $1 -# cd $1 -# info checking out commit $3 -# git checkout $3 -# info setting origin -# git remote set-url origin $4 -# } -# # clone_repo_and_checkout_at_function ends here - -# # [[file:workstation.org::xcode_setup_function][xcode_setup_function]] -# function xcode_setup() { -# # this will accept the license that xcode requires from the command line -# # and also install xcode if required. -# sudo bash -c '(xcodebuild -license accept; xcode-select --install) || exit 0' -# } -# # xcode_setup_function ends here - -# # [[file:workstation.org::is_brew_installed_function][is_brew_installed_function]] -# function is_brew_installed() { -# which brew > /dev/null -# } -# # is_brew_installed_function ends here - -# # [[file:workstation.org::homebrew_setup_function][homebrew_setup_function]] -# function homebrew_setup() { -# /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -# } -# # homebrew_setup_function ends here - -# # [[file:workstation.org::update_apt_install_git_function][update_apt_install_git_function]] -# function update_apt_install_git() { -# sudo bash -c 'apt-get update && apt-get install git' -# } -# # update_apt_install_git_function ends here - -# # [[file:workstation.org::*Bootstraping Script][is_git_repo_cloned_at_function]] -# function is_git_repo_cloned_at(){ -# cd $1 && [[ "$(git remote get-url origin)" == "$2" ]] -# } -# # is_git_repo_cloned_at_function ends here - -# # [[file:workstation.org::*Bootstraping Script][clone_repo_and_checkout_at_function]] -# function clone_repo_and_checkout_at() { -# mv_dated_backup $1 -# info cloning repo into $1 -# git clone $2 $1 -# cd $1 -# info checking out commit $3 -# git checkout $3 -# info setting origin -# git remote set-url origin $4 -# } -# # clone_repo_and_checkout_at_function ends here -# info starting workstation bootstrap -# is_mac && { -# info ensuring xcode is installed -# xcode_setup -# info finished ensuring xcode is installed - -# info ensuring brew is installed -# if ! is_brew_installed; then -# homebrew_setup -# fi -# info finished ensuring brew is installed - -# info installing git -# brew install git -# info finished installing git - -# } -# is_linux && { -# info updating apt, installing git -# update_apt_install_git -# info finished updating apt, installing git -# } -# is_git_repo_cloned_at $WORKSTATION_DIR $WORKSTATION_GIT_ORIGIN || { -# clone_repo_and_checkout_at $WORKSTATION_DIR $WORKSTATION_GIT_ORIGIN_PUB \ -# $WORKSTATION_BOOTSTRAP_COMMIT $WORKSTATION_GIT_ORIGIN -# } -# # at this point, this is hardly necessary; however, the gitignore file is handy -# # i may explore getting rid of this repo entirely and just having a fresh -# # repo without any origin in ~ -# info ensuring dotfiles repo is checked out - -# DOTFILES_ORIGIN='git@github.com:joelmccracken/dotfiles.git' - -# is_git_repo_cloned_at ~ "$DOTFILES_ORIGIN" || -# polite-git-checkout ~ 'https://github.com/joelmccracken/dotfiles.git' \ -# "$DOTFILES_ORIGIN" - -# info finished ensuring dotfiles repo is checked out -# # each workstaion host I use has different settings needs. -# # For example, my remote cloud hosted server has a different setup than -# # my mac laptop, which has a different set up from my work computer. -# # the way I have these settings specified is by having a directory in my home -# # directory which has all of the needed files I would need for such differences. -# # there are different directories for each host I maintain, but on a given host, -# # one of those directories are symlinked into 'current' host, which other things -# # can then refer to - -# export WORKSTATION_HOST_SETTINGS_SRC_DIR=$WORKSTATION_DIR/hosts/$WORKSTATION_NAME - -# info setting current host settings directory... -# info workstation host settings directory: $WORKSTATION_HOST_SETTINGS_SRC_DIR - -# if [ -d $WORKSTATION_HOST_SETTINGS_SRC_DIR ]; then -# info setting current host directory to $WORKSTATION_HOST_SETTINGS_SRC_DIR; -# ln -s $WORKSTATION_HOST_SETTINGS_SRC_DIR $WORKSTATION_HOST_CURRENT_SETTINGS_DIR; -# else -# echo ERROR $WORKSTATION_HOST_SETTINGS_SRC_DIR does not exist, must exit -# exit 5 -# fi - -# info ensuring nix is installed -# ~/workstation/lib/shell/setup/ensure_nix_installed.sh - -# info finished ensuring nix is installed - -# info setting up nix.conf -# ~/workstation/lib/shell/setup/install_system_nix_conf.sh - -# info restarting nix daemon -# ~/workstation/lib/shell/setup/restart_nix_daemon.sh -# info nix daemon restarted - -# NIX_DAEMON_PATH='/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' -# set +u -# source "$NIX_DAEMON_PATH"; -# set -u - -# is_mac && { -# info installing darwin-nix -# ~/workstation/lib/shell/setup/install_nix_darwin.sh -# info finished installing darwin-nix -# } - - -# ~/workstation/lib/shell/setup/install_home_manager.sh - -# ~/workstation/lib/shell/setup/home-manager-flake-switch.sh - -# set +u -# # evaluating this with set -u will cause an unbound variable error -# source $HOME/.nix-profile/etc/profile.d/hm-session-vars.sh -# set -u - -# ~/workstation/lib/shell/setup/install_doom_emacs_no_nix.sh -# info linking dotfiles that should be symlinked -# bash ~/workstation/lib/shell/setup/link-dotfiles.sh -f -c -# info finished linking dotfiles -# info "building the 'ws' script" -# ~/workstation/lib/shell/setup/build_ws_tool.sh - -# info "running the 'ws install' process" -# ~/workstation/lib/shell/setup/ws_install.sh -# info "'ws install' process completed" - -# info linking dotfiles that should be symlinked -# bash ~/workstation/lib/shell/setup/link-dotfiles.sh -f -c -# info finished linking dotfiles -# bash ~/workstation/lib/shell/setup/initial_bitwarden_sync.sh - -# cat <<-EOF -# Success! However, there are some remaining manual set up steps required. -# # [[file:workstation.org::manual-setup-instructions][manual-setup-instructions]] -# There are unfortunately a number of things need to install and set up -# manually: -# - lastpass firefox extension -# - vimium-ff etension -# - dropbox -# - icloud -# - slack -# - spotify -# - install haskell language server in ~/bin (or somwewhere else?) for hls - -# These are the settings I use for slack: -# - accessibility then at bottom changbe up arrow to move focus to last message -# - advanced -# - when in markdown block backticks, enter should do a newline -# - format messages with markup - -# mac settings -# - enable screen sharing, _not_ remote management -# - enable remote login -# - configure hammerspoon -# - open it -# - enable accessability settings -# - launch at login -# # manual-setup-instructions ends here -# EOF -# # Bootstraping Script:1 ends here diff --git a/ws_tool/README.org b/ws_tool/README.org new file mode 100644 index 00000000..5a9320b8 --- /dev/null +++ b/ws_tool/README.org @@ -0,0 +1,25 @@ +#+title: Readme + + +setting up +- download ws_install.sh and run, optionally setting env vars to customize + - sets up repo + - makes various default files etc, esp settings.sh + - maybe use a different dir as source? +- customize ws_profile/settings.sh (where should this go?) + can run gen + + + +e.g. download ws_install and run +download personal workstation configuration, or put in place in some other way +run e.g. workstation bootstrap + + +setup steps +configure any env vars if want installed elsewhere +curl ws_install, run it w bash +execute ws bootstrap () +- at this point, where should configurations be? +implement a -i or -q for interactive/quiet? (-i default?) +where should the settings and config file be located? diff --git a/ws_tool/bin/safe-overwrite b/ws_tool/bin/safe-overwrite new file mode 100755 index 00000000..47376698 --- /dev/null +++ b/ws_tool/bin/safe-overwrite @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +current_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +. "${current_dir}/../lib/lib.bash" +safe_overwrite "$1" "$2" diff --git a/ws_tool/lib/bootstrap_doctor.bash b/ws_tool/lib/bootstrap_doctor.bash new file mode 100644 index 00000000..72931657 --- /dev/null +++ b/ws_tool/lib/bootstrap_doctor.bash @@ -0,0 +1,189 @@ +#!/usr/bin/env bash +set -euo pipefail + +declare -a REPLY + +# bootstrapping and doctoring is closely related enough for now +# decide to keep these in the same file. +doctor_command() { + echo "doctor!"; + run_all_props --fix false --label "doctor" +} + +bootstrap_command_setup() { + if [[ -z "$WORKSTATION_NAME" ]]; then + error "ws: bootstrap: unable to determine workstation name. Provide it as an argument or env var" + exit 1 + fi +} + +bootstrap_command() { + run_all_props --fix true --label "bootstrap" +} + +run_all_props() { + local fix="" label="" + + if (( $# != 4 )); then + echo "requires both --fix and --label flags" 1>&2 + fi + + while (( $# > 0 )); do + local current="$1" + shift + case "$current" in + (--fix) fix="$1"; shift;; + (--label) label="$1"; shift;; + (*) echo "unknown argument '$current', remaining arguments '$*'"; return 10;; + esac + done + + echo "$label: base properties" + local result=0 + run_props --fix "$fix" "${bootstrap_props[@]}" || { result="$?"; : ; } + if (( result > 0 )); then + return "$result"; + fi + + echo "$label: '$WORKSTATION_NAME' properties" + + REPLY=() + get_workstation_properties + local ws_props=() + (( ${#REPLY[@]} > 0)) && ws_props=("${REPLY[@]}") || return 0 + REPLY=() + if (( ${#ws_props[@]} > 0)); then + echo "$label: ${WORKSTATION_NAME} properties: (${ws_props[*]})" + run_props --fix "$fix" "${ws_props[@]}" + else + echo "no properties defined for '${WORKSTATION_NAME}'" + fi +} + +get_workstation_properties() { + ws_props_ptr="workstation_props_$WORKSTATION_NAME" + if declare -p "$ws_props_ptr" &> /dev/null; then + printf -v setprops 'props=("${%s[@]}");' "$ws_props_ptr" + eval "$setprops" + REPLY=("${props[@]}") + else + REPLY=() + fi + return 0 +} + +bootstrap_props=( + prop_ws_check_workstation_dir + prop_ws_check_initial_tooling_setup + prop_ws_check_workstation_repo + prop_ws_config_exists +) + +run_props () { + local fix= + if [[ "$1" == "--fix" ]]; then + fix="$2"; + shift; shift; + else + echo "run_props: arguments: must specify --fix parameter as starting parameter" 1>&2 + return 8 + fi + + local initial_props=("$@") + local props=("${initial_props[@]}") + local prop_result fix_result + local current + local failed_props=() + + while (($#)); do + local current="$1" prop_result + shift + echo "checking: $current..." + REPLY=() + prop_result=0 + "$current" || { prop_result="$?"; : ; } + if (( ${#REPLY[@]} > 1 )) && [[ "${REPLY[0]}" == "additional_props" ]]; then + additional_props=("${REPLY[@]:1}") + REPLY=() # unset to prevent any confusion on next run + echo "$current defines additional properties, adding to top of properties to check: (${additional_props[@]})" + set "${additional_props[@]}" "$@" + fi + if (( prop_result == 0 )); then + echo "checking: $current ... OK" + else + echo "checking: $current ... FAIL" + if [[ "$fix" == "true" ]]; then + echo "fixing: $current ..." + local fix_result=0 + interact "${current}_fix" || { fix_result="$?"; : ; } + if (( fix_result == 0 )); then + echo "fixing: $current .... OK" + prop_result=0 + "${current}" || { prop_result="$?"; : ; } + if (( prop_result == 0 )); then + echo "checking: $current .... OK" + else + echo "checking: $current .... FAIL" + echo "prop $current still failing after running fix, aborting"; + return "$prop_result" + fi + else + echo "fixing: $current .... FAIL" + echo "error while fixing $current, aborting" + return 88 + fi + else + failed_props+=("$current") + fi + fi + done + + if (( ${#failed_props[@]} > 0 )); then + echo "ws: ${label}: unable to satisfy the following props:" 1>&2 + for prop in "${failed_props[@]}"; do + echo " - $prop" 1>&2 + done + echo " Examine earlier log output to see what went wrong." 1>&2 + return 10 + else + return 0 + fi +} + +: "${interact_always_continue:=false}" +do_interact() { + # only interact if stdin is a terminal, + # the workstation_interactive variable is set to true, + # and interact_always_continue is not set to true + [[ -t 0 ]] && \ + [[ "${workstation_interactive:-false}" == "true" ]] && \ + [[ "${interact_always_continue:-false}" != "true" ]] +} + +interact() { + local has_continue=0 the_command="$1" result + + if do_interact ; then + while [ "$has_continue" != "1" ]; do + read -r -e -n 1 -p "About to run '$1', continue? (c/q/!/p/?):" response + case "$response" in + (c) has_continue=1;; + (q) echo "quitting..."; exit 0;; + (\!) interact_always_continue=1; has_continue=1;; + (p) type "$the_command";; + (?) interact_help;; + (*) echo "unrecognized response '$response'." + esac + done + fi + + # if we're here, we must have gotten continue + # or not needed to interact + result=0 + "$the_command" || { result="$?"; : ; } + return "$result"; +} + +interact_help() { + echo "c=continue, q=quit, !=always continue, p=print function definition, ?=print this help"; +} diff --git a/ws_tool/lib/lib.bash b/ws_tool/lib/lib.bash new file mode 100644 index 00000000..289a88df --- /dev/null +++ b/ws_tool/lib/lib.bash @@ -0,0 +1,52 @@ +is_mac() { + [[ "$(uname)" == 'Darwin' ]] +} + +is_linux() { + [[ "$(uname)" == 'Linux' ]] +} + +find_bracketed_content() { + local line phase=before start_bracket="$1" end_bracket="$2" + local before="" content="" after="" + while read -r line; do + if [[ "$phase" == "before" ]]; then + if [[ "$line" == "$start_bracket" ]]; then + phase=content; + content+="$line"$'\n' + else + before+="$line"$'\n' + fi + elif [[ "$phase" == "content" ]]; then + content+="$line"$'\n' + if [[ "$line" == "$end_bracket" ]]; then + phase=end; + fi + elif [[ "$phase" == "end" ]]; then + after+="$line"$'\n' + fi + done + REPLY=("$before" "$content" "$after") + return 0 +} + +_mktemp() { + mktemp -d "${TMPDIR:-/tmp}/${1}.XXXXXXXXX" +} + +mv_to_backup() { + local the_file="$1" new= + new="${the_file}-$(date +"%s")" + if [[ -e "$the_file" ]]; then + mv "$the_file" "$new" > /dev/null + echo "$new" + fi +} + +safe_overwrite() { + new="$1" + orig="$2" + + mv_to_backup "$orig" + mv "$new" "$orig" +} diff --git a/ws_tool/lib/logging.bash b/ws_tool/lib/logging.bash new file mode 100644 index 00000000..eddb7e67 --- /dev/null +++ b/ws_tool/lib/logging.bash @@ -0,0 +1,47 @@ +log_level_num() { + local lvl_num msg_lvl + msg_lvl="$1" + case "$msg_lvl" in + (emerg) lvl_num=1;; + (alert) lvl_num=2;; + (crit) lvl_num=3;; + (error) lvl_num=4;; + (warn) lvl_num=5;; + (notice) lvl_num=6;; + (info) lvl_num=7;; + (debug) lvl_num=8;; + (*) lvl_num=8;; # default at debug, something is wrong + esac; + REPLY=("$lvl_num"); + return 0 +} + +log() { + local this_lvl="$1" + shift; + REPLY=() + log_level_num "$WORKSTATION_LOG_LEVEL" + local global_lvl_num="${REPLY[0]}"; + REPLY=() + log_level_num "$this_lvl" + local this_lvl_num="${REPLY[0]}"; + REPLY=() + + if (( this_lvl_num <= global_lvl_num )); then + local msg + msg="$this_lvl $(date): $*" + echo "$msg" 1>&2 + fi +} + +function error() { + log error "$@" +} + +function debug() { + log debug "$@" +} + +function info() { + log info "$@" +} diff --git a/ws_tool/lib/properties.bash b/ws_tool/lib/properties.bash new file mode 100644 index 00000000..f6a918ad --- /dev/null +++ b/ws_tool/lib/properties.bash @@ -0,0 +1,367 @@ +#!/usr/bin/env bash + +. "$WORKSTATION_DIR/ws_tool/lib/lib.bash" +. "$WORKSTATION_DIR/ws_tool/lib/properties/dotfiles.bash" + +# writing properties +# for a given property foo, define function +# prop_foo +# that determines if property is fulfilled. +# return code 0 indicates its fulfilled, +# nonzero code indicates property is notfulfilled. +# if propery is not fulfilled, +# prop_foo_fix is executed to +# try to fix/fulfill the property. +# after prop_foo_fix completes, if it has zero exit code, +# assume it worked. run original prop function again to ensure +# if prop does not pass now, exit prop checking and fulfilling cycle +# as fix did not work +# +# propery functions can define that they depend upon other properties by +# setting the REPLY global to an array where the first argument is +# "additional_props" and subsequent arguments are those properties. for example, +# say above property foo should have other props bar and baz, then the following +# value would be appropriate: +# REPLY=(additional_props prop_bar prop_baz) +# after prop foo returns with a zero exit code, these props are handled next. +# By default, prop_foo would not be checked again after the other props are fulfilled, but +# you could make it do this by for example +# prop_foo() { +# REPLY=(additional_props prop_bar prop_baz prop_foo) +# } +# Note that prop_foo is included at the end of the additional properties list. +# Of course, you wouldn't want this exact example, otherwise it would imply +# that foo would be checked again and again, ad infinitum. + +prop_ws_check_initial_tooling_setup() +{ + if is_mac; then + REPLY=(additional_props \ + prop_ws_check_mac_cli_tools\ + prop_ws_check_mac_homebrew_installed\ + prop_ws_check_mac_git_installed\ + ) + return 0 + else + if is_linux; then + REPLY=(additional_props prop_ws_check_linux_git_installed) + return 0 + else + # TODO linux is assumed to be debian based + error "unable to determine workstation system type (mac, linux)" + return 1 + fi + fi +} + +# check to ensure that xcode cli tools are installed +# this command will tell without itself trying to install them +prop_ws_check_mac_cli_tools () { + if pkgutil --pkg-info=com.apple.pkg.CLTools_Executables; then + echo "cli tools package is installed"; + return 0 + else + echo "cli tools package not installed" 1>&2 + return 1 + fi +} + +prop_ws_check_mac_cli_tools_fix () { + sudo bash -c '(xcodebuild -license accept; xcode-select --install) || exit 0' +} + +prop_ws_check_mac_homebrew_installed() { + if which brew > /dev/null; then + echo "homebrew is installed" + return 0 + else + echo "homebrew is not installed" 1>&2; + return 1 + fi +} + +prop_ws_check_mac_homebrew_installed_fix() { + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +} + +prop_ws_check_mac_git_installed() { + if which git > /dev/null; then + echo "git is detected" + else + echo "no git is detected" + fi +} + +prop_ws_check_mac_git_installed_fix() { + brew install git +} + +prop_ws_check_linux_git_installed() { + if which git > /dev/null; then + echo "git is detected" + else + echo "no git is detected" + fi +} + +prop_ws_check_linux_git_installed_fix() { + sudo bash -c 'apt-get update && apt-get install git' +} + +prop_ws_check_workstation_dir() { + if [ -d "$WORKSTATION_DIR" ]; then + echo "WORKSTATION_DIR exists" + if [ -x "$WORKSTATION_DIR/ws_tool/ws" ]; then + echo "WORKSTATION_DIR contains ws executable" + return 0 + else + echo "$WORKSTATION_DIR does not contain the ws tool" 1>&2 + return 2 + fi + else + echo "$WORKSTATION_DIR (WORKSTATION_DIR) is absent" 1>&2 + echo "(is workstation installed to a custom location? set WORKSTATION_DIR=path/to/workstation)" 1>&2 + return 1 + fi +} + +prop_ws_check_workstation_dir_fix() { + # TODO this is basically a copy/paste of ws_install.sh + # somehow figure out another way to do this? + TMPINST="$(mktemp -d "${TMPDIR:-/tmp}/ws-install-XXXXXXXXX")" + # installer of ws tool/project + ( cd "$TMPINST"; + curl -L https://github.com/joelmccracken/workstation/archive/${WORKSTATION_VERSION}.tar.gz | tar zx; + + mkdir -p "$WORKSTATION_DIR"; + mv "${TMPINST}"/workstation-*/{,.[^.]}* "$WORKSTATION_DIR"; + ) +} + +prop_ws_check_workstation_repo() { + if [ -d "$WORKSTATION_DIR/.git" ]; then + echo "WORKSTATION_DIR git directory exists" + return 0 + else + echo "$WORKSTATION_DIR/.git directory is absent" 1>&2 + return 1 + fi +} + +prop_ws_check_workstation_repo_fix() { + ( cd "$WORKSTATION_DIR"; + git init .; + git remote add origin "$WORKSTATION_REPO_GIT_ORIGIN"; + git fetch; + git reset --mixed "$WORKSTATION_VERSION"; + ) +} + +: "${WORKSTATION_DOTFILES_TRACK_GIT_DIR:=".git-dotfiles"}" +prop_ws_dotfiles_git_track() { + if [ -d "$HOME/$WORKSTATION_DOTFILES_TRACK_GIT_DIR" ]; then + echo "git directory at $HOME/$WORKSTATION_DOTFILES_TRACK_GIT_DIR exists" + return 0 + else + echo "git directory at $HOME/$WORKSTATION_DOTFILES_TRACK_GIT_DIR not found" 1>&2 + return 1 + fi +} + +prop_ws_dotfiles_git_track_fix() { + export GIT_DIR="$WORKSTATION_DOTFILES_TRACK_GIT_DIR" + ( cd "$HOME"; + git init . + git config --local --get-all core.bare true >/dev/null && \ + git config --local --replace-all core.bare false true + ) + return 0 +} + +prop_ws_config_exists() { + local settings_file="${WORKSTATION_CONFIG_DIR}/settings.sh" + local config_file="${WORKSTATION_CONFIG_DIR}/config.sh" + if [[ -f "$settings_file" ]] && [[ -f "$config_file" ]]; then + echo "found settings and config file exist." + return 0; + else + if ! [[ -f "$settings_file" ]]; then + echo "ws: bootstrap: prop_ws_config_exists: missing settings file from '$settings_file'" 1>&2 + fi + if ! [[ -f "$config_file" ]]; then + echo "ws: bootstrap: prop_ws_config_exists: missing config file from '$config_file'" 1>&2 + fi + return 1 + fi +} + +# depends upon prop_ws_check_workstation_dir +# TODO automate/enforce this somehow? +prop_ws_config_exists_fix() { + local src_dir="${WORKSTATION_DIR}/ws_tool/sample_config"; + if [[ -n "$workstation_initial_config_dir_arg" ]]; then + src_dir="$workstation_initial_config_dir_arg"; + fi + mkdir -p "$WORKSTATION_CONFIG_DIR" + + # hack, because if a relative dir is used for $workstation_initial_config_dir_arg + # we want it to go back... + ( cd "$ws_initial_pwd"; cd "$src_dir"; + # not perfect, but not worth making much more complicated + for f in *; do + if [[ -e "$WORKSTATION_CONFIG_DIR/$f" ]]; then + echo "$WORKSTATION_CONFIG_DIR/$f: aleady exists, skipping" + else + echo "copying file to $WORKSTATION_CONFIG_DIR/$f" + cp -r "$f" "$WORKSTATION_CONFIG_DIR/$f"; + fi + done + ) +} + +prop_ws_current_settings_symlink() { + current_settings_file="$WORKSTATION_CONFIG_DIR/settings.current.sh" + + if [[ -L "$current_settings_file" ]]; then + echo "symlink found at $current_settings_file" + return 0 + fi + + if ! [[ -e "$current_settings_file" ]]; then + echo "no file found at '$current_settings_file'" 1>&2 + fi + + if ! [[ -L "$current_settings_file" ]]; then + { + echo "Warning: File found at '$current_settings_file', but it was not a symlink." + echo " This will probably work, but its possible that something wonky" + echo " has happened." + } 1>&2 + fi + + return 2 +} + +# depends upon prop_ws_config_exists +prop_ws_current_settings_symlink_fix() { + current_settings_file="$WORKSTATION_CONFIG_DIR/settings.current.sh" + src_settings_file="$WORKSTATION_CONFIG_DIR/settings.${WORKSTATION_NAME}.sh" + + prop_ws_config_exists + + if [[ -e "$current_settings_file" ]] && \ + ! [[ -L "$current_settings_file" ]]; then + echo "non-symlink file exists at '$current_settings_file'. Cannot automatically fix." 1>&2 + return 10 + fi + + if ! [[ -e "$src_settings_file" ]]; then + echo "Expecting to find file at '$src_settings_file' to use as symlink src. File not found." 1>&2 + return 3 + fi + + ln -s "$src_settings_file" "$current_settings_file" +} + +prop_ws_nix_daemon_installed() { + if which nix > /dev/null ; then + echo "nix command found" + return 0 + else + echo "nix command not found" 1>&2 + return 1 + fi +} + +: "${WORKSTATION_NIX_PM_VERSION:=nix-2.25.3}" +prop_ws_nix_daemon_installed_fix() { + sh <(curl -L https://releases.nixos.org/nix/$WORKSTATION_NIX_PM_VERSION/install) --daemon; + # load the needful after installing + nix_daemon_profile='/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' + if [[ ! -e "$nix_daemon_profile" ]]; then + echo "nix installed, but cannot find profile file to load" 1>&2 + return 8 + fi + . "$nix_daemon_profile"; + ws_nix__restart_daemon +} + +ws_nix__restart_daemon() { + if is_mac; then + set +e + sudo launchctl unload /Library/LaunchDaemons/org.nixos.nix-daemon.plist + sudo launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist + set -e + else + sudo systemctl restart nix-daemon.service; + fi +} + +ws_nix__conf_filename() { + printf "/etc/nix/nix.conf" +} + +: "${WS_NIX_GLOBAL_CONFIG_LOCATION:=$(ws_nix__conf_filename)}" + +ws_nix__global_conf_content() { + cat <<-EOF + # BEGIN prop_ws_nix_global_config + # configuration from ws property prop_ws_nix_global_config + # AUTOMATICALLY MANAGED: region edits will be overwritten in the future + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= + substituters = https://cache.nixos.org https://cache.iog.io + experimental-features = nix-command flakes + trusted-users = root $(whoami) runner + build-users-group = nixbld + # END prop_ws_nix_global_config +EOF +} + +prop_ws_nix_global_config () { + local conf="$WS_NIX_GLOBAL_CONFIG_LOCATION" + local begin="# BEGIN prop_ws_nix_global_config" + local end="# END prop_ws_nix_global_config" + + REPLY=() + find_bracketed_content "$begin" "$end" < "$conf" + local parts=("${REPLY[@]}") + REPLY=() + if [[ "${parts[1]}" == "$(ws_nix__global_conf_content)"$'\n' ]]; then + echo "config file at '$conf' is up to date" + return 0 + else + echo "config file at '$conf' is out of date"; + return 1 + fi +} + +prop_ws_nix_global_config_fix () { + local conf="$WS_NIX_GLOBAL_CONFIG_LOCATION" + local begin="# BEGIN prop_ws_nix_global_config" + local end="# END prop_ws_nix_global_config" + + REPLY=(); find_bracketed_content "$begin" "$end" < "$conf"; + local parts=("${REPLY[@]}"); REPLY=(); + + new_conf="$(_mktemp "nix-conf")/nix.conf" + + { + echo "${parts[0]}"; + ws_nix__global_conf_content; + echo "${parts[2]}" + } > "$new_conf" + + # complicated because I don't want to deal with sudo when running tests + maybe_sudo="bash" # null option (is there some better way?) + if ! [[ -w "$WS_NIX_GLOBAL_CONFIG_LOCATION" ]]; then + maybe_sudo="sudo" + fi + "$maybe_sudo" "${WORKSTATION_DIR}/ws_tool/bin/safe-overwrite" "$new_conf" "$WS_NIX_GLOBAL_CONFIG_LOCATION" +} + +# prop_ws_nix_homemanager_install() { +# export HOME_MANAGER_BACKUP_EXT +# HOME_MANAGER_BACKUP_EXT="old-$(date +'%s')" +# WORKSTATION_HOME_MANAGER_VERSION=0f4e5b4999fd6a42ece5da8a3a2439a50e48e486 +# nix run "home-manager/$WORKSTATION_HOME_MANAGER_VERSION" -- init "$WORKSTATION_DIR" +# } diff --git a/ws_tool/lib/properties/dotfiles.bash b/ws_tool/lib/properties/dotfiles.bash new file mode 100644 index 00000000..cba46af4 --- /dev/null +++ b/ws_tool/lib/properties/dotfiles.bash @@ -0,0 +1,164 @@ +ws_df_dotfiles_fn_name() { + echo "workstation_props_dotfiles_$WORKSTATION_NAME"; +} + +prop_ws_df_dotfiles() { + local fn + fn="$(ws_df_dotfiles_fn_name)" + if declare -f "$fn" &> /dev/null; then + ws_df_dotfile_mode=check + ws_df_dotfile_run_failure= + "$fn" + if [[ -n "$ws_df_dotfile_run_failure" ]]; then + return 9; + fi + else + echo "warning: no function exists named '$(ws_df_dotfiles_fn_name)', skipping prop" 1>&2; + return 0; + fi +} + +prop_ws_df_dotfiles_fix() { + local fn + fn="$(ws_df_dotfiles_fn_name)" + if declare -f "$fn" &> /dev/null; then + ws_df_dotfile_mode=fix + ws_df_dotfile_run_failure= + "$fn" + if [[ -n "$ws_df_dotfile_run_failure" ]]; then + return 9; + fi + else + echo "warning: no function exists named '$(ws_df_dotfiles_fn_name)', skipping prop" 1>&2; + return 0; + fi +} + +ws_df_dotfile_src_dir_default() { + echo "$WORKSTATION_CONFIG_DIR/dotfiles" +} + +ws_df_dotfile_dest_dir_default() { + echo "$HOME" +} + +: "${ws_df_dotfile_mode:=check}" +: "${ws_df_dotfile_src_dir:="$(ws_df_dotfile_src_dir_default)"}" +# dest dir config useful for testing +: "${ws_df_dotfile_dest_dir:="$(ws_df_dotfile_dest_dir_default)"}" +: "${ws_df_dotfile_run_failure:=}" + +dotfile() { + local dot= filename= ln= dir= + while (( $# > 0 )); do + local current="$1" + shift; + case "$current" in + (--dot) dot=true;; + (--ln) ln=true;; + (--dir) dir=true;; + (*) filename=$current;; + esac + done + local src="${ws_df_dotfile_src_dir}" + local dest="${ws_df_dotfile_dest_dir}" + + if [[ -n "$ln" ]] ; then + local pfx="" + if [[ -n "$dot" ]]; then + pfx="." + fi + dest_full="${dest}/${pfx}${filename}" + if [[ -n "$dir" ]]; then + dotfile_dir "$dest_full" + fi + dotfile_ln "$src/$filename" "$dest_full" + fi +} + +dotfile_ln(){ + case "$ws_df_dotfile_mode" in + (check) dotfile_ln_check "$@";; + (fix) dotfile_ln_fix "$@";; + (*) echo "ws_df_dotfile_mode unexpected value '$ws_df_dotfile_mode'" 1>&2; exit 1;; + esac +} + +dotfile_ln_check() { + local src="$1" dest="$2" dest_actual= + if ! [[ -e "$src" ]]; then + echo "error: no file found at '$src'" 1>&2; + ws_df_dotfile_run_failure=true + return 10; + fi + if [[ -L "$dest" ]]; then + dest_actual="$(readlink -f "$dest")" + if [[ "$dest_actual" == "$src" ]] || + [[ "$dest_actual" == "$(readlink -f "$src")" ]]; then + # second condition is a mac thing, readlink w a temp dir + # ends up in "/private..." in a surprising way + return 0; + else + echo "error: expected '$dest' symlink to '$src', actual '$dest_actual'" 1>&2 + ws_df_dotfile_run_failure=true + return 9; + fi + elif ! [[ -e "$dest" ]]; then + echo "error: '$dest' does not exist (expected symlink to '$src')" 1>&2 + ws_df_dotfile_run_failure=true; + return 8; + else + echo "error: expected '$dest' symlink to '$src', but is normal file" 1>&2 + ws_df_dotfile_run_failure=true; + return 11; + fi +} + +dotfile_ln_fix() { + local src="$1" dest="$2" dest_actual= + + if ! [[ -e "$src" ]]; then + echo "error: no file found at '$src'" 1>&2; + ws_df_dotfile_run_failure=true + return 10; + fi + if [[ -L "$dest" ]]; then + dest_actual="$(readlink -f "$dest")" + if [[ "$dest_actual" == "$src" ]]; then + return 0; + fi; + fi + if [[ -e "$dest" ]]; then + local backup= + backup="$(mv_to_backup "$dest")" + echo "moving '$dest' to backup at '$backup'" + fi + ln -s "$src" "$dest" +} + +dotfile_dir() { + case "$ws_df_dotfile_mode" in + (check) dotfile_dir_check "$@";; + (fix) dotfile_dir_fix "$@";; + (*) echo "ws_df_dotfile_mode unexpected value '$ws_df_dotfile_mode'" 1>&2; exit 1;; + esac +} + +dotfile_dir_check() { + local dest_full="$1" dest_dir + dest_dir="$(dirname "$dest_full")" + if ! [[ -e "$dest_dir" ]]; then + echo "no directory exists at '$dest_dir'" 1>&2 + ws_df_dotfile_run_failure=true + return 8; + fi +} + +dotfile_dir_fix() { + local dest_full="$1" dest_dir + dest_dir="$(dirname "$dest_full")" + if ! [[ -e "$dest_dir" ]]; then + echo "creating directory '$dest_dir'" 1>&2 + mkdir -p "$dest_dir" + fi +} diff --git a/ws_tool/lib/settings.bash b/ws_tool/lib/settings.bash new file mode 100644 index 00000000..cf7ffad8 --- /dev/null +++ b/ws_tool/lib/settings.bash @@ -0,0 +1,25 @@ +ws_config_dir_default () { + printf "%s/.config/workstation" $HOME +} + +: "${WORKSTATION_NAME:=}" +: "${WORKSTATION_VERBOSE:=false}" +: "${WORKSTATION_LOG_LEVEL:=error}" +: "${WORKSTATION_CONFIG_DIR:="$(ws_config_dir_default)"}" +: "${WORKSTATION_DIR:="$WORKSTATION_CONFIG_DIR/workstation_source"}" +: "${WORKSTATION_REPO_GIT_ORIGIN:="https://github.com/joelmccracken/workstation.git"}" +: "${WORKSTATION_VERSION:=master}" + +export WORKSTATION_NAME # META:workstation_setting +export WORKSTATION_VERBOSE # META:workstation_setting +export WORKSTATION_LOG_LEVEL # META:workstation_setting +export WORKSTATION_DIR # META:workstation_setting +export WORKSTATION_CONFIG_DIR # META:workstation_setting +export WORKSTATION_REPO_GIT_ORIGIN # META:workstation_setting +export WORKSTATION_VERSION # META:workstation_setting + +# legacy/intermediate versions of these variables +export WORKSTATION_EMACS_CONFIG_DIR=~/.config/emacs +export WORKSTATION_GIT_ORIGIN_PUB='https://github.com/joelmccracken/workstation.git' +export WORKSTATION_HOST_CURRENT_SETTINGS_DIR=$WORKSTATION_DIR/hosts/current +export WORKSTATION_GIT_ORIGIN="git@github.com:joelmccracken/workstation.git" diff --git a/ws_tool/my_config/config.sh b/ws_tool/my_config/config.sh new file mode 100644 index 00000000..f2921a88 --- /dev/null +++ b/ws_tool/my_config/config.sh @@ -0,0 +1,25 @@ + +workstation_props_angrist=() +workstation_props_angrist+=(prop_ws_current_settings_symlink) +workstation_props_angrist+=(prop_ws_dotfiles_git_track) +workstation_props_angrist+=(prop_ws_nix_daemon_installed) +workstation_props_angrist+=(prop_ws_nix_global_config) +workstation_props_angrist+=(prop_ws_df_dotfiles) + +workstation_props_dotfiles_angrist() { + dotfile --ln --dot bashrc + dotfile --ln --dot ghci + dotfile --ln --dot gitconfig + dotfile --ln --dot hammerspoon + dotfile --ln --dot nix-channels + dotfile --ln --dot npmrc + dotfile --ln --dot reddup.yml + dotfile --ln --dot zshrc + + dotfile --ln Brewfile + dotfile --ln Brewfile.lock.json + dotfile --ln bitbar + + dotfile --ln --dot --dir config/git + dotfile --ln --dot --dir config/doom +} diff --git a/ws_tool/my_config/dotfiles/Brewfile b/ws_tool/my_config/dotfiles/Brewfile new file mode 100644 index 00000000..6fc823c6 --- /dev/null +++ b/ws_tool/my_config/dotfiles/Brewfile @@ -0,0 +1,16 @@ +# -*- mode: ruby -*- +tap "homebrew/bundle" +tap "homebrew/cask-versions" + +brew "haskell-stack" + +# casks +cask "hammerspoon" +cask "firefox-developer-edition" +cask "dropbox" +cask "slack" +cask "spotify" +# while racket is avialable in nix for darwin, +# the gui functionality is broken at time of writing, +# so cask racket instead +cask "racket" diff --git a/ws_tool/my_config/dotfiles/Brewfile.lock.json b/ws_tool/my_config/dotfiles/Brewfile.lock.json new file mode 100644 index 00000000..90af5a81 --- /dev/null +++ b/ws_tool/my_config/dotfiles/Brewfile.lock.json @@ -0,0 +1,744 @@ +{ + "entries": { + "tap": { + "homebrew/bundle": { + "revision": "faf12b3096f5e05aba220c380cfff6a223572917" + }, + "homebrew/cask": { + "revision": "13534a84249bb96a999673e1b05e995930078a8e" + }, + "homebrew/core": { + "revision": "5fe4943f8a803e5b1e08a7e4bea79be17117fa67" + }, + "railwaycat/emacsmacport": { + "revision": "09504b43dffcaba7ee321d1ad3343e678e97b4a4" + }, + "homebrew/cask-versions": { + "revision": "ed94dc52e6d2f783e9c43aed5b29db807d39dc23" + } + }, + "brew": { + "railwaycat/emacsmacport/emacs-mac": { + "version": "emacs-27.2-mac-8.3", + "bottle": false, + "options": { + "args": [ + "with-modules" + ] + } + }, + "git": { + "version": "2.35.1", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_monterey": { + "cellar": "/opt/homebrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/git/blobs/sha256:e19e56133d9990f9097a31b7720fe307e4ba87d79019cce086ad8f1e25993012", + "sha256": "e19e56133d9990f9097a31b7720fe307e4ba87d79019cce086ad8f1e25993012" + }, + "arm64_big_sur": { + "cellar": "/opt/homebrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/git/blobs/sha256:09773f8caeb9490d53dc8fbf552dd4b83c655c2219fec38202d351ab459973fa", + "sha256": "09773f8caeb9490d53dc8fbf552dd4b83c655c2219fec38202d351ab459973fa" + }, + "monterey": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/git/blobs/sha256:ec4d252f6ac282f2770bcf18af011e8032d1f43fc17af39e54465bb8148d1d2f", + "sha256": "ec4d252f6ac282f2770bcf18af011e8032d1f43fc17af39e54465bb8148d1d2f" + }, + "big_sur": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/git/blobs/sha256:212244b5acaaa49fdd33b710fc6795c457aa25e89a854d39407bf36532137ef8", + "sha256": "212244b5acaaa49fdd33b710fc6795c457aa25e89a854d39407bf36532137ef8" + }, + "catalina": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/git/blobs/sha256:362820c1071869ed3a31ecfb8cb9c022aaef715745348f72f975b90b94091ef8", + "sha256": "362820c1071869ed3a31ecfb8cb9c022aaef715745348f72f975b90b94091ef8" + }, + "x86_64_linux": { + "cellar": "/home/linuxbrew/.linuxbrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/git/blobs/sha256:34b29f7801095ae255f03bae5d0dde6fc98910811f17266e8b4af73310c3c314", + "sha256": "34b29f7801095ae255f03bae5d0dde6fc98910811f17266e8b4af73310c3c314" + } + } + } + }, + "ripgrep": { + "version": "13.0.0", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_monterey": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/ripgrep/blobs/sha256:ea67bdf39c1727b2b6b5b5f5110d1736b42b3eb0ec2068aa99903b670545b015", + "sha256": "ea67bdf39c1727b2b6b5b5f5110d1736b42b3eb0ec2068aa99903b670545b015" + }, + "arm64_big_sur": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/ripgrep/blobs/sha256:d3e0ae859dc1e66ebecbc66a8ad1ec2abac59bc707d2305dde66212e71406d36", + "sha256": "d3e0ae859dc1e66ebecbc66a8ad1ec2abac59bc707d2305dde66212e71406d36" + }, + "monterey": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/ripgrep/blobs/sha256:db0260c6be9656c54575a4d82c720fb24141be38a17350d6cddba7be14f104e6", + "sha256": "db0260c6be9656c54575a4d82c720fb24141be38a17350d6cddba7be14f104e6" + }, + "big_sur": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/ripgrep/blobs/sha256:a8f2bd6586de9f7aa36eaaefd36777309f9b5d57f01bf33bf022d715fd3dbb89", + "sha256": "a8f2bd6586de9f7aa36eaaefd36777309f9b5d57f01bf33bf022d715fd3dbb89" + }, + "catalina": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/ripgrep/blobs/sha256:0edcffa1251002e2747020d62a16ae077bd7aa5fb289d351622e0065c9686c40", + "sha256": "0edcffa1251002e2747020d62a16ae077bd7aa5fb289d351622e0065c9686c40" + }, + "mojave": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/ripgrep/blobs/sha256:b57024c0d221249a1f5eaef1069ac90d44e54afdadb146acd117ae23b7de98c6", + "sha256": "b57024c0d221249a1f5eaef1069ac90d44e54afdadb146acd117ae23b7de98c6" + }, + "x86_64_linux": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/ripgrep/blobs/sha256:34e3140b55f0fb5efb8db70e0709afe091632efaa84465e4c1c9ca3c8afa1bf2", + "sha256": "34e3140b55f0fb5efb8db70e0709afe091632efaa84465e4c1c9ca3c8afa1bf2" + } + } + } + }, + "coreutils": { + "version": "9.1", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_ventura": { + "cellar": "/opt/homebrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/coreutils/blobs/sha256:ae9dc313da2a3971c8e633d9f3262fd1bd431c303207b3346924aed60bb0965d", + "sha256": "ae9dc313da2a3971c8e633d9f3262fd1bd431c303207b3346924aed60bb0965d" + }, + "arm64_monterey": { + "cellar": "/opt/homebrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/coreutils/blobs/sha256:6a9a4988eda436fb5bdb5969044579c2e618e21eee8c8bbe32614ad29fe56bd7", + "sha256": "6a9a4988eda436fb5bdb5969044579c2e618e21eee8c8bbe32614ad29fe56bd7" + }, + "arm64_big_sur": { + "cellar": "/opt/homebrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/coreutils/blobs/sha256:85ef910aa223d48c0e73fc187aba54b86930c86f906e3d079ed0b114762bb24e", + "sha256": "85ef910aa223d48c0e73fc187aba54b86930c86f906e3d079ed0b114762bb24e" + }, + "ventura": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/coreutils/blobs/sha256:4564009003601fb30335e57453cee93deaeab1eadf4473050e9e70198c21c892", + "sha256": "4564009003601fb30335e57453cee93deaeab1eadf4473050e9e70198c21c892" + }, + "monterey": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/coreutils/blobs/sha256:7c9f988b4f9207415a5c96efd32376bc8cf2b280a7a36fbebb0b8fc334a14056", + "sha256": "7c9f988b4f9207415a5c96efd32376bc8cf2b280a7a36fbebb0b8fc334a14056" + }, + "big_sur": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/coreutils/blobs/sha256:e446ef889d70bc377d67fa2d7f6a1fbc9faaee444a9e9086a1f5bd484069e5c0", + "sha256": "e446ef889d70bc377d67fa2d7f6a1fbc9faaee444a9e9086a1f5bd484069e5c0" + }, + "catalina": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/coreutils/blobs/sha256:0d2117fa63dfcbb678c4e499f9ca0413c2c5bfa0a1bbdefde620434f2ead93a0", + "sha256": "0d2117fa63dfcbb678c4e499f9ca0413c2c5bfa0a1bbdefde620434f2ead93a0" + }, + "x86_64_linux": { + "cellar": "/home/linuxbrew/.linuxbrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/coreutils/blobs/sha256:3c2fbec99344b50d620695d16197eb112cb8bee6d3f9e47cb682484755b91f38", + "sha256": "3c2fbec99344b50d620695d16197eb112cb8bee6d3f9e47cb682484755b91f38" + } + } + } + }, + "fd": { + "version": "8.3.2", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/fd/blobs/sha256:0a9b6670e3898d06da79c8da5405d4409141c4df1b9db3fbf2ffa56ecacdee2b", + "sha256": "0a9b6670e3898d06da79c8da5405d4409141c4df1b9db3fbf2ffa56ecacdee2b" + }, + "arm64_big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/fd/blobs/sha256:dd2878985b2f4100c897283744826acdca627a57692ba11d3472e203015df3d8", + "sha256": "dd2878985b2f4100c897283744826acdca627a57692ba11d3472e203015df3d8" + }, + "monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/fd/blobs/sha256:544bd266bd9d4689aeea459d5edd822db269647074bd28c682c58ab097dcd13d", + "sha256": "544bd266bd9d4689aeea459d5edd822db269647074bd28c682c58ab097dcd13d" + }, + "big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/fd/blobs/sha256:fda49ccd4fb859c6b040695f69e25dd2571e631c7fb203465702c85f924ff755", + "sha256": "fda49ccd4fb859c6b040695f69e25dd2571e631c7fb203465702c85f924ff755" + }, + "catalina": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/fd/blobs/sha256:492097b85cf2fe8b79700048510c90e4da55fee307552e143e84fcefd3bf552a", + "sha256": "492097b85cf2fe8b79700048510c90e4da55fee307552e143e84fcefd3bf552a" + }, + "x86_64_linux": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/fd/blobs/sha256:22528c35f36907d807a44daf4dcd5c8d4c3598a55e3d73df68059ebe228e0b10", + "sha256": "22528c35f36907d807a44daf4dcd5c8d4c3598a55e3d73df68059ebe228e0b10" + } + } + } + }, + "myrepos": { + "version": "1.20180726", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:1ef1fbe930aac818a5996a5280755f746d5595ed94a2d01ffe4c46d0aa066fb2", + "sha256": "1ef1fbe930aac818a5996a5280755f746d5595ed94a2d01ffe4c46d0aa066fb2" + }, + "arm64_big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:3acd961664e9d84ec19e6fa5044fc7b024bbfc691a3dc3d02a250d773abb6a18", + "sha256": "3acd961664e9d84ec19e6fa5044fc7b024bbfc691a3dc3d02a250d773abb6a18" + }, + "monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:a0f6609e5526c820741400527d23e96699e51490ec9b90c2759ddd0565773a58", + "sha256": "a0f6609e5526c820741400527d23e96699e51490ec9b90c2759ddd0565773a58" + }, + "big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:9b2f724c76a7b2a2504301eeb2dcd5d16d2b919e53fe7f43b404c79f56ce7c75", + "sha256": "9b2f724c76a7b2a2504301eeb2dcd5d16d2b919e53fe7f43b404c79f56ce7c75" + }, + "catalina": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:90ab23bd6811b507860b5ddcc7e9a181abd3f126fc2ab193739987d6d4b31612", + "sha256": "90ab23bd6811b507860b5ddcc7e9a181abd3f126fc2ab193739987d6d4b31612" + }, + "mojave": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:73c8b9b421ea776366f9ded68d90c6c3b75b50401172b5c5248556f6f7f47d6e", + "sha256": "73c8b9b421ea776366f9ded68d90c6c3b75b50401172b5c5248556f6f7f47d6e" + }, + "high_sierra": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:a41bcee5b050ec9f98cf5960a457421528b05773867d8c8dbb8eb32716e09fd5", + "sha256": "a41bcee5b050ec9f98cf5960a457421528b05773867d8c8dbb8eb32716e09fd5" + }, + "sierra": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:bcac4176692f69d47a83cd961cee92e096f6b35f19cb7206973f77b15a1ba71c", + "sha256": "bcac4176692f69d47a83cd961cee92e096f6b35f19cb7206973f77b15a1ba71c" + }, + "el_capitan": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:75fd9c6fbf6dcf833243e4dc9baf0afe81c422e55d3e251f5cfe040b8bc6a254", + "sha256": "75fd9c6fbf6dcf833243e4dc9baf0afe81c422e55d3e251f5cfe040b8bc6a254" + }, + "x86_64_linux": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:fe1931dfcaf7fd8500a523287de75c9a492a187c1b45c51e8a8565f2d52db70d", + "sha256": "fe1931dfcaf7fd8500a523287de75c9a492a187c1b45c51e8a8565f2d52db70d" + } + } + } + }, + "graphviz": { + "version": "3.0.0", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_monterey": { + "cellar": "/opt/homebrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/graphviz/blobs/sha256:c3735f9c7a06e03d883a330fc7bf0cb997c2041d86a358f793fe2f0fcd967ade", + "sha256": "c3735f9c7a06e03d883a330fc7bf0cb997c2041d86a358f793fe2f0fcd967ade" + }, + "arm64_big_sur": { + "cellar": "/opt/homebrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/graphviz/blobs/sha256:f43ff5e042bb74b1e5a5f005d2ecb7ed731886884d5c897b9a3f89881d68e511", + "sha256": "f43ff5e042bb74b1e5a5f005d2ecb7ed731886884d5c897b9a3f89881d68e511" + }, + "monterey": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/graphviz/blobs/sha256:1111378fa7618775b3263c211789f4995f07f02252a4464ed2ceb3c01708213c", + "sha256": "1111378fa7618775b3263c211789f4995f07f02252a4464ed2ceb3c01708213c" + }, + "big_sur": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/graphviz/blobs/sha256:59ab5de4deaad4b07149471b7013500e7595c9f6bdff0074e2339d3087aa78ed", + "sha256": "59ab5de4deaad4b07149471b7013500e7595c9f6bdff0074e2339d3087aa78ed" + }, + "catalina": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/graphviz/blobs/sha256:8bfb00c8e472b66a72f1c69ddc21abb8ba4891388d3c94b23000a3c0744704a0", + "sha256": "8bfb00c8e472b66a72f1c69ddc21abb8ba4891388d3c94b23000a3c0744704a0" + }, + "x86_64_linux": { + "cellar": "/home/linuxbrew/.linuxbrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/graphviz/blobs/sha256:293374d97d2af3bfb5a2d6cc6d21438b356943980f791bf0391c5d1db84bfb20", + "sha256": "293374d97d2af3bfb5a2d6cc6d21438b356943980f791bf0391c5d1db84bfb20" + } + } + } + }, + "jq": { + "version": "1.6", + "bottle": { + "rebuild": 1, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_monterey": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/jq/blobs/sha256:f70e1ae8df182b242ca004492cc0a664e2a8195e2e46f30546fe78e265d5eb87", + "sha256": "f70e1ae8df182b242ca004492cc0a664e2a8195e2e46f30546fe78e265d5eb87" + }, + "arm64_big_sur": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/jq/blobs/sha256:674b3ae41c399f1e8e44c271b0e6909babff9fcd2e04a2127d25e2407ea4dd33", + "sha256": "674b3ae41c399f1e8e44c271b0e6909babff9fcd2e04a2127d25e2407ea4dd33" + }, + "monterey": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/jq/blobs/sha256:7fee6ea327062b37d34ef5346a84810a1752cc7146fff1223fab76c9b45686e0", + "sha256": "7fee6ea327062b37d34ef5346a84810a1752cc7146fff1223fab76c9b45686e0" + }, + "big_sur": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/jq/blobs/sha256:bf0f8577632af7b878b6425476f5b1ab9c3bf66d65affb0c455048a173a0b6bf", + "sha256": "bf0f8577632af7b878b6425476f5b1ab9c3bf66d65affb0c455048a173a0b6bf" + }, + "catalina": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/jq/blobs/sha256:820a3c85fcbb63088b160c7edf125d7e55fc2c5c1d51569304499c9cc4b89ce8", + "sha256": "820a3c85fcbb63088b160c7edf125d7e55fc2c5c1d51569304499c9cc4b89ce8" + }, + "mojave": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/jq/blobs/sha256:71f0e76c5b22e5088426c971d5e795fe67abee7af6c2c4ae0cf4c0eb98ed21ff", + "sha256": "71f0e76c5b22e5088426c971d5e795fe67abee7af6c2c4ae0cf4c0eb98ed21ff" + }, + "high_sierra": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/jq/blobs/sha256:dffcffa4ea13e8f0f2b45c5121e529077e135ae9a47254c32182231662ee9b72", + "sha256": "dffcffa4ea13e8f0f2b45c5121e529077e135ae9a47254c32182231662ee9b72" + }, + "sierra": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/jq/blobs/sha256:bb4d19dc026c2d72c53eed78eaa0ab982e9fcad2cd2acc6d13e7a12ff658e877", + "sha256": "bb4d19dc026c2d72c53eed78eaa0ab982e9fcad2cd2acc6d13e7a12ff658e877" + }, + "x86_64_linux": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/jq/blobs/sha256:2beea2c2c372ccf1081e9a5233fc3020470803254284aeecc071249d76b62338", + "sha256": "2beea2c2c372ccf1081e9a5233fc3020470803254284aeecc071249d76b62338" + } + } + } + }, + "mr": { + "version": "1.20180726", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:1ef1fbe930aac818a5996a5280755f746d5595ed94a2d01ffe4c46d0aa066fb2", + "sha256": "1ef1fbe930aac818a5996a5280755f746d5595ed94a2d01ffe4c46d0aa066fb2" + }, + "arm64_big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:3acd961664e9d84ec19e6fa5044fc7b024bbfc691a3dc3d02a250d773abb6a18", + "sha256": "3acd961664e9d84ec19e6fa5044fc7b024bbfc691a3dc3d02a250d773abb6a18" + }, + "monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:a0f6609e5526c820741400527d23e96699e51490ec9b90c2759ddd0565773a58", + "sha256": "a0f6609e5526c820741400527d23e96699e51490ec9b90c2759ddd0565773a58" + }, + "big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:9b2f724c76a7b2a2504301eeb2dcd5d16d2b919e53fe7f43b404c79f56ce7c75", + "sha256": "9b2f724c76a7b2a2504301eeb2dcd5d16d2b919e53fe7f43b404c79f56ce7c75" + }, + "catalina": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:90ab23bd6811b507860b5ddcc7e9a181abd3f126fc2ab193739987d6d4b31612", + "sha256": "90ab23bd6811b507860b5ddcc7e9a181abd3f126fc2ab193739987d6d4b31612" + }, + "mojave": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:73c8b9b421ea776366f9ded68d90c6c3b75b50401172b5c5248556f6f7f47d6e", + "sha256": "73c8b9b421ea776366f9ded68d90c6c3b75b50401172b5c5248556f6f7f47d6e" + }, + "high_sierra": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:a41bcee5b050ec9f98cf5960a457421528b05773867d8c8dbb8eb32716e09fd5", + "sha256": "a41bcee5b050ec9f98cf5960a457421528b05773867d8c8dbb8eb32716e09fd5" + }, + "sierra": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:bcac4176692f69d47a83cd961cee92e096f6b35f19cb7206973f77b15a1ba71c", + "sha256": "bcac4176692f69d47a83cd961cee92e096f6b35f19cb7206973f77b15a1ba71c" + }, + "el_capitan": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:75fd9c6fbf6dcf833243e4dc9baf0afe81c422e55d3e251f5cfe040b8bc6a254", + "sha256": "75fd9c6fbf6dcf833243e4dc9baf0afe81c422e55d3e251f5cfe040b8bc6a254" + }, + "x86_64_linux": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/mr/blobs/sha256:fe1931dfcaf7fd8500a523287de75c9a492a187c1b45c51e8a8565f2d52db70d", + "sha256": "fe1931dfcaf7fd8500a523287de75c9a492a187c1b45c51e8a8565f2d52db70d" + } + } + } + }, + "rbenv": { + "version": "1.2.0", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_monterey": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/rbenv/blobs/sha256:dede9454bc8a665ac2b1858a0522fb77d95deebb5db7437918cfb056ff119b16", + "sha256": "dede9454bc8a665ac2b1858a0522fb77d95deebb5db7437918cfb056ff119b16" + }, + "arm64_big_sur": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/rbenv/blobs/sha256:d5e6168ad6ab8843946273319fc6949b322c80f2d666a6bdda62466e256e6746", + "sha256": "d5e6168ad6ab8843946273319fc6949b322c80f2d666a6bdda62466e256e6746" + }, + "monterey": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/rbenv/blobs/sha256:42657e04e2d1e8bf9abb9c5f0ba50e567df95f93a2a212491f005e4bd0ad9cee", + "sha256": "42657e04e2d1e8bf9abb9c5f0ba50e567df95f93a2a212491f005e4bd0ad9cee" + }, + "big_sur": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/rbenv/blobs/sha256:8a1b159909d472cc461d0a9b85a192a31ab58860e34f022fcbb33175732d24aa", + "sha256": "8a1b159909d472cc461d0a9b85a192a31ab58860e34f022fcbb33175732d24aa" + }, + "catalina": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/rbenv/blobs/sha256:a2ca52c4fe3b7000d9f84f81836ddcb9b3aea9c20ee092dd71c1e10cf3a6a19a", + "sha256": "a2ca52c4fe3b7000d9f84f81836ddcb9b3aea9c20ee092dd71c1e10cf3a6a19a" + }, + "mojave": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/rbenv/blobs/sha256:87ca53a9f4f84aff56ccbf2f823f903d20bc6669dde548018892857cc8871936", + "sha256": "87ca53a9f4f84aff56ccbf2f823f903d20bc6669dde548018892857cc8871936" + }, + "x86_64_linux": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/rbenv/blobs/sha256:f4be8e4efef32c1fcdaa585312b3262d33b3306d9d7d9c75abd1230227b10bb7", + "sha256": "f4be8e4efef32c1fcdaa585312b3262d33b3306d9d7d9c75abd1230227b10bb7" + } + } + } + }, + "haskell-stack": { + "version": "2.13.1", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_sonoma": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/haskell-stack/blobs/sha256:0426cc31adddad813c139f9fefddce55a6e614893f2c1052b3ae56c0a9958cb7", + "sha256": "0426cc31adddad813c139f9fefddce55a6e614893f2c1052b3ae56c0a9958cb7" + }, + "arm64_ventura": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/haskell-stack/blobs/sha256:3269aa3a8dcf82d1c8cbb8e362ed4609d99193611ece6ef0c00b1c820c9494f4", + "sha256": "3269aa3a8dcf82d1c8cbb8e362ed4609d99193611ece6ef0c00b1c820c9494f4" + }, + "arm64_monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/haskell-stack/blobs/sha256:f20bef09d83372ced23f7cf80a7174a70640da5f228729b1c8b4cff39ea6fa2c", + "sha256": "f20bef09d83372ced23f7cf80a7174a70640da5f228729b1c8b4cff39ea6fa2c" + }, + "sonoma": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/haskell-stack/blobs/sha256:5ec70b9dbe8c49239f6058f8ad647478a063e879ddf663c49be1d9623e11fd1f", + "sha256": "5ec70b9dbe8c49239f6058f8ad647478a063e879ddf663c49be1d9623e11fd1f" + }, + "ventura": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/haskell-stack/blobs/sha256:ece414965294e7d82b7c073cf3607822541cec6ae171360fbcd01cc18da91ef8", + "sha256": "ece414965294e7d82b7c073cf3607822541cec6ae171360fbcd01cc18da91ef8" + }, + "monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/haskell-stack/blobs/sha256:70b7031bd72c6c17ae139094c4471728a9d13d4e9b6141c7ac7818d39fd7fbf0", + "sha256": "70b7031bd72c6c17ae139094c4471728a9d13d4e9b6141c7ac7818d39fd7fbf0" + }, + "x86_64_linux": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/haskell-stack/blobs/sha256:ddcddb8cc82773695f1733fb34caef081a8cb6f9a953e847ae4b7d5c1984c590", + "sha256": "ddcddb8cc82773695f1733fb34caef081a8cb6f9a953e847ae4b7d5c1984c590" + } + } + } + }, + "cmake": { + "version": "3.25.2", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_ventura": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/cmake/blobs/sha256:9b84d2b9844ae326750b498d6143eba05ba90ba85e2413ff8bbba8df52b69cb7", + "sha256": "9b84d2b9844ae326750b498d6143eba05ba90ba85e2413ff8bbba8df52b69cb7" + }, + "arm64_monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/cmake/blobs/sha256:9c795988bd14da5691a246221bbadff427ef2bdabe213a7f97ad5e69b3f8a39e", + "sha256": "9c795988bd14da5691a246221bbadff427ef2bdabe213a7f97ad5e69b3f8a39e" + }, + "arm64_big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/cmake/blobs/sha256:cc74b5362b7fc2d4c51ba4ac5d0859bf0557ddeb4ac2a518522f31785af102f7", + "sha256": "cc74b5362b7fc2d4c51ba4ac5d0859bf0557ddeb4ac2a518522f31785af102f7" + }, + "ventura": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/cmake/blobs/sha256:f502d6ccb79b82ec25b2f4222c15d29e31fb906325ea80609d0e829ead9080f2", + "sha256": "f502d6ccb79b82ec25b2f4222c15d29e31fb906325ea80609d0e829ead9080f2" + }, + "monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/cmake/blobs/sha256:e08c954dfd2cd60b1275370d6e5bbc569af9480fb70c224f4aec44306f04cef4", + "sha256": "e08c954dfd2cd60b1275370d6e5bbc569af9480fb70c224f4aec44306f04cef4" + }, + "big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/cmake/blobs/sha256:6e98740a0ec57228faa96fbdeb0636c46577a9b5c5c803960513e9d16f4f0737", + "sha256": "6e98740a0ec57228faa96fbdeb0636c46577a9b5c5c803960513e9d16f4f0737" + }, + "x86_64_linux": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/cmake/blobs/sha256:6ab7740bbe65b3c5fa816e986a347007c8608083862735ad990d1497779a7d82", + "sha256": "6ab7740bbe65b3c5fa816e986a347007c8608083862735ad990d1497779a7d82" + } + } + } + }, + "pyenv": { + "version": "2.3.13", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_ventura": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/pyenv/blobs/sha256:beea55c96989f84f1b804b63f1612b0b899a0d4f2011f9ecfae4e73d90f92fc1", + "sha256": "beea55c96989f84f1b804b63f1612b0b899a0d4f2011f9ecfae4e73d90f92fc1" + }, + "arm64_monterey": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/pyenv/blobs/sha256:f0f23b8562cee015f0e8c69f73228638bbe78b57ee03a0bf67fc055f2f5fdf99", + "sha256": "f0f23b8562cee015f0e8c69f73228638bbe78b57ee03a0bf67fc055f2f5fdf99" + }, + "arm64_big_sur": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/pyenv/blobs/sha256:2b34ade9cfb53fff88a38df4e5713afed38ef1bc0ac106dc2aa882594055a5a0", + "sha256": "2b34ade9cfb53fff88a38df4e5713afed38ef1bc0ac106dc2aa882594055a5a0" + }, + "ventura": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/pyenv/blobs/sha256:35b2d29269ba890bea675e95ed110a76efd97ce85c5bf06ab1453216d2a38dce", + "sha256": "35b2d29269ba890bea675e95ed110a76efd97ce85c5bf06ab1453216d2a38dce" + }, + "monterey": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/pyenv/blobs/sha256:11c51f2f20084cbf5d022077712245a4cb89779e0a4f982a5f0002991512b4d2", + "sha256": "11c51f2f20084cbf5d022077712245a4cb89779e0a4f982a5f0002991512b4d2" + }, + "big_sur": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/pyenv/blobs/sha256:be30d5ce494bec31c5ec01126b47867abfa9fda59753d438c0260a683af157d3", + "sha256": "be30d5ce494bec31c5ec01126b47867abfa9fda59753d438c0260a683af157d3" + }, + "x86_64_linux": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/pyenv/blobs/sha256:78c314a1fe30a8df290b30ebe008f03c38099515f8c11feca506f273b2a3a2cf", + "sha256": "78c314a1fe30a8df290b30ebe008f03c38099515f8c11feca506f273b2a3a2cf" + } + } + } + }, + "bitwarden-cli": { + "version": "2023.2.0", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_ventura": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/bitwarden-cli/blobs/sha256:6fb370700737923d21f8cfc9e64efcd7959648834eafe0fdac00131f490fce5f", + "sha256": "6fb370700737923d21f8cfc9e64efcd7959648834eafe0fdac00131f490fce5f" + }, + "arm64_monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/bitwarden-cli/blobs/sha256:68f3e1e1a739d837c6701a2658f4a29f15b9593a8a788e89cf8734ff150ad474", + "sha256": "68f3e1e1a739d837c6701a2658f4a29f15b9593a8a788e89cf8734ff150ad474" + }, + "arm64_big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/bitwarden-cli/blobs/sha256:230d1faae76e7d8f409e30184ff8697c464fac4b8f73a2277d9044042550a56c", + "sha256": "230d1faae76e7d8f409e30184ff8697c464fac4b8f73a2277d9044042550a56c" + }, + "ventura": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/bitwarden-cli/blobs/sha256:eccfec7c0b0a9f4fb94c36189d9c0cb2d2383fbc77d6f97af2f07a38a8048e7f", + "sha256": "eccfec7c0b0a9f4fb94c36189d9c0cb2d2383fbc77d6f97af2f07a38a8048e7f" + }, + "monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/bitwarden-cli/blobs/sha256:063ebded1451260c2e38652b98f5a49316da1201b28049b8802f2f449f7c9567", + "sha256": "063ebded1451260c2e38652b98f5a49316da1201b28049b8802f2f449f7c9567" + }, + "big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/bitwarden-cli/blobs/sha256:6f16d56d5d845d43eca130dcb876162ad1cba9224b4c4a69b523dfc03ed69400", + "sha256": "6f16d56d5d845d43eca130dcb876162ad1cba9224b4c4a69b523dfc03ed69400" + }, + "x86_64_linux": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/bitwarden-cli/blobs/sha256:25db80452b26cd7a7f0651de1898faa24a0d96346de6c1cb9012811741a4048a", + "sha256": "25db80452b26cd7a7f0651de1898faa24a0d96346de6c1cb9012811741a4048a" + } + } + } + }, + "wget": { + "version": "1.21.3_1", + "bottle": { + "rebuild": 1, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_ventura": { + "cellar": "/opt/homebrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/wget/blobs/sha256:7415a3b847237e0a981f2df42761578d6b6b285361c450c010219355bd1c0df2", + "sha256": "7415a3b847237e0a981f2df42761578d6b6b285361c450c010219355bd1c0df2" + }, + "arm64_monterey": { + "cellar": "/opt/homebrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/wget/blobs/sha256:ed959d9bd75bfac18aa823bd62c8e5f4736174fd183aee9ebaa913d0810dea36", + "sha256": "ed959d9bd75bfac18aa823bd62c8e5f4736174fd183aee9ebaa913d0810dea36" + }, + "arm64_big_sur": { + "cellar": "/opt/homebrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/wget/blobs/sha256:42233b960709325f6e4ec479eb1786379e1b3757b4b7641bdbbd8e6a058e1013", + "sha256": "42233b960709325f6e4ec479eb1786379e1b3757b4b7641bdbbd8e6a058e1013" + }, + "ventura": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/wget/blobs/sha256:0915596ebf9426fc9aad9307a6813ba35ac860e9dfa755741a23e9d446ac3b93", + "sha256": "0915596ebf9426fc9aad9307a6813ba35ac860e9dfa755741a23e9d446ac3b93" + }, + "monterey": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/wget/blobs/sha256:f97fc2639cd9d2d037c2bf1a94fa664ef2d81143ce8a1fb5b740ce2eb397889c", + "sha256": "f97fc2639cd9d2d037c2bf1a94fa664ef2d81143ce8a1fb5b740ce2eb397889c" + }, + "big_sur": { + "cellar": "/usr/local/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/wget/blobs/sha256:f85c6720bdabd86db32dd54837f577b709bc5de98896622a19f698f8a14e604f", + "sha256": "f85c6720bdabd86db32dd54837f577b709bc5de98896622a19f698f8a14e604f" + }, + "x86_64_linux": { + "cellar": "/home/linuxbrew/.linuxbrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/wget/blobs/sha256:738ec27b5b39877b8004096d9c3edd04ff814e18dd6f6afca89a2f5b4eeedcac", + "sha256": "738ec27b5b39877b8004096d9c3edd04ff814e18dd6f6afca89a2f5b4eeedcac" + } + } + } + } + }, + "cask": { + "hammerspoon": { + "version": "0.9.100", + "options": { + "full_name": "hammerspoon" + } + }, + "firefox-developer-edition": { + "version": "latest", + "options": { + "full_name": "firefox-developer-edition" + } + }, + "dropbox": { + "version": "194.4.6267", + "options": { + "full_name": "dropbox" + } + }, + "slack": { + "version": "4.37.94", + "options": { + "full_name": "slack" + } + }, + "spotify": { + "version": "1.2.33.1039,8ddb5918,3051", + "options": { + "full_name": "spotify" + } + }, + "racket": { + "version": "8.12", + "options": { + "full_name": "racket" + } + } + } + }, + "system": { + "macos": { + "big_sur": { + "HOMEBREW_VERSION": "4.0.3-9-g7e48ed5", + "HOMEBREW_PREFIX": "/usr/local", + "Homebrew/homebrew-core": "api", + "CLT": "12.5.1.0.1.1623191612", + "Xcode": "12.5.1", + "macOS": "11.6.1" + }, + "monterey": { + "HOMEBREW_VERSION": "4.2.1-30-gf3c687e", + "HOMEBREW_PREFIX": "/usr/local", + "Homebrew/homebrew-core": "api", + "CLT": "14.2.0.0.1.1668646533", + "Xcode": "14.2", + "macOS": "12.6.5" + }, + "sonoma": { + "HOMEBREW_VERSION": "4.2.13", + "HOMEBREW_PREFIX": "/usr/local", + "Homebrew/homebrew-core": "api", + "CLT": "15.1.0.0.1.1700200546", + "Xcode": "15.1", + "macOS": "14.3.1" + } + } + } +} diff --git a/ws_tool/my_config/dotfiles/README.md b/ws_tool/my_config/dotfiles/README.md new file mode 100644 index 00000000..06d23ea6 --- /dev/null +++ b/ws_tool/my_config/dotfiles/README.md @@ -0,0 +1,7 @@ +this directory contains a variety of configuration/"dotfiles" +many of them are simply symlinked into their destinations + +some are used in other ways (for example, doom.d directory used with nix) + +symlinking is done with the bin/link-dotfiles.sh script, see it for details on +how that is handled diff --git a/ws_tool/my_config/dotfiles/bashrc b/ws_tool/my_config/dotfiles/bashrc new file mode 100644 index 00000000..4754f4d6 --- /dev/null +++ b/ws_tool/my_config/dotfiles/bashrc @@ -0,0 +1,136 @@ +#!/usr/bin/env bash +export BASH_SILENCE_DEPRECATION_WARNING=1 + +sourceIfExists () { + if [ -f "$1" ]; then + source "$1" + fi +} +if [[ -x "/opt/homebrew/bin/brew" ]]; then + eval "$(/opt/homebrew/bin/brew shellenv)" +fi + +export WORKSTATION_DIR="${WORKSTATION_DIR:-~/workstation}" + +sourceIfExists ${WORKSTATION_DIR}/lib/shell/settings.sh +sourceIfExists ${WORKSTATION_DIR}/lib/shell/paths.sh +sourceIfExists ${WORKSTATION_DIR}/hosts/current/zshrc.sh + + +export EDITOR=emacsclient +export GIT_EDITOR=$EDITOR + +export LANG=en_US.UTF-8 + +export HISTCONTROL=erasedups +export HISTSIZE=10000 +export HISTCONTROL=ignoreboth +export HISTFILESIZE=2000 + +do_command_done_alert() { + osascript -e 'display dialog "Command Done!"' +} + +alert_when_done() { + if test -n "$1"; + then + while kill -0 $1 + do + sleep 1 + done + fi + do_command_done_alert +} +export C_INCLUDE_PATH +C_INCLUDE_PATH="$(xcrun --show-sdk-path)/usr/include/ffi:/opt/homebrew/Cellar/pcre/8.45/include:$C_INCLUDE_PATH" +C_INCLUDE_PATH="/opt/homebrew/Cellar/librdkafka/2.3.0/include:$C_INCLUDE_PATH" +C_INCLUDE_PATH="/opt/homebrew/Cellar/zstd/1.5.5/include:$C_INCLUDE_PATH" +C_INCLUDE_PATH="/opt/homebrew/Cellar/openssl@3/3.2.1/include/openssl:$C_INCLUDE_PATH" +C_INCLUDE_PATH="/opt/homebrew/Cellar/mysql-client@8.0/8.0.36/include/mysql-client:$C_INCLUDE_PATH" +# export C_INCLUDE_PATH="/opt/homebrew/opt/mysql-client/include:$C_INCLUDE_PATH" + +export C_LIBRARY_PATH="/opt/homebrew/Cellar/librdkafka/2.3.0/lib:$C_LIBRARY_PATH" +export C_LIBRARY_PATH="/opt/homebrew/Cellar/zstd/1.5.5/lib:$C_LIBRARY_PATH" +export C_LIBRARY_PATH="/opt/homebrew/Cellar/openssl@3/3.2.1/lib:$C_LIBRARY_PATH" +export C_LIBRARY_PATH="/opt/homebrew/Cellar/mysql-client@8.0/8.0.36/lib:$C_LIBRARY_PATH" +# export C_LIBRARY_PATH="/opt/homebrew/opt/mysql-client/lib:$C_LIBRARY_PATH" + + +export INCLUDE_PATH="$C_INCLUDE_PATH:$INCLUDE_PATH" +export LIBRARY_PATH="$C_LIBRARY_PATH:$LIBRARY_PATH" +export LD_LIBRARY_PATH="$C_LIBRARY_PATH:$LD_LIBRARY_PATH" + +export NVM_DIR="$HOME/.nvm" + +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm + +# >>> conda initialize >>> +# !! Contents within this block are managed by 'conda init' !! +# __conda_setup="$('/opt/homebrew/Caskroom/miniforge/base/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)" +# if [ $? -eq 0 ]; then +# eval "$__conda_setup" +# else +# if [ -f "/opt/homebrew/Caskroom/miniforge/base/etc/profile.d/conda.sh" ]; then +# . "/opt/homebrew/Caskroom/miniforge/base/etc/profile.d/conda.sh" +# else +# export PATH="/opt/homebrew/Caskroom/miniforge/base/bin:$PATH" +# fi +# fi +# unset __conda_setup +# # <<< conda initialize <<< + + + +# To use the bundled libc++ please add the following LDFLAGS: +# LDFLAGS="-L/opt/homebrew/opt/llvm@13/lib/c++ -Wl,-rpath,/opt/homebrew/opt/llvm@13/lib/c++" + +# llvm@13 is keg-only, which means it was not symlinked into /opt/homebrew, +# because this is an alternate version of another formula. + +export PATH="/opt/homebrew/opt/llvm@13/bin:$PATH" +export LDFLAGS="-L/opt/homebrew/opt/llvm@13/lib -L/opt/homebrew/opt/mysql-client@8.0/lib -L/opt/homebrew/opt/libffi/lib" +export CPPFLAGS="-I/opt/homebrew/opt/llvm@13/include -I/opt/homebrew/opt/mysql-client@8.0/include -I/opt/homebrew/opt/libffi/include" +export PKG_CONFIG_PATH="/opt/homebrew/opt/mysql-client@8.0/lib/pkgconfig" + +export PATH="$HOME/.local/bin:$PATH" +export MANPATH="$HOME/.local/share/man:$MANPATH" + +export HISTSIZE=1000 +export SAVEHIST=10000 +export CFLAGS="-arch arm64 ${CFLAGS:-}" + +if [[ -n "$BASH_VERSION" ]]; then + # bash specific settings + shopt -s checkwinsize + shopt -s histappend +fi + +[ -f "/Users/joel.mccraken/.ghcup/env" ] && . "/Users/joel.mccraken/.ghcup/env" # ghcup-env + +# export WORKSTATION_DIR=~/workstation2 +# source ~/workstation2/dotfiles/zshrc +[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion + +export COLUMNS="120" + +export PATH="$PATH:/Users/joel.mccraken/.config/ACLI" + +. ~/freckle/jnm/bin/freckle.bash + + +# added by Snowflake SnowSQL installer v1.2 +export PATH=/Applications/SnowSQL.app/Contents/MacOS:$PATH + +export COLUMNS="120" + +export PATH="$PATH:/Users/joel.mccraken/.config/ACLI" + + +export FR_DOCKERHOST=host.docker.internal + +sourceIfExists /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh +sourceIfExists ~/.nix-profile/etc/profile.d/hm-session-vars.sh +sourceIfExists ~/workstation/lib/shell/funcs.sh +sourceIfExists ~/.ghcup/env + +sourceIfExists ${WORKSTATION_DIR}/lib/shell/funcs.sh diff --git a/ws_tool/my_config/dotfiles/bitbar/ejector.5s.sh b/ws_tool/my_config/dotfiles/bitbar/ejector.5s.sh new file mode 100755 index 00000000..ce99ca1c --- /dev/null +++ b/ws_tool/my_config/dotfiles/bitbar/ejector.5s.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# +# Ejector +# v1.1 +# Carlson Orozco +# carlsonorozco +# Ejector is a plugin for BitBar that enables you to eject all mounted disk / drive / installers / USB connected drives and volumes instantly. +# https://raw.githubusercontent.com/carlsonorozco/ejector/master/image.png +# https://github.com/carlsonorozco/ejector + +drives=( $(df -Hl | grep /Volumes/ | sed 's/.*\/Volumes\/*//') ) + +if [ "$1" = 'eject' ]; then + status=$(diskutil eject "$2" | sed -e 's/\/Volumes\///g') + if [ "$status" = "" ]; then + osascript -e "display notification \"Disk $2 failed to eject\" with title \"Ejector\"" + else + osascript -e "display notification \"$status\" with title \"Ejector\"" + fi + + exit +fi + +if [ "$1" = 'ejectall' ]; then + if [ -z "$2" ]; then + osascript -e ' + try + tell application "Finder" + eject the disks + display notification "Successfully ejected disks." with title "Ejector" + end tell + on error + display notification "Unable to eject all disks." with title "Ejector" + end try' + + exit + fi + + protocol_type=$2 + protocol_type="${protocol_type/dmgs/Disk Image}" + protocol_type="${protocol_type/usbs/USB}" + + IFS=$'**********' + for details in $( diskutil info -all ); do + name=$(echo "$details" | grep "Volume Name:" | sed 's/.*Volume Name:[[:space:]]*//') + ! [[ ${drives[@]} =~ $name ]] && continue + protocol=$(echo "$details" | grep "Protocol:" | sed 's/.*Protocol:[[:space:]]*//') + mount_point=$(echo "$details" | grep "Mount Point:" | sed 's/.*Mount Point:[[:space:]]*//') + [[ "$protocol_type" = "$protocol" ]] && ./"$0" eject "$mount_point" + done + exit +fi + +total_dmg=0 +total_usb=0 + +if [ ${#drives[@]} = 0 ]; then + echo "⏏ | color=gray" + exit +fi + +echo "⏏ | color=black" +echo '---' + +IFS=$'**********' +for details in $( diskutil info -all ); do + name=$(echo "$details" | grep "Volume Name:" | sed 's/.*Volume Name:[[:space:]]*//') + ! [[ ${drives[@]} =~ $name ]] && continue + + mount_point=$(echo "$details" | grep "Mount Point:" | sed 's/.*Mount Point:[[:space:]]*//') + free_space=$(echo "$details" | grep "Volume Free Space:" | sed 's/.*Volume Free Space:[[:space:]]*//' | cut -d ' ' -f -2) + total_size=$(echo "$details" | grep "Total Size:" | sed 's/.*Total Size:[[:space:]]*//' | cut -d ' ' -f -2) + protocol=$(echo "$details" | grep "Protocol:" | sed 's/.*Protocol:[[:space:]]*//') + + [[ $protocol = 'Disk Image' ]] && ((total_dmg++)) + [[ $protocol = 'USB' ]] && ((total_usb++)) + + echo "$name | color=black bash=$0 param1=eject param2=$mount_point terminal=false" + echo "├─ Available: $free_space" + echo "└─ Capacity: $total_size" +done + +if [ ${#drives[@]} -ge 2 ]; then + echo '---' + [ $((total_dmg)) -ge 2 ] && echo "Eject All Disk Images | color=red bash=$0 param1=ejectall param2=dmgs terminal=false" + [ $((total_usb)) -ge 2 ] && echo "Eject All Physical Volumes | color=red bash=$0 param1=ejectall param2=usbs terminal=false" + echo "Eject All | color=red bash=$0 param1=ejectall terminal=false" +fi \ No newline at end of file diff --git a/ws_tool/my_config/dotfiles/bitbar/pomodoro.1s.sh b/ws_tool/my_config/dotfiles/bitbar/pomodoro.1s.sh new file mode 100755 index 00000000..50a0e867 --- /dev/null +++ b/ws_tool/my_config/dotfiles/bitbar/pomodoro.1s.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# +# Pomodoro Timer +# v1.0 +# Goran Gajic +# gorangajic +# Pomodoro Timer that uses Pomodoro Technique™ +# http://i.imgur.com/T0zFY89.png + +WORK_TIME=25 +BREAK_TIME=5 + +SAVE_LOCATION=$TMPDIR/bitbar-promodo +TOMATO='🍅' + +WORK_TIME_IN_SECONDS=$((WORK_TIME * 60)) +BREAK_TIME_IN_SECONDS=$((BREAK_TIME * 60)) + +CURRENT_TIME=$(date +%s) + +if [ -f "$SAVE_LOCATION" ]; +then + DATA=$(cat "$SAVE_LOCATION") + +else + DATA="$CURRENT_TIME|0" +fi + +TIME=$(echo "$DATA" | cut -d "|" -f1) +STATUS=$(echo "$DATA" | cut -d "|" -f2) + +function changeStatus { + echo "$CURRENT_TIME|$1" > "$SAVE_LOCATION"; + osascript -e "display notification \"$2\" with title \"$TOMATO Pomodoro\" sound name \"$3\"" &> /dev/null +} + +function breakMode { + changeStatus "2" "Break Mode" "Glass" +} + +function workMode { + changeStatus "1" "Work (CLOSE DISTRACTIONS)" "Blow" +} + +case "$1" in +"work") + workMode + exit + ;; +"break") + breakMode + exit + ;; +"disable") + changeStatus "0" "Disabled" + exit + ;; +esac + + + +function timeLeft { + local FROM=$1 + local TIME_DIFF=$((CURRENT_TIME - TIME)) + local TIME_LEFT=$((FROM - TIME_DIFF)) + echo "$TIME_LEFT"; +} + +function getSeconds { + echo $(($1 % 60)) +} + +function getMinutes { + echo $(($1 / 60)) +} + +function printTime { + SECONDS=$(getSeconds "$1") + MINUTES=$(getMinutes "$1") + printf "%s %02d:%02d| color=%s\n" "$TOMATO" "$MINUTES" "$SECONDS" "$2" +} + +case "$STATUS" in +# STOP MODE +"0") + echo "$TOMATO" + ;; +"1") + TIME_LEFT=$(timeLeft $WORK_TIME_IN_SECONDS) + if (( "$TIME_LEFT" < 0 )); then + breakMode + else + afplay -v '.5' /System/Library/Sounds/Tink.aiff & + fi + printTime "$TIME_LEFT" "red" + ;; +"2") + TIME_LEFT=$(timeLeft $BREAK_TIME_IN_SECONDS) + if (("$TIME_LEFT" < 0)); then + changeStatus "0" "break is over" "Blow" + # workMode + fi + printTime "$TIME_LEFT" "green" + ;; +esac + +echo "---"; +echo "👔 Work | bash=$0 param1=work terminal=false" +echo "☕ Break | bash=$0 param1=break terminal=false" +echo "🔌 Disable | bash=$0 param1=disable terminal=false" diff --git a/ws_tool/my_config/dotfiles/bitbar/status.5s.rb b/ws_tool/my_config/dotfiles/bitbar/status.5s.rb new file mode 100755 index 00000000..7b2583a8 --- /dev/null +++ b/ws_tool/my_config/dotfiles/bitbar/status.5s.rb @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby + + +number=`cat ~/.redd-up/cache | wc -l`.strip + +puts "Issues: #{number} | color=red" +puts "---" +puts "Open dired cleanup | bash=/Users/joel/bin/emacs-process-inbox terminal=true" + +puts `~/bin/status` diff --git a/ws_tool/my_config/dotfiles/config/doom/config.el b/ws_tool/my_config/dotfiles/config/doom/config.el new file mode 100644 index 00000000..74f63a5f --- /dev/null +++ b/ws_tool/my_config/dotfiles/config/doom/config.el @@ -0,0 +1,169 @@ +;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- + +;; Place your private configuration here! Remember, you do not need to run 'doom +;; sync' after modifying this file! + + +;; Some functionality uses this to identify you, e.g. GPG configuration, email +;; clients, file templates and snippets. +;; (setq no-native-compile t) + +(setq user-full-name "Joel McCracken" + user-mail-address "mccraken.joel@gmail.com") + +(setq haskell-stylish-on-save t) + +;; Doom exposes five (optional) variables for controlling fonts in Doom. Here +;; are the three important ones: +;; +;; + `doom-font' +;; + `doom-variable-pitch-font' +;; + `doom-big-font' -- used for `doom-big-font-mode'; use this for +;; presentations or streaming. +;; +;; They all accept either a font-spec, font string ("Input Mono-12"), or xlfd +;; font string. You generally only need these two: +;; (setq doom-font (font-spec :family "monospace" :size 12 :weight 'semi-light) +;; doom-variable-pitch-font (font-spec :family "sans" :size 13)) + +;; There are two ways to load a theme. Both assume the theme is installed and +;; available. You can either set `doom-theme' or manually load a theme with the +;; `load-theme' function. This is the default: +(setq doom-theme 'doom-one) + +;; This determines the style of line numbers in effect. If set to `nil', line +;; numbers are disabled. For relative line numbers, set this to `relative'. +(setq display-line-numbers-type t) + +;; If you use `org' and don't want your org files in the default location below, +;; change `org-directory'. It must be set before org loads! +;; (setq org-directory "~/freckle/notes/") +(setq org-directory "/Volumes/Personal/EF") + +(setq workstation-config-path + (concat (or (getenv "WORKSTATION_DIR") + "~/workstation") + "/hosts/current/config.el")) + +(when (file-exists-p workstation-config-path) + (load workstation-config-path)) + +(defun jnm/ef-ssh-belthronding () + "open EF via ssh on belthronding" + (interactive) + ;; (find-file "/ssh:joel@belthronding.wildkraken.monster:~/EF/") + (find-file "/ssh:joel@137.184.110.5:~/EF/") ;; + ) + +(map! "C-c e" #'jnm/ef-ssh-belthronding) +(map! "C-c d" #'org-timestamp-inactive) + +;; (map! :leader "SPC" +;; :n "SPC SPC e" #'jnm/ef-ssh-belthronding) + +(after! +popup + ;; added here to change the behavior of *info* buffers (set :quit to nil) + (set-popup-rules! + '(("^\\*Completions" :ignore t) + ("^\\*Local variables\\*$" + :vslot -1 :slot 1 :size +popup-shrink-to-fit) + ("^\\*\\(?:[Cc]ompil\\(?:ation\\|e-Log\\)\\|Messages\\)" + :vslot -2 :size 0.3 :autosave t :quit t :ttl nil) + ("^\\*\\(?:doom \\|Pp E\\)" ; transient buffers (no interaction required) + :vslot -3 :size +popup-shrink-to-fit :autosave t :select ignore :quit t :ttl 0) + ("^\\*doom:" ; editing buffers (interaction required) + :vslot -4 :size 0.35 :autosave t :select t :modeline t :quit nil :ttl t) + ("^\\*doom:\\(?:v?term\\|e?shell\\)-popup" ; editing buffers (interaction required) + :vslot -5 :size 0.35 :select t :modeline nil :quit nil :ttl nil) + ("^\\*\\(?:Wo\\)?Man " + :vslot -6 :size 0.45 :select t :quit t :ttl 0) + ("^\\*Calc" + :vslot -7 :side bottom :size 0.4 :select t :quit nil :ttl 0) + ("^\\*Customize" + :slot 2 :side right :size 0.5 :select t :quit nil) + ("^ \\*undo-tree\\*" + :slot 2 :side left :size 20 :select t :quit t) + ;; `help-mode', `helpful-mode' + ("^\\*\\([Hh]elp\\|Apropos\\)" + :slot 2 :vslot -8 :size 0.42 :select t) + ("^\\*eww\\*" ; `eww' (and used by dash docsets) + :vslot -11 :size 0.35 :select t) + ("^\\*xwidget" + :vslot -11 :size 0.35 :select nil) + ("^\\*info\\*$" ; `Info-mode' + :slot 2 :vslot 2 :size 0.45 :select t :quit nil)) + '(("^\\*Warnings" :vslot 99 :size 0.25) + ("^\\*Backtrace" :vslot 99 :size 0.4 :quit nil) + ("^\\*CPU-Profiler-Report " :side bottom :vslot 100 :slot 1 :height 0.4 :width 0.5 :quit nil) + ("^\\*Memory-Profiler-Report " :side bottom :vslot 100 :slot 2 :height 0.4 :width 0.5 :quit nil) + ("^\\*Process List\\*" :side bottom :vslot 101 :size 0.25 :select t :quit t) + ("^\\*\\(?:Proced\\|timer-list\\|Abbrevs\\|Output\\|Occur\\|unsent mail.*?\\|message\\)\\*" :ignore t)))) + +(after! org + (setq org-agenda-custom-commands + '(("p" "Projects" tags "+CATEGORY=\"PROJ\"+LEVEL=1") + ("a" "Actions" tags "+TODO=\"TODO\"|+TODO=\"LOOP\""))) + + (setq +org-capture-notes-file "inbox.org") + + (add-hook 'org-mode-hook 'turn-on-auto-fill) + + (setq org-src-preserve-indentation t) + (setq org-adapt-indentation t) + (setq org-startup-indented t)) + +;; This determines the style of line numbers in effect. If set to `nil', line +;; numbers are disabled. For relative line numbers, set this to `relative'. +(setq display-line-numbers-type t) + +(setq global-flycheck-mode nil) + +(load-theme 'tsdh-light) + +;; (setq twelf-root "~/vendor/twelf/") +;; (load (concat twelf-root "emacs/twelf-init.el")) + + +;; (add-to-list 'load-path "~/Projects/shen-elisp/") +;; (require 'shen-elisp) +;; (require 'shen-repl) +;; (setq org-src-preserve-indentation nil) + +;; Here are some additional functions/macros that could help you configure Doom: +;; +;; - `load!' for loading external *.el files relative to this one +;; - `use-package!' for configuring packages +;; - `after!' for running code after a package has loaded +;; - `add-load-path!' for adding directories to the `load-path', relative to +;; this file. Emacs searches the `load-path' when you load packages with +;; `require' or `use-package'. +;; - `map!' for binding new keys +;; +;; To get information about any of these functions/macros, move the cursor over +;; the highlighted symbol at press 'K' (non-evil users must press 'C-c c k'). +;; This will open documentation for it, including demos of how they are used. +;; +;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how +;; they are implemented. +(setq safe-local-variable-values + '((lsp-haskell-server-path . "~/bin/haskell-language-server-macOS-8.8.4") + (lsp-haskell-formatting-provider . "stylish-haskell") + (lsp-enable-file-watchers . t) + (lsp-file-watch-threshold . 2000) + (org-babel-noweb-wrap-start . "«") + (org-babel-noweb-wrap-end . "»") + (org-src-preserve-indentation) + (eval progn + (make-local-variable 'projectile-make-test-cmd) + (setq projectile-ruby-test-cmd "rake")) + (eval message "starting yaml-mode") + (eval message "hello there") + (eval progn + (let* + ((load-path + (cons + (locate-dominating-file default-directory "ef.el") + load-path))) + (require 'ef))) + (jnm/in-ef-dir . t) + (ef/files "actions.org" "projects-maintenance.org" "projects.org" "upcoming.org" "waiting.org"))) diff --git a/ws_tool/my_config/dotfiles/config/doom/custom.el b/ws_tool/my_config/dotfiles/config/doom/custom.el new file mode 100644 index 00000000..be34967a --- /dev/null +++ b/ws_tool/my_config/dotfiles/config/doom/custom.el @@ -0,0 +1,12 @@ +(custom-set-variables + ;; custom-set-variables was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(magit-todos-insert-after '(bottom) nil nil "Changed by setter of obsolete option `magit-todos-insert-at'")) +(custom-set-faces + ;; custom-set-faces was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + ) diff --git a/ws_tool/my_config/dotfiles/config/doom/init.el b/ws_tool/my_config/dotfiles/config/doom/init.el new file mode 100644 index 00000000..ca282a6f --- /dev/null +++ b/ws_tool/my_config/dotfiles/config/doom/init.el @@ -0,0 +1,202 @@ +;;; init.el -*- lexical-binding: t; -*- + +;; This file controls what Doom modules are enabled and what order they load +;; in. Remember to run 'doom sync' after modifying it! + +;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's +;; documentation. There you'll find a "Module Index" link where you'll find +;; a comprehensive list of Doom's modules and what flags they support. + +;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or +;; 'C-c c k' for non-vim users) to view its documentation. This works on +;; flags as well (those symbols that start with a plus). +;; +;; Alternatively, press 'gd' (or 'C-c c d') on a module to browse its +;; directory (for easy access to its source code). + +(doom! :input + ;;bidi ; (tfel ot) thgir etirw uoy gnipleh + ;;chinese + ;;japanese + ;;layout ; auie,ctsrnm is the superior home row + + :completion + company ; the ultimate code completion backend + ;; helm ; the *other* search engine for love and life + ;; ido ; the other *other* search engine... + ;; NOTE: I switched from vertico to ivy completion becuase of a + ;; bug that seems to be in the search code for vertico. + ;; no idea when it may get resolved + ; ivy ; a search engine for love and life + vertico ; the search engine of the future + + :ui + ;;deft ; notational velocity for Emacs + doom ; what makes DOOM look the way it does + doom-dashboard ; a nifty splash screen for Emacs + ;; doom-quit ; DOOM quit-message prompts when you quit Emacs + ;;(emoji +unicode) ; 🙂 + hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW + ;;hydra + indent-guides ; highlighted indent columns + ;;ligatures ; ligatures and symbols to make your code pretty again + ;;minimap ; show a map of the code on the side + modeline ; snazzy, Atom-inspired modeline, plus API + ;;nav-flash ; blink cursor line after big motions + ;;neotree ; a project drawer, like NERDTree for vim + ophints ; highlight the region an operation acts on + popup + ; (popup +defaults) ; tame sudden yet inevitable temporary windows + ;;tabs ; a tab bar for Emacs + ;;treemacs ; a project drawer, like neotree but cooler + ;;unicode ; extended unicode support for various languages + (vc-gutter +pretty) ; vcs diff in the fringe + vi-tilde-fringe ; fringe tildes to mark beyond EOB + ;;window-select ; visually switch windows + workspaces ; tab emulation, persistence & separate workspaces + ;;zen ; distraction-free coding or writing + + :editor + (evil +everywhere); come to the dark side, we have cookies + file-templates ; auto-snippets for empty files + fold ; (nigh) universal code folding + ;;(format +onsave) ; automated prettiness + ;;god ; run Emacs commands without modifier keys + ;;lispy ; vim for lisp, for people who don't like vim + ;;multiple-cursors ; editing in many places at once + ;;objed ; text object editing for the innocent + ;;parinfer ; turn lisp into python, sort of + ;;rotate-text ; cycle region at point between text candidates + snippets ; my elves. They type so I don't have to + ;;word-wrap ; soft wrapping with language-aware indent + + :emacs + dired ; making dired pretty [functional] + electric ; smarter, keyword-based electric-indent + ;;ibuffer ; interactive buffer management + undo ; persistent, smarter undo for your inevitable mistakes + vc ; version-control and Emacs, sitting in a tree + + :term + eshell ; the elisp shell that works everywhere + ;;shell ; simple shell REPL for Emacs + ;;term ; basic terminal emulator for Emacs + vterm ; the best terminal emulation in Emacs + + :checkers + syntax ; tasing you for every semicolon you forget + ;;(spell +flyspell) ; tasing you for misspelling mispelling + ;;grammar ; tasing grammar mistake every you make + + :tools + ;;ansible + ;;biblio ; Writes a PhD for you (citation needed) + ;;collab ; buffers with friends + ;;debugger ; FIXME stepping through code, to help you add bugs + ;;direnv + ;;docker + ;;editorconfig ; let someone else argue about tabs vs spaces + ;;ein ; tame Jupyter notebooks with emacs + (eval +overlay) ; run code, run (also, repls) + ;;gist ; interacting with github gists + lookup ; navigate your code and its documentation + lsp ; M-x vscode + magit ; a git porcelain for Emacs + ;;make ; run make tasks from Emacs + ;;pass ; password manager for nerds + ;;pdf ; pdf enhancements + ;;prodigy ; FIXME managing external services & code builders + ;;rgb ; creating color strings + ;;taskrunner ; taskrunner for all your projects + ;;terraform ; infrastructure as code + ;;tmux ; an API for interacting with tmux + tree-sitter ; syntax and parsing, sitting in a tree... + ;;upload ; map local to remote projects via ssh/ftp + + :os + ;; (:if (featurep :system 'macos) macos) ; improve compatibility with macOS + (:if IS-MAC macos) ; improve compatibility with macOS + ;;tty ; improve the terminal Emacs experience + + :lang + ;;agda ; types of types of types of types... + ;;beancount ; mind the GAAP + ;;(cc +lsp) ; C > C++ == 1 + ;;clojure ; java with a lisp + ;;common-lisp ; if you've seen one lisp, you've seen them all + ;;coq ; proofs-as-programs + ;;crystal ; ruby at the speed of c + ;;csharp ; unity, .NET, and mono shenanigans + ;;data ; config/data formats + ;;(dart +flutter) ; paint ui and not much else + ;;dhall + ;;elixir ; erlang done right + ;;elm ; care for a cup of TEA? + emacs-lisp ; drown in parentheses + ;;erlang ; an elegant language for a more civilized age + ;;ess ; emacs speaks statistics + ;;factor + ;;faust ; dsp, but you get to keep your soul + ;;fortran ; in FORTRAN, GOD is REAL (unless declared INTEGER) + ;;fsharp ; ML stands for Microsoft's Language + ;;fstar ; (dependent) types and (monadic) effects and Z3 + ;;gdscript ; the language you waited for + ;;(go +lsp) ; the hipster dialect + ;;(graphql +lsp) ; Give queries a REST + (haskell ;; +lsp + ) ; +dante a language that's lazier than I am + ;;hy ; readability of scheme w/ speed of python + ;;idris ; a language you can depend on + json ; At least it ain't XML + ;;(java +lsp) ; the poster child for carpal tunnel syndrome + javascript ; all(hope(abandon(ye(who(enter(here)))))) + ;;julia ; a better, faster MATLAB + ;;kotlin ; a better, slicker Java(Script) + ;;latex ; writing papers in Emacs has never been so fun + ;; lean ; for folks with too much to prove + ;;ledger ; be audit you can be + lua ; one-based indices? one-based indices + markdown ; writing docs for people to ignore + ;;nim ; python + lisp at the speed of c + nix ; I hereby declare "nix geht mehr!" + ;;ocaml ; an objective camel + (org +roam2 + ) ; organize your plain life in plain text + ;;php ; perl's insecure younger brother + ;;plantuml ; diagrams for confusing people more + ;;purescript ; javascript, but functional + ;;python ; beautiful is better than ugly + ;;qt ; the 'cutest' gui framework ever + racket ; a DSL for DSLs + ;;raku ; the artist formerly known as perl6 + ;;rest ; Emacs as a REST client + ;;rst ; ReST in peace + ;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"} + ;;(rust +lsp) ; Fe2O3.unwrap().unwrap().unwrap().unwrap() + ;;scala ; java, but good + ;;(scheme +guile) ; a fully conniving family of lisps + sh ; she sells {ba,z,fi}sh shells on the C xor + sml + ;;solidity ; do you need a blockchain? No. + ;;swift ; who asked for emoji variables? + ;;terra ; Earth and Moon in alignment for performance. + ;;web ; the tubes + yaml ; JSON, but readable + ;;zig ; C, but simpler + + :email + ;;(mu4e +org +gmail) + ;;notmuch + ;;(wanderlust +gmail) + + :app + ;;calendar + ;;emms + ;;everywhere ; *leave* Emacs!? You must be joking + ;;irc ; how neckbeards socialize + ;;(rss +org) ; emacs as an RSS reader + ;;twitter ; twitter client https://twitter.com/vnought + + :config + ;;literate + (default +bindings +smartparens)) diff --git a/ws_tool/my_config/dotfiles/config/doom/packages.el b/ws_tool/my_config/dotfiles/config/doom/packages.el new file mode 100644 index 00000000..9f0a8df1 --- /dev/null +++ b/ws_tool/my_config/dotfiles/config/doom/packages.el @@ -0,0 +1,56 @@ +;; -*- no-byte-compile: t; -*- +;;; $DOOMDIR/packages.el + +;; To install a package with Doom you must declare them here and run 'doom sync' +;; on the command line, then restart Emacs for the changes to take effect -- or +;; use 'M-x doom/reload'. + + +;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror: +;(package! some-package) + +;; To install a package directly from a remote git repo, you must specify a +;; `:recipe'. You'll find documentation on what `:recipe' accepts here: +;; https://github.com/raxod502/straight.el#the-recipe-format +;(package! another-package +; :recipe (:host github :repo "username/repo")) + +;; If the package you are trying to install does not contain a PACKAGENAME.el +;; file, or is located in a subdirectory of the repo, you'll need to specify +;; `:files' in the `:recipe': +;(package! this-package +; :recipe (:host github :repo "username/repo" +; :files ("some-file.el" "src/lisp/*.el"))) + +;; If you'd like to disable a package included with Doom, you can do so here +;; with the `:disable' property: +;(package! builtin-package :disable t) + +;; You can override the recipe of a built in package without having to specify +;; all the properties for `:recipe'. These will inherit the rest of its recipe +;; from Doom or MELPA/ELPA/Emacsmirror: +;(package! builtin-package :recipe (:nonrecursive t)) +;(package! builtin-package-2 :recipe (:repo "myfork/package")) + +;; Specify a `:branch' to install a package from a particular branch or tag. +;; This is required for some packages whose default branch isn't 'master' (which +;; our package manager can't deal with; see raxod502/straight.el#279) +;(package! builtin-package :recipe (:branch "develop")) + +;; Use `:pin' to specify a particular commit to install. +;(package! builtin-package :pin "1a2b3c4d5e") + + +;; Doom's packages are pinned to a specific commit and updated from release to +;; release. The `unpin!' macro allows you to unpin single packages... +;(unpin! pinned-package) +;; ...or multiple packages +;(unpin! pinned-package another-pinned-package) +;; ...Or *all* packages (NOT RECOMMENDED; will likely break things) +;(unpin! t) + +(when (equal (getenv "DOOM_DISABLE_NATIVE_COMPILE") "true") + (setq straight-disable-native-compile t)) + +(package! vline) +;; (package! xhair) diff --git a/ws_tool/my_config/dotfiles/config/git/ignore b/ws_tool/my_config/dotfiles/config/git/ignore new file mode 100644 index 00000000..9853d7f4 --- /dev/null +++ b/ws_tool/my_config/dotfiles/config/git/ignore @@ -0,0 +1,2 @@ +# Globally ignore these, superannoying +.DS_Store diff --git a/ws_tool/my_config/dotfiles/ghci b/ws_tool/my_config/dotfiles/ghci new file mode 100644 index 00000000..93a8e56f --- /dev/null +++ b/ws_tool/my_config/dotfiles/ghci @@ -0,0 +1,42 @@ +-- GHCI config +-- first off I always want overloaded strings on anyway so I can just +-- have this run every time ghci starts +:set -XOverloadedStrings +import Prelude +-- Read GHCI commands from the file whose name is +-- in the GHCIRC environment variable +-- :def _load const(System.Environment.getEnvironment >>= maybe (return "") readFile . lookup "GHCIRC") +-- :_load +-- :undef _load +-- :module + +-- ** turtle shell +-- I have experimented with using ghci and the turtle library to start making an interacive +-- shell for myself to use in day-to-day work. The advantage of such a thing +-- is that I get to "dog-food" my own experiences with haskell and shell scripting. + +-- Actually making this work well is a bit of a hack though. +-- GHCI doesn't really +-- have a way to pass in a custom file of "commands" to initialize the shell +-- (that is, beyond what the GHCI file would be), and IIRC I am unable to provide +-- a GHCI file for a custom invocation (e.g. many tools have a standard loction where +-- the configuration is located but ALSO provides a way to specify an alternate config file, but it appears that GHCI does not) + +-- I foudn this ghci snippet somewhere on the internet for it, which will look for an environment variable pointing to a new file and if present it will load it. + +-- *** The .ghci file +-- #+begin_src haskell :tangle ~/.ghci :noweb yes +-- -- GHCI config +-- -- first off I always want overloaded strings on anyway so I can just +-- -- have this run every time ghci starts +-- :set -XOverloadedStrings +-- import Prelude +-- -- Read GHCI commands from the file whose name is +-- -- in the GHCIRC environment variable +-- -- :def _load const(System.Environment.getEnvironment >>= maybe (return "") readFile . lookup "GHCIRC") +-- -- :_load +-- -- :undef _load +-- -- :module +-- #+END_SRC +-- ** I... hmmm... need to finish this +-- turtle-shell-rc.hs diff --git a/ws_tool/my_config/dotfiles/gitconfig b/ws_tool/my_config/dotfiles/gitconfig new file mode 100644 index 00000000..620c9513 --- /dev/null +++ b/ws_tool/my_config/dotfiles/gitconfig @@ -0,0 +1,22 @@ +# This is Git's per-user configuration file. +[core] + user = Joel + email = mccracken.joel@gmail.com + editor = "emacsclient -c " +[user] + name = Joel McCracken + email = mccracken.joel@gmail.com +[push] + default = simple +[merge] + conflictstyle = diff3 +[diff] + algorithm = patience +[filesystem "N/A|15.0.1|/dev/disk1s1"] + timestampResolution = 10000 nanoseconds + minRacyThreshold = 0 nanoseconds +[filter "lfs"] + required = true + clean = git-lfs clean -- %f + smudge = git-lfs smudge -- %f + process = git-lfs filter-process diff --git a/ws_tool/my_config/dotfiles/gitignore b/ws_tool/my_config/dotfiles/gitignore new file mode 100644 index 00000000..05f56824 --- /dev/null +++ b/ws_tool/my_config/dotfiles/gitignore @@ -0,0 +1,241 @@ +# history files +.bash_history +.cljsc_history +.lesshst +.irb-history +.sh_history +.pry_history +.psql_history +.node_repl_history + +# scala stuff +.scala_history +.scala_history_jline3 +.scalaide/ +# scala gitter8 templates +.g8 + +# haskell +.ghc +/.ghcjs/ + +# temporary +# will eventually want this to be managed in this repo (probably?) +# +# ?? +.Xauthority +.cups/lpoptions + +# Caches/languages/tools stuff +# (that doesn't need VC'd) +bin/elm-format +.bundle +.cabal +.cache +.cargo +.chef +.elm +.gem +.hoe_template +.hex +.idris +.lein +.m2 +.rbenv +# -- another clojure thing ?? +.mix +.node-gyp +.python-eggs +.npm +.rvm +.stack +.subversion +.vagrant.d +# -- will probably want to un-ignore this someday + +# app stuff +.dropbox +.geeknote +# -- just an error log and db cache +.tox +# -- another part of geeknote +.heroku +.local +# -- the long dark +.uqm +# -- the urquan masters +.uqmhd +# Dirs +Applications +Backup +Desktop +Documents +Downloads +Dropbox +Files +Inbox +Library +Movies +Music +Nextcloud +Pictures +Projects +Public +Reference +EF +Sites +VirtualBox VMs +Blizzard +ttm +brunner +var +browser-sessions + +# SSHHHHH SECRETS +secrets +.rclone.conf +.lpass +.pgpass +.netrc +.ttm_scalr_access_info +.ttm_scalr_aliases.json +.gnupg +.papertrail.yml +.ssh +.vault-token +.toodledo +.account + +# garbage +.oracle_jre_usage +.viminfo +.rnd +.bash_sessions +.dialyxir_core_*.plt +# i think rncache is "react native" cache. seems to have tar.gz files of utils or somethin +.rncache + +# os x stuff +.CFUserTextEncoding +.DS_Store +.Trash + +# log files, caches +.funstation.d/daemon.log +.lldb +.redd-up/cache +.redd-up/error-log +.redd-up/last-run +.swipl-dir-history +.cpu.history +.ex_supervisor + + + +# misc, uncategorized yet +.ammonite/ +.anaconda/ +.bash_profile-anaconda.bak +.bash_profile-anaconda2.bak +.conda/ +.condarc +.continuum/ +.coursier/ +.dotnet/ +.eclipse/ +.ipython/ +.ivy2/ +.nuget/ +.sbt/ +api_cache/ +project/ +secret +.bintray/ +.docker/ +/.docker/ +.exercism.json +.ispell_english +.webdrivers +.webtask +.yarnrc + + +# idk +.nix-defexpr/ +.nix-defexpr/channels +.dockercfg + +# rust -- seems like (currently) there aren't any settings in here I care to keep +.rustup/ +.multirust + +# ignoring for now, since I don't have like an active "this version works" that I am using. each time I try it since that first time and +# had a lot of success basically its been borked +apps/remacs/ +.aws/credentials + +# i think this got created by a react native process? +.babel.json +.android/adbkey +.android/adbkey.pub + +.atom/ +.datastorage/ +.nix-defexpr/channels_root +.tree-sitter/ +.wget-hsts +.xmonad/ +Exercism/ +Justinmind/ +lib/emacs/org-wiki/ +.zsh_history +sesco/ +.kube/ +.ngrok2/ +sesco/ + +.config/PixelPiracy/ +.config/StardewValley/ +.config/configstore/ +.config/gtk-2.0/ +.config/hub +.config/inkscape/ +.config/stripe/ +.rush/ + + +# links to where the installed nix files are, but dont need +# to revision them +.nix-profile + +# this contains the files for doom; should consider this an opaque blob +.emacs.d + +# home dir tmp +/tmp + +# work stuff +tvision + +# local haskell language server, do not want to addd +bin/haskell-language-server-macOS-8.8.4 + + +# ignore these for now +.aws/ +.config/nixpkgs/ +.pyenv/ +.zsh_sessions/ +wshs/result + + +.config/pip/ +.cookiecutter_replay/ +.matplotlib/ +.pylint.d/ +.python_history +.vim/ +workstation/ + +# zsh autocompletion cache file, automatically created if missing +.zcompdump diff --git a/ws_tool/my_config/dotfiles/hammerspoon/init.lua b/ws_tool/my_config/dotfiles/hammerspoon/init.lua new file mode 100644 index 00000000..819ea09c --- /dev/null +++ b/ws_tool/my_config/dotfiles/hammerspoon/init.lua @@ -0,0 +1,96 @@ +hs.hotkey.bind({"cmd", "alt", "ctrl"}, "W", function() + hs.alert.show("Hello World!") +end) + + +-- following is copied/adapted from +-- https://github.com/colindean/hejmo/blob/master/dotfiles/hammerspoon/window_mgmt.lua +-- @colindean's hammerspoon configuration +-- Window Management + +-- Read through the script to see what it does. It's pretty clear based on +-- function name. + +local griderr, grid = pcall(function() return require "hs.grid" end) +local windowerr, window = pcall(function() return require "hs.window" end) +local hotkeyerr, hotkey = pcall(function() return require "hs.hotkey" end) +local alerterr, alert = pcall(function() return require "hs.alert" end) + +function print_if_not_table(var) + if not(type(var) == "table") then print(var) end +end + +if not griderr or not windowerr or not hotkeyerr or not alerterr then + hs.showerror("Some packages appear to be missing.") + print("At least one package was missing. Have you installed the packages? See README.md.") + print_if_not_table(grid) + print_if_not_table(window) + print_if_not_table(hotkey) + print_if_not_table(alert) +end + +mash = {"cmd", "alt", "ctrl"} + +INITIAL_GRID_HEIGHT = 2 +INITIAL_GRID_WIDTH = 4 + +-- disable animations, ugh +window.animationDuration = 0 + +function centerpoint() + local current = grid.getGrid() + return { x = 1, y = 0, w = current.w / 2, h = current.h } +end + +function fullheightatleftwithwidth(width) + return { x = 0, y = 0, w = width, h = grid.getGrid().h } +end +function fullheightatrightwithwidth(width) + local current = grid.getGrid() + return { x = current.w - width, y = 0, w = width, h = current.h } +end + +function interp(s, tab) + return (s:gsub('($%b{})', function(w) return tab[w:sub(3, -2)] or w end)) +end + +grid.setGrid(hs.geometry({w=INITIAL_GRID_WIDTH, h=INITIAL_GRID_HEIGHT})) + +local grid_shortcuts = { + [";"] = function() grid.snap(window.focusedWindow()) alert.show("╔═╦═╗\n s n \n╠═╬═╣\n a p \n╚═╩═╝") end, + J = function() grid.pushWindowUp() alert.show("🔼") end, + H = function() grid.pushWindowLeft() alert.show("◀️") end, + L = function() grid.pushWindowRight() alert.show("▶️") end, + K = function() grid.pushWindowDown() alert.show("🔽") end, + I = function() grid.resizeWindowThinner() alert.show("⏩⏪") end, + O = function() grid.resizeWindowWider() alert.show("⏪⏩") end, + M = function() grid.maximizeWindow() alert.show("⏪⏫⏬⏩") end, + C = function() grid.set(window.focusedWindow(), centerpoint(), window.focusedWindow():screen()) alert.show("↹") end, + ["1"] = function() grid.set(window.focusedWindow(), fullheightatleftwithwidth(1), window.focusedWindow():screen()) alert.show("1") end, + ["2"] = function() grid.set(window.focusedWindow(), fullheightatleftwithwidth(2), window.focusedWindow():screen()) alert.show("2") end, + ["3"] = function() grid.set(window.focusedWindow(), fullheightatleftwithwidth(3), window.focusedWindow():screen()) alert.show("3") end, + ["9"] = function() grid.set(window.focusedWindow(), fullheightatrightwithwidth(3), window.focusedWindow():screen()) alert.show("9") end, + ["0"] = function() grid.set(window.focusedWindow(), fullheightatrightwithwidth(2), window.focusedWindow():screen()) alert.show("0") end, + ["-"] = function() grid.set(window.focusedWindow(), fullheightatrightwithwidth(1), window.focusedWindow():screen()) alert.show("-") end, + + G = function() + local point = grid.get(window.focusedWindow()) + alert.show(interp("⬌ ${x} ⬍ ${y}\n\t${w} × ${h}", point)) + end, + Y = function() grid.resizeWindowTaller() alert.show("⏫⏬") end, + U = function() grid.resizeWindowShorter() alert.show("⏬⏫") end, + N = function() grid.set(window.focusedWindow(), centerpoint(), window.focusedWindow():screen():next()) alert.show("➡️") end, + P = function() grid.set(window.focusedWindow(), centerpoint(), window.focusedWindow():screen():previous()) alert.show("⬅️") end, + T = function() + local cp = centerpoint() + cp["h"] = 1 + grid.set(window.focusedWindow(), cp, window.focusedWindow():screen()) + alert.show("🎥") + end, +} +print("If Hammerspoon console windows can be manipulated, but others cannot, ".. + "ensure that Hammerspoon is allowed in Accessibility preferences.") + +for key, func in pairs(grid_shortcuts) do + hotkey.bind(mash, key, func) +end diff --git a/ws_tool/my_config/dotfiles/nix-channels b/ws_tool/my_config/dotfiles/nix-channels new file mode 100644 index 00000000..e2cf7441 --- /dev/null +++ b/ws_tool/my_config/dotfiles/nix-channels @@ -0,0 +1,2 @@ +https://github.com/nix-community/home-manager/archive/213a06295dff96668a1d673b9fd1c03ce1de6745.tar.gz home-manager +https://nixos.org/channels/nixpkgs-unstable nixpkgs diff --git a/ws_tool/my_config/dotfiles/npmrc b/ws_tool/my_config/dotfiles/npmrc new file mode 100644 index 00000000..38f11c64 --- /dev/null +++ b/ws_tool/my_config/dotfiles/npmrc @@ -0,0 +1 @@ +registry=https://registry.npmjs.org diff --git a/ws_tool/my_config/dotfiles/reddup.yml b/ws_tool/my_config/dotfiles/reddup.yml new file mode 100644 index 00000000..041c5863 --- /dev/null +++ b/ws_tool/my_config/dotfiles/reddup.yml @@ -0,0 +1,40 @@ +locations: + - type: git + location: ~/EF + - type: git + location: ~/Projects/* + - type: inbox + location: ~/Desktop + ignored_files: + - .DS_Store + - type: inbox + location: ~/Inbox + ignored_files: + - .DS_Store +handlers: + git: + commands: + - name: wip with da(t)e + cmd: bash -c 'git add .; git commit -m "wip $(date)"' + key: t + inbox: + commands: + - name: (o)pen + cmd: open "$FILE" + key: o + - name: open (e)nclosing dir + cmd: open . + key: e + refile_dests: + - name: (b)ooks + char: b + dir: ~/Nextcloud/books + - name: (p)apers + char: p + dir: ~/Nextcloud/papers + - name: p(r)ivate + char: r + dir: ~/Nextcloud/private + - name: (f)unny + char: f + dir: ~/Nextcloud/funny diff --git a/ws_tool/my_config/dotfiles/zshrc b/ws_tool/my_config/dotfiles/zshrc new file mode 100644 index 00000000..767de19e --- /dev/null +++ b/ws_tool/my_config/dotfiles/zshrc @@ -0,0 +1,9 @@ +# share for now +. "$HOME/.bashrc" +# zsh specifics +setopt append_history # append rather then overwrite +setopt extended_history # save timestamp +setopt inc_append_history # add history + +# TODO figure out how to make this work in zsh +# shopt -s extglob diff --git a/ws_tool/my_config/run_setup.sh b/ws_tool/my_config/run_setup.sh new file mode 100644 index 00000000..ddef81b5 --- /dev/null +++ b/ws_tool/my_config/run_setup.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env sh + + +rm -rf $HOME/.config/workstation + +unset WORKSTATION_DIR +export WORKSTATION_NAME=angrist +export WORKSTATION_VERSION +WORKSTATION_VERSION="$(git log -n 1 --format="%H")" + +bash ws_install.sh + +~/.config/workstation/workstation_source/ws_tool/ws bootstrap -n angrist --initial-config-dir ./my_config diff --git a/ws_tool/my_config/settings.angrist.sh b/ws_tool/my_config/settings.angrist.sh new file mode 100644 index 00000000..977a9dad --- /dev/null +++ b/ws_tool/my_config/settings.angrist.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +export WORKSTATION_NAME=angrist diff --git a/ws_tool/my_config/settings.sh b/ws_tool/my_config/settings.sh new file mode 100644 index 00000000..8bd82aac --- /dev/null +++ b/ws_tool/my_config/settings.sh @@ -0,0 +1,55 @@ +# the settings.sh file is used to define basic, global settings. + +# location of config dir +# where your personal configuration should be +# (e.g. where this file and config.sh should be) +# the workstation tool needs to know some things to do its job, such as where its +# own file should be found, and the specifics of what the user wants with their +# workstation. Having a central file like this affords a central place to configure +# these things. + +# you may wish to customize this if you want your configuration somewhere else. +export WORKSTATION_CONFIG_DIR=$HOME/.config/workstation + +# location of workstation source. This is where the ws source code should live. +export WORKSTATION_DIR=$WORKSTATION_CONFIG_DIR/workstation_source + +# Workstation name to use. +# Used to identify a machine, determine which settings it should have. +# if you just have one, you can use this here and set it to `default` +# export WORKSTATION_NAME=default + +# workstation_names is a regular variable, though it is used +# for configuration. ws uses expected +workstation_names=(aeglos belthronding angrist); + +workstation_descriptions_aeglos="parimary laptop" +workstation_descriptions_belthronding="cloud VM" +workstation_descriptions_angrist="work computer" + +# at times it is necessary to specify settings differently on different workstations. +# the following can be used to load those workstation-specific settings if such is needed. +# [ -f "settings.${WORKSTATION_NAME}.sh"] && . "settings.${WORKSTATION_NAME}.sh" + +# one way to deal with differing sets is having a specific file symlinked to the file +# for the current workstation config. For example, say I have two workstations, picard and janeway: +# $ touch settings.picard.sh +# $ touch settings.janeway.sh +# Now, when I am settingh up the "picard" machine, I can do: +# $ ln -s settings.picard.sh settings.current.sh +# +# And, on the janeway machine, I can do: +# $ ln -s settings.janeway.sh settings.current.sh +# +# Then, I can have the following in this sesttings file on both, and it will load +# the correct settings on each: +# $ [ -f "settings.current.sh" ] && . "settings.current.sh" + +# Oh yeah, be sure to ignore the settings.current.sh file. you do _not_ want to commit it. +# $ echo "settings.current.sh" >> .gitignore + +[ -f "${WORKSTATION_CONFIG_DIR}/settings.current.sh" ] && . "${WORKSTATION_CONFIG_DIR}/settings.current.sh" || return 0 + +# Oh, you may wish to add the following to your shell profile file: +# export WORKSTATION_CONFIG_DIR=/path/to/specific/location +# export PATH="${WORKSTATION_DIR}/ws_tool:$PATH" diff --git a/ws_tool/sample_config/config.sh b/ws_tool/sample_config/config.sh new file mode 100644 index 00000000..1ba66615 --- /dev/null +++ b/ws_tool/sample_config/config.sh @@ -0,0 +1,2 @@ +workstation_props_default=() +# workstation_props_default+=(prop_ws_current_settings_symlink) diff --git a/ws_tool/sample_config/settings.default.sh b/ws_tool/sample_config/settings.default.sh new file mode 100644 index 00000000..cea59e9b --- /dev/null +++ b/ws_tool/sample_config/settings.default.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +export WORKSTATION_NAME=default diff --git a/ws_tool/sample_config/settings.sh b/ws_tool/sample_config/settings.sh new file mode 100644 index 00000000..7a969ff7 --- /dev/null +++ b/ws_tool/sample_config/settings.sh @@ -0,0 +1,53 @@ +# the settings.sh file is used to define basic, global settings. + +# location of config dir +# where your personal configuration should be +# (e.g. where this file and config.sh should be) +# the workstation tool needs to know some things to do its job, such as where its +# own file should be found, and the specifics of what the user wants with their +# workstation. Having a central file like this affords a central place to configure +# these things. + +# you may wish to customize this if you want your configuration somewhere else. +export WORKSTATION_CONFIG_DIR=$HOME/.config/workstation + +# location of workstation source. This is where the ws source code should live. +export WORKSTATION_DIR=$WORKSTATION_CONFIG_DIR/workstation_source + +# Workstation name to use. +# Used to identify a machine, determine which settings it should have. +# if you just have one, you can use this here and set it to `default` +# export WORKSTATION_NAME=default + +# workstation_names is a regular variable, though it is used +# for configuration. ws uses expected +workstation_names=(default); + +workstation_descriptions_default="primary workstation" + +# at times it is necessary to specify settings differently on different workstations. +# the following can be used to load those workstation-specific settings if such is needed. +# [ -f "settings.${WORKSTATION_NAME}.sh"] && . "settings.${WORKSTATION_NAME}.sh" + +# one way to deal with differing sets is having a specific file symlinked to the file +# for the current workstation config. For example, say I have two workstations, picard and janeway: +# $ touch settings.picard.sh +# $ touch settings.janeway.sh +# Now, when I am settingh up the "picard" machine, I can do: +# $ ln -s settings.picard.sh settings.current.sh +# +# And, on the janeway machine, I can do: +# $ ln -s settings.janeway.sh settings.current.sh +# +# Then, I can have the following in this sesttings file on both, and it will load +# the correct settings on each: +# $ [ -f "settings.current.sh" ] && . "settings.current.sh" + +# Oh yeah, be sure to ignore the settings.current.sh file. you do _not_ want to commit it. +# $ echo "settings.current.sh" >> .gitignore + +[ -f "${WORKSTATION_CONFIG_DIR}/settings.current.sh" ] && . "${WORKSTATION_CONFIG_DIR}/settings.current.sh" || return 0 + +# Oh, you may wish to add the following to your shell profile file: +# export WORKSTATION_CONFIG_DIR=/path/to/specific/location +# export PATH="${WORKSTATION_DIR}/ws_tool:$PATH" diff --git a/test/bats b/ws_tool/test/bats similarity index 100% rename from test/bats rename to ws_tool/test/bats diff --git a/ws_tool/test/ci_full_setup.bash b/ws_tool/test/ci_full_setup.bash new file mode 100644 index 00000000..49fc450d --- /dev/null +++ b/ws_tool/test/ci_full_setup.bash @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -xeuo pipefail + +rm -rf $HOME/.config/workstation + +unset WORKSTATION_DIR + +bash <(curl "https://raw.githubusercontent.com/joelmccracken/workstation/${WORKSTATION_VERSION}/ws_tool/ws_install.sh") + +cd ~/.config/workstation/workstation_source/ws_tool + +if [ "$RUNNER_OS" == "macOS" ]; then + WORKSTATION_NAME=ci_macos +else + WORKSTATION_NAME=ci_ubuntu +fi + +./ws bootstrap -n "$WORKSTATION_NAME" --initial-config-dir ./test/test_config diff --git a/ws_tool/test/test_config/config.sh b/ws_tool/test/test_config/config.sh new file mode 100644 index 00000000..ad99a942 --- /dev/null +++ b/ws_tool/test/test_config/config.sh @@ -0,0 +1,11 @@ +workstation_props__common=() +workstation_props__common+=(prop_ws_current_settings_symlink) +workstation_props__common+=(prop_ws_dotfiles_git_track) +workstation_props__common+=(prop_ws_nix_daemon_installed) +workstation_props__common+=(prop_ws_nix_global_config) + +workstation_props_ci_ubuntu=() +workstation_props_ci_ubuntu+=("${workstation_props__common[@]}") + +workstation_props_ci_macos=() +workstation_props_ci_macos+=("${workstation_props__common[@]}") diff --git a/ws_tool/test/test_config/settings.ci_macos.sh b/ws_tool/test/test_config/settings.ci_macos.sh new file mode 100644 index 00000000..ad6c38a7 --- /dev/null +++ b/ws_tool/test/test_config/settings.ci_macos.sh @@ -0,0 +1 @@ +WORKSTATION_NAME=ci_macos diff --git a/ws_tool/test/test_config/settings.ci_ubuntu.sh b/ws_tool/test/test_config/settings.ci_ubuntu.sh new file mode 100644 index 00000000..358a4f59 --- /dev/null +++ b/ws_tool/test/test_config/settings.ci_ubuntu.sh @@ -0,0 +1 @@ +WORKSTATION_NAME=ci_ubuntu diff --git a/ws_tool/test/test_config/settings.sh b/ws_tool/test/test_config/settings.sh new file mode 100644 index 00000000..b857bf5e --- /dev/null +++ b/ws_tool/test/test_config/settings.sh @@ -0,0 +1,8 @@ +export WORKSTATION_CONFIG_DIR=$HOME/.config/workstation +export WORKSTATION_DIR=$WORKSTATION_CONFIG_DIR/workstation_source + +workstation_names=(ci_macos ci_ubuntu); +workstation_descriptions_ci_macos="profile for macos on CI" +workstation_descriptions_ci_ubuntu="profile for ubuntu on CI" + +[ -f "${WORKSTATION_CONFIG_DIR}/settings.current.sh" ] && . "${WORKSTATION_CONFIG_DIR}/settings.current.sh" || return 0 diff --git a/test/test_helper/bats-assert b/ws_tool/test/test_helper/bats-assert similarity index 100% rename from test/test_helper/bats-assert rename to ws_tool/test/test_helper/bats-assert diff --git a/test/test_helper/bats-support b/ws_tool/test/test_helper/bats-support similarity index 100% rename from test/test_helper/bats-support rename to ws_tool/test/test_helper/bats-support diff --git a/ws_tool/test/test_helper/helper.bash b/ws_tool/test/test_helper/helper.bash new file mode 100644 index 00000000..075babdb --- /dev/null +++ b/ws_tool/test/test_helper/helper.bash @@ -0,0 +1,60 @@ +_setup_common() { + PROJECT_ROOT="$( cd "$(dirname "${BASH_SOURCE[0]}")/../../../" &>/dev/null && pwd)" + BATS_LIB_PATH="$PROJECT_ROOT/ws_tool/test/test_helper:$BATS_LIB_PATH" + bats_load_library "bats-support" + bats_load_library "bats-assert" + + ws_unset_settings + # echo "$PROJECT_ROOT, $BATS_TEST_FILENAME" >&3 + PATH="$PROJECT_ROOT:/bin/:${PROJECT_ROOT}/ws_tool:$PATH" + : "${WORKSTATION_DIR:="$PROJECT_ROOT"}" + . "$PROJECT_ROOT/ws_tool/lib/lib.bash" +} + +set_workstation_version_last_sha() { + export WORKSTATION_VERSION + WORKSTATION_VERSION="$(git log -n 1 --format="%H")" +} + +retfunc() { + # use set -o posix + # plus saving and restoring sets + # to make set print vars (and not functions) + local orig_sets + orig_sets=$(set +o) + set -o posix + "$@"; + set | while read -r i; do + printf "VAR:%s" "$i"; + done + # declare -p REPLY + eval "$orig_sets" +} + +dump_output() { + echo "$output" 1>&3 +} + +ws_get_all_settings() { + all_settings=() + while read -r line; do + if [[ "$line" == export*'META:workstation_setting'* ]]; then + without_export="${line/#export /}" + var_name="${without_export/%# META:workstation_setting/}" + all_settings+=("$var_name") + fi + done < "$PROJECT_ROOT/ws_tool/lib/settings.bash" + read -ra REPLY <<< "${all_settings[@]}" +} + +ws_unset_settings() { + REPLY=() + ws_get_all_settings + read -ra all_settings <<< "${REPLY[@]}" + unset "${all_settings[@]}" +} + +ws_reset_settings () { + ws_unset_settings + . "$PROJECT_ROOT/ws_tool/lib/settings.bash" +} diff --git a/ws_tool/test/unit/bootstrap_doctor.bats b/ws_tool/test/unit/bootstrap_doctor.bats new file mode 100644 index 00000000..86916e02 --- /dev/null +++ b/ws_tool/test/unit/bootstrap_doctor.bats @@ -0,0 +1,116 @@ +#!/usr/bin/env bash + +setup (){ + load '../test_helper/helper' + _setup_common + . "$PROJECT_ROOT/ws_tool/lib/properties.bash" + . "$PROJECT_ROOT/ws_tool/lib/bootstrap_doctor.bash" +} + +@test "ensure props handles additional props correctly" { + props_test_tmp_file= + declare -a prop_exec_hist + + prop_a() { + prop_exec_hist+=("a") + echo "in prop_a" + echo "a" >> "$props_test_tmp_file" + REPLY=(additional_props prop_b prop_c) + return 0 + } + + prop_b() { + prop_exec_hist+=("b") + echo "in prop_b" + echo "b" >> "$props_test_tmp_file" + return 0 + } + + prop_c() { + prop_exec_hist+=("c") + echo "in prop_c" + echo "c" >> "$props_test_tmp_file" + return 0 + } + + prop_f() { + prop_exec_hist+=("f") + echo "f" >> "$props_test_tmp_file" + echo "in prop_f" + return 0 + } + + props_test_tmp_file="$(_mktemp "props-test-tmp")/file" + echo "0" >> "$props_test_tmp_file" + prop_exec_hist=(0) + ws_unset_settings + run_props --fix true prop_a prop_f + + # tested two ways, just keweping for now bc I have a feeling i'll want to see this in the future + assert_equal "${prop_exec_hist[*]}" "0 a b c f" + declare -a 'content=($(cat "${props_test_tmp_file}"))' + assert_equal "${content[*]}" "0 a b c f" +} + +@test "run_all_props runs workstation specific props along with bootstrap" { + props_test_tmp_file="$(_mktemp "props-test-tmp")/file" + prop_a() { + printf " a" >> "$props_test_tmp_file" + return 0 + } + + prop_b() { + printf " b" >> "$props_test_tmp_file" + return 0 + } + + prop_f() { + printf " f" >> "$props_test_tmp_file" + return 0 + } + + ( + ws_unset_settings + bootstrap_props=(prop_a prop_b) + workstation_props_foo=(prop_f) + WORKSTATION_NAME=foo + printf "0" >> "$props_test_tmp_file" + run_all_props --fix true --label "foo" + ) + assert_equal "$(cat "${props_test_tmp_file}")" "0 a b f" +} + +@test "run_all_props aborts if unable to satisfy a property " { + local props_test_tmp_file + props_test_tmp_file="$(_mktemp "props-test-tmp")/file" + prop_a() { + printf " a1" >> "$props_test_tmp_file" + return 0 + } + + prop_b() { + printf " b1" >> "$props_test_tmp_file" + return 55 + } + + prop_b_fix() { + printf " b1_fix" >> "$props_test_tmp_file" + return 56 + } + + prop_f() { + printf " f1" >> "$props_test_tmp_file" + return 0 + } + + ws_unset_settings + bootstrap_props=(prop_a prop_b) + workstation_props_foo=(prop_f) + WORKSTATION_NAME=foo + printf "0" >> "$props_test_tmp_file" + run run_all_props --fix true --label "foo" + # echo "$output" 1>&3 + assert_failure + + assert_equal "$(cat "${props_test_tmp_file}")" "0 a1 b1 b1_fix" +} diff --git a/ws_tool/test/unit/installation_process.bats b/ws_tool/test/unit/installation_process.bats new file mode 100644 index 00000000..3ac6fb09 --- /dev/null +++ b/ws_tool/test/unit/installation_process.bats @@ -0,0 +1,73 @@ +#!/usr/bin/env zsh + +setup (){ + load '../test_helper/helper' + _setup_common +} + +@test "the install script and then run ws bootstrap from this project checkout" { + export WORKSTATION_CONFIG_DIR="$(_mktemp "ws-config-dir")" + export WORKSTATION_DIR="${WORKSTATION_CONFIG_DIR}/workstation_source" + set_workstation_version_last_sha + + run ws_install.sh + assert_success + assert [ -x "${WORKSTATION_DIR}/ws_tool/ws" ] + + # ok, above we demonstrate that the ws_install script in this repo does + # indeed install the ws executable + + # below we use the stuff from this project checkout however to test it + # HACK get the tool to actually run code from current local checkout + ( cd "$PROJECT_ROOT"; + git ls-files | while read -r gitfile; do + cp -r "$gitfile" "$WORKSTATION_DIR/$gitfile" + done; + ) + + cat <<-EOF > "${WORKSTATION_CONFIG_DIR}/settings.sh" + export WORKSTATION_CONFIG_DIR="$WORKSTATION_CONFIG_DIR" + export WORKSTATION_DIR="$PROJECT_ROOT" + export workstation_names=(workstation_a workstation_b) +EOF + + cat <<-EOF > "${WORKSTATION_CONFIG_DIR}/settings.workstation_a.sh" + WORKSTATION_NAME=workstation_a +EOF + + cat <<-EOF > "${WORKSTATION_CONFIG_DIR}/config.sh" + workstation_props_workstation_a=() + workstation_props_workstation_a+=(prop_ws_current_settings_symlink) +EOF + + export WORKSTATION_NAME=workstation_a + run "${WORKSTATION_DIR}/ws_tool/ws" bootstrap + assert_success +} + +@test "the install script from curl/github and then run ws bootstrap" { + export WORKSTATION_CONFIG_DIR="$(_mktemp "ws-config-dir")" + export WORKSTATION_DIR="${WORKSTATION_CONFIG_DIR}/workstation_source" + set_workstation_version_last_sha + + do_ws_install() { + bash <(curl "https://raw.githubusercontent.com/joelmccracken/workstation/${WORKSTATION_VERSION}/ws_tool/ws_install.sh") + } + run do_ws_install + + assert_success + assert [ -x "${WORKSTATION_DIR}/ws_tool/ws" ] + + cat <<-EOF > "${WORKSTATION_CONFIG_DIR}/settings.sh" + export WORKSTATION_CONFIG_DIR="$WORKSTATION_CONFIG_DIR" + export WORKSTATION_DIR="$WORKSTATION_DIR" +EOF + + cat <<-EOF > "${WORKSTATION_CONFIG_DIR}/config.sh" + workstation_names=(workstation_a workstation_b) +EOF + export WORKSTATION_NAME=workstation_b + run "${WORKSTATION_DIR}/ws_tool/ws" bootstrap + + assert_success +} diff --git a/ws_tool/test/unit/installer.bats b/ws_tool/test/unit/installer.bats new file mode 100644 index 00000000..b034a986 --- /dev/null +++ b/ws_tool/test/unit/installer.bats @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +setup (){ + load '../test_helper/helper' + _setup_common +} + +@test "runs ws_install" { + export WORKSTATION_DIR="$(_mktemp "ws-install")" + set_workstation_version_last_sha + # export TO_WORKSTATION_DIR="${TMPDIR}/workstation" + run ws_install.sh + assert [ -x "${WORKSTATION_DIR}/ws_tool/ws" ] +} diff --git a/ws_tool/test/unit/lib.bats b/ws_tool/test/unit/lib.bats new file mode 100644 index 00000000..89582ede --- /dev/null +++ b/ws_tool/test/unit/lib.bats @@ -0,0 +1,66 @@ +setup (){ + load "../test_helper/helper" + _setup_common + . "$PROJECT_ROOT/ws_tool/lib/lib.bash" +} + +@test "find_bracketed_content" { + local content + read -r -d '' src <<-EOF || : + BEFORE + BEGIN + 1 + 2 + END + AFTER +EOF + + REPLY=() + find_bracketed_content "BEGIN" "END" <<< "$src" + local content=("${REPLY[@]}"); + REPLY=() + + assert [ "${content[0]}" == $'BEFORE\n' ] + assert [ "${content[1]}" == $'BEGIN\n1\n2\nEND\n' ] + assert [ "${content[2]}" == $'AFTER\n' ] +} + +@test "find_bracketed_content never ending" { + local content + read -r -d '' src <<-EOF || : + BEFORE + BEGIN + 1 + 2 + AFTER +EOF + + REPLY=() + find_bracketed_content "BEGIN" "END" <<< "$src" + local content=("${REPLY[@]}"); + REPLY=() + + assert [ "${content[0]}" == $'BEFORE\n' ] + assert [ "${content[1]}" == $'BEGIN\n1\n2\nAFTER\n' ] + assert [ "${content[2]}" == '' ] +} + +@test "find_bracketed_content never starts" { + local content + read -r -d '' src <<-EOF || : + BEFORE + 1 + 2 + END + AFTER +EOF + + REPLY=() + find_bracketed_content "BEGIN" "END" <<< "$src" + local content=("${REPLY[@]}"); + REPLY=() + + assert [ "${content[0]}" == $'BEFORE\n1\n2\nEND\nAFTER\n' ] + assert [ "${content[1]}" == '' ] + assert [ "${content[2]}" == '' ] +} diff --git a/ws_tool/test/unit/logging.bats b/ws_tool/test/unit/logging.bats new file mode 100644 index 00000000..8dcd7f74 --- /dev/null +++ b/ws_tool/test/unit/logging.bats @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +setup (){ + load "../test_helper/helper" + _setup_common + . "$PROJECT_ROOT/ws_tool/lib/logging.bash" +} + +@test "log_level_num gets level number from name" { + export BATS_VERBOSE_RUN=true + run retfunc log_level_num error + assert_output --partial 'VAR:REPLY=([0]="4")' +} + +@test "logs by log level" { + WORKSTATION_LOG_LEVEL=debug + run debug "hello world" + assert_output --partial 'hello world' +} + +@test "skips logs when out of log level" { + WORKSTATION_LOG_LEVEL=error + run debug "hello world" + refute_output --partial 'hello world' +} diff --git a/ws_tool/test/unit/properties.bats b/ws_tool/test/unit/properties.bats new file mode 100644 index 00000000..23907712 --- /dev/null +++ b/ws_tool/test/unit/properties.bats @@ -0,0 +1,232 @@ +setup (){ + load '../test_helper/helper' + _setup_common + . "$PROJECT_ROOT/ws_tool/lib/properties.bash" +} + +@test "prop_ws_check_workstation_dir" { + ws_unset_settings + WORKSTATION_DIR="$(_mktemp "ws-dir")" + set_workstation_version_last_sha + . "$PROJECT_ROOT/ws_tool/lib/settings.bash" + + run prop_ws_check_workstation_dir + assert_failure + + run prop_ws_check_workstation_dir_fix + assert_success + + run prop_ws_check_workstation_dir + assert_success +} + +@test "prop_ws_check_workstation_repo" { + ws_unset_settings + WORKSTATION_DIR="$(_mktemp "ws-dir")" + set_workstation_version_last_sha + . "$PROJECT_ROOT/ws_tool/lib/settings.bash" + + # set up the workstation dir, but wont set up git, just project source + run prop_ws_check_workstation_dir_fix + assert_success + + run prop_ws_check_workstation_repo + assert_failure + + # WORKSTATION_REPO_GIT_ORIGIN=https://github.com/joelmccracken/workstation.git + run prop_ws_check_workstation_repo_fix + assert_success + + run prop_ws_check_workstation_repo + assert_success +} + +@test "prop_ws_dotfiles_git_track" { + ws_unset_settings + FAKE_HOME="$(_mktemp "ws-fake-home")" + set_workstation_version_last_sha + + . "$PROJECT_ROOT/ws_tool/lib/settings.bash" + + wrap() { + (export HOME=$FAKE_HOME; prop_ws_dotfiles_git_track) + } + run wrap + assert_failure + + wrap() { + (export HOME=$FAKE_HOME; prop_ws_dotfiles_git_track_fix) + } + run wrap + assert_success + + wrap() { + (export HOME=$FAKE_HOME; prop_ws_dotfiles_git_track) + } + run wrap + assert_success +} + +@test "prop_ws_config_exists default config" { + ws_unset_settings + WORKSTATION_CONFIG_DIR="$(_mktemp "ws-fake-config")" + set_workstation_version_last_sha + WORKSTATION_DIR="$WORKSTATION_CONFIG_DIR/workstation_source" + . "$PROJECT_ROOT/ws_tool/lib/settings.bash" + + # valid scenario requires copying from where the workstation source is + # installed; set this up. + run prop_ws_check_workstation_dir_fix + + run prop_ws_config_exists + assert_failure + + run prop_ws_config_exists_fix + assert_success + + run prop_ws_config_exists + assert_success + + for f in settings.sh config.sh settings.default.sh; do + assert [ -f "${WORKSTATION_CONFIG_DIR}/$f" ] + done +} + +@test "prop_ws_config_exists using custom config" { + ws_unset_settings + WORKSTATION_CONFIG_DIR="$(_mktemp "ws-fake-config")" + set_workstation_version_last_sha + WORKSTATION_DIR="$WORKSTATION_CONFIG_DIR/workstation_source" + . "$PROJECT_ROOT/ws_tool/lib/settings.bash" + + # valid scenario requires copying from where the workstation source is + # installed; set this up. + run prop_ws_check_workstation_dir_fix + + run prop_ws_config_exists + assert_failure + + workstation_initial_config_dir_arg="${WORKSTATION_DIR}/ws_tool/my_config" + + run prop_ws_config_exists_fix + assert_success + + run prop_ws_config_exists + assert_success + + ( cd "$workstation_initial_config_dir_arg"; + for f in *; do + # utter insanity + assert [ "$(cat $f)" == "$(cat "$WORKSTATION_CONFIG_DIR/$f")" ] + done + ) +} + +@test "prop_ws_config_exists config already in place" { + ws_unset_settings + WORKSTATION_CONFIG_DIR="$(_mktemp "ws-fake-config")" + . "$PROJECT_ROOT/ws_tool/lib/settings.bash" + + touch "${WORKSTATION_CONFIG_DIR}/settings.sh" + touch "${WORKSTATION_CONFIG_DIR}/config.sh" + + run prop_ws_config_exists + assert_success +} + +@test "prop_ws_current_settings_symlink works for default" { + ws_unset_settings + WORKSTATION_CONFIG_DIR="$(_mktemp "ws-fake-config")" + set_workstation_version_last_sha + WORKSTATION_NAME=default + . "$PROJECT_ROOT/ws_tool/lib/settings.bash" + + prop_ws_check_workstation_dir_fix + prop_ws_config_exists_fix + + run prop_ws_current_settings_symlink + assert_failure + + run prop_ws_current_settings_symlink_fix + assert_success + + run prop_ws_current_settings_symlink + assert_success + + # echo "$WORKSTATION_CONFIG_DIR" 1>&3 + # ls -lah "$WORKSTATION_CONFIG_DIR" 1>&3 +} + +@test "prop_ws_nix_global_config" { + ws_unset_settings + . "$PROJECT_ROOT/ws_tool/lib/settings.bash" + + nix_config="$(_mktemp "nix-config")/nix.conf" + cat > "$nix_config" <<-EOF || : + other config + # BEGIN prop_ws_nix_global_config + some old config here + # END prop_ws_nix_global_config + final config +EOF + + run_env() { + WS_NIX_GLOBAL_CONFIG_LOCATION="$nix_config"; + WORKSTATION_DIR="$PROJECT_ROOT" + "$1" + } + + run run_env prop_ws_nix_global_config + assert_failure + + run run_env prop_ws_nix_global_config_fix + assert_success + + run run_env prop_ws_nix_global_config + assert_success +} + +## bats test_tags=bats:focus +@test "prop_ws_df_dotfiles basic dotfile test" { + ws_unset_settings + . "$PROJECT_ROOT/ws_tool/lib/settings.bash" + + df_src_dir="$(_mktemp "dotfiles-src")" + df_dest_dir="$(_mktemp "dotfiles-dest")" + + ws_df_dotfile_src_dir="$df_src_dir" + ws_df_dotfile_dest_dir="$df_dest_dir" + + cat > "$df_src_dir/bashrc" <<< "my bash config" + cat > "$df_src_dir/Brewfile" <<< "some homebrew package" + mkdir -p "$df_src_dir/config/git/" + cat > "$df_src_dir/config/git/ignore" <<< ".DS_Store" + + test_ws_name=some_name_$RANDOM + WORKSTATION_NAME="$test_ws_name" + + df_fn_src_file="$(_mktemp "df-fn-src")/df.bash" + cat > "$df_fn_src_file" <<-EOF + workstation_props_dotfiles_${WORKSTATION_NAME} () { + dotfile --ln --dot bashrc + dotfile --ln --dot --dir config/git + dotfile --ln Brewfile + } +EOF + # cat < "$df_fn_src_file" 1>&3 + eval "$(cat < "$df_fn_src_file")" + + run prop_ws_df_dotfiles + # echo "$output" 1>&3 + assert_failure + + run prop_ws_df_dotfiles_fix + assert_success + + run prop_ws_df_dotfiles + assert_success + + assert [ -f "$df_dest_dir/.bashrc" ] + assert [ -f "$df_dest_dir/Brewfile" ] + assert [ -f "$df_dest_dir/.config/git/ignore" ] +} diff --git a/ws_tool/test/unit/settings.bats b/ws_tool/test/unit/settings.bats new file mode 100644 index 00000000..951e3fa9 --- /dev/null +++ b/ws_tool/test/unit/settings.bats @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +setup (){ + load '../test_helper/helper' + _setup_common + ws_reset_settings +} + +@test "ws_reset_settings works like i think it does" { + ORIG_WORKSTATION_DIR="$WORKSTATION_DIR" + WORKSTATION_DIR=poopy + assert [ "$WORKSTATION_DIR" = "poopy" ] + + ws_reset_settings + + assert [ "$WORKSTATION_DIR" = "$ORIG_WORKSTATION_DIR" ] +} + + + +@test "settings sets appropriate default values" { + assert_regex "$WORKSTATION_CONFIG_DIR" .*/.config/workstation + assert_regex "$WORKSTATION_DIR" .*/.config/workstation/workstation_source + assert [ "$WORKSTATION_REPO_GIT_ORIGIN" = 'https://github.com/joelmccracken/workstation.git' ] + assert [ "$WORKSTATION_VERBOSE" = false ] + assert [ "$WORKSTATION_LOG_LEVEL" = error ] +} + +@test "loading settings honors existing env vars" { + ws_unset_settings + WORKSTATION_CONFIG_DIR="$(_mktemp "ws-config-dir")" + WORKSTATION_REPO_GIT_ORIGIN='git@github.com:some-other-user/workstation.git' + MY_WORKSTATION_REPO_GIT_ORIGIN="$WORKSTATION_REPO_GIT_ORIGIN" + . "$PROJECT_ROOT/ws_tool/lib/settings.bash" + + assert [ "$WORKSTATION_CONFIG_DIR" = "$WORKSTATION_CONFIG_DIR" ] + assert [ "$WORKSTATION_DIR" = "$WORKSTATION_CONFIG_DIR/workstation_source" ] + assert [ "$WORKSTATION_REPO_GIT_ORIGIN" = "$MY_WORKSTATION_REPO_GIT_ORIGIN" ] + assert [ "$WORKSTATION_VERBOSE" = false ] + assert [ "$WORKSTATION_LOG_LEVEL" = error ] +} diff --git a/ws_tool/test/unit/ws-cli.bats b/ws_tool/test/unit/ws-cli.bats new file mode 100644 index 00000000..05f4bfa8 --- /dev/null +++ b/ws_tool/test/unit/ws-cli.bats @@ -0,0 +1,54 @@ +setup (){ + load "../test_helper/helper" + _setup_common + . "$PROJECT_ROOT/ws_tool/ws" +} + +@test "supports help flag" { + run ws -h + assert_output --partial 'Usage:' +} + +@test "process_cli_args parse verbose flag" { + process_cli_args -v bootstrap + assert_equal "$WORKSTATION_VERBOSE" true +} + +@test "process_cli_args parse verbose flag (long)" { + process_cli_args --verbose bootstrap + assert_equal "$WORKSTATION_VERBOSE" true +} + +@test "process_cli_args parse bootstrap subcommand" { + process_cli_args bootstrap + assert_equal "$ws_command" "bootstrap" +} + +@test "process_cli_args parse bootstrap subcommand with name flag short" { + process_cli_args -n glamdring bootstrap + assert_equal "$ws_command" "bootstrap" + assert_equal "$workstation_name_arg" "glamdring" +} + +@test "process_cli_args parse bootstrap subcommand with workstation name long flag" { + process_cli_args --name aeglos bootstrap + assert_equal "$ws_command" "bootstrap" + assert_equal "$workstation_name_arg" "aeglos" +} + +@test "process_cli_args parse bootstrap command doctor" { + process_cli_args doctor + assert_equal "$ws_command" "doctor" +} + +@test "fails with unknown long" { + run process_cli_args --foo + assert_failure + assert_output --partial "unknown argument '--foo'" +} + +@test "fails with unknown short" { + run process_cli_args -z + assert_failure + assert_output --partial "ws: argument parsing: unknown argument '-z'" +} diff --git a/ws_tool/ws b/ws_tool/ws new file mode 100755 index 00000000..84c55c3a --- /dev/null +++ b/ws_tool/ws @@ -0,0 +1,145 @@ +#!/usr/bin/env bash + +# prototype of a new workstation tool. goal being an interactive tool that can be used anywhere. +# I'm much better at bash now, and think I can probably accomplish what I need to do. + +# ensure macos bash used: (export PATH="/bin:$PATH"; ./ws -v) +# (ensures that any other bash processes will use builtin too) +# set -euo pipefail + +ws_script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +ws_initial_pwd="$PWD" + +# set -x + +. "${ws_script_dir}/lib/settings.bash" +. "${ws_script_dir}/lib/logging.bash" +. "${ws_script_dir}/lib/properties.bash" +. "${ws_script_dir}/lib/bootstrap_doctor.bash" + +REPLY=() # global "out" var, hack to use return values +ws_command=help # show help if nothing provided +declare -a ws_command_arguments +workstation_initial_config_dir_arg= +workstation_name_arg= +workstation_interactive= + +usage_and_quit() { + print_usage + exit "$1" +} + +load_if_exists() { + if [ -f "$1" ]; then + . "$1" + fi +} + +load_expected() { + if [ -f "$1" ]; then + . "$1" + else + error "ws: init: expected to load file $1, but no file found" + fi +} + +print_usage() { + echo "Workstation configuration tool." + echo + echo "Usage:" + echo " ws [options] bootstrap" + echo " ws [options] doctor" + echo + echo "Subcommands:" + echo " bootstrap : run the bootstrap process" + echo " doctor : Run checks on local setup" + echo " help : display this message" + echo + echo "Options:" + echo "-h --help : Display this message and exit" + echo "-v -verbose : Be verbose" + echo "-n NAME, --name NAME : Specify the name of this workstation." + echo "-i, --interactive : Interactive mode." + echo "-c, --initial-config-dir : Initial configuration directory." + echo " If user already has a workstation configuration, " + echo " specifies location for tool to use it." + echo " Installs this configuration at default configuration location." +} + +process_cli_args() { + ws_command_arguments=("$@") + local args=("$@") + local i; # + for ((i=0;i < ${#args[@]}; i++)); do + debug "iter:$i ; current:${args[i]} ; max:${#args[@]}" + local current="${args[i]}" + + case "$current" in + (-v|--verbose) + WORKSTATION_VERBOSE=true + WORKSTATION_LOG_LEVEL=info + ;; + (-n|--name) + workstation_name_arg="${args[i+1]}"; + (( i+=1 )); + ;; + (-c|--initial-config-dir) + workstation_initial_config_dir_arg="${args[i+1]}"; + (( i+=1 )); + ;; + (-h|--help|help) + usage_and_quit 0; + ;; + (-i|--interactive) + workstation_interactive=true; + ;; + (bootstrap) + ws_command="$current"; + ;; + (doctor) + ws_command="$current"; + ;; + (*) + error "ws: argument parsing: unknown argument '$current'"; + exit 10; + ;; + esac + done + + return 0 +} + +help_command() { + usage_and_quit 0; +} + +ws_main() { + process_cli_args "$@" + [ -n "$workstation_name_arg" ] && WORKSTATION_NAME="$workstation_name_arg" + + if [ "$WORKSTATION_VERBOSE" = "true" ]; then + set -x + fi + + if [[ -n "$workstation_initial_config_dir_arg" ]]; then + load_expected "$workstation_initial_config_dir_arg/settings.sh" + load_expected "$workstation_initial_config_dir_arg/config.sh" + fi + + if [[ -d "$(ws_config_dir_default)" ]]; then + load_expected "$(ws_config_dir_default)/settings.sh" + load_expected "$(ws_config_dir_default)/config.sh" + fi + + case "$ws_command" in + (bootstrap) bootstrap_command;; + (doctor) doctor_command;; + ("help") help_command;; + (*) error "unknown command $ws_command; how did we get here?" + esac +} + +# if being run directly, run main +(return 0 2>/dev/null) || ws_main "$@" + diff --git a/ws_tool/ws_install.sh b/ws_tool/ws_install.sh new file mode 100755 index 00000000..e1553d8b --- /dev/null +++ b/ws_tool/ws_install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +: "${WORKSTATION_DIR:=$HOME/.config/workstation/workstation_source}" +: "${WORKSTATION_VERSION:=workcomp}" + +TMPINST=$(mktemp -d "${TMPDIR:-/tmp}/ws-install.XXXXXXXXX") +# installer of ws tool/project +( cd "$TMPINST"; + curl -L https://github.com/joelmccracken/workstation/archive/${WORKSTATION_VERSION}.tar.gz | tar zx + + if [[ -e "$WORKSTATION_DIR" ]]; then + mv "$WORKSTATION_DIR" "${WORKSTATION_DIR}-$(date +"%s")" + fi + + mkdir -p "$WORKSTATION_DIR" + mv "${TMPINST}"/workstation-*/{,.[^.]}* "$WORKSTATION_DIR" +)