From 22e971940240cedd031808f34dba1f7f80bb4f5e Mon Sep 17 00:00:00 2001 From: Nathaniel Landau Date: Thu, 31 Aug 2023 08:53:42 -0400 Subject: [PATCH] build(precommit): lint typos --- .pre-commit-config.yaml | 15 +- .typos.toml | 7 + CHANGELOG.md | 2 +- poetry.lock | 45 +- pyproject.toml | 4 + scripts/pre-commit-hook.sh | 821 ------------------------------------- 6 files changed, 58 insertions(+), 836 deletions(-) create mode 100644 .typos.toml delete mode 100755 scripts/pre-commit-hook.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b21fd4e..469669b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -72,12 +72,21 @@ repos: hooks: - id: vulture + - repo: "https://github.com/crate-ci/typos" + rev: "v1.16.8" + hooks: + - id: typos + - repo: local hooks: - - id: custom - name: custom pre-commit script - entry: scripts/pre-commit-hook.sh + # This calls a custom pre-commit script. + # Disable if you don't have it. + - id: stopwords + name: stopwords + entry: bash -c '~/bin/git-stopwords ${PWD}/"$@"' language: system + pass_filenames: true + types: [text] - id: black name: black diff --git a/.typos.toml b/.typos.toml new file mode 100644 index 0000000..f58c635 --- /dev/null +++ b/.typos.toml @@ -0,0 +1,7 @@ +[default] + default.locale = "en_us" + + [default.extend-words] + nd = "nd" # In the context of 2nd +[files] + extend-exclude = ["*_cache", ".venv", "src/jdfile/utils/strings.py", "tests/fixtures/"] diff --git a/CHANGELOG.md b/CHANGELOG.md index 68b1503..1d4ba0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,7 +95,7 @@ ### Fix -- **ui**: add seperator to top of select lists +- **ui**: add separator to top of select lists - allow adding inline tags with same key different values (#17) - remove unnecessary question when viewing diffs diff --git a/poetry.lock b/poetry.lock index b1a2f1e..f070e0e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -365,19 +365,22 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "filelock" -version = "3.12.2" +version = "3.12.3" description = "A platform independent file lock." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, - {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, + {file = "filelock-3.12.3-py3-none-any.whl", hash = "sha256:f067e40ccc40f2b48395a80fcbd4728262fab54e232e090a4063ab804179efeb"}, + {file = "filelock-3.12.3.tar.gz", hash = "sha256:0ecc1dd2ec4672a10c8550a8182f1bd0c0a5088470ecd5a125e45f49472fac3d"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.11\""} + [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] [[package]] name = "identify" @@ -1366,16 +1369,36 @@ files = [ {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, ] +[[package]] +name = "typos" +version = "1.16.9" +description = "Source Code Spelling Correction" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typos-1.16.9-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:a57a2bb3c2cefe635a311656e68c37befaee6380af7b5c670250125781862cdb"}, + {file = "typos-1.16.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:22c3006eb56410d1854c78e982b2c61a2f35d5530fa9b58a5c61c9fff80a550e"}, + {file = "typos-1.16.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a0424c6536dc7210892437c610d761278b13dc8a755e35a8a2ee16017bcf112"}, + {file = "typos-1.16.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e26df48469ce64d994b7abcfc31ac18080429e4099ac2d6485b610b589cf418"}, + {file = "typos-1.16.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62abe376396b97b3a9830b51125af1207a0b598c8bad83a4a9c593e0a9e228a8"}, + {file = "typos-1.16.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b4a6dc96a9e8f46f5ef7f49b6b8c504ac432e12ade37e08df4c488acca18b76f"}, + {file = "typos-1.16.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:de0641a1c09f6c5255b9025e6de4e4137a3aaf910dc067312c288a22d3eb245c"}, + {file = "typos-1.16.9-py3-none-win32.whl", hash = "sha256:abcd1dde8b5c598363a392a32ebb1572442a377ad67377cb912b367d269e6a4a"}, + {file = "typos-1.16.9-py3-none-win_amd64.whl", hash = "sha256:1a3f65697e8d290abb05fda06704b64a90489e2b66802d1c2bdc1122d5fdc784"}, + {file = "typos-1.16.9.tar.gz", hash = "sha256:ebc3437484aff83c85cde05128533aaa2f4fdeb29054e7ae7511921d14bb7ce8"}, +] + [[package]] name = "virtualenv" -version = "20.24.3" +version = "20.24.4" description = "Virtual Python Environment builder" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.3-py3-none-any.whl", hash = "sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02"}, - {file = "virtualenv-20.24.3.tar.gz", hash = "sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc"}, + {file = "virtualenv-20.24.4-py3-none-any.whl", hash = "sha256:29c70bb9b88510f6414ac3e55c8b413a1f96239b6b789ca123437d5e892190cb"}, + {file = "virtualenv-20.24.4.tar.gz", hash = "sha256:772b05bfda7ed3b8ecd16021ca9716273ad9f4467c801f27e83ac73430246dca"}, ] [package.dependencies] @@ -1384,7 +1407,7 @@ filelock = ">=3.12.2,<4" platformdirs = ">=3.9.1,<4" [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] @@ -1448,4 +1471,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "eedcfa6c0a971d3a332cd1e09e0819cb3ae0dc6978537d45fbc98f9c3f9e31bb" +content-hash = "6aca7ce8bb2d4e097d7e62625026bf85ab82710a010dacaf49b13371216bdbfa" diff --git a/pyproject.toml b/pyproject.toml index f2144bd..4957110 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,7 @@ ruff = "^0.0.286" sh = "^2.0.6" types-python-dateutil = "^2.8.19.14" + typos = "^1.16.9" vulture = "^2.9.1" [tool.black] @@ -269,6 +270,9 @@ [[tool.poe.tasks.lint.sequence]] shell = "yamllint ." + [[tool.poe.tasks.lint.sequence]] + shell = "typos" + [[tool.poe.tasks.lint.sequence]] shell = "interrogate -c pyproject.toml ." diff --git a/scripts/pre-commit-hook.sh b/scripts/pre-commit-hook.sh deleted file mode 100755 index 126058e..0000000 --- a/scripts/pre-commit-hook.sh +++ /dev/null @@ -1,821 +0,0 @@ -#!/usr/bin/env bash -# shellcheck disable=SC2317 - -_mainScript_() { - - _customStopWords_() { - # DESC: Check if any specified stop words are in the commit diff. If found, the pre-commit hook will exit with a non-zero exit code. - # ARGS: - # $1 (Required): Path to file - # OUTS: - # 0: Success - # 1: Failure - # USAGE: - # _customStopWords_ "/path/to/file.sh" - # NOTE: - # Requires a plaintext stopword file located at - # `~/.git_stop_words` containing one stopword per line. - - [[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" - - local _gitDiffTmp - local FILE_TO_CHECK="${1}" - - _gitDiffTmp="${TMP_DIR}/${RANDOM}.${RANDOM}.${RANDOM}.diff.txt" - - if [ -f "${STOP_WORD_FILE}" ]; then - - if [[ $(basename "${STOP_WORD_FILE}") == "$(basename "${FILE_TO_CHECK}")" ]]; then - debug "$(basename "${1}"): Don't check stop words file for stop words." - return 0 - fi - debug "$(basename "${FILE_TO_CHECK}"): Checking for stop words..." - - # remove blank lines from stopwords file - sed '/^$/d' "${STOP_WORD_FILE}" >"${TMP_DIR}/pattern_file.txt" - - # Check for stopwords - if git diff --cached -- "${FILE_TO_CHECK}" | grep –i -q "new file mode"; then - if grep -i --file="${TMP_DIR}/pattern_file.txt" "${FILE_TO_CHECK}"; then - return 1 - else - return 0 - fi - else - # Add diff to a temporary file - git diff --cached -- "${FILE_TO_CHECK}" | grep '^+' >"${_gitDiffTmp}" - if grep -i --file="${TMP_DIR}/pattern_file.txt" "${_gitDiffTmp}"; then - return 1 - else - return 0 - fi - fi - - else - - notice "Could not find git stopwords file expected at '${STOP_WORD_FILE}'. Continuing..." - return 0 - fi - } - - # Don;t lint binary files - if [[ ${ARGS[0]} =~ \.(jpg|jpeg|gif|png|exe|zip|gzip|tiff|tar|dmg|ttf|otf|m4a|mp3|mkv|mov|avi|eot|svg|woff2?|aac|wav|flac|pdf|doc|xls|ppt|7z|bin|dmg|dat|sql|ico|mpe?g)$ ]]; then - _safeExit_ 0 - fi - - if ! _customStopWords_ "${ARGS[0]}"; then - error "Stop words found in ${ARGS[0]}" - _safeExit_ 1 - fi -} -# end _mainScript_ - -# ################################## Flags and defaults -# Required variables -LOGFILE="${HOME}/logs/$(basename "$0").log" -QUIET=false -LOGLEVEL=ERROR -VERBOSE=false -FORCE=false -DRYRUN=false -declare -a ARGS=() - -# Script specific -LOGLEVEL=NONE -STOP_WORD_FILE="${HOME}/.git_stop_words" -shopt -s nocasematch -# ################################## Custom utility functions (Pasted from repository) - -# ################################## Functions required for this template to work - -_setColors_() { - # DESC: - # Sets colors use for alerts. - # ARGS: - # None - # OUTS: - # None - # USAGE: - # printf "%s\n" "${blue}Some text${reset}" - - if tput setaf 1 >/dev/null 2>&1; then - bold=$(tput bold) - underline=$(tput smul) - reverse=$(tput rev) - reset=$(tput sgr0) - - if [[ $(tput colors) -ge 256 ]] >/dev/null 2>&1; then - white=$(tput setaf 231) - blue=$(tput setaf 38) - yellow=$(tput setaf 11) - green=$(tput setaf 82) - red=$(tput setaf 9) - purple=$(tput setaf 171) - gray=$(tput setaf 250) - else - white=$(tput setaf 7) - blue=$(tput setaf 38) - yellow=$(tput setaf 3) - green=$(tput setaf 2) - red=$(tput setaf 9) - purple=$(tput setaf 13) - gray=$(tput setaf 7) - fi - else - bold="\033[4;37m" - reset="\033[0m" - underline="\033[4;37m" - # shellcheck disable=SC2034 - reverse="" - white="\033[0;37m" - blue="\033[0;34m" - yellow="\033[0;33m" - green="\033[1;32m" - red="\033[0;31m" - purple="\033[0;35m" - gray="\033[0;37m" - fi -} - -_alert_() { - # DESC: - # Controls all printing of messages to log files and stdout. - # ARGS: - # $1 (required) - The type of alert to print - # (success, header, notice, dryrun, debug, warning, error, - # fatal, info, input) - # $2 (required) - The message to be printed to stdout and/or a log file - # $3 (optional) - Pass '${LINENO}' to print the line number where the _alert_ was triggered - # OUTS: - # stdout: The message is printed to stdout - # log file: The message is printed to a log file - # USAGE: - # [_alertType] "[MESSAGE]" "${LINENO}" - # NOTES: - # - The colors of each alert type are set in this function - # - For specified alert types, the funcstac will be printed - - local _color - local _alertType="${1}" - local _message="${2}" - local _line="${3-}" # Optional line number - - [[ $# -lt 2 ]] && fatal 'Missing required argument to _alert_' - - if [[ -n ${_line} && ${_alertType} =~ ^fatal && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then - _message="${_message} ${gray}(line: ${_line}) $(_printFuncStack_)" - elif [[ -n ${_line} && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then - _message="${_message} ${gray}(line: ${_line})" - elif [[ -z ${_line} && ${_alertType} =~ ^fatal && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then - _message="${_message} ${gray}$(_printFuncStack_)" - fi - - if [[ ${_alertType} =~ ^(error|fatal) ]]; then - _color="${bold}${red}" - elif [ "${_alertType}" == "info" ]; then - _color="${gray}" - elif [ "${_alertType}" == "warning" ]; then - _color="${red}" - elif [ "${_alertType}" == "success" ]; then - _color="${green}" - elif [ "${_alertType}" == "debug" ]; then - _color="${purple}" - elif [ "${_alertType}" == "header" ]; then - _color="${bold}${white}${underline}" - elif [ "${_alertType}" == "notice" ]; then - _color="${bold}" - elif [ "${_alertType}" == "input" ]; then - _color="${bold}${underline}" - elif [ "${_alertType}" = "dryrun" ]; then - _color="${blue}" - else - _color="" - fi - - _writeToScreen_() { - ("${QUIET}") && return 0 # Print to console when script is not 'quiet' - [[ ${VERBOSE} == false && ${_alertType} =~ ^(debug|verbose) ]] && return 0 - - if ! [[ -t 1 || -z ${TERM-} ]]; then # Don't use colors on non-recognized terminals - _color="" - reset="" - fi - - if [[ ${_alertType} == header ]]; then - printf "${_color}%s${reset}\n" "${_message}" - else - printf "${_color}[%7s] %s${reset}\n" "${_alertType}" "${_message}" - fi - } - _writeToScreen_ - - _writeToLog_() { - [[ ${_alertType} == "input" ]] && return 0 - [[ ${LOGLEVEL} =~ (off|OFF|Off) ]] && return 0 - if [ -z "${LOGFILE-}" ]; then - LOGFILE="$(pwd)/$(basename "$0").log" - fi - [ ! -d "$(dirname "${LOGFILE}")" ] && mkdir -p "$(dirname "${LOGFILE}")" - [[ ! -f ${LOGFILE} ]] && touch "${LOGFILE}" - - # Don't use colors in logs - local _cleanmessage - _cleanmessage="$(printf "%s" "${_message}" | sed -E 's/(\x1b)?\[(([0-9]{1,2})(;[0-9]{1,3}){0,2})?[mGK]//g')" - # Print message to log file - printf "%s [%7s] %s %s\n" "$(date +"%b %d %R:%S")" "${_alertType}" "[$(/bin/hostname)]" "${_cleanmessage}" >>"${LOGFILE}" - } - - # Write specified log level data to logfile - case "${LOGLEVEL:-ERROR}" in - ALL | all | All) - _writeToLog_ - ;; - DEBUG | debug | Debug) - _writeToLog_ - ;; - INFO | info | Info) - if [[ ${_alertType} =~ ^(error|fatal|warning|info|notice|success) ]]; then - _writeToLog_ - fi - ;; - NOTICE | notice | Notice) - if [[ ${_alertType} =~ ^(error|fatal|warning|notice|success) ]]; then - _writeToLog_ - fi - ;; - WARN | warn | Warn) - if [[ ${_alertType} =~ ^(error|fatal|warning) ]]; then - _writeToLog_ - fi - ;; - ERROR | error | Error) - if [[ ${_alertType} =~ ^(error|fatal) ]]; then - _writeToLog_ - fi - ;; - FATAL | fatal | Fatal) - if [[ ${_alertType} =~ ^fatal ]]; then - _writeToLog_ - fi - ;; - OFF | off) - return 0 - ;; - *) - if [[ ${_alertType} =~ ^(error|fatal) ]]; then - _writeToLog_ - fi - ;; - esac - -} # /_alert_ - -error() { _alert_ error "${1}" "${2-}"; } -warning() { _alert_ warning "${1}" "${2-}"; } -notice() { _alert_ notice "${1}" "${2-}"; } -info() { _alert_ info "${1}" "${2-}"; } -success() { _alert_ success "${1}" "${2-}"; } -dryrun() { _alert_ dryrun "${1}" "${2-}"; } -input() { _alert_ input "${1}" "${2-}"; } -header() { _alert_ header "${1}" "${2-}"; } -debug() { _alert_ debug "${1}" "${2-}"; } -fatal() { - _alert_ fatal "${1}" "${2-}" - _safeExit_ "1" -} - -_printFuncStack_() { - # DESC: - # Prints the function stack in use. Used for debugging, and error reporting. - # ARGS: - # None - # OUTS: - # stdout: Prints [function]:[file]:[line] - # NOTE: - # Does not print functions from the alert class - local _i - declare -a _funcStackResponse=() - for ((_i = 1; _i < ${#BASH_SOURCE[@]}; _i++)); do - case "${FUNCNAME[${_i}]}" in - _alert_ | _trapCleanup_ | fatal | error | warning | notice | info | debug | dryrun | header | success) - continue - ;; - *) - _funcStackResponse+=("${FUNCNAME[${_i}]}:$(basename "${BASH_SOURCE[${_i}]}"):${BASH_LINENO[_i - 1]}") - ;; - esac - - done - printf "( " - printf %s "${_funcStackResponse[0]}" - printf ' < %s' "${_funcStackResponse[@]:1}" - printf ' )\n' -} - -_safeExit_() { - # DESC: - # Cleanup and exit from a script - # ARGS: - # $1 (optional) - Exit code (defaults to 0) - # OUTS: - # None - - if [[ -d ${SCRIPT_LOCK-} ]]; then - if command rm -rf "${SCRIPT_LOCK}"; then - debug "Removing script lock" - else - warning "Script lock could not be removed. Try manually deleting ${yellow}'${SCRIPT_LOCK}'" - fi - fi - - if [[ -n ${TMP_DIR-} && -d ${TMP_DIR-} ]]; then - if [[ ${1-} == 1 && -n "$(ls "${TMP_DIR}")" ]]; then - command rm -r "${TMP_DIR}" - else - command rm -r "${TMP_DIR}" - debug "Removing temp directory" - fi - fi - - trap - INT TERM EXIT - exit "${1:-0}" -} - -_trapCleanup_() { - # DESC: - # Log errors and cleanup from script when an error is trapped. Called by 'trap' - # ARGS: - # $1: Line number where error was trapped - # $2: Line number in function - # $3: Command executing at the time of the trap - # $4: Names of all shell functions currently in the execution call stack - # $5: Scriptname - # $6: $BASH_SOURCE - # USAGE: - # trap '_trapCleanup_ ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${FUNCNAME[*]}" "${0}" "${BASH_SOURCE[0]}"' EXIT INT TERM SIGINT SIGQUIT SIGTERM ERR - # OUTS: - # Exits script with error code 1 - - local _line=${1-} # LINENO - local _linecallfunc=${2-} - local _command="${3-}" - local _funcstack="${4-}" - local _script="${5-}" - local _sourced="${6-}" - - # Replace the cursor in-case 'tput civis' has been used - tput cnorm - - if declare -f "fatal" &>/dev/null && declare -f "_printFuncStack_" &>/dev/null; then - - _funcstack="'$(printf "%s" "${_funcstack}" | sed -E 's/ / < /g')'" - - if [[ ${_script##*/} == "${_sourced##*/}" ]]; then - fatal "${7-} command: '${_command}' (line: ${_line}) [func: $(_printFuncStack_)]" - else - fatal "${7-} command: '${_command}' (func: ${_funcstack} called at line ${_linecallfunc} of '${_script##*/}') (line: ${_line} of '${_sourced##*/}') " - fi - else - printf "%s\n" "Fatal error trapped. Exiting..." - fi - - if declare -f _safeExit_ &>/dev/null; then - _safeExit_ 1 - else - exit 1 - fi -} - -_makeTempDir_() { - # DESC: - # Creates a temp directory to house temporary files - # ARGS: - # $1 (Optional) - First characters/word of directory name - # OUTS: - # Sets $TMP_DIR variable to the path of the temp directory - # USAGE: - # _makeTempDir_ "$(basename "$0")" - - [ -d "${TMP_DIR-}" ] && return 0 - - if [ -n "${1-}" ]; then - TMP_DIR="${TMPDIR:-/tmp/}${1}.${RANDOM}.${RANDOM}.$$" - else - TMP_DIR="${TMPDIR:-/tmp/}$(basename "$0").${RANDOM}.${RANDOM}.${RANDOM}.$$" - fi - (umask 077 && mkdir "${TMP_DIR}") || { - fatal "Could not create temporary directory! Exiting." - } - debug "\$TMP_DIR=${TMP_DIR}" -} - -# shellcheck disable=SC2120 -_acquireScriptLock_() { - # DESC: - # Acquire script lock to prevent running the same script a second time before the - # first instance exits - # ARGS: - # $1 (optional) - Scope of script execution lock (system or user) - # OUTS: - # exports $SCRIPT_LOCK - Path to the directory indicating we have the script lock - # Exits script if lock cannot be acquired - # NOTE: - # If the lock was acquired it's automatically released in _safeExit_() - - local _lockDir - if [[ ${1-} == 'system' ]]; then - _lockDir="${TMPDIR:-/tmp/}$(basename "$0").lock" - else - _lockDir="${TMPDIR:-/tmp/}$(basename "$0").${UID}.lock" - fi - - if command mkdir "${_lockDir}" 2>/dev/null; then - readonly SCRIPT_LOCK="${_lockDir}" - debug "Acquired script lock: ${yellow}${SCRIPT_LOCK}${purple}" - else - if declare -f "_safeExit_" &>/dev/null; then - error "Unable to acquire script lock: ${yellow}${_lockDir}${red}" - fatal "If you trust the script isn't running, delete the lock dir" - else - printf "%s\n" "ERROR: Could not acquire script lock. If you trust the script isn't running, delete: ${_lockDir}" - exit 1 - fi - - fi -} - -_setPATH_() { - # DESC: - # Add directories to $PATH so script can find executables - # ARGS: - # $@ - One or more paths - # OPTS: - # -x - Fail if directories are not found - # OUTS: - # 0: Success - # 1: Failure - # Adds items to $PATH - # USAGE: - # _setPATH_ "/usr/local/bin" "${HOME}/bin" "$(npm bin)" - - [[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" - - local opt - local OPTIND=1 - local _failIfNotFound=false - - while getopts ":xX" opt; do - case ${opt} in - x | X) _failIfNotFound=true ;; - *) - { - error "Unrecognized option '${1}' passed to _backupFile_" "${LINENO}" - return 1 - } - ;; - esac - done - shift $((OPTIND - 1)) - - local _newPath - - for _newPath in "$@"; do - if [ -d "${_newPath}" ]; then - if ! printf "%s" "${PATH}" | grep -Eq "(^|:)${_newPath}($|:)"; then - if PATH="${_newPath}:${PATH}"; then - debug "Added '${_newPath}' to PATH" - else - debug "'${_newPath}' already in PATH" - fi - else - debug "_setPATH_: '${_newPath}' already exists in PATH" - fi - else - debug "_setPATH_: can not find: ${_newPath}" - if [[ ${_failIfNotFound} == true ]]; then - return 1 - fi - continue - fi - done - return 0 -} - -_useGNUutils_() { - # DESC: - # Add GNU utilities to PATH to allow consistent use of sed/grep/tar/etc. on MacOS - # ARGS: - # None - # OUTS: - # 0 if successful - # 1 if unsuccessful - # PATH: Adds GNU utilities to the path - # USAGE: - # # if ! _useGNUUtils_; then exit 1; fi - # NOTES: - # GNU utilities can be added to MacOS using Homebrew - - ! declare -f "_setPATH_" &>/dev/null && fatal "${FUNCNAME[0]} needs function _setPATH_" - - if _setPATH_ \ - "/usr/local/opt/gnu-tar/libexec/gnubin" \ - "/usr/local/opt/coreutils/libexec/gnubin" \ - "/usr/local/opt/gnu-sed/libexec/gnubin" \ - "/usr/local/opt/grep/libexec/gnubin" \ - "/usr/local/opt/findutils/libexec/gnubin" \ - "/opt/homebrew/opt/findutils/libexec/gnubin" \ - "/opt/homebrew/opt/gnu-sed/libexec/gnubin" \ - "/opt/homebrew/opt/grep/libexec/gnubin" \ - "/opt/homebrew/opt/coreutils/libexec/gnubin" \ - "/opt/homebrew/opt/gnu-tar/libexec/gnubin"; then - return 0 - else - return 1 - fi - -} - -_homebrewPath_() { - # DESC: - # Add homebrew bin dir to PATH - # ARGS: - # None - # OUTS: - # 0 if successful - # 1 if unsuccessful - # PATH: Adds homebrew bin directory to PATH - # USAGE: - # # if ! _homebrewPath_; then exit 1; fi - - ! declare -f "_setPATH_" &>/dev/null && fatal "${FUNCNAME[0]} needs function _setPATH_" - - if _uname=$(command -v uname); then - if "${_uname}" | tr '[:upper:]' '[:lower:]' | grep -q 'darwin'; then - if _setPATH_ "/usr/local/bin" "/opt/homebrew/bin"; then - return 0 - else - return 1 - fi - fi - else - if _setPATH_ "/usr/local/bin" "/opt/homebrew/bin"; then - return 0 - else - return 1 - fi - fi -} - -_parseOptions_() { - # DESC: - # Iterates through options passed to script and sets variables. Will break -ab into -a -b - # when needed and --foo=bar into --foo bar - # ARGS: - # $@ from command line - # OUTS: - # Sets array 'ARGS' containing all arguments passed to script that were not parsed as options - # USAGE: - # _parseOptions_ "$@" - - # Iterate over options - local _optstring=h - declare -a _options - local _c - local i - while (($#)); do - case $1 in - # If option is of type -ab - -[!-]?*) - # Loop over each character starting with the second - for ((i = 1; i < ${#1}; i++)); do - _c=${1:i:1} - _options+=("-${_c}") # Add current char to options - # If option takes a required argument, and it's not the last char make - # the rest of the string its argument - if [[ ${_optstring} == *"${_c}:"* && -n ${1:i+1} ]]; then - _options+=("${1:i+1}") - break - fi - done - ;; - # If option is of type --foo=bar - --?*=*) _options+=("${1%%=*}" "${1#*=}") ;; - # add --endopts for -- - --) _options+=(--endopts) ;; - # Otherwise, nothing special - *) _options+=("$1") ;; - esac - shift - done - set -- "${_options[@]-}" - unset _options - - # Read the options and set stuff - # shellcheck disable=SC2034 - while [[ ${1-} == -?* ]]; do - case $1 in - # Custom options - - # Common options - -h | --help) - _usage_ - _safeExit_ - ;; - --loglevel) - shift - LOGLEVEL=${1} - ;; - --logfile) - shift - LOGFILE="${1}" - ;; - -n | --dryrun) DRYRUN=true ;; - -v | --verbose) VERBOSE=true ;; - -q | --quiet) QUIET=true ;; - --force) FORCE=true ;; - --endopts) - shift - break - ;; - *) - if declare -f _safeExit_ &>/dev/null; then - fatal "invalid option: $1" - else - printf "%s\n" "ERROR: Invalid option: $1" - exit 1 - fi - ;; - esac - shift - done - - if [[ -z ${*} || ${*} == null ]]; then - ARGS=() - else - ARGS+=("$@") # Store the remaining user input as arguments. - fi -} - -_columns_() { - # DESC: - # Prints a two column output from a key/value pair. - # Optionally pass a number of 2 space tabs to indent the output. - # ARGS: - # $1 (required): Key name (Left column text) - # $2 (required): Long value (Right column text. Wraps around if too long) - # $3 (optional): Number of 2 character tabs to indent the command (default 1) - # OPTS: - # -b Bold the left column - # -u Underline the left column - # -r Reverse background and foreground colors - # OUTS: - # stdout: Prints the output in columns - # NOTE: - # Long text or ANSI colors in the first column may create display issues - # USAGE: - # _columns_ "Key" "Long value text" [tab level] - - [[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}" - - local opt - local OPTIND=1 - local _style="" - while getopts ":bBuUrR" opt; do - case ${opt} in - b | B) _style="${_style}${bold}" ;; - u | U) _style="${_style}${underline}" ;; - r | R) _style="${_style}${reverse}" ;; - *) fatal "Unrecognized option '${1}' passed to ${FUNCNAME[0]}. Exiting." ;; - esac - done - shift $((OPTIND - 1)) - - local _key="${1}" - local _value="${2}" - local _tabLevel="${3-}" - local _tabSize=2 - local _line - local _rightIndent - local _leftIndent - if [[ -z ${3-} ]]; then - _tabLevel=0 - fi - - _leftIndent="$((_tabLevel * _tabSize))" - - local _leftColumnWidth="$((30 + _leftIndent))" - - if [ "$(tput cols)" -gt 180 ]; then - _rightIndent=110 - elif [ "$(tput cols)" -gt 160 ]; then - _rightIndent=90 - elif [ "$(tput cols)" -gt 130 ]; then - _rightIndent=60 - elif [ "$(tput cols)" -gt 120 ]; then - _rightIndent=50 - elif [ "$(tput cols)" -gt 110 ]; then - _rightIndent=40 - elif [ "$(tput cols)" -gt 100 ]; then - _rightIndent=30 - elif [ "$(tput cols)" -gt 90 ]; then - _rightIndent=20 - elif [ "$(tput cols)" -gt 80 ]; then - _rightIndent=10 - else - _rightIndent=0 - fi - - local _rightWrapLength=$(($(tput cols) - _leftColumnWidth - _leftIndent - _rightIndent)) - - local _first_line=0 - while read -r _line; do - if [[ ${_first_line} -eq 0 ]]; then - _first_line=1 - else - _key=" " - fi - printf "%-${_leftIndent}s${_style}%-${_leftColumnWidth}b${reset} %b\n" "" "${_key}${reset}" "${_line}" - done <<<"$(fold -w${_rightWrapLength} -s <<<"${_value}")" -} - -_usage_() { - cat <