forked from ConnectedHumber/Air-Quality-Web
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build
executable file
·394 lines (302 loc) · 12.5 KB
/
build
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
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
#!/usr/bin/env bash
# Make sure the current directory is the location of this script to simplify matters
cd "$(dirname $(readlink -f $0))";
if [ ! -d "${PWD}/.git" ]; then
echo -e "\033[1m\033[31mError: The .git folder does not appear to exist. Please ensure you clone this repository with git, like this:\n\n\tgit clone https://github.com/ConnectedHumber/Air-Quality-Web.git\n\033[0m";
exit 1;
fi
################
### Settings ###
################
# The name of this project
project_name="Air Quality Mapper";
# The path to the lantern build engine git submodule
lantern_path="./lantern-build-engine";
###
# Custom Settings
###
# Put any custom settings here.
# Client-side build output
cache_dir="./.cache";
build_output_folder="./app";
# Database settings for ssh port forwarding task
database_host="db.connectedhumber.org";
database_name="aq_db";
# Minimum major version of npm
min_npm_version_major="6";
# Deployment settings
deploy_ssh_user="ci";
deploy_ssh_host="www.connectedhumber.org";
deploy_ssh_port="22";
deploy_root_dir="Air-Quality-Web";
###############################################################################
# Check out the lantern git submodule if needed
if [ ! -f "${lantern_path}/lantern.sh" ]; then git submodule update --init "${lantern_path}"; fi
source "${lantern_path}/lantern.sh";
if [[ "$#" -lt 1 ]]; then
echo -e "${FBLE}${project_name}${RS} build script";
echo -e " by Starbeamrainbowlabs";
echo -e "${LC}Powered by the lantern build engine, v${version}${RS}";
echo -e "";
echo -e "${CSECTION}Usage${RS}";
echo -e " ./build ${CTOKEN}{action}${RS} ${CTOKEN}{action}${RS} ${CTOKEN}{action}${RS} ...";
echo -e "";
echo -e "${CSECTION}Available actions${RS}";
echo -e " ${CACTION}setup${RS} - Perform initial setup";
echo -e " ${CACTION}setup-dev${RS} - Perform additional setup for development environments. Run after ${CACTION}setup${RS}.";
echo -e " ${CACTION}database${RS} - Connect to the database via SSH & open MariaDB CLI connection, prompting for a password";
echo -e " ${CACTION}dev-server${RS} - Start a development server";
echo -e " ${CACTION}dev-server-stop${RS} - Stop the currently running development server";
echo -e " ${CACTION}client${RS} - Build the client web app";
echo -e " ${CACTION}client-watch${RS} - Watch for changes to the client code & rebuild automatically";
echo -e " ${CACTION}docs${RS} - Render the documentation";
echo -e " ${CACTION}ci${RS} - Perform CI tasks";
echo -e " ${LC}${CACTION}archive${RS} - CI: Create release archive";
echo -e "";
exit 1;
fi
###############################################################################
# ███████ ███████ ████████ ██ ██ ██████
# ██ ██ ██ ██ ██ ██ ██
# ███████ █████ ██ ██ ██ ██████
# ██ ██ ██ ██ ██ ██
# ███████ ███████ ██ ██████ ██
task_download-composer() {
if [ -f "${cache_dir}/composer" ]; then
return 0;
fi
[ ! -d "${cache_dir}" ] && mkdir "${cache_dir}";
task_begin "Downloading composer";
execute curl "https://getcomposer.org/composer.phar" -o "${cache_dir}/composer"; exit_code=$?;
chmod +x "${cache_dir}/composer";
task_end ${exit_code};
}
check_php_module() {
module_name="$1";
subtask_begin "Checking for ${module_name} PHP module";
if [[ "$(php -m | grep -i pdo_mysql | wc -l)" -eq "0" ]]; then
subtask_end 1 "Error: The php_mysql PHP module is not installed.";
fi
subtask_end 0;
}
task_setup() {
stage_begin "Setting up";
task_begin "Checking environment";
check_command git true;
check_command php true;
check_command node true;
check_command npm true;
check_php_module pdo_mysql;
if [ ! -w "${PWD}" ]; then
task_end 1 "${HC}${FRED}Error: Can't write to the repository directory! This usually you have a permission error of some kind. Try using sudo to run this build command as the user that owns this cloned repository.";
fi
npm_version_major="$(npm --version | head -c 1)";
if [[ "${npm_version_major}" -lt "${min_npm_version_major}" ]]; then
echo "${FRED}${HC}Error: Your version of npm is too far out of date. You're running version $(npm --version), but version 6+ is required.";
fi
task_end $?;
task_begin "Initialising submodules";
execute git submodule update --init;
task_end $?;
task_begin "Installing client dependencies";
echo -e "${HC}Not including development dependencies. To complete setup for development, execute the ${CACTION}setup-dev${RS} ${HC}build task.${RS}";
execute npm install --production;
task_end $?;
tasks_run download-composer;
task_begin "Installing server dependencies";
execute "${cache_dir}/composer" install --no-dev;
task_end $?;
if [ ! -d "./data" ]; then
task_begin "Setting up initial data folder";
mkdir "./data"; chmod 0700 "./data";
echo -e "# -------[ Custom Settings File - Last updated $(date) ]-------" >"./data/settings.toml";
echo -e '[database]\nusername = "INSERT_DATABASE_USERNAME_HERE"\npassword = "INSERT_DATABASE_PASSWORD_HERE"' >>"./data/settings.toml";
chmod 0600 "./data/settings.toml";
echo -e "${HC}Don't forget to edit './data/settings.toml' to specify the database username and password${RS}";
echo -e "";
task_end $?;
fi
stage_end $?;
}
task_setup-dev() {
task_begin "Checking environment";
check_command mysql true optional;
task_end $?;
task_begin "Installing client development dependencies";
execute npm install;
task_end $?;
task_begin "Installing server development dependencies";
execute "${cache_dir}/composer" install;
task_end $?;
}
# ██████ ███████ ██ ██
# ██ ██ ██ ██ ██
# ██ ██ █████ ██ ██
# ██ ██ ██ ██ ██
# ██████ ███████ ████
task_database() {
task_begin "Connecting to the database";
set_title "Database";
ssh -TN "${database_host}" -L 3306:localhost:3306 &
ssh_pid=$!;
sleep 1;
mysql --host 127.0.0.1 --port 3306 --database "${database_name}" --user "${USER}" --password;
kill "${ssh_pid}"; wait; sleep 0.5;
task_end $?;
}
task_dev-server() {
task_begin "Starting development server";
php -S [::1]:40482 &
exit_code=$?;
echo $! >/tmp/micro-lantern-dev-server.pid;
task_end $?; # Should be 0 unless php died for some reason
sleep 1;
}
task_dev-server-stop() {
task_begin "Stopping development server";
kill "$(cat /tmp/micro-lantern-dev-server.pid)";
rm /tmp/micro-lantern-dev-server.pid;
task_end $?;
}
# ██████ ██ ██ ███████ ███ ██ ████████
# ██ ██ ██ ██ ████ ██ ██
# ██ ██ ██ █████ ██ ██ ██ ██
# ██ ██ ██ ██ ██ ██ ██ ██
# ██████ ███████ ██ ███████ ██ ████ ██
task_client() {
task_begin "Packaging Javascript";
execute node_modules/rollup/bin/rollup --sourcemap --config rollup.config.js;
task_end $? "Error: rollup packing failed!";
task_begin "Copying html";
execute cp client_src/index.html "${build_output_folder}";
task_end $?;
# task_begin "Copying css";
# # FUTURE: Package this up too?
# cp -r client_src/css/ "${build_output_folder}";
# task_end $?;
}
task_client-watch() {
set_title "Client Watcher";
echo -e "Watching for changes.";
while :; do # : = infinite loop
# Wait for an update
# inotifywait's non-0 exit code forces an exit for some reason :-/
inotifywait -qr --event modify --format '%:e %f' client_src;
# Rebuild the client code - spawn a sub-process to avoid the hard exit
# This still doesn't work though, which is *really* annoying
stage_begin "Rebuilding client code";
./build client;
stage_end $?;
done
}
# ██████ ██████ ██████ ███████
# ██ ██ ██ ██ ██ ██
# ██ ██ ██ ██ ██ ███████
# ██ ██ ██ ██ ██ ██
# ██████ ██████ ██████ ███████
task_docs() {
task_begin "Rendering docs";
execute node_modules/.bin/nightdocs --config nightdocs.toml;
task_end $?;
task_begin "Copying images";
cp -r docs/images/ __nightdocs/;
task_end $?;
}
# ██████ ██
# ██ ██
# ██ ██
# ██ ██
# ██████ ██
task_ci() {
tasks_run setup setup-dev
NODE_ENV="production" tasks_run client docs archive;
latest_commit="$(git log -n 1 --pretty=format:"%H")";
current_commit="$(git rev-parse HEAD)";
if [ "${GIT_REF_NAME}" == "refs/heads/master" ] && [ "${latest_commit}" == "${current_commit}" ]; then
tasks_run deploy;
else
echo "Not deploying, as this build wasn't on the master branch.";
fi
}
task_archive() {
task_begin "Preparing to archive";
execute mv vendor vendor.bak;
execute "${cache_dir}/composer" install --no-dev;
task_end $?;
task_begin "Packing archive";
# We include the data directory here because we assume that this task is ONLY run in a CI environment, so it should only contain the default setup generated by an earlier task.
execute tar cafv "${ARCHIVE}/Air-Quality-Web.tar.gz" app/ __nightdocs/ lib/ logic/ vendor/ data/ *.php *.md LICENSE version settings.default.toml;
task_end $?;
task_begin "Cleaning up";
execute rm -rf vendor;
execute mv vendor.bak vendor;
task_end $?;
}
task_deploy() {
stage_begin "Deploying to ${deploy_ssh_host}....";
if [ "${SSH_KEY_PATH}" == "" ]; then
echo "${FRED}${HC}Error: Can't find the SSH key as the environment variable SSH_KEY_PATH isn't set.${RS}" >&2;
stage_end 1;
fi
task_begin "Preparing upload";
subtask_begin "Creating temporary directory";
temp_dir="$(mktemp -d --suffix "-air-quality-upload")";
subtask_end $? "Error: Failed to create temporary directory";
subtask_begin "Unpacking release files";
execute tar -xf "${ARCHIVE}/Air-Quality-Web.tar.gz" -C "${temp_dir}";
subtask_end $? "Failed to unpack release files";
subtask_begin "Removing data directory";
rm -r "${temp_dir}/data"; # Delete the default data directory - there's one on the server already
subtask_end $?;
subtask_begin "Unwinding symlinks";
find "${temp_dir}" -type l -exec bash -c 'ln -f "$(readlink -m "$0")" "$0"' {} \;
subtask_end $?;
task_end $?;
# Define the directory whose contents we want to upload
source_upload_dir="${temp_dir}/";
task_begin "Acquiring upload lock";
# Acquire an exclusive project-wide lock so that we only upload stuff one-at-a-time
exec 9<"${WORKSPACE}";
flock --exclusive 9;
task_end $? "Failed to acquire lock!";
task_begin "Uploading release";
sftp -i "${SSH_KEY_PATH}" -P "${deploy_ssh_port}" -o PasswordAuthentication=no "${deploy_ssh_user}@${deploy_ssh_host}" << SFTPCOMMANDS
mkdir ${deploy_root_dir}/www-new
put -r ${source_upload_dir}/* ${deploy_root_dir}/www-new
bye
SFTPCOMMANDS
task_end $?;
task_begin "Making release live";
# Actions:
# 1. Connect to remote server
# 2. Upload new files
# 3. Create data dir symlink
# 4. Swap in new directory
# 5. Delete old directory
lftp_commands_filename="$(mktemp --suffix "-commands.lftp")";
(
echo "set sftp:connect-program 'ssh -x -i ${SSH_KEY_PATH}'";
# We have an extra : before the @ here to avoid the password prompt
echo "connect sftp://${deploy_ssh_user}:@${deploy_ssh_host}:${deploy_ssh_port}";
echo "ln -s \"../data\" \"${deploy_root_dir}/www-new/data\"";
echo "mv \"${deploy_root_dir}/www\" \"${deploy_root_dir}/www-old\"";
echo "mv \"${deploy_root_dir}/www-new\" \"${deploy_root_dir}/www\"";
echo "rm -r \"${deploy_root_dir}/data/cache\"";
echo "rm -r \"${deploy_root_dir}/www-old\"";
echo "bye";
) >"${lftp_commands_filename}";
execute lftp --version;
execute cat "${lftp_commands_filename}";
execute lftp -f "${lftp_commands_filename}";
exit_code=$?
task_end "${exit_code}" "Failed to make release live";
task_begin "Releasing lock";
exec 9>&- # Close file descriptor 9 and release the lock
task_end $?;
task_begin "Cleaning up";
execute rm -r "${temp_dir}";
task_end $?;
stage_end $? "Failed to deploy to ${deploy_ssh_host}.";
}
#########################################################################
tasks_run $@;