summaryrefslogtreecommitdiffstats
path: root/git-syncd
blob: b2bf1fdcf93ae521221956a0455c028b760a9698 (plain) (blame)
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
#!/bin/bash

GIT_SYNCD_CONFIG_DIR=${GIT_SYNCD_CONFIG_DIR:-"$HOME/.config/git-sync"}
GIT_SYNCD_CONFIG=${GIT_SYNCD_CONFIG:-"$GIT_SYNCD_CONFIG_DIR/syncd.rc"}

git_syncd=$0

git_syncd_repos=()

# auto sync exclude regex pattern
declare -g -A git_syncd_exclude=()

# maximum time seconds between fetching changes and syncing
git_syncd_default_sync_timeout=600
declare -g -A git_syncd_sync_timeout=()

# number of seconds to wait after deteced change to push
git_syncd_default_sync_delay=300
declare -g -A git_syncd_sync_delay=()

sync() {
	echo "starting sync.."
	cd "$repo" && git-sync -n -s || notify-send "Sync failed for $repo"
}

watcher() {
	repo=$1
	echo $repo ${git_syncd_exclude[@]} ${git_syncd_exclude[$repo]}
	exclude=${git_syncd_exclude[$repo]:-'\.git'}
	sync_delay=${git_syncd_sync_delay[$repo]:-$git_syncd_default_sync_delay}
	sync_timeout=${git_syncd_sync_timeout[$repo]:-$git_syncd_default_sync_timeout}
	sync "$repo"
	timeout=$sync_timeout
	while true; do
		if [ ! -e "$repo" ]; then
			echo "Repo does not exist"
			echo "sleeping (${timeout}s)"
			sleep $timeout
			continue
		fi
		echo "watching (${timeout}s)"
		file=$(timeout "$timeout" wd "$repo" inotifywait "." -r \
			-e modify,move,create,delete --exclude "$exclude" 2>/dev/null)
		rc=$?
		if [ ! -z "$file" ]; then
			echo "inotify wake: $file"
			timeout=$sync_delay
		elif [ $rc -eq 124 ]; then
			sync "$repo"
			timeout=$sync_timeout
		fi
		sleep 1
	done
}

log_prefix() {
	repo="$1"
	repo_name=$(basename "$repo")
	repo_dir_name=$(basename $(dirname "$repo"))
	while read -r line; do
		prefix="$(date "+%Y-%m-%d %T")" #$repo_dir_name/$repo_name"
		prefix="$(echo "$prefix" | tr -d "\"" | tr -d "'")"
		echo "[$prefix] $line"
	done
}

kill_all() {
	pkill -A -9 git-syncd
}

git_syncd_watchers=()
kill_watchers() {
	kill_all
	return
	fail=0
	for pid in "${git_syncd_watchers[@]}"; do
		echo "killing $pid.." >&2
		pkill -P "$pid" &>/dev/null
		waitpid -t 10 "$pid" &>/dev/null
		kill -0 -P "$pid" &>/dev/null && notify-send "Failed to kill git-syncd watcher" && fail=1
	done
	[ $fail -ne 0 ] && exit 1
	git_syncd_watchers=()
}
start_watchers() {
	for repo in "${git_syncd_repos[@]}"; do
		echo "watching '$repo'.."
		$git_syncd watch "$repo" &
		sleep 1 # wait a bit
		git_syncd_watchers+=($!)
	done
}

load_config() {
	git_syncd_repos=()
	declare -g -A git_syncd_exclude=()
	declare -g -A git_syncd_sync_delay=()
	declare -g -A git_syncd_sync_timeout=()
	if [ -e "$GIT_SYNCD_CONFIG" ]; then
		echo "sourcing '$GIT_SYNCD_CONFIG'.."
		source "$GIT_SYNCD_CONFIG"
	fi
}

if [ "$1" = "watch" ]; then
	shift
	repo="$1"; shift
	repo_dir_name="$(basename $(dirname "$repo"))"
	repo_name="$(basename "$repo")"
	log_path="$HOME/.log/git-sync/$repo_dir_name"
	mkdir -p "$log_path"
	load_config
	watcher "$repo" 2>&1 | log_prefix "$repo" > "$log_path/$repo_name"
	exit
fi

load_config
trap kill_all EXIT
start_watchers
while true; do
	file=$(inotifywait --format "%w%f" -e modify,delete "$GIT_SYNCD_CONFIG")
	if [ ! -z "$file" ]; then
		mod_path="$(realpath "$file" 2>/dev/null)"
		config_path="$(realpath "$GIT_SYNCD_CONFIG" 2>/dev/null)"
		echo "config $mod_path $config_path"
		if [ "$mod_path" = "$config_path" -o "$mod_path" = "$config_path~" ]; then
			kill_watchers
			load_config
			start_watchers
		fi
	fi
	sleep 2
done