diff --git a/README.md b/README.md index ffc4dc9..079624a 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Base needs Bash version 4.2 or above. Set up is easy. Essentially, this is what you have to do: -* Check out Base. The standard location for Base is $HOME/base. In case your git directory is elsewhere, symlink `$HOME/git` to it or specify the path by setting `BASE_HOME` in `$HOME/.baserc` file. +* Check out Base. The standard location for Base is $HOME/git/base. In case your git directory is elsewhere, symlink `$HOME/git` to it or specify the path by setting `BASE_HOME` in `$HOME/.baserc` file. * Consolidate your individual settings from your current `.bash_profile` and `.bashrc` into `$USER.sh` file. Place this file under `base/user` directory and check it in to git. * Make a backup of your `.bash_profile`. Replace this file with a symlink to `base/lib/bash_profile`. * Make a backup of your `.bashrc`. Replace this file with a symlink to `base/lib/bashrc`. @@ -37,10 +37,10 @@ Here is an example: mkdir git && cd git git clone git@github.com:codeforester/base.git cd $HOME - mv .bash_profile .bash_profile.safe && ln -sf $HOME/base/lib/bash_profile .bash_profile - mv .bashrc .bashrc.safe && ln -sf $HOME/base/lib/bashrc .bashrc - cp $USER.sh $HOME/base/user - cd $HOME/base + mv .bash_profile .bash_profile.safe && ln -sf $HOME/git/base/lib/bash_profile .bash_profile + mv .bashrc .bashrc.safe && ln -sf $HOME/git/base/lib/bashrc .bashrc + cp $USER.sh $HOME/git/base/user + cd $HOME/git/base git add user/$USER.sh git commit -m "Adding the initial version of $USER.sh" git push @@ -80,11 +80,12 @@ In a typical setting, `.bashrc` sources in `$BASE_HOME/base_init.sh` which does # **Functions exported by base_init.sh** * import - sources in libraries from any place under `BASE_HOME` directory +* base_wrapper - initializes Base inside scripts * base_update - does a `git pull` on Base git directory; add it to `user/.sh` to "auto update" Base # **FAQ** -## My git location is not `$HOME/base`. What should I do? +## My git location is not `$HOME/git/base`. What should I do? You can either @@ -92,7 +93,7 @@ You can either BASE_HOME=/path/to/base -* symlink `$HOME/base` to the right place +* symlink `$HOME/git/base` to the right place You need to do this on every host where you want Base. @@ -122,19 +123,19 @@ Yes, you can, though you will lose the flexibility of keeping your `.bash_profil To turn on Base upon login, add this to your `.bash_profile`: - export BASE_HOME=/path/to/base source "$BASE_HOME/base_init.sh" after making sure you have the base repo checked out under `$BASE_HOME` directory. -If you don't want to change your `.bash_profile` at all, you can still turn Base on and off as needed. First, make sure BASE_HOME is set appropriately, ideally in your `.bash_profile`. +If you don't want to change your `.bash_profile` at all, you can still turn Base on and off as needed. -Run this command to get a shell with Base turned on: +To turn it on: - $BASE_HOME/base.sh shell + source "$BASE_HOME/base_init.sh" + +To turn it off: -or - $BASE_HOME/base.sh + base_deactivate # **Debugging** diff --git a/base.sh b/base.sh deleted file mode 100755 index 93aee37..0000000 --- a/base.sh +++ /dev/null @@ -1,399 +0,0 @@ -#!/usr/bin/env bash - -# -# base.sh -# -# This is a wrapper or a common entry point for Base. It helps in two main ways: -# -# 1. Install base or change Base settings (install, embrace, set-team, set-shared-teams) -# 2. Do things with the installed version of Base (status, run, shell) -# -# In shell mode, we would create a Bash shell: -# a) using Base's bash_profile in case Base is installed -# b) using the in-line common bash_profile in case Base is not installed -# - -error_exit() { printf 'ERROR: %s\n' "$@" >&2; exit 1; } -exit_if_error() { local ec=$1; shift; (($ec)) && error_exit "$@"; } -cd_base() { cd -- "$BASE_HOME" || exit_if_error 1 "Can't cd to BASE_HOME at '$BASE_HOME'"; } -usage_error() { - printf '%s\n' "$@" >&2 - show_common_help >&2 - exit 2 -} - -show_common_help() { - cat << EOF -Usage: base [-b DIR] [-t TEAM] [-x] [install|embrace|update|run|status|shell|set-team|set-shared-teams|version|help] ... --b DIR - use DIR as BASE_HOME directory --t TEAM - use TEAM as BASE_TEAM --s TEAM - use TEAM as BASE_SHARED_TEAMS [use space delimited strings for multiple teams] --f - ignore the existing installation and force install [relevant only for 'base install' command] --v - show the CLI version --x - turn on bash debug mode - -install - install Base -embrace - override .bash_profile and .bashrc so that Base gets enabled upon login -update - update Base by running 'git pull' in BASE_HOME directory -run - run the rest of the command line after initializing Base -shell - if Base is installed, create an interactive Bash shell with Base initialized - if Base is not installed, create an interactive Bash shell with default settings -status - check if Base is installed or not -set-team TEAM - set BASE_TEAM in $HOME/.baserc -set-shared-teams TEAM - set shared BASE_SHARED_TEAMS in $HOME/.baserc [use space delimited strings for multiple teams] -version - show the CLI version -help - show this help message -man - print one line summary of all Base scripts, use '-t team' to filter by team - -Invoking without any arguments would result in an interactive Bash shell with default settings. -EOF -} - -base_init() { - local base_init=$BASE_HOME/base_init.sh - [[ -f $base_init ]] && source "$base_init" -} - -get_base_home() { - if [[ ! $HOME ]]; then - error_exit "Environment variable 'HOME' is not set!" - fi - if [[ ! -d $HOME ]]; then - error_exit "\$HOME '$HOME' is not a directory!" - fi - - # if BASE_HOME is not already set, source .baserc to see it is defined there - if [[ ! $BASE_HOME ]]; then - local baserc=$HOME/.baserc - [[ -f $baserc ]] && source "$baserc" - fi - - # if BASE_HOME is still not set, go with the default value - BASE_HOME=${BASE_HOME:-$HOME/base} -} - -create_base_home() { - # if set, BASE_HOME must hold a directory name - if [[ -e $BASE_HOME && ! -d $BASE_HOME ]]; then - error_exit "$BASE_HOME exists but it is not a directory!" - else - mkdir -- "$BASE_HOME" - exit_if_error $? "Can't create directory '$BASE_HOME'" - fi -} - -verify_base() { - # now make sure BASE_HOME directory is actually a git repo - local git=$BASE_HOME/.git - if [[ ! -d $git ]]; then - glb_error_message="Directory '$BASE_HOME' isn't a git repo; check if Base is installed" - return 1 - else - local oldpwd=$PWD - cd -- "$git" || { glb_error_message="Can't cd to '$git' directory"; return 1; } - if ! git rev-parse --git-dir &>/dev/null; then - glb_error_message="Directory '$git' isn't a git repo; check if Base is installed" - return 1 - fi - local file missing=() - for file in base_init.sh lib/bash_profile lib/bashrc; do - if [[ ! -f $BASE_HOME/$file ]]; then - missing+=($file) - fi - done - cd -- "$oldpwd" - if (( ${#missing[@]} > 0)); then - glb_error_message="Files missing in Base repo: ${missing[@]}" - return 1 - fi - fi - return 0 -} - -patch_baserc() { - local var value base_text_array=() grep_expr - local marker="# BASE_MARKER, do not delete" - local baserc=$HOME/.baserc baserc_temp=$HOME/.baserc.temp - for var; do - value=${!var} - if [[ $value ]]; then - base_text_array+=("export $var=\"$value\" $marker") - fi - if [[ $grep_expr ]]; then - grep_expr="$grep_expr|$var=.*$marker" - else - grep_expr="$var=.*$marker" - fi - done - if [[ ! -f $baserc ]]; then - touch -- "$baserc" - exit_if_error $? "Couldn't create '$baserc'" - fi - rm -f "$baserc_temp" - if [[ $grep_expr ]]; then - grep -Ev -- "$grep_expr" "$baserc" > "$baserc_temp" - else - touch -- "$baserc_temp" - fi - [[ -f $baserc_temp ]] || exit_if_error 1 "Couldn't create '$baserc_temp'" - printf '%s\n' "${base_text_array[@]}" >> "$baserc_temp" - exit_if_error $? "Couldn't append to '$baserc_temp'" - mv -f -- "$baserc_temp" "$baserc" - exit_if_error $? "Couldn't overwrite '$baserc'" - return 0 -} - -do_install() { - local repo="ssh://git@github.com:codeforester/base.git" - if [[ -d $BASE_HOME ]]; then - if ((force_install)); then - local base_home_backup=$BASE_HOME.$current_time - if mv -- "$BASE_HOME" "$base_home_backup"; then - printf '%s\n' "Moved current base home directory '$BASE_HOME' to '$base_home_backup'" - else - exit_if_error 1 "Couldn't move current base home directory '$BASE_HOME' to '$base_home_backup'" - fi - else - printf '%s\n' "Base is already installed at '$BASE_HOME'" - exit 0 - fi - fi - - git clone "$repo" "$BASE_HOME" - exit_if_error $? "Couldn't install Base" - printf '%s\n' "Installed Base at '$BASE_HOME'" - - # - # patch .baserc - # This is how we remember custom BASE_HOME path and BASE_TEAM values. - # The user is free to put custom code into the .baserc file. - # A marker is appended to the lines managed by base CLI. - # - BASE_TEAM=$base_team - BASE_SHARED_TEAMS=$base_shared_teams - patch_baserc BASE_HOME BASE_TEAM BASE_SHARED_TEAMS - - exit 0 -} - -do_embrace() { - if ! verify_base; then - error_exit "$glb_error_message" - fi - local base_bash_profile=$BASE_HOME/lib/bash_profile - local base_bashrc=$BASE_HOME/lib/bashrc - local bash_profile=$HOME/.bash_profile - local bashrc=$HOME/.bashrc - if [[ -L $bash_profile ]]; then - local bash_profile_link=$(readlink "$bash_profile") - fi - if [[ -L $bashrc ]]; then - local bashrc_link=$(readlink "$bashrc") - fi - if [[ $bash_profile_link = $base_bash_profile ]]; then - printf '%s\n' "$bash_profile is already symlinked to $base_bash_profile" - else - if [[ -f $bash_profile ]]; then - local bash_profile_backup=$HOME/.bash_profile.$current_time - printf '%s\n' "Backing up $bash_profile to $bash_profile_backup and overriding it with $base_bash_profile" - if ! cp -- "$bash_profile" "$bash_profile_backup"; then - exit_if_error $? "ERROR: can't create a backup of $bash_profile" - fi - fi - if ln -sf -- "$base_bash_profile" "$bash_profile"; then - printf '%s\n' "Symlinked '$bash_profile' to '$base_bash_profile'" - fi - fi - if [[ $bashrc_link = $base_bashrc ]]; then - printf '%s\n' "$bashrc is already symlinked to $base_bashrc" - else - if [[ -f $bashrc ]]; then - local bashrc_backup=$HOME/.bashrc.$current_time - printf '%s\n' "Backing up $bashrc to $bashrc_backup and overriding it with $base_bashrc" - if ! cp -- "$bashrc" "$bashrc_backup"; then - exit_if_error $? "ERROR: can't create a backup of $bashrc" - fi - fi - if ln -sf -- "$base_bashrc" "$bashrc"; then - printf '%s\n' "Symlinked '$bash_profile' to '$base_bash_profile'" - fi - fi -} - -do_update() { - if [[ -d $BASE_HOME ]]; then - cd -- "$BASE_HOME" || error_exit "Can't cd to BASE_HOME at '$BASE_HOME'" - git pull - else - printf '%s\n' "ERROR: Base is not installed at BASE_HOME '$BASE_HOME'" - exit 1 - fi -} - -do_run() { - if ! verify_base; then - error_exit "$glb_error_message" - fi - base_init - "$@" -} - -do_status() { - if [[ ! -d $BASE_HOME ]]; then - printf '%s\n' "Base is not installed at '$BASE_HOME'" - exit 1 - fi - - if ! verify_base; then - error_exit "$glb_error_message" - else - printf '%s\n' "Base is installed at $BASE_HOME" - fi - exit 0 -} - -do_shell() { - local base_bash_profile=$BASE_HOME/lib/bash_profile - if [[ -d $BASE_HOME && -f $base_bash_profile ]]; then - export BASE_SHELL=1 - exec bash --rcfile "$base_bash_profile" - else - do_common_shell - fi -} - -do_common_shell() { - local common_bash_profile=${0%/*}/bash_profile - if [[ -f $common_bash_profile ]]; then - exec bash --rcfile "$common_bash_profile" - else - error_exit "Common bash profile '$common_bash_profile' not found" - fi -} - -do_version() { - printf '%s\n' "base version $BASE_VERSION" -} - -do_man() { - local dir bin desc dirs team - local -A teams - if ! verify_base; then - error_exit "$glb_error_message" - fi - if ! command -v base-wrapper >/dev/null; then - error_exit "base-wrapper needs to be in your \$PATH to be able to run this command." - fi - dirs=(bin company/bin) - [[ $base_team ]] || base_team=$BASE_TEAM - if [[ $base_team ]]; then - dirs+=(team/$base_team/bin) - teams[$base_team]=1 - fi - # note: BASE_SHARED_TEAMS could be a space delimited string or an array - for team in $BASE_SHARED_TEAMS "${BASE_SHARED_TEAMS[@]}"; do - [[ ${teams[$team]} ]] && continue - dirs+=(team/$team/bin) - teams[$team]=1 - done - for dir in "${dirs[@]}"; do - dir=$BASE_HOME/$dir - [[ -d $dir ]] || continue - cd -- "$dir" || continue - printf '%s\n' "${dir#$BASE_HOME/}:" - for bin in *; do - [[ -f $bin ]] || continue - if head -1 "$bin" | grep -Eq '!/usr/bin/env[[:space:]]+base-wrapper[[:space:]]*'; then - desc=$(./"$bin" --describe) - printf '\t\t%s\n' "$bin: $desc" - fi - done - done -} - -do_set_team() { - if (($# > 1)); then - usage_error "Got too many arguments" - else - if [[ $1 ]]; then - BASE_TEAM=$1 - else - BASE_TEAM=$base_team - fi - if [[ ! $BASE_TEAM ]]; then - usage_error "Usage: base set-team TEAM" - fi - fi - - patch_baserc BASE_TEAM -} - -do_set_shared_teams() { - if (($# > 0)); then - BASE_SHARED_TEAMS=$* - elif [[ $base_shared_teams ]]; then - BASE_SHARED_TEAMS=$base_shared_teams - else - usage_error "Usage: base set-shared-teams TEAM ..." - fi - patch_baserc BASE_SHARED_TEAMS -} - -assert_bash_version() { - local curr_version=$1 min_needed_version=$2 - if ((curr_version < min_needed_version)); then - error_exit "Need Bash version >= $min_needed_version; your version is $curr_version" - fi -} - -main() { - local bash_version="${BASH_VERSINFO[0]}${BASH_VERSINFO[1]}" timefmt="%Y-%m-%d:%H:%M:%S" - if [[ $1 =~ -h|--help|-help|help ]]; then - show_common_help - exit 0 - fi - if [[ $1 =~ --version|-version|-v ]]; then - do_version - exit 0 - fi - force_install=0 - if ((bash_version >= 42)); then - printf -v current_time "%($timefmt)T" -1 - else - current_time=$(date +"$timefmt") - fi - while getopts "fhb:s:t:vx" opt; do - case $opt in - b) export BASE_HOME=$OPTARG;; - t) export base_team=$OPTARG;; - s) export base_shared_teams=$OPTARG;; - f) force_install=1;; - v) do_version - exit 0;; - x) set -x;; - *) show_common_help >&2 - exit 2;; - esac - done - shift $((OPTIND-1)) - command=$1 - shift 2>/dev/null - get_base_home - case $command in - embrace) do_embrace;; - help) show_common_help;; - install) assert_bash_version "$bash_version" 42; do_install;; - run) do_run "$@";; - set-shared-teams) do_set_shared_teams "$@";; - set-team) do_set_team "$@";; - shell) do_shell;; - status) do_status;; - update) do_update;; - version) do_version;; - man) do_man;; - "") do_common_shell;; - *) usage_error "Unrecognized command: $command";; - esac -} - -main "$@" diff --git a/base_init.sh b/base_init.sh index dbebf2f..69cab2b 100755 --- a/base_init.sh +++ b/base_init.sh @@ -35,6 +35,39 @@ check_bash_version() { return $rc } +base_activate() { + local rc=0 + if [[ ! $BASE_HOME ]]; then + printf '%s\n' "ERROR: BASE_HOME is not set" + rc=1 + else + local script=$BASE_HOME/base_init.sh + if [[ -f "$script" ]]; then + unset __base_init_sourced__ # bypass the "idempotence" check + source "$script" # which makes sure the script really gets sourced + else + printf '%s\n' "ERROR: Base init script '$script' does not exist" + rc=1 + fi + fi + return $rc +} + +base_deactivate() { + if [[ $_old_vars_saved ]]; then + PATH=$_old_PATH + PS1=$_old_PS1 + [[ $_old_BASE_HOME ]] && BASE_HOME=$_old_BASE_HOME + + unset _old_PATH _old_PS1 _old_vars_saved _old_BASE_HOME + unset BASE_OS BASE_HOST BASE_DEBUG BASE_SOURCES + unset -f check_bash_version do_init base_debug base_error set_base_home source_it \ + import_libs_and_profiles base_update base_wrapper base_main \ + base_deactivate + unset __base_init_sourced__ + fi +} + do_init() { local rc=0 [[ -f $HOME/.base_debug ]] && export BASE_DEBUG=1 @@ -57,6 +90,14 @@ do_init() { BASE_HOST=$(hostname -s) export BASE_SOURCES=() BASE_OS BASE_HOST + # + # save variables that need to be restored in deactivate + # + _old_vars_saved=1 + _old_PATH=$PATH + _old_PS1=$PS1 + _old_BASE_HOME=$BASE_HOME + return $rc } @@ -71,7 +112,7 @@ set_base_home() { # set BASE_HOME to default in case it is not set [[ -z $BASE_HOME ]] && { - local dir=$HOME/base + local dir=$HOME/git/base base_debug "BASE_HOME not set; defaulting it to '$dir'" BASE_HOME=$dir } @@ -108,8 +149,8 @@ import_libs_and_profiles() { source_it "$BASE_HOME/lib/stdlib.sh" # common library source_it "$BASE_HOME/company/lib/company.sh" # company specific library source_it -i "$BASE_HOME/company/lib/bashrc" # company specific bashrc for interactive shells - source_it -i "$BASE_HOME/user/$USER.sh" # user specific bashrc in the repo for interactive shells - source_it -i "$HOME/.baserc-$USER" # user specific bashrc outside the repo for interactive shells + source_it -i "$BASE_HOME/user/$USER.sh" # user specific bashrc for interactive shells + add_to_path "$BASE_HOME/company/bin" # add company bin to PATH # # team specific actions @@ -131,9 +172,6 @@ import_libs_and_profiles() { add_to_path "$BASE_HOME/team/$team/bin" # add team bin to PATH (gets priority over company bin) teams[$team]=1 done - - # add company bin to PATH; team bins, if any, take priority over company bin - add_to_path "$BASE_HOME/company/bin" } # @@ -146,6 +184,48 @@ base_update() ( } ) +# +# base_wrapper +# +# This function is meant to be called by scripts that are built on top of base. +# base_wrapper is exported so that it is visible to sub processes started from the login shell. +# It discovers base_init and sources it. It also looks at the command line arguments and interprets a few of those, +# like --debug. It calls the main function the modified argument list. The main function is expected to be defined by +# the calling script. +# +base_wrapper() { + local grab_debug=0 arg args script + [[ $1 = "-d" ]] && { grab_debug=1; shift; } + [[ $BASE_HOME ]] || { printf '%s\n' "ERROR: BASE_HOME is not set" >&2; exit 1; } + [[ -d $BASE_HOME ]] || { printf '%s\n' "ERROR: BASE_HOME '$BASE_HOME'is not a directory or is not readable" >&2; exit 1; } + script=$BASE_HOME/base_init.sh + [[ -f $script ]] || { printf '%s\n' "ERROR: base_init script '$script'is not present or is not readable" >&2; exit 1; } + # shellcheck source=/dev/null + source "$script" + ((grab_debug)) && { + # + # grab out '-debug' or '--debug' from argument list and set a global variable to turn on debug mode + # + for arg; do + if [[ $arg = "-debug" || $arg = "--debug" ]]; then + BASE_DEBUG=1 + elif [[ $arg = "-describe" || $arg = "--describe" ]]; then + _describe + exit $? + elif [[ $arg = "-help" || $arg = "--help" ]]; then + _help + exit $? + else + args+=("$arg") + fi + done + + set -- "${args[@]}" + } + + main "$@" +} + base_main() { check_bash_version 4 2 || return $? do_init || return $? @@ -161,7 +241,7 @@ base_main() { # # these functions need to be available to user's subprocesses # - export -f base_update import + export -f base_update base_wrapper import base_activate base_deactivate } # diff --git a/bin/base-wrapper b/bin/base-wrapper deleted file mode 100755 index 32ab0b3..0000000 --- a/bin/base-wrapper +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bash - -# -# base_wrapper -# -# This script is meant to be used in the shebang line of Base scripts, like this: -# -# #!/usr/bin/env base-wrapper -# -# What does this wrapper do? -# -# It discovers base_init and sources it. It also looks at the command line options and interprets a few of those, -# like --debug, --help, --describe etc. It calls the main function with the special options removed from the argument list. -# The main function is expected to be defined by the wrapped script. -# - -_bw_name="base-wrapper" -_bw_description="Run shell scripts in a standardized environment enriched with Base features" -_bw_check_and_execute() { - local cmd=$1; shift - if command -v -- "$cmd" &>/dev/null; then - "$cmd" "$@" - exit $? - else - print_error "Function '$cmd' not implemented" - exit 1 - fi -} - -_bw_describe() { - printf '%s\n' "$_bw_description" -} - -_bw_usage() { - printf '%s\n' "$_bw_name: $_bw_description" - printf '%s\n' "Usage: $_bw_name [options] script [args]" - cat << EOF -Options: --debug|--debug - Turn on DEBUG logging --shell-debug|--shell-debug - Turn shell debug on through 'set -x' --describe|--describe - Invoke base_describe function if defined in script --help|--help - Invoke base_help function if defined in script; if no script specified, show this help -EOF -} - -base_wrapper() { - local arg args script - - ## - ## Do Base set up - ## - - [[ $1 = "-d" ]] && { grab_debug=1; shift; } - [[ $BASE_HOME ]] || { printf '%s\n' "ERROR: BASE_HOME is not set" >&2; exit 1; } - [[ -d $BASE_HOME ]] || { printf '%s\n' "ERROR: BASE_HOME '$BASE_HOME'is not a directory or is not readable" >&2; exit 1; } - script=$BASE_HOME/base_init.sh - [[ -f $script ]] || { printf '%s\n' "ERROR: base_init script '$script'is not present or is not readable" >&2; exit 1; } - # shellcheck source=/dev/null - source "$script" - import lib/stdlib.sh - - ## - ## Execute the script after processing the special command line arguments - ## - - script=$1 - if [[ ! $script || $script = -* ]]; then - _bw_usage >&2 - exit 2 - elif [[ ! -f $script ]]; then - print_error "Script '$script' does not exist" - _bw_usage >&2 - exit 1 - fi - source "$1" - shift - for arg; do - if [[ $arg =~ ^-debug$|^--debug$ ]]; then - export BASE_DEBUG=1 - set_log_level DEBUG - elif [[ $arg =~ ^-shell-debug$|^--shell-debug$ ]]; then - set -x - elif [[ $arg =~ ^-describe$|^--describe$|^-desc$|^--desc$ ]]; then - _bw_check_and_execute base_describe - elif [[ $arg =~ ^-help$|^--help$|^-h$|^--help$ ]]; then - _bw_check_and_execute base_help - else - args+=("$arg") - fi - done - - set -- "${args[@]}" - log_debug "Invoking 'main' with arguments: $@" - _bw_check_and_execute main "$@" -} - -base_wrapper "$@" diff --git a/bin/caff b/bin/caff index b08638a..17f702d 100755 --- a/bin/caff +++ b/bin/caff @@ -1,12 +1,8 @@ -#!/usr/bin/env base-wrapper - # # caff: call caffeinate for a named process # -name=caff -description="Caffeinate a named process" -base_help() { +_help() { cat << EOUSAGE $description Usage: caff process_name @@ -14,16 +10,11 @@ If process_name matches multiple running process, we pick up the first one. EOUSAGE } -base_describe() { +_describe() { printf '%s\n' "$description" } main() { - silent=0 - if [[ $1 = "-s" ]]; then - silent=1 - shift - fi if ! type -ft caffeinate >/dev/null; then print_error "There is no caffeinate command on your system" exit 1 @@ -31,7 +22,7 @@ main() { (($# != 1)) && { print_error "need an argument" - base_help + _help exit 2 } @@ -45,7 +36,7 @@ main() { if [[ $cpid ]]; then caffeinate_pid=$(ps -o args -p "$cpid" | awk 'NR==2 {print $3}') if [[ $caffeinate_pid == $vpid ]]; then - ((silent)) || printf '%s\n' "Alreading caffeinating: $process_name pid=$vpid, caffeinate pid=$cpid" + printf '%s\n' "Alreading caffeinating: $process_name pid=$vpid, caffeinate pid=$cpid" exit 0 fi fi @@ -54,3 +45,9 @@ main() { caffeinate -iw "$vpid" & disown exit $? } + +description="Caffeinate a named process" +base_wrapper -d "$@" || { + printf '%s\n' "You need to initialize Base before running this script." >&2 + exit 1 +} diff --git a/bin/sort-in-place b/bin/sort-in-place deleted file mode 100755 index 8df74ce..0000000 --- a/bin/sort-in-place +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env base-wrapper - -# -# sort-in-place: sort files in place -# - -name=sort-in-place -description="Sort text files in place" -base_describe() { - printf '%s\n' "$description" -} - -base_help() { - printf '%s\n' "$name: $description" - printf '%s\n' "Usage: $name [-u] file ..." -} - -main() { - local u_flag file temp rc=0 - if [[ $1 = "-u" ]]; then - u_flag=$1 - shift - fi - - for file; do - if [[ ! -f $file ]]; then - print_warning "$file is not a regular file; skipping" - continue - fi - temp="$file._tmp" - if [[ -f "$temp" ]]; then - print_warning "$temp already exists; skipping $file" - continue - fi - sort $u_flag "$file" > "$temp" - if (($? != 0)); then - print_error "Can't write to '$temp'" - rc=1 - else - if ! mv -- "$temp" "$file"; then - print_error "Can't move '$temp' to '$file'" - rc=1 - fi - fi - done - - exit $rc -} diff --git a/bin/test-command1 b/bin/test-command1 deleted file mode 100755 index 8efd118..0000000 --- a/bin/test-command1 +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env base-wrapper -# -# ^^^ this shebang line is needed -# - -# -# test command: -# - -name=test-command1 -description="Test command 1" - -# -# base-wrapper invokes this function when the script is invoked with '--describe' or '-describe' option -# -base_describe() { - printf '%s\n' "$description" -} - -# -# base-wrapper invokes this function when the script is invoked with '--help' or '-help' or '-h' option -# -base_help() { - printf '%s\n' "$name: $description" - printf '%s\n' "Usage: $name ..." -} - -# -# base-wrapper invokes the main function after stripping out standard options like --describe, --debug, and --help from -# the command line arguments list -# -main() { - if (($# != 1)); then - print_error "Invalid arguments" - base_help - exit 2 - fi - - # - # base-wrapper imports stdlib.sh. So, all standard functions, including logging, are available. - # - log_info "Starting" - - # do something - log_info "Finished" -} - -# -# no need to call main function since that responsibility is delegated to base-wrapper -# diff --git a/company/bin/test-command1 b/company/bin/test-command1 deleted file mode 100755 index 7b574ca..0000000 --- a/company/bin/test-command1 +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env base-wrapper - -# -# see bin/test-command1 to understand the structure of a Base-wrapped script -# - -# -# test command for team -# -main() { - log_info "Starting" - # do something - log_info "Finished" -} diff --git a/company/bin/test_command1 b/company/bin/test_command1 new file mode 100755 index 0000000..a18a5e9 --- /dev/null +++ b/company/bin/test_command1 @@ -0,0 +1,10 @@ +# +# test command +# +main() { + log_info "Starting" + # do something + log_info "Finished" +} + +base_wrapper "$@" || { printf '%s\n' "ERROR: base environment not initialized; make sure you have sourced base_init.sh before invoking this script" >&2; exit 1; } diff --git a/lib/assertions.sh b/lib/assertions.sh index 6b9c8b7..67c1435 100644 --- a/lib/assertions.sh +++ b/lib/assertions.sh @@ -52,16 +52,16 @@ assert_regex_match() { # assert if variables are set # if any variable is not set, exit 1 (when -f option is set) or return 1 otherwise # -# Usage: assert_var_not_null [-f] variable ... +# Usage: assert_not_null [-f] variable ... # -assert_var_not_null() { +assert_not_null() { local fatal var num_null=0 [[ "$1" = "-f" ]] && { shift; fatal=1; } for var in "$@"; do [[ -z "${!var}" ]] && printf '%s\n' "Variable '$var' not set" >&2 && ((num_null++)) done - + if ((num_null > 0)); then [[ "$fatal" ]] && exit 1 return 1 @@ -74,46 +74,6 @@ assert_var_not_null() { # assert_valid_url() { (($#)) || return 0 - local url=$1 + url=$1 curl --fail --head -o /dev/null --silent "$url" || fatal_error "Invalid URL - '$url'" } - -# -# assert if directories do exist -# -assert_dir_exists() { - local dir - local rc=0 - for dir; do - if [[ ! -d "$dir" ]]; then - log_error "Directory '$dir' does not exist" - ((rc++)) - fi - done - ((rc)) && exit 1 -} - -# -# assert if directories do exist -# -assert_file_exists() { - local file - local rc=0 - for file; do - if [[ ! -f "$file" ]]; then - log_error "File '$file' does not exist" - ((rc++)) - fi - done - ((rc)) && exit 1 -} - -# -# assert that we are running on the right OS -# -assert_os() { - (($#)) || return - if [[ $BASE_OS != "$1" ]]; then - fatal_error "Required OS: $1, current OS: $BASE_OS" - fi -} diff --git a/lib/bashrc b/lib/bashrc index 66ec47d..23e8a6c 100644 --- a/lib/bashrc +++ b/lib/bashrc @@ -40,7 +40,7 @@ base_init() { # set BASE_HOME to default in case it is not set [[ -z $BASE_HOME ]] && { - dir=$HOME/base + dir=$HOME/git/base base_debug "Defaulting BASE_HOME to '$dir'" export BASE_HOME=$dir } diff --git a/lib/file.sh b/lib/file.sh index 35ced50..95e3aef 100644 --- a/lib/file.sh +++ b/lib/file.sh @@ -1,7 +1,6 @@ ## ## file related functions ## - dirname2() { local path=$1 [[ $path =~ ^[^/]+$ ]] && dir=. || { # if path has no slashes, set dir to . @@ -17,51 +16,3 @@ dirname2() { [[ $dir ]] && printf '%s\n' "$dir" # print only if not empty } - -# -# Attempt to create a list of directories; throw fatal error lazily in case any mkdir fails -# -base_mkdir() { - local dir fails=0 failed_dirs=() - for dir; do - mkdir -p -- "$dir" - if (($? != 0)); then - ((fails++)) - failed_dirs+=("$dir") - fi - done - if ((fails == 1)); then - fatal_error "Couldn't create directory '${failed_dirs[0]}'" - elif ((fails > 1)); then - fatal_error "Couldn't create these directories: ${failed_dirs[@]}" - fi - return 0 -} - -# -# Simple copy with error check -# -base_simple_cp() { - local src=$1 dest=$2 - if (($# != 2)); then - fatal_error "Usage: base_simple_cp source dest" - fi - - if ! command cp -- "$src" "$dest"; then - fatal_error "Can't cp '$src' to '$dest'" - fi -} - -# -# Simple move with error check -# -base_simple_mv() { - local src=$1 dest=$2 - if (($# != 2)); then - fatal_error "Usage: base_simple_mv source dest" - fi - - if ! command mv -- "$src" "$dest"; then - fatal_error "Can't mv '$src' to '$dest'" - fi -} diff --git a/lib/net.sh b/lib/net.sh index baeb5c5..1fadb84 100644 --- a/lib/net.sh +++ b/lib/net.sh @@ -2,8 +2,6 @@ # networking related functions # -import lib/assertions.sh - # # check if $1 is a valid IPV4 address; return 0 if true, 1 otherwise # @@ -19,16 +17,3 @@ validate_ip4() { done return 0 } - -# -# check if URL is valid. Credit: https://stackoverflow.com/a/12199125/6862601 -# -is_valid_url() { - assert_arg_count $# 1 "is_valid_url: expected 1 argument, got $#" - curl --output /dev/null --silent --head --fail "$1" -} - -is_valid_url_no_head() { - assert_arg_count $# 1 "is_valid_url_no_head: expected 1 argument, got $#" - curl --output /dev/null --silent --fail -r 0-0 "$1" -} diff --git a/lib/stdlib.sh b/lib/stdlib.sh index a750da2..35f543a 100644 --- a/lib/stdlib.sh +++ b/lib/stdlib.sh @@ -89,19 +89,12 @@ print_path() { #################################################### LOGGING ########################################################### __log_init__() { - if [[ -t 1 ]]; then - # colors for logging in interactive mode - [[ $COLOR_BOLD ]] || COLOR_BOLD="\033[1m" - [[ $COLOR_RED ]] || COLOR_RED="\033[0;31m" - [[ $COLOR_GREEN ]] || COLOR_GREEN="\033[0;34m" - [[ $COLOR_YELLOW ]] || COLOR_YELLOW="\033[0;33m" - [[ $COLOR_BLUE ]] || COLOR_BLUE="\033[0;32m" - [[ $COLOR_OFF ]] || COLOR_OFF="\033[0m" - else - # no colors to be used if non-interactive - COLOR_RED= COLOR_GREEN= COLOR_YELLOW= COLOR_BLUE= COLOR_OFF= - fi - readonly COLOR_RED COLOR_GREEN COLOR_YELLOW COLOR_BLUE COLOR_OFF + # colors for logging + [[ $COLOR_RED ]] || COLOR_RED="\e[1;31m" + [[ $COLOR_YELLOW ]] || COLOR_YELLOW="\e[1;33m" + [[ $COLOR_BLUE ]] || COLOR_BLUE="\e[1;34m" + [[ $COLOR_OFF ]] || COLOR_OFF="\e[0m" + readonly COLOR_RED COLOR_YELLOW COLOR_OFF # # map log level strings (FATAL, ERROR, etc.) to numeric values @@ -207,10 +200,7 @@ log_info_leave() { _print_log INFO "Leaving function ${FUNCNAME[1]}"; } log_debug_leave() { _print_log DEBUG "Leaving function ${FUNCNAME[1]}"; } log_verbose_leave() { _print_log VERBOSE "Leaving function ${FUNCNAME[1]}"; } -# -# THe print routines don't prefix the messages with the timestamp -# - +# print an error message to stderr print_error() { { printf "${COLOR_RED}ERROR: " @@ -219,6 +209,7 @@ print_error() { } >&2 } +# print a warning message to stdout print_warn() { printf "${COLOR_YELLOW}WARN: " printf '%s\n' "$@" @@ -231,27 +222,6 @@ print_info() { printf "$COLOR_OFF" } -print_success() { - printf "${COLOR_GREEN}SUCCESS: " - printf '%s\n' "$@" - printf "$COLOR_OFF" -} - -print_bold() { - printf '%b\n' "$COLOR_BOLD$@$COLOR_OFF" -} - -print_message() { - printf '%s\n' "$@" -} - -# print only if output is going to terminal -print_tty() { - if [[ -t 1 ]]; then - printf '%s\n' "$@" - fi -} - ################################################## ERROR HANDLING ###################################################### dump_trace() { @@ -280,7 +250,6 @@ exit_if_error() { dump_trace "$@" exit $rc } - return 0 } fatal_error() { @@ -289,43 +258,6 @@ fatal_error() { exit_if_error "$ec" "$@" } -# -# run a simple command (no compound statements or pipelines) and exit if it exits with non-zero -# -run_simple() { - log_debug "Running command: $*" - "$@" - exit_if_error $? "run failed: $@" -} - -# -# safe cd -# -base_cd() { - local dir=$1 - [[ $dir ]] || fatal_error "No arguments or an empty string passed to base_cd" - cd -- "$dir" || fatal_error "Can't cd to '$dir'" -} - -base_cd_nonfatal() { - local dir=$1 - [[ $dir ]] || return 1 - cd -- "$dir" || return 1 - return 0 -} - -# -# safe_unalias -# -safe_unalias() { - # Ref: https://stackoverflow.com/a/61471333/6862601 - local alias_name - for alias_name; do - [[ ${BASH_ALIASES[$alias_name]} ]] && unalias "$alias_name" - done - return 0 -} - ################################################# MISC FUNCTIONS ####################################################### # # For functions that need to return a single value, we use the global variable OUTPUT. @@ -347,14 +279,6 @@ get_my_source_dir() { OUTPUT="$(cd "$(dirname "${BASH_SOURCE[1]}")" >/dev/null 2>&1 && pwd -P)" } -# -# wait for user to hit Enter key -# -wait_for_enter() { - local prompt=${1:-"Press Enter to continue"} - read -r -n1 -s -p "Press Enter to continue" &2; exit 1; } diff --git a/team/test-team2/bin/test-command1 b/team/test-team2/bin/test-command1 deleted file mode 100644 index 7b574ca..0000000 --- a/team/test-team2/bin/test-command1 +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env base-wrapper - -# -# see bin/test-command1 to understand the structure of a Base-wrapped script -# - -# -# test command for team -# -main() { - log_info "Starting" - # do something - log_info "Finished" -} diff --git a/team/test-team2/bin/test_command1 b/team/test-team2/bin/test_command1 new file mode 100644 index 0000000..701eff8 --- /dev/null +++ b/team/test-team2/bin/test_command1 @@ -0,0 +1,10 @@ +# +# test command for team +# +main() { + log_info "Starting" + # do something + log_info "Finished" +} + +base_wrapper "$@" || { printf '%s\n' "ERROR: base environment not initialized; make sure you have sourced base_init.sh before invoking this script" >&2; exit 1; }