ZSH Profile

# PATH
export PATH="/opt/homebrew/opt/ruby@2.7/bin:$PATH"

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

phpcs-test-compat() {
	# $1 - PHP version to check compatibility, default 8.0
	# $2 - file or directory to scan, default current directory

	PHP_VERSION="$1"
	if [[ -z "$PHP_VERSION" ]]; then
		PHP_VERSION="8.0"
	fi

	SOURCE="$2"
	if [[ -z "$SOURCE" ]]; then
		SOURCE="."
	fi

	phpcs -p --ignore="*/vendor/*" --extensions=php --standard=PHPCompatibilityWP --runtime-set testVersion "$PHP_VERSION" "$SOURCE"
}

alias sublime='open -a "Sublime Text"'

# Purple Turtle Creative
alias ptc-pull-backups='bash /Users/michelle/web/scripts/purple-turtle-creative/pull-backups.sh'
alias ptc-update-staging='bash /Users/michelle/web/scripts/purple-turtle-creative/update-staging.sh'

ptc-resources() {

	PTC_RESOURCES_ABSPATH="/var/www/html/wp-content/plugins/ptc-resources-server/resources"

	echo
	echo "ABSPATH: $PTC_RESOURCES_ABSPATH"
	echo
	echo 'Available plugins resources:'
	echo
	ssh ptc "ls $PTC_RESOURCES_ABSPATH/plugins/*" | sed -e "s#$PTC_RESOURCES_ABSPATH/##"
}

ptc-push-resource() {
	# $1 - source file to upload
	# $2 - resources directory destination (eg. plugins/completionist)

	SOURCE="$1"
	if [[ -z "$SOURCE" ]]; then
		echo 'Missing argument 1: source file to upload'
		return 1
	fi

	SOURCE_BASENAME=$(basename "$SOURCE")

	# Remove all trailing slashes.
	RESOURCE_DEST=$(echo "$2" | sed 's#/*$##')
	if [[ -z "$RESOURCE_DEST" ]]; then
		echo 'Missing argument 2: resources directory destination (ie. plugins/completionist)'
		return 2
	fi

	if [[ $(echo "$RESOURCE_DEST" | sed -E 's#^([^/]+).*#\1#') != 'plugins' ]]; then
		echo 'Invalid argument 2: resources directory destination must begin with "plugins" since that is the only supported resources type at this time'
		return 3
	fi

	RESOURCE_DEST_ABS="/var/www/html/wp-content/plugins/ptc-resources-server/resources/$RESOURCE_DEST/$SOURCE_BASENAME"

	echo "SOURCE            = $SOURCE"
	echo "SOURCE_BASENAME   = $SOURCE_BASENAME"
	echo "RESOURCE_DEST     = $RESOURCE_DEST"
	echo "RESOURCE_DEST_ABS = $RESOURCE_DEST_ABS"

	scp "$SOURCE" ptc:"$RESOURCE_DEST_ABS"
	ssh ptc "chmod 775 \"$RESOURCE_DEST_ABS\"; chgrp www-data \"$RESOURCE_DEST_ABS\""
}

ptc-download-resource() {
	# $1 - resource file to download (eg. plugins/completionist-pro/completionist-pro-1.1.0.zip)
	# $2 - local file destination (eg. ~/Downloads)

	PTC_RESOURCES_ABSPATH="/var/www/html/wp-content/plugins/ptc-resources-server/resources"

	RESOURCE_FILE="$1"
	if [[ -z "$RESOURCE_FILE" ]]; then
		echo 'Missing argument 1: resource file to download (eg. plugins/completionist-pro/completionist-pro-1.1.0.zip)'
		ptc-resources
		return 1
	elif [[ $(echo "$RESOURCE_FILE" | sed -E 's#^([^/]+).*#\1#') != 'plugins' ]]; then
		echo 'Invalid argument 1: resource file to download must begin with "plugins" since that is the only supported resources type at this time'
		return 1
	elif [[ "${RESOURCE_FILE##*.}" != 'test' ]]; then
		echo "Invalid argument 1: resource file to download should end with .zip extension, found ${RESOURCE_FILE##*.}"
		return 1
	fi

	RESOURCE_FILE_ABS="$PTC_RESOURCES_ABSPATH/$RESOURCE_FILE"

	# Remove all trailing slashes.
	LOCAL_DEST=$(echo "$2" | sed 's#/*$##')
	if [[ -z "$LOCAL_DEST" ]]; then
		echo 'Missing argument 2: local file destination (eg. ~/Downloads)'
		return 2
	fi

	echo "RESOURCE_FILE      = $RESOURCE_FILE"
	echo "RESOURCE_FILE_ABS  = $RESOURCE_FILE_ABS"
	echo "LOCAL_DEST         = $LOCAL_DEST"

	scp ptc:"$RESOURCE_FILE_ABS" "$LOCAL_DEST"
}

