-
Notifications
You must be signed in to change notification settings - Fork 3
/
K1-Backup.sh
executable file
·308 lines (274 loc) · 9.63 KB
/
K1-Backup.sh
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
#!/bin/sh
#
# This program is based off of gitwatch @ https://github.com/gitwatch/gitwatch.git
# Copyright (C) 2013-2018 Patrick Lehner
# with modifications and contributions by:
# - Matthew McGowan
# - Dominik D. Geyer
# - Phil Thompson
# - Dave Musicant
#
# Edited to work on busybox ash shell, specifically the Creality K1 & K1Max
#############################################################################
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#############################################################################
#
# Idea and original code taken from http://stackoverflow.com/a/965274
# original work by Lester Buck
# (but heavily modified by now)
#
# Requires the command 'inotifywait' to be available, which is part of
# the inotify-tools (See https://github.com/rvoicilas/inotify-tools ),
# and (obviously) git.
# Will check the availability of both commands using the `which` command
# and will abort if either command (or `which`) is not found.
#
INSTALL=0
PAUSE=0
RESUME=0
STOP=0
REMOTE=""
BRANCH=""
TARGET=""
EVENTS="${EVENTS:-close_write,move,move_self,delete,create,modify}"
SLEEP_TIME=5
DATE_FMT="+%Y-%m-%d %H:%M:%S"
COMMITMSG="Scripted auto-commit on change (%d) by gitwatch.sh"
SKIP_IF_MERGING=0
# Function to print script help
shelp() {
echo "Usage: $(basename "$0") [-i] [-p] [-r] [-s] -b branch -t target -g remote"
echo "Options:"
echo " -i Install"
echo " -p Pause"
echo " -r Resume"
echo " -s Stop"
echo " -b branch Specify branch for git push"
echo " -t target Specify target directory or file to watch"
echo " -g remote Specify remote for git push"
}
# Parse command-line arguments
while getopts "iprsb:t:g:hn" option; do
case "${option}" in
i) INSTALL=1 ;;
p) PAUSE=1 ;;
r) RESUME=1 ;;
s) STOP=1 ;;
b) BRANCH="${OPTARG}" ;;
t) TARGET="${OPTARG}" ;;
g) REMOTE="${OPTARG}" ;;
h)
shelp
exit 0
;;
\?)
echo "Invalid option: -$OPTARG" >&2
shelp
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
shelp
exit 1
;;
*)
shelp
exit 0
;;
esac
done
# Check if more than one flag is used
if [ "$((INSTALL + PAUSE + RESUME + STOP))" -gt 1 ]; then
echo "Error: Only one flag is allowed at a time."
shelp
exit 1
fi
# Pause, Resume, Stop flags
if [ "$PAUSE" = 1 ]; then
echo "Pausing automatic backups until the next reboot or manually restarted..."
/etc/init.d/S52K1-Backup stop
exit 0
elif [ "$STOP" = 1 ]; then
echo "Stopping automatic backups until manually restarted...."
mv /etc/init.d/S52K1-Backup /etc/init.d/disabled.S52K1-Backup
exit 0
elif [ "$RESUME" = 1 ]; then
echo "Resuming automatic backups..."
mv /etc/init.d/disabled.S52K1-Backup /etc/init.d/S52K1-Backup
exit 0
elif [ "$INSTALL" = 1 ]; then
# Install required packages using opkg
if command -v opkg >/dev/null; then
opkg update
opkg install inotifywait procps-ng-pkill
else
echo "Error: opkg package manager not found. Please install opkg manually."
exit 1
fi
# Prompt user for configuration
echo "Please enter the configuration information:"
read -p "Enter GitHub personal access token: " GITHUB_TOKEN
read -p "Enter backup repository name: " REPO_NAME
read -p "Enter user name: " USER_NAME
# Prompt user to select folders to be watched
IFS=/usr/data/printer_data/config
# Clone K1 Backup Repo
git clone https://github.com/lokiagent/K1-Backup.git /usr/data/K1-Backup
# Connect config directory to github
cd "$IFS" || exit
git init
git remote add origin "https://$USER_NAME:$GITHUB_TOKEN@github.com/$USER_NAME/$REPO_NAME.git"
git checkout -b "$BRANCH"
git add .
git commit -m "Initial Backup"
git push -u origin "$BRANCH"
# Write configuration to .env file
echo "IFS=$IFS" > "$IFS/.env"
echo "GITHUB_TOKEN=$GITHUB_TOKEN" >> "$IFS/.env"
echo "REMOTE=$REPO_NAME" >> "$IFS/.env"
echo "BRANCH=$BRANCH" >> "$IFS/.env"
echo "USER=$USER_NAME" >> "$IFS/.env"
# Create .gitignore file to protect .env variables
echo ".env" > "$IFS/.gitignore"
# Insert .env to S52gitwatch.sh and move to init.d
cp -f /usr/data/K1-Backup/S52K1-Backup /etc/init.d/S52K1-Backup
sed -i "2i source $IFS/.env" /etc/init.d/S52K1-Backup
chmod +x /etc/init.d/S52K1-Backup
/etc/init.d/S52K1-Backup start
echo "K1 Backup has been installed and configured."
exit 0
fi
# print all arguments to stderr
stderr() {
echo "$@" >&2
}
# clean up at end of program, killing the remaining sleep process if it still exists
cleanup() {
if [ -n "$SLEEP_PID" ] && kill -0 "$SLEEP_PID" 2>/dev/null; then
kill "$SLEEP_PID" 2>/dev/null
fi
exit 0
}
# Tests for the availability of a command
is_command() {
command -v "$1" >/dev/null 2>&1
}
# Test whether or not current git directory has ongoing merge
is_merging () {
[ -f "$(git rev-parse --git-dir)"/MERGE_HEAD ]
}
shift $((OPTIND - 1)) # Shift the input arguments, so that the input file (last arg) is $1 in the code below
GIT="git"
RL="readlink"
INW="inotifywait"
# Check availability of selected binaries and die if not met
for cmd in "$GIT" "$INW"; do
is_command "$cmd" || {
stderr "Error: Required command '$cmd' not found."
exit 2
}
done
SLEEP_PID="" # pid of timeout subprocess
trap "cleanup" EXIT # make sure the timeout is killed when exiting script
# Expand the path to the target to absolute path
if [ "$(uname)" != "Darwin" ]; then
IN=$($RL -f "$TARGET")
else
if is_command "greadlink"; then
IN=$(greadlink -f "$TARGET")
else
IN=$($RL -f "$TARGET")
if [ $? -eq 1 ]; then
echo "Seems like your readlink doesn't support '-f'. Running without. Please 'brew install coreutils'."
IN=$($RL "$TARGET")
fi
fi
fi
if [ -d "$TARGET" ]; then # if the target is a directory
TARGETDIR=$(echo "$IN" | sed -e "s/\/*$//") # dir to CD into before using git commands: trim trailing slash, if any
# construct inotifywait-commandline
if [ "$(uname)" != "Darwin" ]; then
INW_ARGS="-qmr -e $EVENTS $TARGETDIR"
fi
GIT_ADD="git add -A ." # add "." (CWD) recursively to index
GIT_COMMIT_ARGS="-a" # add -a switch to "commit" call just to be sure
else
stderr "Error: The target is neither a regular file nor a directory."
exit 3
fi
# CD into the right dir
cd "$TARGETDIR" || {
stderr "Error: Can't change directory to '${TARGETDIR}'."
exit 5
}
if [ -n "$REMOTE" ]; then # are we pushing to a remote?
if [ -z "$BRANCH" ]; then # Do we have a branch set to push to ?
PUSH_CMD="$GIT push $REMOTE" # Branch not set, push to remote without a branch
else
# check if we are on a detached HEAD
if HEADREF=$($GIT symbolic-ref HEAD 2> /dev/null); then # HEAD is not detached
#PUSH_CMD="$GIT push $REMOTE $(sed "s_^refs/heads/__" <<< "$HEADREF"):$BRANCH"
PUSH_CMD="$GIT push $REMOTE ${HEADREF#refs/heads/}:$BRANCH"
else # HEAD is detached
PUSH_CMD="$GIT push $REMOTE $BRANCH"
fi
fi
else
PUSH_CMD="" # if no remote is selected, make sure the push command is empty
fi
# main program loop: wait for changes and commit them
# whenever inotifywait reports a change, we spawn a timer (sleep process) that gives the writing
# process some time (in case there are a lot of changes or w/e); if there is already a timer
# running when we receive an event, we kill it and start a new one; thus we only commit if there
# have been no changes reported during a whole timeout period
# Custom timeout function
# main program loop: wait for changes and commit them
# Custom timeout function
timeout() {
sleep "5" &
timeout_pid=$!
trap "kill $timeout_pid 2>/dev/null" EXIT
wait $timeout_pid 2>/dev/null
}
while true; do
# Start inotifywait to monitor changes
eval "$INW $INW_ARGS" | while read -r line; do
# Check if there were any changes reported during the timeout period
if [ -n "$line" ]; then
# Process changes
if [ -n "$DATE_FMT" ]; then
COMMITMSG=$(echo "$COMMITMSG" | awk -v date="$(date "$DATE_FMT")" '{gsub(/%d/, date)}1') # splice the formatted date-time into the commit message
fi
cd "$TARGETDIR" || {
stderr "Error: Can't change directory to '${TARGETDIR}'."
exit 6
}
STATUS=$($GIT status -s)
if [ -n "$STATUS" ]; then # only commit if status shows tracked changes.
if [ "$SKIP_IF_MERGING" -eq 1 ] && is_merging; then
echo "Skipping commit - repo is merging"
continue
fi
$GIT_ADD # add file(s) to index
$GIT commit $GIT_COMMIT_ARGS -m "$COMMITMSG" # construct commit message and commit
if [ -n "$PUSH_CMD" ]; then
echo "Push command is $PUSH_CMD"
eval "$PUSH_CMD"
pkill 'inotifywait'
timeout
fi
fi
fi
done
done