-
Notifications
You must be signed in to change notification settings - Fork 15
/
functions.sh
191 lines (164 loc) · 5.39 KB
/
functions.sh
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
#!/bin/sh
# This is a file full of helper functions that are of use in hook scripts,
# as well as being common to different scripts in the giddyup deployment
# ecosystem.
#
# These functions rely on the correct, pre-existing global definition of the
# environment variables defined in the "Hook environment" section of
# README.md. If you attempt to use these functions without those variables
# being set, Bad Things will likely happen.
###########################################################################
# Fetch a git config item from the giddyup section of the repo's config
get_config() {
local option="$1"
local default="${2:-}"
git config --file "${REPO}/config" --get "giddyup.${option}" || echo "$default"
}
# Create a symlink from within the `$RELEASE` into somewhere within
# `$ROOT/shared`. The relative path within both `$RELEASE` and
# `$ROOT/shared` is given by the first (and only) argument to this function.
#
# Example:
#
# share some/location
#
# This will create a symlink from $RELEASE/some/location to
# $ROOT/shared/some/location.
#
# NOTE: This function behaves differently depending on whether the symlink
# source (`$RELEASE/some/location`) already exists or not, and whether or
# not the destination exists. The logic is as follows:
#
# * If the parent directory of the source location (in our example,
# `$RELEASE/some`) or the destination location (in our example,
# `$ROOT/shared/some`) does not already exist, it will be created.
#
# * If the source does not exist, then a symlink is created unconditionally.
# If `$ROOT/shared/some/location` doesn't already exist, the symlink will
# dangle until something (eg. the start hook, or the application itself)
# creates it.
#
# * If the source *does* exist, but the destination does not, then the
# source will be moved to the destination before the symlink is created.
# This allows you to ship a default dataset in your application bundle,
# safe in the knowledge that future updates won't overwrite it once it's
# in the `shared` tree.
#
share() {
local shareditem="$1"
case "$shareditem" in
*../*|*/..*)
echo "Nice try, buddy." >&2
exit 1
esac
local src="${RELEASE}/${shareditem}"
local dst="${ROOT}/shared/${shareditem}"
local srcparent
srcparent="$(dirname "$src")"
local dstparent
dstparent="$(dirname "$dst")"
if [ ! -d "$dstparent" ]; then
mkdir -p "$dstparent"
fi
if [ ! -d "$srcparent" ]; then
mkdir -p "$srcparent"
fi
if [ -e "$src" ]; then
if [ ! -e "$dst" ]; then
mv "$src" "$dst"
fi
# Yes, this'll be a NOOP if we've just done the above
rm -rf "$src"
fi
ln -sf "$dst" "$src"
}
# Execute the specified hook.
#
# Example:
#
# run_hook start
#
# This function will look in the configured hooks directory for either
# a file or directory whose name exactly matches the specified hook name
# (`start` in our example). If a directory is found, it will attempt to
# execute all the files in that directory. If a single file is found,
# it will attempt to execute that file.
#
run_hook() {
local hook="$1"
local hookdir
hookdir="$(get_config hookdir "config/hooks")"
if [ -d "${RELEASE}/${hookdir}/${hook}" ]; then
for f in "${RELEASE}/${hookdir}/${hook}/"*; do
exec_hook_file "$f"
done
else
exec_hook_file "${RELEASE}/${hookdir}/${hook}"
fi
}
# Attempts to execute a single hook file, whose fully-qualified path is
# given as the sole argument. Respects the `autochmodhooks` config variable
# when deciding whether or not to execute the file.
#
# Example:
#
# exec_hook_file /home/foo/staging/releases/20130229-225960/config/hooks/start/something
#
exec_hook_file() {
local hook_file="$1"
local autochmodhooks
autochmodhooks="$(get_config autochmodhooks)"
if [ "${autochmodhooks}" = "true" ]; then
chmod +x "$hook_file"
fi
if [ -x "$hook_file" ]; then
env PATH="$PATH" \
APP_ENV="$APP_ENV" \
ROOT="$ROOT" \
REPO="$REPO" \
RELEASE="$RELEASE" \
NEWREV="$NEWREV" \
OLDREV="$OLDREV" \
FUNCS="${GIDDYUP_HOME}/functions.sh" \
REF="$REF" \
"$hook_file"
elif [ -e "$hook_file" ]; then
cat <<EOF >&2
WARNING: file $hook_file does not have executable permissions.
You may want to enable giddyup.autochmodhooks, or fix the permissions.
EOF
fi
}
# Sets up a bunch of common environment variables and the basic directory
# structures required to install a release.
#
# Takes no arguments and returns nothing.
#
init_env() {
APP_ENV="$(get_config environment)"
HOOKDIR="$(get_config hookdir)"
HOOKDIR="${HOOKDIR:-config/hooks}"
RELEASE_DATE="$(date +%Y%m%d-%H%M%S)"
RELEASE="${ROOT}/releases/${RELEASE_DATE}"
mkdir -p "${ROOT}/shared"
mkdir -p "${RELEASE}"
}
# Do the hard yards of running hook scripts and re-symlinking the new
# release. Assumes that `$RELEASE` has been successfully populated with a
# complete release of the project.
#
# Takes no arguments and returns nothing.
#
cycle_release() {
local keep_releases
keep_releases="$(get_config keepreleases "5")"
run_hook stop
rm -f current
ln -s "${RELEASE}" current
run_hook start
# Tidy up old releases
if [ "${keep_releases}" != "0" ]; then
cd "${ROOT}/releases"
find . -mindepth 1 -maxdepth 1 -type d | sort -r | tail -n +$((keep_releases + 1)) | xargs rm -rf
fi
}