-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsyn
executable file
·464 lines (390 loc) · 12.9 KB
/
syn
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
#!/bin/bash
# SYN
#
# Easily synchronise website content (database and asset files) between environments
#
# @version 1.0.2
# @author Rick Hambrook <rick@rickhambrook.com>
# @copyright Copyright (c) 2018 Rick Hambrook
# @license http://opensource.org/licenses/GPL-3.0 GNU Public License
# TODO
# [ ] Docs
# [ ] - Overview GIF
# [ ] - Quick start (simplest config)
# [ ] - RSYNC to separate file
# [ ] "Namespace" everything to a SYN namespace?
# [ ] Use centralised config file for paths and setting, docker/docker-machine (location optionally configurable via env var)
# [ ] Add boot2docker support
# [ ] Add pre-flight validation checks for each plugin
# [ ] Add core validation functions for use by plugins
# [ ] - ssh connection works (maybe, might cause too many connections)
# [ ] - docker container exists
# [ ] - docker container on ssh host is accessible and exists
# [ ] Check all quotes and escape sequences
# [ ] See if there is an easier to way merge defaults with supplied values
# [ ] Maybe load a single location as global config, maybe ~/.syn/config
# [ ] Add shorthand parameters?
# [ ] Enable dumping of sample config from each plugin?
_SYN_VERSION=1.0.2
_SYN_AUTHOR="Rick Hambrook"
_SYN_WEBSITE="https://www.rickhambrook.com"
## ## ### ######## #### ### ######## ## ######## ######
## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ## ## ## ## ## ##
## ## ## ## ######## ## ## ## ######## ## ###### ######
## ## ######### ## ## ## ######### ## ## ## ## ##
## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
### ## ## ## ## #### ## ## ######## ######## ######## ######
# Initial settings
declare cmd="sync"
declare src
declare dst
declare plugin_cnt
declare config_cnt
declare config_files=""
declare local_root=""
declare autocomplete=false
declare -A actions # proposed list of actions (honouring --only and --plus)
declare -A actions_all # key/value list of all actions and their optional flag for the specified environment
declare -A commands
declare -A environments
declare -a plugins # ordered alphabetically
declare -a plugins_exec # ordered for execution
declare -A exec_order
declare app_dir
declare plugin_dir_builtin
declare plugin_dir_custom
declare default_config_dir
declare colour_enabled=true
declare time_start=`date +"%s"`
declare -A formatting # must be declared here, not in lib file
#declare -A api_versions
# Default settings for plugins to extend
declare -A config
# Flags
declare -A flags=(
[debug]=false
[dryrun]=false
[force]=false
)
declare -A flags_help=(
#[debug]="Internal use only for now"
[dryrun]="Show the commands that will be used, but don't run them"
[force]="Push to live/prod/'warn' without confirmation prompt (if applicable)"
)
# Vars
declare -A vars=(
[config]=""
[only]=""
[plus]=""
[autocomplete-current]=""
[autocomplete-previous]=""
)
declare -A vars_help=(
[config]="Specify a config file to load (after other attempts)"
[only]="Select only the actions you want to take (comma separated)"
[plus]="Select actions to take in addition to defaults (comma separated)"
)
###### ####### ## ## ## ## ### ## ## ######## ######
## ## ## ## ### ### ### ### ## ## ### ## ## ## ## ##
## ## ## #### #### #### #### ## ## #### ## ## ## ##
## ## ## ## ### ## ## ### ## ## ## ## ## ## ## ## ######
## ## ## ## ## ## ## ######### ## #### ## ## ##
## ## ## ## ## ## ## ## ## ## ## ### ## ## ## ##
###### ####### ## ## ## ## ## ## ## ## ######## ######
# Do the actual synchronising
function syn_cmd_sync() {
# Check if we have any configs set
if (( config_cnt == 0 )); then
syn_error "No config files were found"
fi
syn_validate_require_two_envs
syn_validate_allow
if ${flags[dryrun]}; then
printf "$(_ bg_green)\n\tDRY RUN: No actions will be taken, commands will be output instead of run\n$(_ reset)\n\n"
fi
# Pre-process summary
printf "Proceeding to sync %s from $(_ bold)%s$(_ r_bold) to $(_ bold)%s$(_ r_bold)\n" "$(printf "${!actions[@]}" | sed -e 's/,/, /')" "$src" "$dst"
# Check that all the actions exist
for x in ${!actions[@]}; do
local p=$(syn_get_plugin_name_from_fuzzy $x)
if [[ ! $(syn_validate_plugin "$p") ]]; then
syn_error "Plugin '$p' not found"
fi
#syn_api_version_check $p
done
# Run all the actions exist
for a in ${!actions[@]}; do
printf "\n$(_ green bold)Running action: %s$(_ reset)\n" "${actions[$a]}"
local p=$(syn_get_plugin_name_from_fuzzy $a)
eval "syn_plugin_${p} \"${actions[$a]}\""
if [ $? != 0 ]; then
syn_error "Plugin '$p' encountered an error so processing has stopped"
fi
done
if ! ${flags[dryrun]} || ${flags[debug]}; then
syn_post_summary
fi
}
function syn_cmd_actions() {
local acts=""
for k in "${!actions[@]}"; do
acts+="\n ${k}"
done
if [[ ! "${acts}" ]]; then
acts="\n <none>"
fi
printf "Proposed actions for this sync:${acts}\n"
}
function syn_cmd_actions_help() {
printf "Show the proposed actions that are configured for a src, dst, or both"
}
function syn_cmd_actions-all() {
local acts=""
for k in "${!actions_all[@]}"; do
acts+="\n ${actions_all[$k]}${k}"
done
if [[ ! "${acts}" ]]; then
acts="\n <none>"
fi
printf "All available actions for this sync:${acts}\n"
}
function syn_cmd_actions-all_help() {
printf "Show all actions that are configured for a src, dst, or both"
}
# Show environments
function syn_cmd_envs() {
# $1 = [true/false] show 'readonly' status
local envs=""
for e in ${environments[*]}; do
envs+=" $(_ yellow)${e}$(_ default)"
if [[ ! "$1" == true && "${config[${e}/_allow]}" == false ]]; then
envs+=" [read only]"
fi
envs+="\n"
done
if [[ ! "${envs}" ]]; then
envs=" <none>\n"
fi
syn_cli_render_title "Loaded Environments:"
printf "${envs}"
}
function syn_cmd_envs_help() {
printf "List available environments"
}
# Show paths
function syn_cmd_paths() {
local tmp_plugin_dir_custom
local tmp_default_config_dir
if [[ "${SYN_PLUGIN_PATH}" ]]; then
if [[ -d "${SYN_PLUGIN_PATH}" ]]; then
tmp_plugin_dir_custom="${SYN_PLUGIN_PATH}"
else
tmp_plugin_dir_custom="${SYN_PLUGIN_PATH} (DOES NOT EXIST)"
fi
else
tmp_plugin_dir_custom="<not set>"
fi
if [[ "${SYN_DEFAULT_PATH}" ]]; then
if [[ -d "${SYN_DEFAULT_PATH}" ]]; then
tmp_default_config_dir="${SYN_DEFAULT_PATH}"
else
tmp_default_config_dir="${SYN_DEFAULT_PATH} (DOES NOT EXIST)"
fi
else
tmp_default_config_dir="<not set>"
fi
syn_cli_render_title "Custom Paths:"
syn_cli_render_kv_row "SYN_PLUGIN_PATH:" "${tmp_plugin_dir_custom}" "magenta"
syn_cli_render_kv_row "SYN_DEFAULT_PATH:" "${tmp_default_config_dir}" "magenta"
}
function syn_cmd_paths_help() {
printf "List configured paths"
}
# Show plugins
function syn_cmd_plugins() {
syn_cli_render_title "Loaded Plugins:"
if (( ${#plugins[@]} > 0 )); then
printf " $(_ lightcyan)%s$(_ default)\n" "${plugins[@]}"
else
printf " <none>\n"
fi
}
function syn_cmd_plugins_help() {
printf "List all available plugins"
}
# Show configuration files
function syn_cmd_configs() {
#todo: migrate to use syn_cli_render_title
syn_cli_render_title "Loaded Configs:"
printf " %s\n" "${config_files[@]//"\n"/""}"
if [[ "${config_files[@]}" = "" ]]; then
printf " <none>\n"
fi
}
function syn_cmd_configs_help() {
printf "List all available configuration files"
}
# Install the thing
function syn_cmd_install() {
if [[ ! -L "/etc/bash_completion.d/syn" ]]; then
sudo ln -s "${app_dir}/other/syncomplete.bash" "/etc/bash_completion.d/syn"
if [[ -L "${BASH_SOURCE[0]}" ]]; then
printf "Bash completion file added. Try it out!\n\n"
fi
fi
if [[ -L "${BASH_SOURCE[0]}" ]]; then
syn_error "Syn is already installed as a SymLink."
fi
if [[ -e "/usr/local/bin/syn" ]]; then
syn_error "Syn is already installed to your path."
fi
sudo ln -s "$(readlink -f "$0")" "/usr/local/bin/syn"
if syn_notifications_has_powershell && ! syn_notifications_has_burnttoast; then
syn_notifications_burnttoast_install_help
fi
printf "You can now run this script simply by typing 'syn'\n"
}
function syn_cmd_install_help() {
printf "Installs Syn to your executable path for ease-of-use\n"
}
# Update from Github (because I'm lazy)
function syn_cmd_self-update() {
if [[ ! -d "${app_dir}/.git" ]]; then
syn_error "Cannot self update, cannot find .git folder in \"${app_dir}\""
fi
local latest_version=$(wget -q -O - https://raw.githubusercontent.com/Hambrook/Syn/master/syn | grep -oP '_SYN_VERSION=([^\n]+)' | sed -e 's/_SYN_VERSION=//')
printf "Current version: %s\n" $_SYN_VERSION
printf "Latest version: %s\n" $latest_version
if ! syn_confirm "Do you wish to update?" "Y"; then
printf "Aborting\n"
exit
fi
(cd "${app_dir}" && git pull)
#printf "cd \"${app_dir}\" && git pull\n"
syn --version
}
function syn_cmd_self-update_help() {
printf "Updates Syn from the Github repo\n"
}
function syn_cmd_version() {
printf "Syn v%s\n" "${_SYN_VERSION}"
}
function syn_cmd_version_help() {
printf "Show the version and exit"
}
####### ######## ## ## ######## ######## ###### ######## ## ## ######## ########
## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ## ## ## ## ## ##
## ## ## ######### ###### ######## ###### ## ## ## ###### ######
## ## ## ## ## ## ## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
####### ## ## ## ######## ## ## ###### ## ####### ## ##
# The banner
function syn_banner() {
printf "$(_ lightgreen bold)
_____
/ ____|
| (___ _ _ _ __ $(_ r_bold)Version: v%s$(_ bold)
\___ \| | | | '_ \\
____) | |_| | | | | $(_ r_bold)Author: %s$(_ bold)
|_____/ \__, |_| |_|
__/ | $(_ r_bold)Website: %s$(_ bold)
|___/
$(_ reset)" "${_SYN_VERSION}" "${_SYN_AUTHOR}" "${_SYN_WEBSITE}"
}
# Initialise a few paths etc
function syn_init() {
local real_path="${BASH_SOURCE[0]}"
if [[ -L "${real_path}" ]]; then
real_path="$(readlink "${real_path}")"
fi
app_dir="$( cd "$( dirname "${real_path}" )" && pwd )"
plugin_dir_builtin="${app_dir}/plugins"
if [[ "${SYN_PLUGIN_PATH}" && -d "${SYN_PLUGIN_PATH}" ]]; then
plugin_dir_custom="${SYN_PLUGIN_PATH}"
fi
if [[ "${SYN_DEFAULT_PATH}" && -d "${SYN_DEFAULT_PATH}" ]]; then
default_config_dir="${SYN_DEFAULT_PATH}"
fi
# Load libs
if [[ -d "$plugin_dir_builtin" ]]; then
for filename in ${app_dir}/lib/*.bash; do
. "$filename"
done
fi
# Load plugins
plugin_cnt=0
if [[ -d "$plugin_dir_builtin" ]]; then
for filename in ${plugin_dir_builtin}/*.synPlugin; do
. "$filename"
(( plugin_cnt++ ))
done
fi
if [[ -d "$plugin_dir_custom" ]]; then
for filename in ${plugin_dir_custom}/*.synPlugin; do
. "$filename"
(( plugin_cnt++ ))
done
fi
}
# Generate and display a post-process summary
function syn_post_summary() {
local summary_text="${src} > ${dst}"
if [[ "${vars[file]}" ]]; then
summary_text="[${vars[file]}] ${summary_text}"
fi
# Time reporting
local time_diff=$(( `date +"%s"` - $time_start ))
local time_diff_str=""
if (( time_diff > 3599 )); then
# hours, minutes, seconds
time_diff_str=$(date -u -d @"${time_diff}" +'%-Hh %-Mm %-Ss');
elif (( time_diff > 59 )); then
# minutes, seconds
time_diff_str=$(date -u -d @"${time_diff}" +'%-Mm %-Ss');
else
# seconds
time_diff_str=$(date -u -d @"${time_diff}" +'%-Ss');
fi
# Only
local plugins_str="<all>"
if [[ "${#actions[@]}" ]]; then
# This version removes the space afte rhte comma
#plugins_str=$(join ", " ${actions[@]});
plugins_str=${actions[@]};
plugins_str=${plugins_str//" "/", "};
# Remove the "!" prefix
plugins_str=${plugins_str//"!"/""};
fi
local tmp_configs=$(printf "\n\t\t%s" "${config_files[@]//"\n"/""}")
# Inline summary
printf "$(_ bg_green)
$(_ bold)SYN COMPLETE$(_ r_bold)
From: $(_ bold)%s$(_ r_bold) to $(_ bold)%s$(_ r_bold)
Plugins: $(_ bold)%s$(_ r_bold)
Time: $(_ bold)%s$(_ r_bold)
Config files: ${tmp_configs}
$(_ bg_default)
" "${src}" "${dst}" "${plugins_str}" "${time_diff_str}"
syn_notifications_show "Syn Complete (${time_diff_str})" "${summary_text}" "${app_dir}/assets/icon.png" "transfer.complete"
}
# Main processing function
function main() {
# Load and parse everything
syn_init
syn_load_configs
syn_parse_commands
syn_parse_plugins
syn_parse_parameters "$@"
syn_load_config_specific
syn_parse_environments
syn_parse_actions
syn_check_autocomplete_request "$@"
syn_check_help_request "$@"
# Do the chosen command
eval "syn_cmd_${cmd}"
# Let's get out of here
exit
}
main "$@"