diff options
Diffstat (limited to 'ves-init.sh')
| -rwxr-xr-x[-rw-r--r--] | ves-init.sh | 232 |
1 files changed, 221 insertions, 11 deletions
diff --git a/ves-init.sh b/ves-init.sh index e323aaa..8885cf9 100644..100755 --- a/ves-init.sh +++ b/ves-init.sh @@ -7,8 +7,8 @@ # # Note, the correct functioning of other sh-ves functions requires that this # file be sourced prior to calling them. As such, they will check for -# SH_VES_INIT to be created prior to doing anything. If is not suggested to try -# to set this variable manually to get around sourcing this file. +# SH_VES_INIT to be created prior to doing anything. It is not suggested to +# try to set this variable manually to get around sourcing this file. # # This file also provides default values for several sh-ves configuration # variables. You may override these settings by setting the variables @@ -16,11 +16,13 @@ # or by overwriting their values after sourcing the file. if [ -z "${XDG_DATA_HOME+x}" ]; then - SHVES_ENV_DIR="$HOME/.local/share/ves/envs" + SHVES_DATA_DIR="$HOME/.local/share/ves" else - SHVES_ENV_DIR="$XDG_DATA_HOME/ves/envs" + SHVES_DATA_DIR="$XDG_DATA_HOME/ves" fi +SHVES_ENV_DIR="$SHVES_DATA_DIR/envs" + if [ -z "${SHVES_OVERRIDE_VARS+x}" ]; then SHVES_OVERRIDE_VARS="PATH LDPATH LD_LIBRARY_PATH CPATH" fi @@ -31,20 +33,33 @@ else SHVES_BIN="$SHVES_SCRIPTS_DIR" fi +if [ ! -d "$SHVES_ENV_DIR" ]; then + mkdir -p "$SHVES_ENV_DIR" +fi + +# +# Validation is done with case globs rather than grep so that it keeps +# working even when an environment has truncated PATH. +# _shves_check_env_name() { - if ! echo $1 | grep "^[[:alpha:][:digit:]_-]*$" > /dev/null; then - printf "ERROR: Environment [%s] is invalid. Name must contain only letters, -, and _\n" $1 > /dev/stderr - return 1 - fi + case $1 in + ""|*[!a-zA-Z0-9_-]*) + printf "ERROR: Environment [%s] is invalid. Name must contain only letters, digits, -, and _\n" "$1" >&2 + return 1 + ;; + esac return 0 } - +# +# Check that environment $1 exists. If a second argument is given, the +# check is quiet; otherwise an error is printed on failure. +# _shves_check_env_exists() { if [ ! -f "$SHVES_ENV_DIR/$1" ]; then if [ "$#" -lt 2 ]; then - printf "ERROR: Environment [%s] does not exist.\n" $1 > /dev/stderr + printf "ERROR: Environment [%s] does not exist.\n" "$1" >&2 fi return 1 @@ -53,6 +68,196 @@ _shves_check_env_exists() { return 0 } +_shves_check_var_name() { + case $1 in + ""|[!a-zA-Z_]*|*[!a-zA-Z0-9_]*) + printf "ERROR: Variable name [%s] is invalid.\n" "$1" >&2 + return 1 + ;; + esac + + return 0 +} + +# +# Resolve and validate the target environment for a command. $1 is the +# requested environment name (possibly empty); when empty, the active +# environment is used. The name is checked for validity and existence, +# and printed on success. +# +_shves_resolve_env() { + if [ -n "$1" ]; then + _shves_env="$1" + elif [ -n "$SHVES_ENV_NM" ]; then + _shves_env="$SHVES_ENV_NM" + else + printf "ERROR: No environment active or specified.\n" >&2 + return 1 + fi + + if ! _shves_check_env_name "$_shves_env"; then + return 1 + fi + + if ! _shves_check_env_exists "$_shves_env"; then + return 1 + fi + + printf '%s' "$_shves_env" + return 0 +} + +# +# Print the stored value of variable $2 within the environment file $1. +# Prints nothing if the variable is not stored in the environment. +# +_shves_get_var() { + grep "^export_var:$2=" "$1" | cut -d '=' -f 2- +} + +# +# Returns 0 if variable $2 is stored in environment file $1, 1 otherwise. +# +_shves_has_var() { + grep "^export_var:$2=" "$1" > /dev/null +} + +# +# Set variable $2 to value $3 within environment file $1, replacing any +# existing definition. The file is rewritten rather than edited in place +# with sed, so values may safely contain characters special to sed. +# +_shves_set_var() { + grep -v "^export_var:$2=" "$1" > "$1.tmp" + printf "export_var:%s=%s\n" "$2" "$3" >> "$1.tmp" + mv "$1.tmp" "$1" +} + +# +# Remove variable $2 from environment file $1. +# +_shves_del_var() { + grep -v "^export_var:$2=" "$1" > "$1.tmp" + mv "$1.tmp" "$1" +} + +# +# Expand value $2 for path-like variable $1 according to the sh-ves +# convenience rules: values not beginning with / or ./ are taken to be +# relative to $SHVES_DATA_DIR/bin (for PATH) or $SHVES_DATA_DIR/lib +# (for LDPATH and LD_LIBRARY_PATH). Other variables are left untouched. +# +_shves_expand_path() { + case $2 in + /*|./*) + printf '%s' "$2" + return 0 + ;; + esac + + case $1 in + PATH) + printf '%s' "$SHVES_DATA_DIR/bin/$2" + ;; + LDPATH|LD_LIBRARY_PATH) + printf '%s' "$SHVES_DATA_DIR/lib/$2" + ;; + *) + printf '%s' "$2" + ;; + esac +} + +# +# Returns 0 if variable $1 is recorded in the activation save-state. The +# names in SHVES_SAVED_VARS are space-separated, so padding both the list +# and the pattern with spaces matches whole names only. +# +_shves_is_saved() { + case " $SHVES_SAVED_VARS " in + *" $1 "*) + return 0 + ;; + esac + + return 1 +} + +# +# Restore variable $1 to its pre-activation value from the activation +# save-state, and clear the variable's bookkeeping. The caller is +# responsible for removing the variable from SHVES_SAVED_VARS. +# +# The variable name is only known at run time, so the references must be +# built with eval. For $1 = PATH, the lines below expand to: +# [ "$SHVES_SAVEDSET_PATH" = 1 ] +# export PATH="$SHVES_SAVED_PATH" +# +_shves_restore_var() { + if eval "[ \"\$SHVES_SAVEDSET_$1\" = 1 ]"; then + eval "export $1=\"\$SHVES_SAVED_$1\"" + else + unset "$1" + fi + + unset "SHVES_SAVED_$1" "SHVES_SAVEDSET_$1" +} + +# +# Begin and end word-splitting of a :-delimited value. Between the two +# calls, an unquoted expansion splits into one word per entry, with +# globbing disabled so entries containing wildcards pass through intact. +# +_shves_split_begin() { + case $- in + *f*) _shves_had_f=1 ;; + *) _shves_had_f=0 ;; + esac + set -f + _shves_old_ifs="$IFS" + IFS=: +} + +_shves_split_end() { + IFS="$_shves_old_ifs" + if [ "$_shves_had_f" -eq 0 ]; then + set +f + fi + unset _shves_had_f _shves_old_ifs +} + +# +# Export variable $1 with value $2 into the live shell, recording the prior +# value in the activation save-state (if it is not already recorded) so that +# ves_deactivate restores it properly. Only call while an environment is +# active. +# +# The save-state variables are exported so that the state survives across +# subshell invocations. This allows non-POSIX shells (such as fish) to drive +# sh-ves through a wrapper that runs each command in a fresh sh subshell. +# +_shves_live_export() { + if ! _shves_is_saved "$1"; then + # The eval lines build references to the variable named in $1. + # For $1 = PATH, they expand to: + # [ -n "${PATH+x}" ] (is PATH set at all?) + # SHVES_SAVED_PATH=$PATH + if eval "[ -n \"\${$1+x}\" ]"; then + eval "SHVES_SAVEDSET_$1=1" + eval "SHVES_SAVED_$1=\$$1" + export "SHVES_SAVED_$1" + else + eval "SHVES_SAVEDSET_$1=0" + fi + + export "SHVES_SAVEDSET_$1" + SHVES_SAVED_VARS="$SHVES_SAVED_VARS $1" + export SHVES_SAVED_VARS + fi + + export "$1=$2" +} + . "$SHVES_BIN"/ves.sh . "$SHVES_BIN"/ves-export.sh . "$SHVES_BIN"/ves-activate.sh @@ -61,5 +266,10 @@ _shves_check_env_exists() { . "$SHVES_BIN"/ves-var-rm.sh . "$SHVES_BIN"/ves-create.sh . "$SHVES_BIN"/ves-delete.sh +. "$SHVES_BIN"/ves-list.sh +. "$SHVES_BIN"/ves-unset.sh +. "$SHVES_BIN"/ves-show.sh +. "$SHVES_BIN"/ves-copy.sh +. "$SHVES_BIN"/ves-run.sh - +SH_VES_INIT=1 |