aboutsummaryrefslogtreecommitdiffstats
path: root/ves-init.sh
blob: 8885cf9f767768c198bcf60008bcda3b7ce8e03a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
#! /bin/sh
#
# Initialize the sh-ves system within a shell session by sourcing the relevant
# files to add function definitions for functionality that cannot be
# implemented via scripts, as well as initialing some local variables used by
# the system. This file should be sourced in your shell's rc or profile file.
#
# 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. 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
# prior to sourcing this file, in which case they will not be modified,
# or by overwriting their values after sourcing the file.

if [ -z "${XDG_DATA_HOME+x}" ]; then
    SHVES_DATA_DIR="$HOME/.local/share/ves"
else
    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

if [ -z "${SHVES_SCRIPTS_DIR+x}" ]; then
    SHVES_BIN="$HOME/.local/bin/ves_scripts"
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() {
    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" >&2
        fi

        return 1
    fi

    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
. "$SHVES_BIN"/ves-deactivate.sh
. "$SHVES_BIN"/ves-var-add.sh
. "$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