-
Notifications
You must be signed in to change notification settings - Fork 1
/
goodnight.bash
170 lines (122 loc) · 5.37 KB
/
goodnight.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
# Copyright (c) 2023 Michael Federczuk
# SPDX-License-Identifier: MPL-2.0 AND Apache-2.0
# `goodnight` is an end-of-day function that performs the following steps:
# 1. (if available) updates the installed packages via the command `pkgsup` (see file 'pkgsup.bash')
# 2. (if available) creates a backup via the command `mkbak` (see <https://github.com/mfederczuk/mkbak>)
# 3. (if present) executes the file '~/goodnight_tasks'
# 4. (if available) updates the installed packages and shuts the system down via `upshut` (see file 'pkgsup.bash' again)
# 4a. if `upshut` is not available, shuts the system down via `shutdown`
if ! command -v trace_cmd > '/dev/null'; then
return
fi
function __dotfiles_bash_funcs_goodnight__exec_mkbak() {
if ! command -v mkbak > '/dev/null'; then
return
fi
local today new_backup_archive_filename || return
today="$(date +'%Y-%m-%d')" || return
new_backup_archive_filename="backups/$today.tar.gz" || return
local backup_archive_parent_directory_filename || return
backup_archive_parent_directory_filename="$(dirname -- "$new_backup_archive_filename" && printf x)" || return
backup_archive_parent_directory_filename="${backup_archive_parent_directory_filename%$'\nx'}" || return
mkdir -p -- "$backup_archive_parent_directory_filename" || return
unset -v backup_archive_parent_directory_filename || return
if [ -e "$new_backup_archive_filename" ]; then
# we're assuming GNU system here, because otherwise it'd be a pain trying to get the birth/mod time in hours
# of a file
# TODO: find a way to do this with POSIX without wanting to blow my brains out
local existing_backup_archive_filename existing_backup_archive_file_timestamp existing_backup_archive_file_hour current_hour || return
existing_backup_archive_filename="$new_backup_archive_filename" || return
# %W -> birth time in unix epoch
existing_backup_archive_file_timestamp="$(stat --format='%W' -- "$existing_backup_archive_filename")" || return
if [ "$existing_backup_archive_file_timestamp" -eq 0 ]; then
# %Y -> last mod time in unix epoch
existing_backup_archive_file_timestamp="$(stat --format='%Y' -- "$existing_backup_archive_filename")" || return
fi
existing_backup_archive_file_hour="$(date --date="@$existing_backup_archive_file_timestamp" +'%H')" || return
current_hour="$(date +'%H')" || return
if [ "$current_hour" != "$existing_backup_archive_file_hour" ]; then
mv -- "$existing_backup_archive_filename" \
"${existing_backup_archive_filename%".tar.gz"}_H$existing_backup_archive_file_hour.tar.gz" || return
new_backup_archive_filename="${new_backup_archive_filename%".tar.gz"}_H$current_hour.tar.gz" || return
fi
unset -v current_hour existing_backup_archive_file_hour existing_backup_archive_file_timestamp existing_backup_archive_filename || return
fi
trace_cmd mkbak --output="$new_backup_archive_filename" || return
}
function __dotfiles_bash_funcs_goodnight__final_shutdown() {
if command -v upshut > '/dev/null'; then
trace_cmd upshut
return
fi
if [ -n "${HISTFILE-}" ] && [ ! -e "$HISTFILE" ]; then
local histfile_parent_dir_pathname || return
histfile_parent_dir_pathname="$(dirname -- "$HISTFILE" && printf x)" || return
histfile_parent_dir_pathname="${histfile_parent_dir_pathname%$'\nx'}" || return
mkdir -p -- "$histfile_parent_dir_pathname" || return
unset -v histfile_parent_dir_pathname || return
fi
history -a || return
trace_cmd shutdown 0
}
function goodnight() {
#region checking environment
if ! command -v trace_cmd > '/dev/null'; then
printf '%s: trace_cmd: program missing\n' "${FUNCNAME[0]}" >&2
return 27
fi
#region environment variables
if [ -z "${HOME-}" ]; then
printf '%s: HOME environment variable must not be unset or empty\n' "${FUNCNAME[0]}" >&2
exit 48
fi
if [[ ! "$HOME" =~ ^'/' ]]; then
printf '%s: %s: HOME environment variable must be an absolute path\n' "${FUNCNAME[0]}" "$HOME" >&2
exit 49
fi
#endregion
#endregion
if (($# > 0)); then
printf '%s: too many arguments: %i\n' "${FUNCNAME[0]}" $# >&2
return 4
fi
#region checking tasks executable
local tasks_executable_pathname || return
tasks_executable_pathname="$HOME/goodnight_tasks" || return
readonly tasks_executable_pathname
local tasks_executable_present || return
tasks_executable_present=false || return
if [ -e "$tasks_executable_pathname" ]; then
if [ ! -f "$tasks_executable_pathname" ]; then
local what || return
if [ -d "$tasks_executable_pathname" ]; then
what='file' || return
else
what='regular file' || return
fi
readonly what || return
printf '%s: %s: not a %s\n' "${FUNCNAME[0]}" "$tasks_executable_pathname" "$what" >&2
return 26
fi
if [ ! -x "$tasks_executable_pathname" ]; then
printf '%s: %s: permission denied: executable permissions missing\n' "${FUNCNAME[0]}" "$tasks_executable_pathname" >&2
return 77
fi
tasks_executable_present=true || return
fi
readonly tasks_executable_present
#endregion
cd || return
if command -v pkgsup > '/dev/null'; then
trace_cmd pkgsup || return
fi
__dotfiles_bash_funcs_goodnight__exec_mkbak || return
if $tasks_executable_present; then
printf 'Executing goodnight tasks...\n' >&2 || return
"$tasks_executable_pathname" || return
printf 'Goodnight Tasks executed successfully\n' >&2 || return
rm -- "$tasks_executable_pathname" || return
fi
__dotfiles_bash_funcs_goodnight__final_shutdown || return
}
complete goodnight