-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.script
804 lines (710 loc) · 26 KB
/
main.script
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
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
#
# Main logic: start/stop/restart/status a JAVA program
#
# Author: mail _^_ AT _^_ wangbo _^_ im
#
#
# Enable strict bash mode
set -euo pipefail
IFS=$'\t\n'
################################################################################
#
# Customizable variables and functions for different profile
#
################################################################################
#
# Profile (refer to different config directories)
PROFILE="${PROFILE:-}"
#
# Full main class to be ran
#
# If set, java would be ran using `java -cp ... $MAIN_CLASS` style command,
# otherwise, run `java -jar first_jar_found_in_project_dir.jar`
MAIN_CLASS="${MAIN_CLASS:-}"
#
# Customize java VM options.
#
# Both variables JAVA_OPT and JAVA_OPTS would be used to add new customized arguments.
#
# When using JAVA_OPT, append customized arguments like: JAVA_OPT="$JAVA_OPT --arg1 --arg2"
JAVA_OPT=""
# When using JAVA_OPTS, append customized arguments like:
# JAVA_OPTS[${#JAVA_OPTS[@]}]="--arg1"
# JAVA_OPTS[${#JAVA_OPTS[@]}]="--arg2"
JAVA_OPTS=("")
#
# Customize main application arguments.
#
# Both variables MAIN_ARG and MAIN_ARGS would be used to add new customized arguments.
#
# When using MAIN_ARG, append customized arguments like: MAIN_ARG="$MAIN_ARG --arg1 --arg2"
MAIN_ARG=""
# When using MAIN_ARGS, append customized arguments like:
# MAIN_ARGS[${#MAIN_ARGS[@]}]="--arg1"
# MAIN_ARGS[${#MAIN_ARGS[@]}]="--arg2"
MAIN_ARGS=("")
LOG_LEVEL="${LOG_LEVEL:-WARN}"
################################################################################
#
# Main logic started here
#
################################################################################
CONFIG="config"
CLASSES="classes"
LIBS=(
"lib"
"libs"
)
ENVS=(
".env"
"env"
"ENV"
"env.conf"
)
LOG4J2_FILENAMES=(
"log4j2.properties"
"log4j2.yaml"
"log4j2.yml"
"log4j2.json"
"log4j2.jsn"
"log4j2.xml"
)
LOGBACK_FILENAMES=(
"logback.groovy"
"logback.xml"
)
JUL_FILENAMES=(
"logging.properties"
)
#
# Dirs
SCRIPT_FILE_PATH=`realpath $0`
SCRIPT_DIR_PATH=`dirname "${SCRIPT_FILE_PATH}"`
MAIN_SCRIPT_PATH="${SCRIPT_DIR_PATH}/main.script"
# source common config
for each_i in "${SCRIPT_DIR_PATH}"/include.*.conf; do
if [ -f "$each_i" ]; then . "$each_i"; fi
done
#
# find java cmd
__javaPath() {
if [ -n "${JAVA_HOME:-}" ]; then
echo "$JAVA_HOME/bin/java"
else
p=$(type java 2>&1 | awk '{print $3}')
if [ -x "$p" ]; then
echo "$p"
else
__warn "No java found in PATH"
false
fi
fi
}
#
# $1: java executable name/path
__javaVersion() {
#
# Typical output of `java -version`:
#
# java version "1.8.0_231"
# Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
# Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)
#
# java version "11.0.7" 2020-04-14 LTS
# Java(TM) SE Runtime Environment 18.9 (build 11.0.7+8-LTS)
# Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.7+8-LTS, mixed mode)
#
# openjdk version "11.0.7" 2020-04-14 LTS
# OpenJDK Runtime Environment Corretto-11.0.7.10.1 (build 11.0.7+10-LTS)
# OpenJDK 64-Bit Server VM Corretto-11.0.7.10.1 (build 11.0.7+10-LTS, mixed mode)
#
# java version "11.0.7" 2020-04-14 LTS
# Java(TM) SE Runtime Environment GraalVM LIBGRAAL_EE_BASH 19.3.2 (build 11.0.7+8-LTS-jvmci-19.3-b09)
# Java HotSpot(TM) 64-Bit Server VM GraalVM LIBGRAAL_EE_BASH 19.3.2 (build 11.0.7+8-LTS-jvmci-19.3-b09, mixed mode, sharing)
#
v=$("$1" -version 2>&1 | awk '/version/{print $3}' | sed -n 's/"//gp; q')
echo "$v"
}
#
# Execute predefined java cmd
#
# $1: target project directory
# $2: target project tag
# $3: "FOREGROUND" or "BACKGROUND"
__execute() {
local project_dir="${1:?No project dir specified}"
local iam_tag="${2:?No tag specified}"
local foreground="" # default to background
if [ "$3" == "FOREGROUND" ]; then
foreground="1"
elif [ "$3" == "BACKGROUND" ]; then
foreground=""
else
__fatal "Invalid argument \$3: \"$3\""
false
fi
__debug "Starting java project \"$project_dir\" tagged with \"$iam_tag\""
local unslashed_project_dir="${project_dir%%/}"
if [ -z "$unslashed_project_dir" ]; then
__warn "Invalid project dir specified: \"$project_dir\""
false
fi
local unslashed_working_dir="${unslashed_project_dir}.working_dir"
mkdir -p "$unslashed_working_dir"
__info "Project directory set to \"$unslashed_project_dir\""
__info "Working directory set to \"$unslashed_working_dir\""
local java_cmd=`__javaPath`
__debug "Java binary: \"$java_cmd\""
local java_version=`__javaVersion $java_cmd`
__debug "Java version: \"$java_version\""
local start_datetime="`date +%Y%m%dT%H%M%S`"
local tz="`date +%z`"
# Predefined JVM options
local java_opts=(
"-Diam.startedAt=${start_datetime}${tz}"
"-Diam.tagged=${iam_tag}"
)
# load project env
# Usually define PROFILE
bflag=""
for each_i in "${ENVS[@]}"; do
each_i="${each_i##/}"
each_i="${each_i%%/}"
if [ -n "$each_i" ]; then
local env_filepath="$unslashed_project_dir/$each_i"
if [ -f "$env_filepath" -a -z "$bflag" ]; then
__info "Loading project env from \"$env_filepath\""
. "${env_filepath}"
bflag="1"
elif [ -f "$env_filepath" ]; then
__debug "Project env file \"$env_filepath\" found but ignored"
else
__debug "Project env file \"$env_filepath\" not found so ignored"
fi
env_filepath="$unslashed_working_dir/$each_i"
if [ -f "$env_filepath" -a -z "$bflag" ]; then
__info "Loading project env from \"$env_filepath\""
. "${env_filepath}"
bflag="1"
elif [ -f "$env_filepath" ]; then
__debug "Project env file \"$env_filepath\" found but ignored"
else
__debug "Project env file \"$env_filepath\" not found so ignored"
fi
fi
done
# profile name trimmed leading '/' and trailing '/'
local current_profile="${PROFILE:-}"
current_profile="${current_profile##/}"
current_profile="${current_profile%%/}"
__info "Profile set to \"$current_profile\""
java_opts[${#java_opts[@]}]="-Diam.profile=${current_profile:-NOT_SET}"
java_opts[${#java_opts[@]}]="-Dfile.encoding=UTF-8"
case "$java_version" in
1.6* | 1.7* | 1.8*)
java_opts[${#java_opts[@]}]="-Xloggc:gc.${start_datetime}.log"
java_opts[${#java_opts[@]}]="-XX:+PrintGCDetails"
java_opts[${#java_opts[@]}]="-XX:+PrintGCTimeStamps"
java_opts[${#java_opts[@]}]="-XX:+PrintGCDateStamps"
;;
*)
# 9 | 10 | 11 and later
java_opts[${#java_opts[@]}]="--illegal-access=warn"
java_opts[${#java_opts[@]}]="-Xlog:gc+heap=info:file=gc.${start_datetime}.log::filecount=10,filesize=100M"
;;
esac
__debug "Java opts before processing configs:\\"
for each_arg in "${java_opts[@]}"; do
__debug " \"${each_arg}\" \\"
done
# create dir links in working dir pointing to target profile
local unslashed_p_config_dir="${unslashed_project_dir}/$CONFIG"
local unslashed_config_dir="${unslashed_working_dir}/$CONFIG"
if [ -n "${current_profile}" ]; then
local tmp="${unslashed_p_config_dir}/${current_profile}"
if [ -d "${tmp}" ]; then
unslashed_p_config_dir="${tmp}"
__debug "Profile named \"${current_profile}\" found in \"${unslashed_p_config_dir}\""
else
__debug "No profile named \"${current_profile}\" found in \"${unslashed_p_config_dir}\""
fi
fi
if [ -d "${unslashed_p_config_dir}" ]; then
__debug "Dir \"$unslashed_p_config_dir/\" found, try to symlink it as \"$unslashed_config_dir\""
if [ -L "${unslashed_config_dir}" ]; then
__debug "Delete old existed symlink \"$unslashed_config_dir\" pointing to \"$(realpath $unslashed_config_dir)\""
rm -f "${unslashed_config_dir}"
elif [ -e "$unslashed_config_dir" ]; then
local tmp="${unslashed_config_dir}.saved_$start_datetime"
__debug "Rename old existed file/directory \"$unslashed_config_dir\" to \"$tmp\""
mv "${unslashed_config_dir}" "$tmp"
fi
ln -sf "${unslashed_p_config_dir}/" "${unslashed_config_dir}"
__debug "Create symlink \"$unslashed_config_dir\" to \"$unslashed_p_config_dir/\""
__info "Config directory set to \"$unslashed_config_dir\""
else
__debug "Dir \"$unslashed_p_config_dir\" not found, ignore symlink config step"
fi
local bflag=""
__debug "Java opts before loading customized settings:\\"
for each_arg in "${java_opts[@]}"; do
__debug " \"${each_arg}\" \\"
done
# load profile specific env
# Usually define JAVA_OPT/JAVA_OPTS/MAIN_ARG/MAIN_ARGS
bflag=""
for each_i in "${ENVS[@]}"; do
each_i="${each_i##/}"
each_i="${each_i%%/}"
if [ -n "$each_i" ]; then
local env_filepath="$unslashed_config_dir/$each_i"
if [ -f "$env_filepath" -a -z "$bflag" ]; then
__info "Loading profile env from \"$env_filepath\""
. "${env_filepath}"
bflag="1"
elif [ -f "$env_filepath" ]; then
__debug "Profile env file \"$env_filepath\" found but ignored"
else
__debug "Profile env file \"$env_filepath\" not found so ignored"
fi
fi
done
# Customized JVM options
#
# Var JAVA_OPT use space to separate items
IFS=$' \t\n'
for each_opt in $JAVA_OPT; do
case "$each_opt" in
"")
# Do nothing
;;
"-"*)
java_opts[${#java_opts[@]}]="${each_opt}"
;;
*)
__warn "Found illegal java option \"$each_opt\" customzied using JAVA_OPT"
;;
esac
done
IFS=$'\t\n'
# Var JAVA_OPTS use array to store items
for each_opt in "${JAVA_OPTS[@]}"; do
case "$each_opt" in
"")
# Do nothing
;;
"-"*)
java_opts[${#java_opts[@]}]="${each_opt}"
;;
*)
__warn "Found illegal java option customzied using JAVA_OPTS"
;;
esac
done
__debug "Java opts after loading customized jvm settings:\\"
for each_arg in "${java_opts[@]}"; do
__debug " \"${each_arg}\" \\"
done
# Option for log4j2 config file
bflag=""
for each_i in "${LOG4J2_FILENAMES[@]}"; do
each_i="${each_i##/}"
each_i="${each_i%%/}"
if [ -n "$each_i" -a -z "$bflag" ]; then
local logging_file="${unslashed_config_dir}/$each_i"
if [ -f "${logging_file}" ]; then
__debug "Log4j2 config file \"$logging_file\" found, add log4j2 related options"
java_opts[${#java_opts[@]}]="-Dlog4j.configurationFile=${logging_file}"
# See for jul bridge details: https://logging.apache.org/log4j/2.0/log4j-jul/index.html
java_opts[${#java_opts[@]}]="-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager"
bflag="1"
fi
fi
done
# Option for logback config file
bflag=""
for each_i in "${LOGBACK_FILENAMES[@]}"; do
each_i="${each_i##/}"
each_i="${each_i%%/}"
if [ -n "$each_i" -a -z "$bflag" ]; then
local logging_file="${unslashed_config_dir}/$each_i"
if [ -f "${logging_file}" ]; then
__debug "Logback config file \"$logging_file\" found, add logback related options"
java_opts[${#java_opts[@]}]="-Dlogback.configurationFile=${logging_file}"
# See for jul bridge details: http://www.slf4j.org/legacy.html#jul-to-slf4j
bflag="1"
fi
fi
done
# Option for jul config file
bflag=""
for each_i in "${JUL_FILENAMES[@]}"; do
each_i="${each_i##/}"
each_i="${each_i%%/}"
if [ -n "$each_i" -a -z "$bflag" ]; then
local logging_file="${unslashed_config_dir}/$each_i"
if [ -f "${logging_file}" ]; then
__debug "java.util.logging config file \"$logging_file\" found, add jul related options"
java_opts[${#java_opts[@]}]="-Djava.util.logging.config.file=${logging_file}"
bflag="1"
fi
fi
done
__debug "Java opts after detecting logging config files:\\"
for each_arg in "${java_opts[@]}"; do
__debug " \"${each_arg}\" \\"
done
# if not defined MAIN_CLASS, run java with "-jar",
# otherwise using main class
if [ -n "${MAIN_CLASS:-}" ]; then
__info "MAIN_CLASS set to \"$MAIN_CLASS\", try to start project using MAIN CLASS way"
# Option for classpath, "-classpath"
local classpath=""
local classes_dirpath="${unslashed_project_dir}/$CLASSES"
if [ -d "${classes_dirpath}/" ]; then
classpath="${classpath}:${classes_dirpath}"
__debug "Append \"$classes_dirpath\" into classpath"
fi
classes_dirpath="${unslashed_config_dir}"
if [ -d "${classes_dirpath}/" ]; then
classpath="${classpath}:${classes_dirpath}"
__debug "Append \"$classes_dirpath\" into classpath"
fi
for each_i in "${LIBS[@]}"; do
each_i="${each_i##/}"
each_i="${each_i%%/}"
if [ -n "$each_i" ]; then
classpath_dirpath="${unslashed_project_dir}/$each_i"
if [ -d "${classpath_dirpath}" ]; then
for each_jar in "${classpath_dirpath}"/*.jar; do
if [ -f "${each_jar}" ]; then
classpath="${classpath}:${each_jar}"
__debug "Append \"$each_jar\" into classpath"
fi
done
fi
fi
done
classpath="${classpath#:}"
if [ -n "${classpath}" ]; then
java_opts[${#java_opts[@]}]="-classpath"
java_opts[${#java_opts[@]}]="${classpath}"
fi
# Main-Class option
java_opts[${#java_opts[@]}]="$MAIN_CLASS"
else
__info "No MAIN_CLASS set, try to start project using MAIN JAR way"
# Option for "-jar"
local main_jar_filepath=""
for each_i in "$unslashed_project_dir"/*.jar; do
if [ -f "$each_i" ]; then
main_jar_filepath="$main_jar_filepath $each_i"
__debug "Found main jar \"$each_i\""
fi
done
main_jar_filepath="${main_jar_filepath## }"
if [ -f "$main_jar_filepath" ]; then
java_opts[${#java_opts[@]}]="-jar"
java_opts[${#java_opts[@]}]="${main_jar_filepath}"
elif [ -n "$main_jar_filepath" ]; then
# multiple jars found
__fatal "Multiple jars found in \"$unslashed_project_dir\", please package into a single executable jar: $main_jar_filepath"
false
else
# no jar found
__fatal "No jar found in \"$unslashed_project_dir\", please package a single executable jar"
false
fi
fi
__debug "Java opts after adding -classpath or -jar entrypoint:\\"
for each_arg in "${java_opts[@]}"; do
__debug " \"${each_arg}\" \\"
done
# Customized main args
# Var MAIN_ARG use space to separate items
IFS=$' \t\n'
for each_opt in $MAIN_ARG; do
if [ -n "$each_opt" ]; then
java_opts[${#java_opts[@]}]="${each_opt}"
fi
done
IFS=$'\t\n'
# Var MAIN_ARGS use array to store items
for each_opt in "${MAIN_ARGS[@]}"; do
if [ -n "$each_opt" ]; then
java_opts[${#java_opts[@]}]="${each_opt}"
fi
done
__debug "Java opts after loading customized main settings:\\"
for each_arg in "${java_opts[@]}"; do
__debug " \"${each_arg}\" \\"
done
__info "Entering directory \"${unslashed_working_dir}\" ..."
cd "$unslashed_working_dir"
__info "Executing service \"${unslashed_project_dir}\" ..."
__info "Executing: ${java_cmd} \\"
for each_arg in "${java_opts[@]}"; do
__info " \"${each_arg}\" \\"
done
# actual executing
if [ -n "$foreground" ]; then
"${java_cmd}" "${java_opts[@]}" >console.${start_datetime}.log 2>&1
else
nohup "${java_cmd}" "${java_opts[@]}" >console.${start_datetime}.log 2>&1 &
fi
}
#
# Run predefined java cmd in background (daemon).
#
# $1: target project directory
# $2: target project tag
__start() {
__execute "$1" "$2" "BACKGROUND"
}
#
# Run predefined java cmd in foreground (blocking waiting for exit).
#
# $1: target project directory
# $2: target project tag
__run() {
__execute "$1" "$2" "FOREGROUND"
}
#
# Stop predefined java cmd, wait until stopped
#
# Always exit with 0
#
# However the exit code is ignored. The result of this stopping
# process is determined by __check function, i.e., __check exits with 1 indicating
# a successful stopping, otherwise a failed stopping.
#
# $1: target project directory
# $2: target project tag
__stop() {
local project_dir="${1:?No project dir specified}"
local iam_tag="${2:?No tag specified}"
__debug "Stopping java project \"$project_dir\" tagged with \"$iam_tag\""
local prev_process=`ps -o pid,command -C "java" | grep -F "iam.tagged=${iam_tag}" | awk '{print $1}'`
while [ -n "${prev_process}" ]; do
__info Stopping service \"${project_dir}\" \"${prev_process}\"
# Double check to ensure the target process exists
local temp_str=`ps --no-headers -o pid,command -p "${prev_process}"`
if [ -n "${temp_str}" ]; then
__info kill "${prev_process}"
kill "${prev_process}"
# No need to sleep waiting for killing result
sleep 1s
fi
__info Waiting service \"${project_dir}\" \"${prev_process}\" to exit
prev_process=`ps -o pid,command -C "java" | grep -F "iam.tagged=${iam_tag}" | awk '{print $1}'`
done
}
#
# Check if pid exists by java cmd and project name
#
# Always exit with 0
#
# $1: target project directory
# $2: target project tag
__status() {
local project_dir="${1:?No project dir specified}"
local iam_tag="${2:?No tag specified}"
__debug "Checking status of java project \"$project_dir\" tagged with \"$iam_tag\""
# grep exit with code 0 if found matched item, otherwise non-zero (typically 1)
local iam_tag="${2:?No tag specified}"
ps -o pid,command -C "java" | {
grep -F "iam.tagged=${iam_tag}" || __warn Project \"$project_dir\" stopped or not started
}
}
#
# Check if pid exists by java cmd and project name
#
# Exit with 0 if found process for given project, otherwise non-zero.
#
# $1: target project directory
# $2: target project tag
__check() {
local project_dir="${1:?No project dir specified}"
local iam_tag="${2:?No tag specified}"
__debug "Checking status of java project \"$project_dir\" tagged with \"$iam_tag\""
# grep exit with code 0 if found matched item, otherwise non-zero (typically 1)
local iam_tag="${2:?No tag specified}"
ps -o pid,command -C "java" | grep -F "iam.tagged=${iam_tag}"
}
#
# Deploy artifact and update symlinks
#
# $1: target project directory
# $2: artifact file(Support jar/gz(*.tar.gz *.tgz)/bz2(*.tar.bz2 *.tar.bz *.tbz *.tbz2)/xz(*.tar.xz *.txz) format)
__deploy() {
local project_dir="${1:?No project dir specified}"
local artifact_file="${2:?No artifact file specified}"
__debug "Deploying java project \"$project_dir\" from artifact \"$artifact_file\""
local unslashed_project_dir="${project_dir%%/}"
if [ -z "$unslashed_project_dir" ]; then
__fatal "Invalid project dir specified: \"$project_dir\""
false
fi
local dt=$(date +%Y%m%dT%H%M%S)
if [ -f "$artifact_file" ]; then
local tagged_project_dir="$unslashed_project_dir.deployed_at_$dt"
mkdir -p "${tagged_project_dir}"
case "$artifact_file" in
*".tar.gz"|*".tgz")
__debug "Unpacking \"$artifact_file\" into \"$tagged_project_dir\": gzip"
tar -zxf "$artifact_file" -C "$tagged_project_dir/"
;;
*".tar.bz2"|*".tbz2"|*".tar.bz"|*".tbz")
__debug "Unpacking \"$artifact_file\" into \"$tagged_project_dir\": bzip2"
tar -jxf "$artifact_file" -C "$tagged_project_dir/"
;;
*".tar.xz"|*".txz")
__debug "Unpacking \"$artifact_file\" into \"$tagged_project_dir\": xz"
tar -Jxf "$artifact_file" -C "$tagged_project_dir/"
;;
*)
__debug "Moving \"$artifact_file\" into \"$tagged_project_dir\": unknown"
cp -f "$artifact_file" "$tagged_project_dir/"
;;
esac
if [ -L "$unslashed_project_dir" ]; then
__debug "Delete old existed symlink \"$unslashed_project_dir\" pointing to \"$(realpath $unslashed_project_dir)\""
rm -f "$unslashed_project_dir"
elif [ -e "$unslashed_project_dir" ]; then
local tmp="$unslashed_project_dir.saved_$dt"
__debug "Rename old existed file/directory \"$unslashed_project_dir\" to \"$tmp\""
mv "${unslashed_project_dir}" "$tmp"
fi
ln -sf "$tagged_project_dir" "$unslashed_project_dir"
__info "Artifact file \"$artifact_file\" being deployed into \"$tagged_project_dir\""
else
__fatal "Artifact file \"$artifact_file\" not exists"
false
fi
}
#
# Deploy artifact and update symlinks
#
# $1: target project directory
__rollback() {
local project_dir="${1:?No project dir specified}"
__debug "Rollbacking java project \"$project_dir\""
local unslashed_project_dir="${project_dir%%/}"
if [ -z "$unslashed_project_dir" ]; then
__fatal "Invalid project dir specified: \"$project_dir\""
false
fi
local cur="$(realpath $unslashed_project_dir)"
__info "Current deployment: $cur"
local c=("")
__info "Available deployments to be rollbacked:"
for each_i in "$unslashed_project_dir.deployed_at_"*; do
if [ -d "$each_i" -a "$each_i" != "$cur" ]; then
__info "[${#c[@]}] $each_i"
c[${#c[@]}]="$each_i"
fi
done
if [ ${#c[@]} -gt 1 ]; then
printf "Choose a deployment to be rollbacked (by index or by name): "
read choice
local citem=""
local tmp=0
for each_i in "${c[@]}"; do
if [ $tmp -gt 0 -a -z "$citem" ]; then
__debug "Item [$tmp] \"$each_i\""
if [ "$choice" == "$tmp" ]; then
__debug "Chosen by index"
citem="$each_i"
elif [ "$choice" == "$each_i" ]; then
__debug "Chosen by name"
citem="$each_i"
else
__debug "Ignored"
fi
fi
tmp=$(($tmp + 1))
done
__debug "Choose \"$citem\" by \"$choice\""
if [ -n "$citem" ]; then
if [ -L "$unslashed_project_dir" ]; then
__debug "Delete old existed symlink \"$unslashed_project_dir\" pointing to \"$(realpath $unslashed_project_dir)\""
rm -f "$unslashed_project_dir"
elif [ -e "$unslashed_project_dir" ]; then
local tmp="$unslashed_project_dir.saved_$dt"
__debug "Rename old existed file/directory \"$unslashed_project_dir\" to \"$tmp\""
mv "${unslashed_project_dir}" "$tmp"
fi
ln -sf "$citem" "$unslashed_project_dir"
__info "Project \"$unslashed_project_dir\" being rollbacked to \"$citem\""
else
__fatal "Invalid choice \"$choice\""
false
fi
fi
}
__assert_directory_exists_or_exit() {
if [ -z "$1" ]; then
__fatal "Project directory not specified"
__usage
exit 1
elif [ ! -d "$1" ]; then
__fatal "Project directory \"$1\" not exists"
__usage
exit 1
fi
}
#
# Main entry
# $1 is parsed as target working directory
target_project_dir="${1:-.}"; shift
__debug "Parsed target_project_dir: \"$target_project_dir\""
target_project_dir=$(realpath -s "${target_project_dir}")
__debug "Expanded target_project_dir: \"$target_project_dir\""
# trim and keep only 1 slash ('/') as suffix, to avoid problems of soft symbolic to directory
target_project_dir="${target_project_dir%%/}/"
if [ -d "$target_project_dir" ]; then
iam_tag=`realpath -s $target_project_dir | sha256sum | cut -d ' ' -f 1`
else
iam_tag=`realpath -s $0 | sha256sum | cut -d ' ' -f 1`
fi
# $2 .. $N is/are parsed as commands
while [ "$#" -gt "0" ]; do
each_arg="$1"; shift
__debug "Parsed command \"$each_arg\""
case "${each_arg}" in
"run")
__assert_directory_exists_or_exit "$target_project_dir"
__run "$target_project_dir" "$iam_tag"
;;
"start")
__assert_directory_exists_or_exit "$target_project_dir"
__start "$target_project_dir" "$iam_tag"
;;
"stop")
__assert_directory_exists_or_exit "$target_project_dir"
__stop "$target_project_dir" "$iam_tag"
;;
"check")
__assert_directory_exists_or_exit "$target_project_dir"
__check "$target_project_dir" "$iam_tag"
;;
"status")
__assert_directory_exists_or_exit "$target_project_dir"
__status "$target_project_dir" "$iam_tag"
;;
"deploy")
tmp="${1:-}"; shift
if [ -n "$tmp" -a -f "$tmp" ]; then
__deploy "$target_project_dir" "$tmp"
fi
;;
"rollback")
__rollback "$target_project_dir"
;;
*)
__fatal "Unknown command \"${each_arg}\""
false
;;
esac
done
# vim:set nu rnu list et sr ts=4 sw=4 ft=sh: