-
-
Notifications
You must be signed in to change notification settings - Fork 22
/
build.sh
executable file
·361 lines (292 loc) · 11.5 KB
/
build.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
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
#!/usr/bin/env bash
# Make sure the current directory is the location of this script to simplify matters
cd "$(dirname $(readlink -f $0))";
################
### Settings ###
################
# The name of this project
project_name="Pepperminty Wiki";
# The path to the lantern build engine git submodule
lantern_path="./lantern-build-engine";
###
# Custom Settings
###
# Put any custom settings here.
# The file to store the development server's PID in.
server_pid_file="/tmp/pepperminty-wiki-dev-server.pid";
###############################################################################
# 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, check the environment (skip if only building Pepperminty Wiki itself)";
echo -e " ${CACTION}build${RS} - Build Pepperminty Wiki";
echo -e " ${CACTION}docker${RS} - Build the Docker image";
echo -e " ${CACTION}themes${RS} - Rebuild the theme index";
echo -e " ${CACTION}docs${RS} - Build the documentation";
echo -e " ${CACTION}docs-livereload${RS} - Start the documentation livereload server";
echo -e " ${CACTION}start-server${RS} - Start a development server";
echo -e " ${CACTION}stop-server${RS} - Stop the development server";
echo -e " ${CACTION}sign${RS} - Sign the current build with SHA256 & GPG";
echo -e " ${CACTION}clean${RS} - Delete all build outputs (WARNING: THIS WILL DELETE ALL WIKI DATA)";
echo -e "";
exit 1;
fi
# Tests to see if a PHP module is installed.
# $1 - The name of the module to check for
# $2 - The mode of operation. Values: optional, required
# $3 - The error message to show
test_php_module() {
module_name="${1}";
mode="${2}";
reason="${3}";
subtask_begin "Checking for ${module_name} PHP module";
php -m | grep -q "${module_name}";
exit_code="${?}";
if [[ "${mode}" = "optional" ]] && [[ "${exit_code}" -ne 0 ]]; then
echo "${FYEL}${HC}Warning: The PHP module ${module} was not found. It is needed to ${reason}.${RS}";
fi
subtask_end "${exit_code}";
}
###############################################################################
task_setup() {
task_begin "Checking Environment";
check_command git true;
check_command npm true;
check_command php true;
test_php_module "mbstring" "required" "handle utf-8 characters correctly";
test_php_module "imagick" "optional" "generate image previews";
test_php_module "fileinfo" "optional" "properly check the mime type of uploaded files";
test_php_module "zip" "optional" "compressing exports";
test_php_module "intl" "required" "transliteration in the search engine and when sending emails when utf-8 is disabled";
test_php_module "sqlite" "optional" "store the inverted search index";
check_command jq true optional;
[[ "$?" -eq 0 ]] || echo -e "${FYEL}${HC}Warning: jq is required to update the theme index.${RS}";
check_command firefox true optional;
[[ "$?" -eq 0 ]] || echo -e "${FYEL}${HC}Warning: firefox is required to generate theme previews.${RS}";
check_command convert true optional;
[[ "$?" -eq 0 ]] || echo -e "${FYEL}${HC}Warning: The convert imagemagick command is required to generate theme previews.${RS}";
check_command nproc true optional;
[[ "$?" -eq 0 ]] || echo -e "${FYEL}${HC}Warning: nproc is required to generate theme previews.${RS}";
task_end $?;
task_begin "Initialising submodules";
git submodule update --init;
task_end $?;
task_begin "Installing packages";
npm install;
task_end $?;
task_begin "Creating build folders";
mkdir -p build/_tmp;
echo "This folder contains build tools automatically downloaded." >build/_tmp/README.txt;
task_end $?;
}
task_build() {
if [ -f "./build/index.php" ]; then
task_begin "Deleting old build result";
rm build/index.php;
task_end "$?";
fi
task_begin "Building";
php build.php
task_end $?;
}
task_docker() {
task_build;
task_begin "Building Docker image";
if [[ -n "${DO_DOCKER_SUDO}" ]]; then
sudo docker build --tag pepperminty-wiki .;
else
docker build --tag pepperminty-wiki .;
fi
task_end "$?" "Failed to build Docker image";
}
task_themes() {
if [[ ! -f "${server_pid_file}" ]]; then
NO_BROWSER=true tasks_run start-server;
fi
stage_begin "Updating theme index";
task_begin "Preparing";
[ -f "themes/themeindex.json" ] && cp "themes/themeindex.json" "themes/themeindex.json.old";
# Temporary firefox profile directory
tmp_profile="$(mktemp -d /tmp/peppermint-firefox-profile-XXXXXXX)";
# Temporary file for theme index items
tmp_themeindex_parts="$(mktemp /tmp/peppermint-themeindex-items-XXXXXXX)";
task_end $?;
preview_regen=false;
while read -r filename; do
task_begin "Processing ${filename}";
hash="$(sha256sum "${filename}" | cut -d' ' -f1)";
read -r -d "" awk_script <<'AWK'
BEGIN {
items[0] = "\"hash\": \"" prop_hash "\"";
count=1;
}
/\s+\*\s+@/ {
atrule=$2;
gsub(/@/, "", atrule);
gsub(/\s*\*\s*@[a-z\_]+\s+/, "", $0);
items[count] = "\"" atrule "\": \"" $0 "\"";
count++;
}
END {
result="{";
for(i = 0; i < count; i++) {
result = result items[i];
if(i < count - 1) result = result ",";
}
print(result "}");
}
AWK
# TODO: Consider mapping it out as TSV, then using JQ to generate the object
subtask_begin "Generating index entry";
awk -v prop_hash="${hash}" "${awk_script}" <"${filename}" >>"${tmp_themeindex_parts}";
subtask_end "$?";
# Capture the screenshot
if [ -f "themes/themeindex.json.old" ]; then
theme_id="$(awk '/@id/ { print $3 }' <"${filename}")";
old_hash="$(jq --raw-output --arg theme_id "${theme_id}" '.[] | select(.id == $theme_id).hash' <"themes/themeindex.json")";
# If the hash is the same as last time, don't bother to retake the screenshot
if [[ "${hash}" = "${old_hash}" ]]; then
continue;
fi
fi
preview_regen=true;
screenshot_loc_full="$(dirname "${filename}")/preview_large.png";
screenshot_loc_small="$(dirname "${filename}")/preview_small.png";
# Set the theme
cp "build/peppermint.json" "build/peppermint.json.bak";
tmp_file="$(mktemp /tmp/peppermint-json-XXXXXXX)";
jq --arg theme_css "$(cat "${filename}")" '.css = $theme_css' <"build/peppermint.json" >"${tmp_file}";
mv "${tmp_file}" "build/peppermint.json";
# Capture the full-res screenshot
execute firefox --new-instance --headless --profile "${tmp_profile}" --window-size 1920,1080 --screenshot "${screenshot_loc_full}" "http://[::1]:35623/index.php";
# Resize to get the smaller preview
execute convert "${screenshot_loc_full}" -resize 512x512 "${screenshot_loc_small}";
mv "build/peppermint.json.bak" "build/peppermint.json";
task_end "$?";
done < <(find themes -type f -name "theme.css");
task_begin "Optimising new previews";
find "themes/" -iname "*.png" -print0 | xargs -0 -P"$(nproc)" -n1 optipng -preserve;
task_end "$?";
task_begin "Generating theme index";
jq --tab --slurp . <"${tmp_themeindex_parts}" >"themes/themeindex.json"
task_end "$?";
# Clean up
task_begin "Cleaning up";
[[ -d "${tmp_profile}" ]] && rm -r "${tmp_profile}";
[[ -f "themes/themeindex.json.old" ]] && rm "themes/themeindex.json.old";
task_end 0;
stage_end 0;
}
task_docs() {
task_begin "Building HTTP API Docs";
node_modules/apidoc/bin/apidoc -o './docs/RestApi/' --config apidoc.json --input . -f '.*\.php' -e 'index.php|ModuleApi'
exit_code="$?";
rm -rf doc/;
task_end "${exit_code}";
task_begin "Building PHP Module API Docs";
if [ ! -f "./build/_tmp/phpdoc" ]; then
subtask_begin "Downloading PHPDoc";
# Create the temporary directory if it doesn't exist yet
[ -d "./build/_tmp" ] || mkdir -p "./build/_tmp/";
curl -sSL https://phpdoc.org/phpDocumentor.phar -o ./build/_tmp/phpdoc
subtask_end $?;
fi
php ./build/_tmp/phpdoc run \
--directory . \
--target docs/ModuleApi\
--cache-folder build/_tmp/ModuleApiCache \
--ignore build/,Parsedown*,*.html \
--title "Pepperminty Wiki Module API" \
--visibility public;
task_end $?;
task_begin "Building Main Documentation";
node_modules/.bin/nightdocs -c nightdocs.toml
task_end $?;
}
task_docs-livereload() {
task_begin "Listening for changes to docs";
while :; do
inotifywait -qr -e modify --format '%:e %f' ./docs/ nightdocs.toml;
node_modules/.bin/nightdocs -c nightdocs.toml;
done
task_end $?;
}
task_start-server() {
task_begin "Starting server";
if [ -f "${server_pid_file}" ]; then
task_end 1 "${FRED}${HC}Error: A development server appears to be running already. Try running the 'stop-server' task before starting it again.${RS}";
fi
php -S [::]:35623 -t build/ &
local exit_code=$?; local pid=$!;
echo "${pid}" >"${server_pid_file}";
task_end "${exit_code}" "";
task_begin "Starting theme server";
php -S [::]:35624 -t themes/ &
exit_code=$?; pid=$!;
echo "${pid}" >"${server_pid_file}.themes";
task_end "${exit_code}";
if [[ -z "${NO_BROWSER}" ]]; then
task_begin "Opening Browser";
# sensible-browser isn't opening the right browser :-/
xdg-open "http://[::]:35623";
task_end $?;
fi
}
task_stop-server() {
task_begin "Stopping server";
kill "$(cat "${server_pid_file}")";
rm "${server_pid_file}";
task_end $?;
task_begin "Stopping theme server";
kill "$(cat "${server_pid_file}.themes")";
rm "${server_pid_file}.themes";
task_end "$?";
}
task_sign() {
task_begin "Preparing to sign release";
if [[ ! -f "build/index.php" ]]; then
task_end 1 "Error: build/index.php doesn't exist";
fi
temp_dir="$(mktemp --tmpdir -d "pepperminty-wiki-XXXXXXX")";
cp "build/index.php" "${temp_dir}";
task_end "$?";
task_begin "Signing release";
pushd "${temp_dir}" || { echo "Error: Failed to cd to temporary directory"; exit 1; };
# Generate hashes
find . -type f -not -name "*.SHA256" -print0 | xargs -0 -I{} -P"$(nproc)" sha256sum -b "{}" >HASHES.SHA256;
# Generate GPG signature
gpg --sign --detach-sign --armor HASHES.SHA256;
popd || { echo ""; exit 1; };
task_end "$?";
task_begin "Finalising";
cp "${temp_dir}/HASHES.SHA256" "./build";
cp "${temp_dir}/HASHES.SHA256.asc" "./build";
echo -e "Written output files to ${HC}$(display_url "${PWD}/build/HASHES.SHA256" "HASHES.SHA256") ${RS}and ${HC}$(display_url "${PWD}/build/HASHES.SHA256.asc" "HASHES.SHA256.asc").${RS}";
rm -r "${temp_dir}";
task_end "$?" "Failed to finalise!";
}
task_clean() {
task_begin "Clearing out build outputs";
if [[ "${PEPPERMINT_REALLY_CLEAN}" != "yes" ]]; then
echo -e "Are you SURE you want to continue? This will delete ALL your wiki data!";
echo -e "Set the environment variable PEPPERMINT_REALLY_CLEAN to 'yes' (without quotes) to actually do the deletion.\n\n";
task_end 1 "Aborted.";
exit 1; # Just in case
fi
echo "[PEPPERMINT_REALLY_CLEAN] I sure hope you know what you're doing.";
rm -rf build module_index.json themes/themeindex.json node_modules __nightdocs ;
find themes -type f -name "preview_large.png" -delete;
find themes -type f -name "preview_small.png" -delete;
task_end "$?" "Failed to completely clear out all build outputs";
}
###############################################################################
tasks_run $@;