Easily archive entire directories in whichever manner you wish.
1#!/usr/bin/env bash
2# dependencies:
3# tar, xz, stat, par2create (from par2cmdline package), md5sum, du, awk, jq
4set -e
5
6check_command() {
7 CMD="$1"
8
9 if ! command -v "$CMD" 2>&1 /dev/null
10 then
11 gum log -l "fatal" "Executable: $CMD was not found."
12 exit 1
13 fi
14}
15
16gum log -t kitchen -l info "Checking for dependencies:"
17check_command awk
18check_command du
19check_command find
20check_command jq
21check_command md5sum
22check_command par2create
23check_command stat
24check_command tar
25check_command xz
26gum log -t kitchen -l info "All dependencies found!"
27
28ARCHIVE_DB="$HOME"/.local/state/archives.json
29
30create_archive() {
31 ARCHIVE_NAME="$1"
32 ARCHIVE_DESTINATION="$2"
33 TARGET="$3"
34
35 gum log -t kitchen -l info "Creating tar for $TARGET."
36 tar cfP "$ARCHIVE_NAME".tar "$TARGET"
37 mv "$ARCHIVE_NAME".tar "$ARCHIVE_DESTINATION"
38 gum log -t kitchen -l info "Finished creating tar for $TARGET."
39
40 gum log -l info "Proceeding to archive."
41 cd "$ARCHIVE_DESTINATION" || exit 0
42 [ -f "$ARCHIVE_NAME".tar.xz ] && rm "$ARCHIVE_NAME".tar.xz && gum log -t kitchen -l info "Removed old $ARCHIVE_NAME.tar.xz."
43
44 gum log -l info -t kitchen "Compressing: $ARCHIVE_NAME.tar"
45 xz -v -e -9 "$ARCHIVE_NAME".tar
46
47 DIR_SIZE="$(du -sh "$TARGET" | awk '{print $1}')"
48 ARCHIVE_SIZE="$(du -sh "$ARCHIVE_NAME".tar.xz | awk '{print $1}')"
49 gum log -l info -t kitchen "Finished archiving $TARGET."
50 gum style --bold "Compressed $TARGET ($DIR_SIZE) to $ARCHIVE_NAME ($ARCHIVE_SIZE)."
51}
52
53create_parchive() {
54 gum log -l info -t kitchen "Creating parity archive."
55 ARCHIVE="$1"
56 find . -name '*par2' -exec rm {} \;
57 par2create -r30 -n1 "$ARCHIVE"
58}
59
60update_json() {
61 INDEX="$1"
62 ARCHIVE_TIME="$2"
63 UPLOAD_TIME="$3"
64 MD5SUM="$4"
65
66 FOO="$(jq ".[$INDEX].timestamps.last_archive = $ARCHIVE_TIME" < "$ARCHIVE_DB" \
67 | jq ".[$INDEX].timestamps.last_upload = $UPLOAD_TIME" \
68 | jq ".[$INDEX].md5sum = \"$MD5SUM"\")"
69 echo "$FOO" > "$ARCHIVE_DB"
70}
71
72ARCHIVE_COUNT="$(jq '.[].name' < "$ARCHIVE_DB" | wc -l)"
73ARCHIVE_COUNT="$((ARCHIVE_COUNT - 1))"
74for i in $(seq 0 "$ARCHIVE_COUNT")
75do
76 JSON="$(jq ".[$i]" < "$ARCHIVE_DB")"
77 TARGET="$(echo "$JSON" | jq -r '.target')"
78 TARGET="${TARGET/#\~/$HOME}"
79 ARCHIVE="$(echo "$JSON" | jq '.archive')"
80 ARCHIVE_NAME="$(echo "$ARCHIVE" | jq -r '.name')"
81 ARCHIVE_PATH="$(echo "$ARCHIVE" | jq -r '.destination')"
82 ARCHIVE_PATH="${ARCHIVE_PATH/#\~/$HOME}"
83 SYNC_COMMAND="$(echo "$JSON" | jq -r '.sync_command')"
84 mkdir -p "$ARCHIVE_PATH"
85
86 create_archive "$ARCHIVE_NAME" "$ARCHIVE_PATH" "$TARGET"
87
88 create_parchive "$ARCHIVE_NAME".tar.xz
89
90 ARCHIVE_TIME="$(stat -c %W "$ARCHIVE_NAME".tar.xz)"
91 MD5SUM="$(md5sum "$ARCHIVE_NAME".tar.xz | awk '{print $1}')"
92
93 bash -c "$SYNC_COMMAND"; UPLOAD_TIME="$(date +%s)"
94
95 update_json "$i" "$ARCHIVE_TIME" "$UPLOAD_TIME" "$MD5SUM"
96done