-
Notifications
You must be signed in to change notification settings - Fork 2
/
hum
executable file
·782 lines (644 loc) · 25 KB
/
hum
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
#!/usr/bin/env bash
# This file:
#
# - Runs various tasks for HuMC Hugo site manager and starter kit
#
# Usage:
#
# LOG_LEVEL=7 ./hum -f /tmp/x -d (change this for your script)
#
# Based on a template by BASH3 Boilerplate v2.3.0
# http://bash3boilerplate.sh/#authors
#
# The MIT License (MIT)
# Copyright (c) 2013 Kevin van Zonneveld and contributors
# Exit on error. Append "|| true" if you expect an error.
set -o errexit
# Exit on error inside any functions or subshells.
set -o errtrace
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
set -o nounset
# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
set -o pipefail
# Turn on traces, useful while debugging but commented out by default
#set -o xtrace
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
__i_am_main_script="0" # false
if [[ "${__usage+x}" ]]; then
if [[ "${BASH_SOURCE[1]}" = "${0}" ]]; then
__i_am_main_script="1" # true
fi
__b3bp_external_usage="true"
__b3bp_tmp_source_idx=1
fi
else
__i_am_main_script="1" # true
[[ "${__usage+x}" ]] && unset -v __usage
[[ "${__helptext+x}" ]] && unset -v __helptext
fi
# Set magic variables for current file, directory, os, etc.
__dir="$(cd "$(dirname "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")" && pwd)"
__file="${__dir}/$(basename "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")"
__base="$(basename "${__file}" .sh)"
# Define the environment variables (and their defaults) that this script depends on
LOG_LEVEL="${LOG_LEVEL:-6}" # 7 = debug -> 0 = emergency
NO_COLOR="${NO_COLOR:-}" # true = disable color. otherwise autodetected
### Functions
##############################################################################
function __b3bp_log () {
local log_level="${1}"
shift
# shellcheck disable=SC2034
local color_debug="\x1b[35m"
# shellcheck disable=SC2034
local color_info="\x1b[32m"
# shellcheck disable=SC2034
local color_notice="\x1b[34m"
# shellcheck disable=SC2034
local color_warning="\x1b[33m"
# shellcheck disable=SC2034
local color_error="\x1b[31m"
# shellcheck disable=SC2034
local color_critical="\x1b[1;31m"
# shellcheck disable=SC2034
local color_alert="\x1b[1;33;41m"
# shellcheck disable=SC2034
local color_emergency="\x1b[1;4;5;33;41m"
local colorvar="color_${log_level}"
local color="${!colorvar:-${color_error}}"
local color_reset="\x1b[0m"
if [[ "${NO_COLOR:-}" = "true" ]] || ( [[ "${TERM:-}" != "xterm"* ]] && [[ "${TERM:-}" != "screen"* ]] ;) || [[ ! -t 2 ]]; then
if [[ "${NO_COLOR:-}" != "false" ]]; then
# Don't use colors on pipes or non-recognized terminals
color=""; color_reset=""
fi
fi
# all remaining arguments are to be printed
local log_line=""
while IFS=$'\n' read -r log_line; do
echo -e "${color}$(printf "[%s]" "${log_level}")${color_reset} ${log_line}" 1>&2
done <<< "${@:-}"
}
function emergency () { __b3bp_log emergency "${@}"; exit 1; }
function alert () { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && __b3bp_log alert "${@}"; true; }
function critical () { [[ "${LOG_LEVEL:-0}" -ge 2 ]] && __b3bp_log critical "${@}"; true; }
function error () { [[ "${LOG_LEVEL:-0}" -ge 3 ]] && __b3bp_log error "${@}"; true; }
function warning () { [[ "${LOG_LEVEL:-0}" -ge 4 ]] && __b3bp_log warning "${@}"; true; }
function notice () { [[ "${LOG_LEVEL:-0}" -ge 5 ]] && __b3bp_log notice "${@}"; true; }
function info () { [[ "${LOG_LEVEL:-0}" -ge 6 ]] && __b3bp_log info "${@}"; true; }
function debug () { [[ "${LOG_LEVEL:-0}" -ge 7 ]] && __b3bp_log debug "${@}"; true; }
function help () {
echo "" 1>&2
echo " ${*}" 1>&2
echo "" 1>&2
echo " ${__usage:-No usage available}" 1>&2
echo "" 1>&2
if [[ "${__helptext:-}" ]]; then
echo " ${__helptext}" 1>&2
echo "" 1>&2
fi
exit 1
}
### Parse commandline options
##############################################################################
# Commandline options. This defines the usage page, and is used to parse cli
# opts & defaults from. The parsing is unforgiving so be precise in your syntax
# - A short option must be preset for every long option; but every short option
# need not have a long option
# - `--` is respected as the separator between options and arguments
# - We do not bash-expand defaults, so setting '~/app' as a default will not resolve to ${HOME}.
# you can use bash variables to work around this (so use ${HOME} instead)
# shellcheck disable=SC2015
[[ "${__usage+x}" ]] || read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
-f --file [arg] Name of config file.
-v Enable verbose mode, print script as it is executed
-d --debug Enables debug mode
-h --help This page
-w --no-color Disable color output
-n --new-site [arg] Create a new site with name
-p --pull-sites Pull changes to sites in sites/
-j --node-sync Sync node_modules in themes
-s --setup Check for dependencies and setup
-c --create-conf Create sites/conf and init a git repository
-u --update-conf Fetch changes to sites/conf repository
-a --archive [arg] Archive site to zipped-sites
-l --list-sites List of sites
-k --clean-sites Archive any site in sites/ without .conf
EOF
# shellcheck disable=SC2015
[[ "${__helptext+x}" ]] || read -r -d '' __helptext <<-'EOF' || true # exits non-zero when EOF encountered
This is hum's help text.
EOF
# Translate usage string -> getopts arguments, and set $arg_<flag> defaults
while read -r __b3bp_tmp_line; do
if [[ "${__b3bp_tmp_line}" =~ ^- ]]; then
# fetch single character version of option string
__b3bp_tmp_opt="${__b3bp_tmp_line%% *}"
__b3bp_tmp_opt="${__b3bp_tmp_opt:1}"
# fetch long version if present
__b3bp_tmp_long_opt=""
if [[ "${__b3bp_tmp_line}" = *"--"* ]]; then
__b3bp_tmp_long_opt="${__b3bp_tmp_line#*--}"
__b3bp_tmp_long_opt="${__b3bp_tmp_long_opt%% *}"
fi
# map opt long name to+from opt short name
printf -v "__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}" '%s' "${__b3bp_tmp_opt}"
printf -v "__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt}" '%s' "${__b3bp_tmp_long_opt//-/_}"
# check if option takes an argument
if [[ "${__b3bp_tmp_line}" =~ \[.*\] ]]; then
__b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
__b3bp_tmp_init="" # it has an arg. init with ""
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "1"
elif [[ "${__b3bp_tmp_line}" =~ \{.*\} ]]; then
__b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
__b3bp_tmp_init="" # it has an arg. init with ""
# remember that this option requires an argument
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
else
__b3bp_tmp_init="0" # it's a flag. init with 0
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "0"
fi
__b3bp_tmp_opts="${__b3bp_tmp_opts:-}${__b3bp_tmp_opt}"
fi
[[ "${__b3bp_tmp_opt:-}" ]] || continue
if [[ "${__b3bp_tmp_line}" =~ (^|\.\ *)Default= ]]; then
# ignore default value if option does not have an argument
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}"
if [[ "${!__b3bp_tmp_varname}" != "0" ]]; then
__b3bp_tmp_init="${__b3bp_tmp_line##*Default=}"
__b3bp_tmp_re='^"(.*)"$'
if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
__b3bp_tmp_init="${BASH_REMATCH[1]}"
else
__b3bp_tmp_re="^'(.*)'$"
if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
__b3bp_tmp_init="${BASH_REMATCH[1]}"
fi
fi
fi
fi
if [[ "${__b3bp_tmp_line}" =~ (^|\.\ *)Required\. ]]; then
# remember that this option requires an argument
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
fi
printf -v "arg_${__b3bp_tmp_opt:0:1}" '%s' "${__b3bp_tmp_init}"
done <<< "${__usage:-}"
# run getopts only if options were specified in __usage
if [[ "${__b3bp_tmp_opts:-}" ]]; then
# Allow long options like --this
__b3bp_tmp_opts="${__b3bp_tmp_opts}-:"
# Reset in case getopts has been used previously in the shell.
OPTIND=1
# start parsing command line
set +o nounset # unexpected arguments will cause unbound variables
# to be dereferenced
# Overwrite $arg_<flag> defaults with the actual CLI options
while getopts "${__b3bp_tmp_opts}" __b3bp_tmp_opt; do
[[ "${__b3bp_tmp_opt}" = "?" ]] && help "Invalid use of script: ${*} "
if [[ "${__b3bp_tmp_opt}" = "-" ]]; then
# OPTARG is long-option-name or long-option=value
if [[ "${OPTARG}" =~ .*=.* ]]; then
# --key=value format
__b3bp_tmp_long_opt=${OPTARG/=*/}
# Set opt to the short option corresponding to the long option
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}"
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
OPTARG=${OPTARG#*=}
else
# --key value format
# Map long name to short version of option
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${OPTARG//-/_}"
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
# Only assign OPTARG if option takes an argument
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt}"
printf -v "OPTARG" '%s' "${@:OPTIND:${!__b3bp_tmp_varname}}"
# shift over the argument if argument is expected
((OPTIND+=__b3bp_tmp_has_arg_${__b3bp_tmp_opt}))
fi
# we have set opt/OPTARG to the short value and the argument as OPTARG if it exists
fi
__b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}"
__b3bp_tmp_default="${!__b3bp_tmp_varname}"
__b3bp_tmp_value="${OPTARG}"
if [[ -z "${OPTARG}" ]] && [[ "${__b3bp_tmp_default}" = "0" ]]; then
__b3bp_tmp_value="1"
fi
printf -v "${__b3bp_tmp_varname}" '%s' "${__b3bp_tmp_value}"
debug "cli arg ${__b3bp_tmp_varname} = (${__b3bp_tmp_default}) -> ${!__b3bp_tmp_varname}"
done
set -o nounset # no more unbound variable references expected
shift $((OPTIND-1))
if [[ "${1:-}" = "--" ]] ; then
shift
fi
fi
### Automatic validation of required option arguments
##############################################################################
for __b3bp_tmp_varname in ${!__b3bp_tmp_has_arg_*}; do
# validate only options which required an argument
[[ "${!__b3bp_tmp_varname}" = "2" ]] || continue
__b3bp_tmp_opt_short="${__b3bp_tmp_varname##*_}"
__b3bp_tmp_varname="arg_${__b3bp_tmp_opt_short}"
[[ "${!__b3bp_tmp_varname}" ]] && continue
__b3bp_tmp_varname="__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt_short}"
printf -v "__b3bp_tmp_opt_long" '%s' "${!__b3bp_tmp_varname}"
[[ "${__b3bp_tmp_opt_long:-}" ]] && __b3bp_tmp_opt_long=" (--${__b3bp_tmp_opt_long//_/-})"
help "Option -${__b3bp_tmp_opt_short}${__b3bp_tmp_opt_long:-} requires an argument"
done
### Cleanup Environment variables
##############################################################################
for __tmp_varname in ${!__b3bp_tmp_*}; do
unset -v "${__tmp_varname}"
done
unset -v __tmp_varname
### Externally supplied __usage. Nothing else to do here
##############################################################################
if [[ "${__b3bp_external_usage:-}" = "true" ]]; then
unset -v __b3bp_external_usage
return
fi
### Signal trapping and backtracing
##############################################################################
function __b3bp_cleanup_before_exit () {
info "Cleaning up. Done"
}
trap __b3bp_cleanup_before_exit EXIT
# requires `set -o errtrace`
__b3bp_err_report() {
local error_code
error_code=${?}
error "Error in ${__file} in function ${1} on line ${2}"
exit ${error_code}
}
# Uncomment the following line for always providing an error backtrace
# trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
### Command-line argument switches (like -d for debugmode, -h for showing helppage)
##############################################################################
# debug mode
if [[ "${arg_d:?}" = "1" ]]; then
set -o xtrace
LOG_LEVEL="7"
# Enable error backtracing
trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
fi
# verbose mode
if [[ "${arg_v:?}" = "1" ]]; then
set -o verbose
fi
# no color mode
if [[ "${arg_w:?}" = "1" ]]; then
NO_COLOR="true"
fi
# help mode
if [[ "${arg_h:?}" = "1" ]]; then
# Help exists with code 1
help "Help using ${0}"
fi
### Validation. Error out if the things required for your script are not present
##############################################################################
#[[ "${arg_f:-}" ]] || help "Setting a filename with -f or --file is required"
[[ "${LOG_LEVEL:-}" ]] || emergency "Cannot continue without LOG_LEVEL. "
### Runtime
##############################################################################
#info "__i_am_main_script: ${__i_am_main_script}"
# info "__file: ${__file}"
# info "__dir: ${__dir}"
# info "__base: ${__base}"
# info "OSTYPE: ${OSTYPE}"
# info "arg_f: ${arg_f}"
#info "arg_d: ${arg_d}"
#info "arg_v: ${arg_v}"
#info "arg_h: ${arg_h}"
# info "arg_n is: ${arg_n}"
# info "arg_s is: ${arg_s}"
# info "arg_c is: ${arg_c}"
#info "arg_a is: ${arg_a}"
# info "$(echo -e "multiple lines example - line #1\nmultiple lines example - line #2\nimagine logging the output of 'ls -al /path/'")"
# All of these go to STDERR, so you can use STDOUT for piping machine readable information to other software
# debug "Info useful to developers for debugging the application, not useful during operations."
# info "Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required."
# notice "Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required."
# warning "Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time. This is a debug message"
# error "Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time."
# critical "Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection."
# alert "Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection."
# emergency "A \"panic\" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call."
### Hum Global variables
################################
DATE=$(date +%d-%m-%Y)
### Hum Functions
################################
function check_hugo() {
# Check if hugo is installed
if ! command -v hugo > /dev/null; then
critical "Hugo is not installed. Aborting."
notice "Please install Hugo: https://gohugo.io/getting-started/installing/"
exit 1
else
info "Hugo found."
fi
}
function check_node() {
# Check node js is installed
if ! command -v node > /dev/null; then
critical "Node.js is not installed. Aborting."
notice "Please install nodejs: https://nodejs.org/en/"
exit 1
else
info "Node.js found."
fi
}
function check_theme_nodemod() {
# Check if theme/node_modules exists, run install if not
if [[ -L "starters/five-page/themes/bunait/node_modules" ]]; then
info "Bunait theme node_modules found."
else
info "Running npm install to fetch node_modules..."
cd starters/five-page/themes/bunait
npm install
fi
}
function check_conf() {
# create conf folder if not found
if [[ -d "sites/conf" ]]; then
info "sites/conf found."
else
info "Creating sites configuration directory"
mkdir sites/conf
fi
# create README file if not found
if [[ ! -f "sites/conf/README" ]]; then
info "Creating sites README file"
echo -e '# One conf file per site is added by --new-site task\n# Push to a remote to sync sites/ between devices and users' > sites/conf/README
fi
# Check if a git repo exists in sites/conf
# init repo is not
if [[ -d "sites/conf/.git" ]]; then
info "Found a git repo in sites/conf."
else
info "Init git repository for configuration"
cd sites/conf && git init
info "Adding and committing config files to repository..."
git add .
git commit --quiet -m"Initial Commit of HuMC sites conf directory"
notice "Please add a git remote and git push\n to save your config"
fi
}
function update_conf() {
# cd into sites/conf and git pull if changes available
if [[ -d "sites/conf/.git" ]]; then
info "Examining changes to sites/conf repository."
cd sites/conf
# Update all remotes
git remote update
# Check repo status
# @ is short for HEAD, @{u} is short for the upstream branch tracking current local branch
LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse --abbrev-ref @{u})
BASE=$(git merge-base @ @{u})
if [ $LOCAL = $REMOTE ]; then
notice "sites/conf repository is up to date."
elif [ $REMOTE = $BASE ]; then
warning "You need to push you local changes to sites/conf. Stopping."
# Automate the push - check for changes and commit.
return
elif [ $LOCAL = $BASE ]; then
notice "Pulling changes to sites/conf repository."
# safe pull ff only?
git pull
else
alert "Remote and local copies of sites/conf have divereged! Stopping."
return
fi
else
notice "You don't appear to have a git repository in sites/conf. Run 'hum -s' to rerun setup."
fi
}
function new_site() {
info "Adding new site in sites/${arg_n} ..."
# Notes:
# For 'cp' and 'mv'
# -r is recursive
# -n will not overwrite existing
# -v is verbose
cp -rn starters/five-page sites/${arg_n}
info "Change sitename from bunait to ${arg_n}..."
find sites/${arg_n}/config/_default -name 'config.toml' -exec sed -i "s/title = \"bunait\"/title = \"${arg_n}\"/gI" {} \;
info "Adding site config file sites/conf/${arg_n}.conf"
declare -A site='( ["loc"]="sites/${arg_n}" ["remote"]="ADD-REMOTE" )'
declare -p site > sites/conf/${arg_n}.conf
(
# Sub shell because of the cd
cd sites/conf
info "Adding and committing site config file..."
git add .
git commit --quiet -m"Added new site config file ${arg_n}.conf"
# TODO Check if remote actually exists before push?
# git diff --quiet @{u} @ <- errors if remote doesn't exist
if [[ -d ".git/refs/remotes" ]]; then
info "Attempting to push new config to remote..."
git push
else
warning "No remotes are defined for the conf repository. Not pushing."
fi
)
(
# Sub shell because of the cd
info "Init git repository..."
cd sites/${arg_n} && git init
info "Adding and committing all files to repository..."
git add .
git commit --quiet -m"Initial Commit of HuMC generated site"
info "Adding staging and production branches..."
git branch staging
git branch production
)
notice "$(echo -e "Please add a git remote and\n'git push -u origin --all'\nAlso edit sites/conf/${arg_n}.conf to add the remote\nbefore before starting work on ${arg_n}.")"
}
function list_sites() {
# loop over sites/conf and list site names
siteconf=$(find "sites/conf" -type f -name "*.conf")
echo "Available sites"
echo "---------------"
for file in ${siteconf}
do
source $file
if [[ -d "${site[loc]}" ]]; then
filepath="${site[loc]}"
echo $(basename "${filepath%.conf}")
else
warning "${file} exists but ${site[loc]} does not. Run 'hum -p' to clone site."
fi
done
echo "---------------"
}
function archive_site() {
# Compress sites/sitename and sites/conf/sitename.conf into
# zipped-sites/sitename.tgz
config="sites/conf/${arg_a}.conf"
if [[ -f "${config}" ]]; then
source ${config}
info "Archiving site ${arg_a} and conf file..."
if tar cjf zipped-sites/"${arg_a}"-"${DATE}".tar.bz --exclude="${site[loc]}"/themes/bunait/node_modules "${site[loc]}" sites/conf/"${arg_a}".conf ; then
notice "Removing site ${arg_a}."
rm -rf "${site[loc]}"
notice "Removing ${arg_a}.conf"
rm -rf "${config}"
info "Updating conf repository"
(
cd sites/conf
git commit --quiet -m"Removing archived configuration for ${arg_a}" ${arg_a}.conf
git push
)
fi
else
warning "Specified site ${arg_a} doesn't seem to exist. ${arg_a}.conf missing. Aborting."
return
fi
}
function clean_sites() {
# Get a list of site folders (exclude conf)
sites=$(find "sites/" -maxdepth 1 -mindepth 1 -not -name conf -type d -exec basename {} \;)
# get list of sitename.conf files but strip .conf extension
sitesconf=$(find "sites/conf" -type f -name "*.conf" -exec basename {} .conf \;)
# Filter site folders without matching sitename.conf
# See https://unix.stackexchange.com/a/293254/310450
missing_conf=$(echo ${sites[@]} ${sitesconf[@]} | sed 's/ /\n/g' | sort | uniq -d | xargs echo ${sites[@]} | sed 's/ /\n/g' | sort | uniq -u)
for i in ${missing_conf};
do
info "Found site folder ${i} but no ${i}.conf file"
info "Assuming removed and archiving site to zipped-sites..."
if tar cjf zipped-sites/"${i}"-noconf-"${DATE}".tar.bz sites/"${i}" ; then
warning "Removing site ${i}..."
rm -rf sites/"${i}"
fi
done
}
function pull_sites() {
# use 'command subsitution' to store results as a variable
siteconf=$(find "sites/conf" -type f -name "*.conf")
for file in ${siteconf}
do
source $file
if [[ -d "${site[loc]}" ]]; then
info "Checking status of ${site[loc]}"
(
cd "${site[loc]}"
git fetch
# check for unstaged changes
if ! git diff-files --quiet --ignore-submodules --
then
info "Unstaged changes found, resolve manually then run 'hum -p' again."
# check for uncommitted changes
elif ! git diff-index --cached --quiet @ --ignore-submodules --
then
info "Uncommitted changes found, resolve manually then run 'hum -p' again."
# check for unpushed commits
elif [ -n "$(git log @{u}.. --ignore-submodules)" ]
then
info "Unpushed commits found, resolve manually then run 'hum -p' again."
# result of previous command is stored in $?
elif [ "$(git rev-list @...@{u} --count)" -gt 0 ]
then
# check for changes which at this point should be in remote repo
# --count would include local commits but we stop above if those exist
changes=$(git rev-list @...@{u} --count)
if [ ${changes} -gt 0 ]
then
info "${changes} remote changes found, pulling..."
git pull
fi
else
info "No changes found, ${site[loc]} is up to date."
fi
)
# TODO
# What about other branches?
# Need master/staging/production all to be checked and updated
else
info "Cloning new site ${site[loc]}"
git clone "${site[remote]}" "${site[loc]}"
fi
echo "------------------------------------------------------------"
done
}
#function stage_site() {
# Get cwd
# Get current branch
# check we are on master
# if on master dry-run merge to staging
# if dry run finds merge conflict stop and report
# if dry run ends successfully do the actual merge
# dry run push to remote staging branch or check remote staging for changes
# if no changes in remote and it safe to push, push to remote staging branch
# switch working copy back to master branch
#}
function node_modules_sync() {
# 'hum -j' Run 'npm install' inside themes
# find package.json in theme folders, limit depth to avoid node modules own package.jsons
themes_with_node=$(find 'sites/' 'starters' -mindepth 1 -maxdepth 4 -not -path '*/\.git*' -type f -readable -name "package.json" -exec dirname {} \; | sort -u)
# run npm i in those folders
for dir in ${themes_with_node}
do
(
info "Syncing node_modules in ${dir}..."
cd ${dir}
npm install
echo "------------------------------------------------------------"
)
done
}
#########
# Hum logic (calls to functions)
# Create new site with name
# 'hum -n SITENAME'
if [[ -n "${arg_n}" ]]; then
# Check if site/name already exists
if [[ -d "sites/${arg_n}" ]]; then
error "sites/${arg_n} already exists"
else
new_site
fi
fi
# Check hum setup 'hum -s'
if [[ "${arg_s}" -eq 1 ]]; then
check_hugo
#check_nodemod
check_theme_nodemod
fi
# Create sites/conf directory and repo
# 'hum -c'
if [[ "${arg_c}" -eq 1 ]]; then
check_conf
fi
# Update sites/conf working copy
if [[ "${arg_u}" -eq 1 ]]; then
update_conf
fi
# Checkout new sites to site/sitename
# Update sites/sitename working copies
if [[ "${arg_p}" -eq 1 ]]; then
pull_sites
fi
# Update node_modules in theme folders
# Intended for use after 'hum -p'
# 'hum -j'
if [[ "${arg_j}" -eq 1 ]]; then
node_modules_sync
fi
# List sites
if [[ "${arg_l}" -eq 1 ]]; then
list_sites
fi
# Clean sites/
if [[ "${arg_k}" -eq 1 ]]; then
clean_sites
fi
# Archive a site
if [[ -n "${arg_a}" ]]; then
archive_site
fi
# Stage a site
#if [[ -n "${arg_t}" ]]; then
# stage_site
#fi