alias rsync-plugin='rsync --archive --delete --progress --exclude="*/.git*" --exclude=".gitignore" --exclude=".DS_Store" --exclude="*.log" --exclude="*/node_modules/*"'

# Docker
alias docker-stop-all='docker stop $(docker ps -q)'
alias docker-remove-all='docker rm $(docker ps -aq)'
alias docker-forget-all='docker volume rm $(docker volume ls -q)'
alias docker-shutdown='docker-stop-all && docker-remove-all && docker network prune -f'
alias docker-this-container='pwd | xargs basename | xargs -I% docker ps --filter name=%'
alias docker-forget-this='pwd | xargs basename | xargs -I% docker volume rm %_db_data'
# this container
alias docker-this-container='pwd | xargs basename | xargs -I% docker ps --filter name=%'
alias docker-this-ports='docker-this-container --format "table \t"'
alias docker-this-urls='docker-this-ports | grep -Eo "0\.0\.0\.0:[0-9]{4}->80\/tcp" | sed -e "s#0.0.0.0:#http://localhost:#g" -e "s#->80/tcp#/#g"'
alias docker-forget-this='pwd | xargs basename | xargs -I% docker volume rm %_db_data'
##### Currently doesn't work: the input device is not a TTY
# alias docker-login='pwd | xargs basename | xargs -I% docker exec -it %_wordpress_1 bash'
#####
alias list-site-ports='grep -rio --include docker-compose.yml "\-\s*8\d\d\d:80" /Users/michelle/web/docker'
alias list-claimed-site-ports='grep -rioh --include docker-compose.yml "\-\s*8\d\d\d:80" /Users/michelle/web/docker | sort'

# Git
alias git-default-branch="git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'"
alias git-prune-local="git branch -vv | grep ': gone]' | awk '{print \$1}' | xargs git branch -d"
alias git-update='git checkout $(git-default-branch) && git fetch --prune && git pull && git-prune-local'

# Files
alias prepare-package="zip -rT9 --exclude='*/.git*' --exclude='*/.DS_Store' --exclude='*.log'"
alias grep-wp="grep -FRin --exclude='*/.git*' --exclude='*/node_modules/*' --exclude='*/vendor/*'"

# Tools
alias mailinator='echo;echo michelleb.$(date +%s)@mailinator.com;echo;'
alias sublime='open -a "Sublime Text"'

###############################
### Workflow Processes
###############################

sed-replace-from-file() {
	# $1 - file to search/replace
	# $2 - file containing search/replace sed rules

	echo 'Replacing file contents...'
	LC_ALL=C sed -E -i '.old' -f "$2" "$1"
	if [[ -f "${1}.old" ]]; then
		echo 'Successfully updated the file!'
		rm -f "${1}.old"
	else
		echo 'FAILED to update the file.'
	fi
}

docker-switch() {
	# $1 - site dir name to switch to

	if [[ -z "$1" ]]; then
		echo 'You must specify a site. Here are all available sites:'
		find -s /Users/michelle/web/docker -maxdepth 1 -type d ! -path /Users/michelle/web/docker -exec basename {} \;
		return 1
	elif [[ ! -d /Users/michelle/web/docker/"$1" ]]; then
		echo 'That site does not exist.'
		echo 'Run [docker-switch] with no args to list the available sites.'
		return 1
	fi

	SITE_DIR=/Users/michelle/web/docker/"$1"
	cd "$SITE_DIR"
	docker-shutdown

	# Update Site
	REPO_DIR=`pwd`/`find . -maxdepth 1 -type d ! -path . | sed 1q | xargs basename`
	cd "$REPO_DIR" && git-update
	# Open in Finder
	open "$REPO_DIR"/wp-content

	# Launch Site
	cd "$SITE_DIR"
	docker compose up -d
	# Open Incognito
	open -na "Google Chrome" --args -incognito `docker-this-urls | grep -F 'http://localhost:8'`

	# End in Repo Directory
	cd "$REPO_DIR"
	git restore wp-config-sample.php
}

eval "$(/opt/homebrew/bin/brew shellenv)"

Installing Binaries

When on my Intel-based MacBook Pro, I simply created command aliases to enable binaries that I’d install from GitHub such as PHPCS.

Now, I’m using a better approach by simply creating symbolic links of the installed binaries in the typical $PATH directory like /usr/local/bin. This is useful because I can still update and version control these binaries with git which adds a lot of extra files and directories. Additionally, I can organize those repositories wherever I’d like while the symbolic link adds the executable binaries to my standard $PATH to keep command name lookups quick and standard.

For example, you do this like so:

ln -s /Users/michelle/web/bin/phpcs/bin/phpcs /usr/local/bin

For binaries that have a complicated build, make, configuration, versioning, or other installation process, I like to instead use Homebrew, a package manager for MacOS. PHP is the primary example.