-
Notifications
You must be signed in to change notification settings - Fork 0
/
Setup Development Environment.bash
executable file
·725 lines (623 loc) · 28.1 KB
/
Setup Development Environment.bash
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
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
#!/usr/bin/env bash
#shellcheck disable=SC2034
# The above line will be here next to the shebang instead of below of "## Meta about This Program" due to ShellCheck <0.4.6's bug. This should be moved after Ubuntu's provided version of ShellCheck <0.4.6 EoL'd. Refer https://github.com/koalaman/shellcheck/issues/779 for more information.
# Comments prefixed by BASHDOC: are hints to specific GNU Bash Manual's section:
# https://www.gnu.org/software/bash/manual/
## Metadata about This Program
### Program's name, by default it is determined in runtime according to the filename, set this variable to override the autodetection, default: ${RUNTIME_EXECUTABLE_NAME}(optional)
declare META_PROGRAM_NAME_OVERRIDE=""
### Program's identifier, program's name with character limitation exposed by platform(optional)
declare META_PROGRAM_IDENTIFIER=""
### Program's description, default(optional)
declare META_PROGRAM_DESCRIPTION="Setup environment used for developing this project"
### Intellectual property license applied to this program(optional)
### Choose a License
### https://choosealicense.com/
declare META_PROGRAM_LICENSE=""
### Years since any fraction of copyright material is activated, indicates the year when copyright protection will be outdated(optional)
declare META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE="2017"
### Whether program should pause and expect user pressing enter when program ended, which is useful when launching scripts in GUI, which may undesirebly close the terminal emulator window when the script is exited and leaving user no chance to check execution result
### 0: Don't pause(default)
### 1: Pause
### This parameter is overridable, in case of command-line options like --interactive and --no-interactive
declare -i META_PROGRAM_PAUSE_BEFORE_EXIT="0"
## Metadata about the application this program belongs to
### Human-readable name of application(optional)
declare META_APPLICATION_NAME=""
### Application's identifier, application's name with limitation posed by other software, default(not implemented): unnamed-application
declare META_APPLICATION_IDENTIFIER=""
### Developers' name of application(optional)
declare META_APPLICATION_DEVELOPER_NAME=""
### Application's official site URL(optional)
declare META_APPLICATION_SITE_URL=""
### Application's issue tracker, if there's any(optional)
declare META_APPLICATION_ISSUE_TRACKER_URL=""
### An action to let user get help from developer or other sources when error occurred
declare META_APPLICATION_SEEKING_HELP_OPTION="contact developer"
### The Software Directory Configuration this application uses, refer below section for more info
declare META_APPLICATION_INSTALL_STYLE="SHC"
### These are the dependencies that the script foundation needs, and needs to be checked IMMEDIATELY
### BASHDOC: Bash Features - Arrays(associative array)
declare -r META_RUNTIME_DEPENDENCIES_DESCRIPTION_GNU_COREUTILS="GNU Coreutils"
declare -Ar META_RUNTIME_DEPENDENCIES_CRITICAL=(
["basename"]="${META_RUNTIME_DEPENDENCIES_DESCRIPTION_GNU_COREUTILS}"
["realpath"]="${META_RUNTIME_DEPENDENCIES_DESCRIPTION_GNU_COREUTILS}"
)
### These are the dependencies that are used later and also checked later
declare -Ar META_RUNTIME_DEPENDENCIES=()
## Common constant definitions
declare -ir COMMON_RESULT_SUCCESS=0
declare -ir COMMON_RESULT_FAILURE=1
declare -ir COMMON_BOOLEAN_TRUE=0
declare -ir COMMON_BOOLEAN_FALSE=1
## Notes
### realpath's commandline option, `--strip` will be replaced in favor of `--no-symlinks` after April 2019(Ubuntu 14.04's Support EOL)
## Makes debuggers' life easier - Unofficial Bash Strict Mode
## http://redsymbol.net/articles/unofficial-bash-strict-mode/
## BASHDOC: Shell Builtin Commands - Modifying Shell Behavior - The Set Builtin
### Prematurely terminates the script on any command returning non-zero, append " || true"(BASHDOC: Basic Shell Features » Shell Commands » Lists of Commands) if the non-zero return value is rather intended to happen. A trap on `ERR', if set, is executed before the shell exits.
set -o errexit
### If set, any trap on `ERR' is also inherited by shell functions, command substitutions, and commands executed in a subshell environment.
set -o errtrace
### If set, the return value of a pipeline(BASHDOC: Basic Shell Features » Shell Commands » Pipelines) is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully.
set -o pipefail
### Treat unset variables and parameters other than the special parameters `@' or `*' as an error when performing parameter expansion. An error message will be written to the standard error, and a non-interactive shell will exit.
### NOTE: errexit will NOT be triggered by this condition
### bash - Correct behavior of EXIT and ERR traps when using `set -eu` - Unix & Linux Stack Exchange
### https://unix.stackexchange.com/questions/208112/correct-behavior-of-exit-and-err-traps-when-using-set-eu
set -o nounset
## Unset all null META_PROGRAM_* parameters and readonly all others
for parameter_name in \
META_PROGRAM_NAME_OVERRIDE\
META_PROGRAM_IDENTIFIER\
META_PROGRAM_DESCRIPTION\
META_PROGRAM_LICENSE\
META_PROGRAM_PAUSE_BEFORE_EXIT\
META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE\
; do
if [ -v "${parameter_name}" ]; then
if [ -n "${parameter_name}" ]; then
declare -r "${parameter_name}"
else
unset "${parameter_name}"
fi
fi
done
## Traps
## Functions that will be triggered if certain condition met
## BASHDOC: Shell Builtin Commands » Bourne Shell Builtins(trap)
### Collect all information useful for debugging
meta_trap_err_print_debugging_info(){
if [ ${#} -ne 3 ]; then
printf "ERROR: %s: Wrong function argument quantity!\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
local -ir line_error_location=${1}; shift # The line number that triggers the error
local -r failing_command="${1}"; shift # The failing command
local -ir failing_command_return_status=${1} # The failing command's return value
# Don't print trace for printf commands
set +o xtrace
printf "ERROR: %s has encountered an error and is ending prematurely, %s for support.\n" "${META_PROGRAM_NAME_OVERRIDE:-This program}" "${META_APPLICATION_SEEKING_HELP_OPTION}" 1>&2
printf "\n" # Separate paragraphs
printf "Technical information:\n"
printf "\n" # Separate list title and items
printf " * The error happens at line %s\n" "${line_error_location}"
printf " * The failing command is \"%s\"\n" "${failing_command}"
printf " * Failing command's return status is %s\n" "${failing_command_return_status}"
printf " * Intepreter info: GNU Bash v%s on %s platform\n" "${BASH_VERSION}" "${MACHTYPE}"
printf "\n" # Separate list and further content
return "${COMMON_RESULT_SUCCESS}"
}; declare -rf meta_trap_err_print_debugging_info
meta_trap_err(){
if [ ${#} -ne 3 ]; then
printf "ERROR: %s: Wrong function argument quantity!\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
local -ir line_error_location=${1}; shift # The line number that triggers the error
local -r failing_command="${1}"; shift # The failing command
local -ir failing_command_return_status=${1} # The failing command's return value
meta_trap_err_print_debugging_info "${line_error_location}" "${failing_command}" "${failing_command_return_status}"
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_trap_err
# Variable is expanded when trap triggered, not now
#shellcheck disable=SC2016
declare -r TRAP_ERREXIT_ARG='meta_trap_err ${LINENO} "${BASH_COMMAND}" ${?}'
# We separate the arguments to TRAP_ERREXIT_ARG, so it should be expand here
#shellcheck disable=SC2064
trap "${TRAP_ERREXIT_ARG}" ERR
meta_util_is_parameter_set_and_not_null(){
if [ "${#}" -ne 1 ]; then
printf "%s: Error: argument quantity illegal\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
declare -n name_reference
name_reference="${1}"
if [ ! -v name_reference ]; then
return "${COMMON_RESULT_FAILURE}"
else
if [ -z "${name_reference}" ]; then
return "${COMMON_RESULT_FAILURE}"
else
return "${COMMON_RESULT_SUCCESS}"
fi
fi
}; declare -fr meta_util_is_parameter_set_and_not_null
### Introduce the program and software at leaving
meta_trap_exit_print_application_information(){
# No need to debug this area, keep output simple
set +o xtrace
# Only print the line if:
#
# * There's info to be print
# * Pausing program is desired(META_PROGRAM_PAUSE_BEFORE_EXIT=1)
#
# ...cause it's kinda stupid for a trailing line at end-of-program-output
if meta_util_is_parameter_set_and_not_null META_APPLICATION_NAME\
|| meta_util_is_parameter_set_and_not_null META_APPLICATION_DEVELOPER_NAME\
|| meta_util_is_parameter_set_and_not_null META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE\
|| meta_util_is_parameter_set_and_not_null META_PROGRAM_LICENSE\
|| meta_util_is_parameter_set_and_not_null META_APPLICATION_LICENSE\
|| meta_util_is_parameter_set_and_not_null META_APPLICATION_SITE_URL\
|| meta_util_is_parameter_set_and_not_null META_APPLICATION_ISSUE_TRACKER_URL\
|| (\
meta_util_is_parameter_set_and_not_null META_PROGRAM_PAUSE_BEFORE_EXIT\
&& [ "${META_PROGRAM_PAUSE_BEFORE_EXIT}" -eq 1 ] \
); then
printf -- "------------------------------------\n"
fi
if meta_util_is_parameter_set_and_not_null META_APPLICATION_NAME; then
printf "%s\n" "${META_APPLICATION_NAME}"
fi
if meta_util_is_parameter_set_and_not_null META_APPLICATION_DEVELOPER_NAME; then
printf "%s et. al." "${META_APPLICATION_DEVELOPER_NAME}"
if [ -n "${META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE}" ]; then
printf " " # Separator with ${META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE}
else
printf "\n"
fi
fi
if meta_util_is_parameter_set_and_not_null META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE; then
printf "© %s\n" "${META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE}"
fi
if meta_util_is_parameter_set_and_not_null META_PROGRAM_LICENSE; then
printf "Intellectual Property License: %s\n" "${META_PROGRAM_LICENSE}"
elif meta_util_is_parameter_set_and_not_null META_APPLICATION_LICENSE; then
printf "Intellectual Property License: %s\n" "${META_APPLICATION_LICENSE}"
fi
if meta_util_is_parameter_set_and_not_null META_APPLICATION_SITE_URL; then
printf "Official Website: %s\n" "${META_APPLICATION_SITE_URL}"
fi
if meta_util_is_parameter_set_and_not_null META_APPLICATION_ISSUE_TRACKER_URL; then
printf "Issue Tracker: %s\n" "${META_APPLICATION_ISSUE_TRACKER_URL}"
fi
if meta_util_is_parameter_set_and_not_null META_PROGRAM_PAUSE_BEFORE_EXIT\
&& [ "${META_PROGRAM_PAUSE_BEFORE_EXIT}" -eq 1 ]; then
local enter_holder
printf "Press ENTER to quit the program.\n"
read -r enter_holder
fi
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_trap_exit_print_application_information
meta_trap_exit(){
meta_trap_exit_print_application_information
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_trap_exit
trap 'meta_trap_exit' EXIT
## Workarounds
### Temporarily disable errexit
meta_workaround_errexit_setup() {
if [ ${#} -ne 1 ]; then
printf "ERROR: %s: Wrong function argument quantity!\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
local option=${1} # on: enable errexit; off: disable errexit
if [ "${option}" == "on" ]; then
set -o errexit
# We separate the arguments to TRAP_ERREXIT_ARG, so it should be expand here
#shellcheck disable=SC2064
trap "${TRAP_ERREXIT_ARG}" ERR
elif [ "${option}" == "off" ]; then
set +o errexit
trap - ERR
else
printf "ERROR: %s: Wrong function argument format!\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_workaround_errexit_setup
meta_util_declare_global_parameters(){
if [ "${#}" -eq 0 ]; then
printf "%s: Error: Function parameter quantity illegal\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
for parameter_name in "${@}"; do
declare -g "${parameter_name}"
done
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_util_declare_global_parameters
meta_util_unset_global_parameters_if_null(){
if [ "${#}" -eq 0 ]; then
printf "%s: Error: Function parameter quantity illegal\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
for parameter_name in "${@}"; do
if [ -z "${parameter_name}" ]; then
unset "${parameter_name}"
fi
done
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_util_unset_global_parameters_if_null
## Runtime Dependencies Checking
## shell - Check if a program exists from a Bash script - Stack Overflow
## http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script
meta_checkRuntimeDependencies() {
local -n array_ref="${1}"
if [ "${#array_ref[@]}" -eq 0 ]; then
return "${COMMON_RESULT_SUCCESS}"
else
declare -i exit_status
for a_command in "${!array_ref[@]}"; do
meta_workaround_errexit_setup off
command -v "${a_command}" >/dev/null 2>&1
exit_status="${?}"
meta_workaround_errexit_setup on
if [ ${exit_status} -ne 0 ]; then
printf "ERROR: Command \"%s\" not found, program cannot continue like this.\n" "${a_command}" 1>&2
printf "ERROR: Please make sure %s is installed and it's executable path is in your operating system's executable search path.\n" "${array_ref["${a_command}"]}" >&2
printf "Goodbye.\n"
exit "${COMMON_RESULT_FAILURE}"
fi
done
unset exit_status
return "${COMMON_RESULT_SUCCESS}"
fi
}; declare -fr meta_checkRuntimeDependencies
meta_checkRuntimeDependencies META_RUNTIME_DEPENDENCIES_CRITICAL
meta_checkRuntimeDependencies META_RUNTIME_DEPENDENCIES
## Info acquired from runtime environment
## --------------------------------------
## https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#runtime-determined-settings
## The following variables defines the environment aspects that can only be detected in runtime, we use RUNTIME_ namespace for these variables.
## These variables will not be set if technically not available(e.g. the program is provided to intepreter/etc. via stdin), or just not implemented yet
### The running executable's filename(without the underlying path)
declare RUNTIME_EXECUTABLE_FILENAME
### The running program's filename(like RUNTIME_EXECUTABLE_FILENAME, but without the filename extension
### (default: script's filename without extension, META_PROGRAM_NAME_OVERRIDE if set
declare RUNTIME_EXECUTABLE_NAME
### The path of the directory that the executable reside in
declare RUNTIME_EXECUTABLE_DIRECTORY
### Executable's absolute path(location + filename)
declare RUNTIME_EXECUTABLE_PATH_ABSOLUTE
### Executable's relative path(to current working directory)
declare RUNTIME_EXECUTABLE_PATH_RELATIVE
### Runtime environment's executable search path priority array
declare -a RUNTIME_PATH_DIRECTORIES
IFS=':' read -r -a RUNTIME_PATH_DIRECTORIES <<< "${PATH}" || true # Without this `read` will return 1
declare -r RUNTIME_PATH_DIRECTORIES
### The guessed user input base command (without the arguments), this is handy when showing help, where the proper base command can be displayed(default: auto-detect, unset if not available)
### If ${RUNTIME_EXECUTABLE_DIRECTORY} is in ${RUNTIME_PATH_DIRECTORIES}, this would be ${RUNTIME_EXECUTABLE_FILENAME}, if not this would be ./${RUNTIME_EXECUTABLE_PATH_RELATIVE}
declare RUNTIME_COMMAND_BASE
if [ ! -v BASH_SOURCE ]; then
# S.H.C. isn't possible(probably from stdin), force STANDALONE mode
META_APPLICATION_INSTALL_STYLE=STANDALONE
unset RUNTIME_EXECUTABLE_FILENAME RUNTIME_EXECUTABLE_DIRECTORY RUNTIME_EXECUTABLE_PATH_ABSOLUTE RUNTIME_EXECUTABLE_PATH_RELATIVE
else
# BashFAQ/How do I determine the location of my script? I want to read some config files from the same place. - Greg's Wiki
# http://mywiki.wooledge.org/BashFAQ/028
RUNTIME_EXECUTABLE_FILENAME="$(basename "${BASH_SOURCE[0]}")"
declare -r RUNTIME_EXECUTABLE_FILENAME
RUNTIME_EXECUTABLE_NAME="${META_PROGRAM_NAME_OVERRIDE:-${RUNTIME_EXECUTABLE_FILENAME%.*}}"
RUNTIME_EXECUTABLE_DIRECTORY="$(dirname "$(realpath --strip "${0}")")"
declare -r RUNTIME_EXECUTABLE_DIRECTORY
declare -r RUNTIME_EXECUTABLE_PATH_ABSOLUTE="${RUNTIME_EXECUTABLE_DIRECTORY}/${RUNTIME_EXECUTABLE_FILENAME}"
declare -r RUNTIME_EXECUTABLE_PATH_RELATIVE="${0}"
declare pathdir
for pathdir in "${RUNTIME_PATH_DIRECTORIES[@]}"; do
# It is possible that the pathdir is invalid (e.g. wrong configuration or misuse ":" as path content which is not allowed in PATH), simply ignore it
if [ ! -d "${pathdir}" ]; then
continue
fi
resolved_pathdir="$(realpath "${pathdir}")"
# If resolved path isn't the same path (id. est. symbolic links), also check the resolved path
if [ "${pathdir}" != "${resolved_pathdir}" ]; then
if [ "${RUNTIME_EXECUTABLE_DIRECTORY}" == "${resolved_pathdir}" ]; then
RUNTIME_COMMAND_BASE="${RUNTIME_EXECUTABLE_FILENAME}"
break
fi
fi
unset resolved_pathdir
if [ "${RUNTIME_EXECUTABLE_DIRECTORY}" == "${pathdir}" ]; then
RUNTIME_COMMAND_BASE="${RUNTIME_EXECUTABLE_FILENAME}"
break
fi
done
unset pathdir
declare -r RUNTIME_COMMAND_BASE="${RUNTIME_COMMAND_BASE:-${0}}"
fi
### Collect command-line arguments
declare -ir RUNTIME_COMMANDLINE_ARGUMENT_QUANTITY="${#}"
if [ "${RUNTIME_COMMANDLINE_ARGUMENT_QUANTITY}" -ne 0 ]; then
declare -a RUNTIME_COMMANDLINE_ARGUMENT_LIST
RUNTIME_COMMANDLINE_ARGUMENT_LIST=("${@:1}")
declare -r RUNTIME_COMMANDLINE_ARGUMENT_LIST
fi
## Software Directories Configuration(S.D.C.)
## This section defines and determines the directories used by the software
## REFER: https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#software-directories-configurationsdc
meta_util_declare_global_parameters\
SDC_EXECUTABLES_DIR\
SDC_LIBRARIES_DIR\
SDC_SHARED_RES_DIR\
SDC_I18N_DATA_DIR\
SDC_SETTINGS_DIR\
SDC_TEMP_DIR
case "${META_APPLICATION_INSTALL_STYLE}" in
FHS)
# Filesystem Hierarchy Standard(F.H.S.) configuration paths
# http://refspecs.linuxfoundation.org/FHS_3.0/fhs
## Software installation directory prefix, should be overridable by configure/install script
declare -r FHS_PREFIX_DIR="/usr/local"
declare -r SDC_EXECUTABLES_DIR="${FHS_PREFIX_DIR}/bin"
declare -r SDC_LIBRARIES_DIR="${FHS_PREFIX_DIR}/lib"
declare -r SDC_I18N_DATA_DIR="${FHS_PREFIX_DIR}/share/locale"
if [ -n "${META_APPLICATION_IDENTIFIER}" ]; then
declare -r SDC_SHARED_RES_DIR="${FHS_PREFIX_DIR}/share/${META_APPLICATION_IDENTIFIER}"
declare -r SDC_SETTINGS_DIR="/etc/${META_APPLICATION_IDENTIFIER}"
declare -r SDC_TEMP_DIR="/tmp/${META_APPLICATION_IDENTIFIER}"
else
unset\
SDC_SHARED_RES_DIR\
SDC_SETTINGS_DIR\
SDC_TEMP_DIR
fi
;;
SHC)
# Setup Self-contained Hierarchy Configuration(S.H.C.)
# https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#self-contained-hierarchy-configurationshc
# https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#path_to_software_installation_prefix_directorysourceshc-only
# https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#shc_prefix_dirshc-only
if [ -f "${RUNTIME_EXECUTABLE_DIRECTORY}/APPLICATION_METADATA.source" ]; then
SHC_PREFIX_DIR="${RUNTIME_EXECUTABLE_DIRECTORY}"
else
if [ ! -f "${RUNTIME_EXECUTABLE_DIRECTORY}/PATH_TO_SOFTWARE_INSTALLATION_PREFIX_DIRECTORY.source" ]; then
printf "GNU Bash Script Template: Error: PATH_TO_SOFTWARE_INSTALLATION_PREFIX_DIRECTORY.source not exist, can't setup Self-contained Hierarchy Configuration.\n" 1>&2
exit 1
fi
# Scope of Flexible Software Installation Specification
# shellcheck disable=SC1090,SC1091
source "${RUNTIME_EXECUTABLE_DIRECTORY}/PATH_TO_SOFTWARE_INSTALLATION_PREFIX_DIRECTORY.source"
if ! meta_util_is_parameter_set_and_not_null PATH_TO_SOFTWARE_INSTALLATION_PREFIX_DIRECTORY; then
printf "GNU Bash Script Template: Error: PATH_TO_SOFTWARE_INSTALLATION_PREFIX_DIRECTORY not defined, can't setup Self-contained Hierarchy Configuration.\n" 1>&2
exit 1
fi
SHC_PREFIX_DIR="$(realpath --strip "${RUNTIME_EXECUTABLE_DIRECTORY}/${PATH_TO_SOFTWARE_INSTALLATION_PREFIX_DIRECTORY}")"
fi
declare -r SHC_PREFIX_DIR
# Read external software directory configuration(S.D.C.)
# https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#software-directories-configurationsdc
# Scope of Flexible Software Installation Specification
# shellcheck disable=SC1090,SC1091
source "${SHC_PREFIX_DIR}/SOFTWARE_DIRECTORY_CONFIGURATION.source" 2>/dev/null || true
meta_util_unset_global_parameters_if_null\
SDC_EXECUTABLES_DIR\
SDC_LIBRARIES_DIR\
SDC_SHARED_RES_DIR\
SDC_I18N_DATA_DIR\
SDC_SETTINGS_DIR\
SDC_TEMP_DIR
;;
STANDALONE)
# Standalone Configuration
# This program don't rely on any directories, make no attempt defining them
unset SDC_EXECUTABLES_DIR SDC_LIBRARIES_DIR SDC_SHARED_RES_DIR SDC_I18N_DATA_DIR SDC_SETTINGS_DIR SDC_TEMP_DIR
;;
*)
printf "Error: Unknown software directories configuration, program can not continue.\n" 1>&2
exit 1
;;
esac
for parameter_name in \
SDC_EXECUTABLES_DIR\
SDC_LIBRARIES_DIR\
SDC_SHARED_RES_DIR\
SDC_I18N_DATA_DIR\
SDC_SETTINGS_DIR\
SDC_TEMP_DIR\
; do
if meta_util_is_parameter_set_and_not_null "${parameter_name}"; then
declare -r "${parameter_name}"
else
unset "${parameter_name}"
fi
done
## Setup application metadata
case "${META_APPLICATION_INSTALL_STYLE}" in
FHS)
if [ -v "${SDC_SHARED_RES_DIR}" ] && [ -n "${SDC_SHARED_RES_DIR}" ]; then
:
else
# Scope of external project
# shellcheck disable=SC1090,SC1091
source "${SDC_SHARED_RES_DIR}/APPLICATION_METADATA.source" 2>/dev/null || true
fi
;;
SHC)
# Scope of external project
# shellcheck disable=SC1090,SC1091
source "${SHC_PREFIX_DIR}/APPLICATION_METADATA.source" 2>/dev/null || true
;;
STANDALONE)
: # metadata can only be set from header
;;
*)
printf "Error: Unknown META_APPLICATION_INSTALL_STYLE, program can not continue.\n" 1>&2
exit 1
;;
esac
for parameter_name in \
META_APPLICATION_NAME\
META_APPLICATION_DEVELOPER_NAME\
META_APPLICATION_LICENSE\
META_APPLICATION_SITE_URL\
META_APPLICATION_ISSUE_TRACKER_URL\
META_APPLICATION_SEEKING_HELP_OPTION\
; do
if meta_util_is_parameter_set_and_not_null "${parameter_name}"; then
declare -r "${parameter_name}"
else
unset "${parameter_name}"
fi
done
## Program's Commandline Options Definitions
declare -r COMMANDLINE_OPTION_DISPLAY_HELP_LONG="--help"
declare -r COMMANDLINE_OPTION_DISPLAY_HELP_SHORT="-h"
declare -r COMMANDLINE_OPTION_DISPLAY_HELP_DESCRIPTION="Display help message"
declare -r COMMANDLINE_OPTION_ENABLE_DEBUGGING_LONG="--debug"
declare -r COMMANDLINE_OPTION_ENABLE_DEBUGGING_SHORT="-d"
declare -r COMMANDLINE_OPTION_ENABLE_DEBUGGING_DESCRIPTION="Enable debug mode"
## Program Configuration Variables
declare -i global_just_show_help="${COMMON_BOOLEAN_FALSE}"
declare -i global_enable_debugging="${COMMON_BOOLEAN_FALSE}"
## Drop first element from array and shift remaining elements 1 element backward
meta_util_array_shift(){
local -n array_ref="${1}"
# Check input validity
# When -v test is used against a nameref, the name is tested
if [ "${#array_ref[@]}" -eq 0 ]; then
printf "ERROR: array is empty!\n" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
# Unset the 1st element
unset "array_ref[0]"
# Repack array if element still available in array
if [ "${#array_ref[@]}" -ne 0 ]; then
array_ref=("${array_ref[@]}")
fi
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_util_array_shift
## Understand what argument is in the command, and set the global variables accordingly.
meta_processCommandlineArguments() {
if [ "${RUNTIME_COMMANDLINE_ARGUMENT_QUANTITY}" -eq 0 ]; then
return "${COMMON_RESULT_SUCCESS}"
else
local -a arguments=("${RUNTIME_COMMANDLINE_ARGUMENT_LIST[@]}")
while :; do
# BREAK if no arguments left
if [ ! -v arguments ]; then
break
else
case "${arguments[0]}" in
"${COMMANDLINE_OPTION_DISPLAY_HELP_LONG}"|"${COMMANDLINE_OPTION_DISPLAY_HELP_SHORT}")
global_just_show_help="${COMMON_BOOLEAN_TRUE}"
;;
"${COMMANDLINE_OPTION_ENABLE_DEBUGGING_LONG}"|"${COMMANDLINE_OPTION_ENABLE_DEBUGGING_SHORT}")
global_enable_debugging="${COMMON_BOOLEAN_TRUE}"
;;
*)
printf "ERROR: Unknown command-line argument \"%s\"\n" "${arguments[0]}" >&2
return ${COMMON_RESULT_FAILURE}
;;
esac
meta_util_array_shift arguments
fi
done
fi
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_processCommandlineArguments
## Print single segment of commandline option help
meta_util_printSingleCommandlineOptionHelp(){
if [ "${#}" -ne 3 ] && [ "${#}" -ne 4 ]; then
printf "ERROR: %s: Wrong parameter quantity!\n" "${FUNCNAME[0]}" >&2
return "${COMMON_RESULT_FAILURE}"
fi
local description="${1}"; shift # Option description
local long_option="${1}"; shift # The long version of option
local short_option="${1}"; shift # The short version of option
declare -r description long_option short_option
if [ "${#}" -ne 0 ]; then
local current_value="${1}"; shift # Current value of option, if option has value
declare -r current_value
fi
printf "### %s / %s ###\n" "${long_option}" "${short_option}"
printf "%s\n" "${description}"
if [ -v current_value ]; then
printf "Current value: %s\n" "${current_value}"
fi
printf "\n" # Separate with next option(or next heading)
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_util_printSingleCommandlineOptionHelp
## Print help message whenever:
## * User requests it
## * An command syntax error has detected
meta_printHelpMessage(){
printf "# %s #\n" "${RUNTIME_EXECUTABLE_NAME}"
if meta_util_is_parameter_set_and_not_null META_PROGRAM_DESCRIPTION; then
printf "%s\n" "${META_PROGRAM_DESCRIPTION}"
printf "\n"
fi
printf "## Usage ##\n"
printf "\t%s (Command-line Options)\n" "${RUNTIME_COMMAND_BASE}"
printf "\n"
printf "## Command-line Options ##\n"
meta_util_printSingleCommandlineOptionHelp "${COMMANDLINE_OPTION_DISPLAY_HELP_DESCRIPTION}" "${COMMANDLINE_OPTION_DISPLAY_HELP_LONG}" "${COMMANDLINE_OPTION_DISPLAY_HELP_SHORT}"
meta_util_printSingleCommandlineOptionHelp "${COMMANDLINE_OPTION_ENABLE_DEBUGGING_DESCRIPTION}" "${COMMANDLINE_OPTION_ENABLE_DEBUGGING_LONG}" "${COMMANDLINE_OPTION_ENABLE_DEBUGGING_SHORT}"
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_printHelpMessage
## Defensive Bash Programming - init function, program's entry point
## http://www.kfirlavi.com/blog/2012/11/14/defensive-bash-programming/
init() {
if ! meta_processCommandlineArguments; then
meta_printHelpMessage
exit "${COMMON_RESULT_FAILURE}"
fi
# Secure configuration variables by marking them readonly
declare -gr \
global_just_show_help\
global_enable_debugging
if [ "${global_enable_debugging}" -eq "${COMMON_BOOLEAN_TRUE}" ]; then
set -o xtrace
fi
if [ "${global_just_show_help}" -eq "${COMMON_BOOLEAN_TRUE}" ]; then
meta_printHelpMessage
exit "${COMMON_RESULT_SUCCESS}"
fi
printf "Setting Git clean filter..."
git --git-dir="${SHC_PREFIX_DIR}/.git" --work-tree="${SHC_PREFIX_DIR}" config include.path ../.gitconfig
printf "done.\n"
printf "Fetching submodules..."
git submodule init\
&& git submodule update --recursive\
&& printf "done\n"\
|| printf "failed\n"
printf "Setting Git Hooks..."
if [ ! -v SDC_GIT_HOOKS_DIR ] || [ -z "${SDC_GIT_HOOKS_DIR}" ]; then
printf "\n%s: Error: Unable to locate Git Hooks directory\n" "${RUNTIME_EXECUTABLE_NAME}" 1>&2
exit 1
fi
# SOFTWARE_DIRECTORY_CONFIGURATION.source is scope of Flexible Software Installation Specification
# shellcheck disable=SC1090
if ! source "${SDC_GIT_HOOKS_DIR}"/SOFTWARE_DIRECTORY_CONFIGURATION.source\
|| ! meta_util_is_parameter_set_and_not_null SDC_GNU_BASH_PRECOMMIT_HOOK_DIR; then
printf "\n%s: Error: Unable to locate Bash Pre-commit hook directory\n" "${RUNTIME_EXECUTABLE_NAME}" 1>&2
exit 1
fi
ln \
--symbolic\
--verbose\
--relative\
--force\
"${SDC_GNU_BASH_PRECOMMIT_HOOK_DIR}/Pre-commit Script.bash"\
"${SHC_PREFIX_DIR}/.git/hooks/pre-commit"\
&& printf "done\n"\
|| printf "failed\n"
exit "${COMMON_RESULT_SUCCESS}"
}; declare -fr init
init
## This script is based on the GNU Bash Shell Script Template project
## https://github.com/Lin-Buo-Ren/GNU-Bash-Shell-Script-Template
## and is based on the following version:
declare -r META_BASED_ON_GNU_BASH_SHELL_SCRIPT_TEMPLATE_VERSION="v1.24.1"
## You may rebase your script to incorporate new features and fixes from the template
## This script is comforming to Flexible Software Installation Specification
## https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification
## and is based on the following version: v1.5.0