From b5ab89ac604d2ab9c2f690099623e8469d42a40f Mon Sep 17 00:00:00 2001 From: pgfm Date: Sun, 22 Nov 2020 14:12:06 -0600 Subject: [PATCH] Initialize repository with working versions of core scripts. --- LICENSE | 12 ++++ README.md | 15 +++++ install.sh | 66 +++++++++++++++++++ src/,adr | 99 +++++++++++++++++++++++++++++ src/,replace-all | 133 +++++++++++++++++++++++++++++++++++++++ src/,squash-merge | 154 +++++++++++++++++++++++++++++++++++++++++++++ src/,update-neovim | 136 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 615 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100755 install.sh create mode 100755 src/,adr create mode 100755 src/,replace-all create mode 100755 src/,squash-merge create mode 100755 src/,update-neovim diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..36f31a3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,12 @@ + + +MIT License + +Copyright (c) 2024 Patrick Garrity (pfm) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..02ef624 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Scripts + +## Installation + +The default installation target is `$HOME/.local/bin` + +```bash +$ ./install.sh +``` + +Please use `./install.sh --help` for more information and options. + +## License + +These scripts are available under the [MIT License](./LICENSE). diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..c09f04f --- /dev/null +++ b/install.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +set -o errexit +set -o errtrace +set -o nounset +set -o pipefail + +# The directory where this script lives - used as the base for finding all +# of the scripts to be installed. +src_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +# Set default values for installation parameters. +script_dir="$HOME/.local/bin" +install_target="all" +install_scripts=true + +display_targets () { + echo 'Valid targets: all, scripts' +} + +display_usage () { + echo 'Usage: install.sh [--script-dir ] [-h|--help]' + echo '' + echo 'Install scripts.' + echo '' + echo ' --script-dir Location for installed scripts.' + echo " Default = \$HOME/.local/bin" + echo ' -h|--help Display this usage text.' + echo '' + echo 'Examples:' + echo '' + echo "./install.sh" +} + +while [[ $# -gt 0 ]] +do +key="$1" + +case $key in + --script-dir) + script_dir="$2" + shift + shift + ;; + -h|--help) + display_usage + exit 0 + ;; + *) + echo "Unrecognized option: $1" + display_usage + exit 1 + ;; +esac +done + +# Validate the selected script directory. +if [ ! -d "$script_dir" ]; then + echo "Installation directory for scripts does not exist or is not a directory (${script_dir})" + exit 1 +fi + +if $install_scripts; then + echo "Installing all scripts to: ${script_dir}" + cp -f "$src_dir"/src/* "${script_dir}" +fi diff --git a/src/,adr b/src/,adr new file mode 100755 index 0000000..4a1443b --- /dev/null +++ b/src/,adr @@ -0,0 +1,99 @@ +#!/bin/bash + +set -o errexit +set -o errtrace +set -o nounset +set -o pipefail + +adr_template="$HOME/.adr/template.md" + +usage() { + cat < + +Available Options: + +-h, --help Print this help and exit +-o, --open Open any impacted ADR files in \$EDITOR + +Available Commands: + +new [dir] Create a new ADR with the given name. If some destination + directory is specified, place the file in that directory. + +Examples: + +\$ adr new 0001-use-adrs.md adr/common +\$ adr --open new 0001-use-adrs.md adr/common +EOF + exit +} + +open_after=false; + +new_adr() { + local adr_name="$1" + local adr_dest="${adr_name}.md" + + if [ -n "${2+xxx}" ]; then + # We have a value - validate it and generate the path. + # First step is to remove all trailing slashes from the path. + adr_dir=$(echo "$2" | sed 's:/*$::') + + if [ ! -d "$adr_dir" ]; then + echo "The specified path ($adr_dir) is not a directory. Cannot create an ADR at that location." + exit 1 + else + adr_dest="${adr_dir}/${adr_name}.md" + fi + fi + + if cp "$adr_template" "$adr_dest"; then + echo "Created new ADR: $adr_dest" + + if $open_after; then + $EDITOR "$adr_dest" + fi + + exit 0 + else + echo "Failed to create a new ADR!" + exit 1 + fi +} + +if [ $# -eq 0 ]; then + usage +fi + +# Parameter parsing +while [[ $# -gt 0 ]] +do +key="$1" + +case $key in + -o|--open) + open_after=true + shift + ;; + new) + if [ -z ${2+x} ]; then + echo "The first argument to the command must be the desired name of the ADR file. Example: 0001-my-adr" + exit 1 + fi + + if [ -z ${3+x} ]; then + new_adr "$2" + else + new_adr "$2" "$3" + fi + ;; + -h|--help) + usage + ;; + *) + echo "Unrecognized option: $1" + usage + ;; +esac +done diff --git a/src/,replace-all b/src/,replace-all new file mode 100755 index 0000000..f02e9b1 --- /dev/null +++ b/src/,replace-all @@ -0,0 +1,133 @@ +#!/bin/bash + +set -eo pipefail + +display_usage() { + echo "Usage: replace-all <-f|--find \$QUERY> <-r|--replace \$LITERAL>" + echo ' [-n|--no-backup] [-v|--verbose] [-h|--help]' + echo '' + echo 'Perform global find/replace in the current directory hierarchy.' + echo '' + echo " -f|--find \$QUERY is used directly in \`sed\`, and identifies the" + echo ' text to replace.' + echo " -r|--replace \$LITERAL is used directly in \`sed\`, and will be inserted" + echo ' literally in place of every match.' + echo ' -d|--dry-run Perform a search and list the impacted files.' + echo ' -n|--no-backup Do not create backup files.' + echo ' -v|--verbose Enable verbose output. Lists impacted files.' + echo ' -h|--help Display this usage text.' + echo '' + echo 'Examples:' + echo '' + echo "replace-all -f 'com.example.foo.v0' -r 'com.example.foo.v1' -d" +} + +# Default values for flags +write_backup=true +verbose=false +dry_run=false + +# Parameter parsing +while [[ $# -gt 0 ]] +do +key="$1" + +case $key in + -f|--find) + find_target="$2" + shift + shift + ;; + -r|--replace) + replace_literal="$2" + shift + shift + ;; + -d|--dry-run) + dry_run=true + shift + ;; + -n|--no-backup) + write_backup=false + shift + ;; + -v|--verbose) + verbose=true + shift + ;; + -h|--help) + display_usage + exit 0 + ;; + *) + echo "Unrecognized option: $1" + display_usage + exit 1 + ;; +esac +done + +# Parameter validation -- ensure we have find and replace set. +if [ -z "${find_target+xxx}" ]; then + echo "Please specify a find query with '-f|--find'" + exit 1 +fi + +if [ -z "$find_target" ] && [ "${find_target+xxx}" = "xxx" ]; then + echo "Please specify a find query with '-f|--find'" + exit 1 +fi + +if [ -z "${replace_literal+xxx}" ]; then + echo "Please specify a replacement value with '-r|--replace'" + exit 1 +fi + +if [ -z "$replace_literal" ] && [ "${replace_literal+xxx}" = "xxx" ]; then + echo "Please specify a replacement value with '-r|--replace'" + exit 1 +fi + +# Start the application - we have everything we need. +if $verbose ; then + if $dry_run ; then + echo 'DRY RUN - no files will be modified:' + else + echo "Performing find/replace in all files within current tree:" + fi + echo -e "\tFinding: '$find_target'" + echo -e "\tReplace With: '$replace_literal'" + echo '' +fi + +# Calculate the impacted files with a ripgrep query. +affected_files=$(rg -l --color never "$find_target") + +tmp_store="${TMPDIR:-/tmp}/replace-all" + +# If backups are enabled, ensure the target directory exists. +if $write_backup ; then + mkdir -p "$tmp_store" +fi + +IFS=$'\n' +for file in $affected_files; do + if $dry_run ; then + # This is a DRY run -- just list the impacted files. + echo "$file" + else + # This is a LIVE run -- perform actual updates to files. + if $write_backup ; then + if $verbose ; then + echo "$file|$tmp_store/${file}.bak" + fi + sed -i'.bak' "s/$find_target/$replace_literal/g" "$file" + mv "${file}.bak" "$tmp_store" + else + if $verbose ; then + echo "$file|" + fi + sed -i "s/$find_target/$replace_literal/g" "$file" + fi + fi +done diff --git a/src/,squash-merge b/src/,squash-merge new file mode 100755 index 0000000..ad5cd78 --- /dev/null +++ b/src/,squash-merge @@ -0,0 +1,154 @@ +#!/bin/bash + +set -eo pipefail + +display_usage() { + echo 'Usage: ,squash-merge [-h|--help] [-b|--base ] [-d|--delete]' + echo ' [-n|--no-push-base] [-r|--remote ] ' + echo '' + echo 'Squash and merge the target branch into the base (main) branch.' + echo 'By default, the base branch will be pushed to the default remote.' + echo '' + echo ' -b|--base Merge to the selected branch.' + echo ' (Default Base Branch: "main")' + echo ' -d|--delete Delete the target branch after merging.' + echo ' -n|--no-remote Do not take any remote actions.' + echo ' -r|--remote Remote where the base branch will be pushed.' + echo ' (Default Remote: "origin")' + echo ' -rb|--rebase Rebase against the base branch (interactive).' + echo ' -q|--quiet Suppress output.' + echo ' The branch to merge into the base branch.' + echo ' -h|--help Display this usage text.' + echo '' + echo '**Examples**' + echo '' + echo ' ,squash-merge my-feature' + echo ' ,squash-merge -d my-feature' + echo ' ,squash-merge -b master -d my-feature' + echo ' ,squash-merge -d -n my-feature' +} + +err() { + if ! $1; then + >&2 echo "$2"; + fi +} + +base_branch="main" +delete_target=false +use_remote=true +git_remote="origin" +quiet=false +do_rebase=false + +while [[ $# -gt 0 ]] +do +key="$1" + +case $key in + -b|--base) + base_branch="$2" + shift + shift + ;; + -d|--delete) + delete_target=true + shift + ;; + -n|--no-remote) + use_remote=false + shift + ;; + -r|--remote) + git_remote="$2" + shift + shift + ;; + -rb|--rebase) + do_rebase=true + shift + ;; + -q|--quiet) + quiet=true; + shift + ;; + -h|--help) + display_usage + exit 0 + ;; + *) + if [ -n "$target_branch" ]; then + echo "Error: Unrecognized argument '$1'" + display_usage + exit 1 + fi + target_branch="$1" + shift + ;; +esac +done + +if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then + err $quiet "Error: not in a git repository." + exit 1 +fi + +# Ensure that the target branch exists. +if ! git show-ref --verify --quiet "refs/heads/$target_branch"; then + err $quiet "Error: Target branch '$target_branch' does not exist." + exit 1 +fi + +# Ensure that the base branch exists. +if ! git show-ref --verify --quiet "refs/heads/$base_branch"; then + err $quiet "Error: base branch '$base_branch' does not exist." + exit 1 +fi + +# Allow the user to rebase if they so choose. +if $do_rebase; then + if [ ! "$(git rev-parse --abbrev-ref HEAD)" = "$target_branch" ]; then + git checkout "$target_branch" + fi + git rebase -i "$base_branch" +fi + +# Switch to the base branch. +if [ ! "$(git rev-parse --abbrev-ref HEAD)" = "$base_branch" ]; then + if ! git checkout "$base_branch"; then + err $quiet "Error: Failed to checkout base branch '$base_branch'" + exit 1 + fi +fi + +# Cherry pick the target branch (single commit) into the base branch. +if ! git cherry-pick "$target_branch"; then + err $quiet "Error: Failed to merge '$target_branch' into '$base_branch'" + exit 1 +fi + +# By default, the base branch is pushed on success. If the user has not opted +# out, push to the selected remote (origin). +if $use_remote; then + if ! git push -u "$git_remote" "$base_branch"; then + err $quiet "Error: Failed to push '$base_branch' to remote '$git_remote'" + exit 1 + fi +fi + +# If the user opts to delete their target branch, do so. If we reach this point, +# the merge has completed successfully and it's just cleanup. +if $delete_target; then + err $quiet "Notice: Merge successful. Deleting branch $target_branch" + git branch -D "$target_branch" + + if $use_remote; then + # If the target branch was never pushed, that's OK. + git push "$git_remote" --delete "$target_branch" || true + + # Clean up the tracking against the selected remote. + git remote prune "$git_remote" + fi +fi + +err $quiet "Successfully merged '$target_branch' into '$base_branch'" diff --git a/src/,update-neovim b/src/,update-neovim new file mode 100755 index 0000000..354671c --- /dev/null +++ b/src/,update-neovim @@ -0,0 +1,136 @@ +#!/bin/bash + +set -eo pipefail + +display_usage() { + echo 'Usage: ,update-neovim [-h|--help] [-d|--dir ] ' + echo '' + echo 'Replace a Neovim installation with a new version.' + echo '' + echo ' -d|--dir Install to the selected directory.' + echo ' (Default : $HOME/.local/install)' + echo ' The version of Neovim to download. If "nightly" is' + echo ' specified, the latest nightly build will be downloaded.' + echo ' -h|--help Display this usage text.' + echo '' + echo '**Examples**' + echo '' + echo ' ,update-neovim nightly' + echo ' ,update-neovim --dir $HOME/tmp nightly' +} + +default_base_dir="$HOME/.local/install" + +# Base directory for Neovim installation. +base_dir="$default_base_dir" + +# Filename of the archive to be downloaded. +nvim_archive="nvim-linux64.tar.gz" + +while [[ $# -gt 0 ]] +do +key="$1" + +case $key in + -d|--dir) + base_dir="$2" + shift + shift + ;; + -h|--help) + display_usage + exit 0 + ;; + *) + if [ -z ${nvim_version+x} ] + then + nvim_version="$1" + else + echo "[Error] The version is already set." + exit 1 + fi + shift + ;; +esac +done + +if [ -z ${nvim_version} ] +then + echo "[Error] The version was not set! Please specify the Neovim version to download." + display_usage + exit 1 +fi + +if [ ! -d "$base_dir" ] +then + echo "[Error] The specified path, '$base_dir', is not a directory." + echo "Please use the -d|--dir option to set a valid directory, or create '$default_base_dir'." + exit 1 +fi + +# The installation directory of the new version. +nvim_dir="$base_dir/nvim-$nvim_version" + +# The symbolic link that controls our Neovim installation. +nvim_sym="$base_dir/nvim" + +# The exact URL for downloading Neovim. +if [ "$nvim_version" = "nightly" ]; +then + nvim_url="https://github.com/neovim/neovim/releases/download/nightly/$nvim_archive" +else + nvim_url="https://github.com/neovim/neovim/releases/download/${nvim_version}/$nvim_archive" +fi + +# Check if we have already installed this version of Neovim: +if [ ! "$nvim_version" = "nightly" ]; then + if [ -d "$nvim_dir" ]; then + echo "[Info] Neovim '${nvim_version}' is already installed! Please see: $nvim_dir" + exit 1 + fi +fi + +echo "Upgrading Neovim to ${nvim_version}..." +echo " - Installation Target: $nvim_dir" +echo " - Download URL: $nvim_url" + +# Attempt to download Neovim, suppressing the normal `wget` output. +wget --quiet "$nvim_url" + +# Validate the download - if `wget` exited with a status not equal to 0, the +# download failed. We can use `$?` to get the last exit status. +if [ "$?" != "0" ]; then + echo "Failed to download Neovim, please ensure the specified version ($nvim_version) is valid." + exit 1 +fi + +echo "" +echo "Successfully downloaded Neovim ($nvim_version)! Unpacking..." + +# Remove the symlink if it exists. +rm $nvim_sym 2>/dev/null || true + +# For nightly installation: +# Backup the existing nightly build if necessary. +if [ "$nvim_version" = "nightly" ] +then + if [ -d "$nvim_dir" ] + then + backup_dir="$base_dir/nvim-nightly-backup" + rm -fr "$backup_dir" 2>/dev/null || true + mv "$nvim_dir" "$backup_dir" + echo "Created a backup of the existing Neovim installation at '$backup_dir'" + fi +fi + +# Extract Neovim to the installation directory +mkdir $nvim_dir +tar xzf "$nvim_archive" -C $nvim_dir --strip-components 1 + +# Clean up: remove the archive that we downloaded. +rm "$nvim_archive" + +# Replace symbolic link to Neovim with the newest version. +ln -s "$nvim_dir" "$nvim_sym" + +echo "Successfully updated Neovim!"