-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdotenv
executable file
·125 lines (109 loc) · 3.55 KB
/
dotenv
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
#!/usr/bin/env bash
# shellcheck disable=SC2128
# shellcheck disable=SC2178
__dotenv=
__dotenv_file=
__dotenv_cmd=.env
.env() {
REPLY=()
[[ $__dotenv_file || ${1-} == -* ]] || .env.--file .env || return
# shellcheck disable=SC2145
if declare -F -- ".env.${1-}" >/dev/null; then .env."$@"; return ; fi
.env --help >&2; return 64
}
.env.-f() { .env.--file "$@"; }
.env.get() {
.env::arg "get requires a key" "$@" &&
[[ "$__dotenv" =~ ^(.*(^|$'\n'))([ ]*)"$1="(.*)$ ]] &&
REPLY=${BASH_REMATCH[4]%%$'\n'*} && REPLY=${REPLY%"${REPLY##*[![:space:]]}"}
}
.env.parse() {
local line key
while IFS= read -r line; do
line=${line#"${line%%[![:space:]]*}"} # trim leading whitespace
line=${line%"${line##*[![:space:]]}"} # trim trailing whitespace
if [[ ! "$line" || "$line" == '#'* ]]; then continue ; fi
if (($#)); then
for key; do
if [[ $key == "${line%%=*}" ]]; then REPLY+=("$line"); break;
fi
done
else
REPLY+=("$line")
fi
done <<<"$__dotenv"
((${#REPLY[@]}))
}
.env.export() { ! .env.parse "$@" || export "${REPLY[@]}"; }
.env.set() {
.env::file load || return ; local key saved=$__dotenv
while (($#)); do
key=${1#+}; key=${key%%=*}
if .env.get "$key"; then
REPLY=()
if [[ $1 == +* ]]; then shift; continue # skip if already found
elif [[ $1 == *=* ]]; then
__dotenv=${BASH_REMATCH[1]}${BASH_REMATCH[3]}$1$'\n'${BASH_REMATCH[4]#*$'\n'}
else
__dotenv=${BASH_REMATCH[1]}${BASH_REMATCH[4]#*$'\n'}
continue # delete all occurrences
fi
elif [[ $1 == *=* ]]; then
__dotenv+="${1#+}"$'\n'
fi
shift
done
[[ $__dotenv == "$saved" ]] || .env::file save
}
.env.puts() { echo "${1-}">>"$__dotenv_file" && __dotenv+="$1"$'\n'; }
.env.generate() {
.env::arg "key required for generate" "$@" || return
.env.get "$1" && return || REPLY=$("${@:2}") || return
.env::one "generate: ouptut of '${*:2}' has more than one line" "$REPLY" || return
.env.puts "$1=$REPLY"
}
.env.--file() {
.env::arg "filename required for --file" "$@" || return
__dotenv_file=$1; .env::file load || return
(($#<2)) || .env "${@:2}"
}
.env::arg() { [[ "${2-}" ]] || { echo "$__dotenv_cmd: $1" >&2; return 64; }; }
.env::one() { [[ "$2" != *$'\n'* ]] || .env::arg "$1"; }
.env::file() {
local REPLY=$__dotenv_file
case "$1" in
load)
__dotenv=; ! [[ -f "$REPLY" ]] || __dotenv="$(<"$REPLY")"$'\n' || return ;;
save)
if [[ -L "$REPLY" ]] && declare -F -- realpath.resolved >/dev/null; then
realpath.resolved "$REPLY"
fi
{ [[ ! -f "$REPLY" ]] || cp -p "$REPLY" "$REPLY.bak"; } &&
printf %s "$__dotenv" >"$REPLY.bak" && mv "$REPLY.bak" "$REPLY"
esac
}
.env.-h() { .env.--help "$@"; }
.env.--help() {
echo "Usage:
$__dotenv_cmd [-f|--file FILE] COMMAND [ARGS...]
$__dotenv_cmd -h|--help
Options:
-f, --file FILE Use a file other than .env
Read Commands:
get KEY Get raw value of KEY (or fail)
parse [KEY...] Get trimmed KEY=VALUE lines for named keys (or all)
export [KEY...] Export the named keys (or all) in shell format
Write Commands:
set [+]KEY[=VALUE]... Set or unset values (in-place w/.bak); + sets default
puts STRING Append STRING to the end of the file
generate KEY [CMD...] Set KEY to the output of CMD unless it already exists;
return the new or existing value."
}
__dotenv() {
set -eu
__dotenv_cmd=${0##*/}
.env.export() { .env.parse "$@" || return 0; printf 'export %q\n' "${REPLY[@]}"; REPLY=(); }
.env "$@" || return $?
${REPLY[@]+printf '%s\n' "${REPLY[@]}"}
}
if [[ $0 == "${BASH_SOURCE-}" ]]; then __dotenv "$@"; exit; fi