This repository was archived by the owner on Jul 8, 2024. It is now read-only.
Repository navigation
Expand file tree
/
Copy pathhal-sync
More file actions
executable file
·208 lines (181 loc) · 4.39 KB
/
Copy pathhal-sync
File metadata and controls
executable file
·208 lines (181 loc) · 4.39 KB
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
#!/bin/bash
set ${CHANG_SET:--eu}
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NO_COLOR='\033[0m'
CLEAR_LINE='\r\033[K'
DIM='\e[2m'
STEP_LINE=false
fail() {
printf "${CLEAR_LINE}${RED}⚡️ ${@:?}${NO_COLOR}\n" 1>&2
exit 1
}
step() {
STEP_LINE=true
style=$(${VERBOSE} && printf ${YELLOW} || printf ${DIM})
printf "${CLEAR_LINE}${NO_COLOR}${style}▷ ${@:?}${NO_COLOR}" 1>&2
}
finish_step_line() {
printf "$(${STEP_LINE} && echo "\n")" 1>&2
STEP_LINE=false
}
start_server() {
require_changignore
stop_server
create_volume_if_not_exists
docker run \
-d \
-v $(docker_volume):/chang \
-e CHANG_UID=${CHANG_UID} \
-e CHANG_GID=${CHANG_GID} \
-p 127.0.0.1::${CHANG_SYNC_SERVER_PORT} \
--name $(docker_container) \
${DOCKER_IMAGE} > /dev/null
test_server 50
}
stop_server() {
if server_exists; then
docker rm -f $(docker_container) >/dev/null 2>&1
fi
}
server_exists() {
! test -z $(docker ps -aq --filter name=^/$(docker_container)$ 2>/dev/null)
}
server_running() {
! test -z $(docker ps -q --filter name=^/$(docker_container)$)
}
initial_sync() {
chang_unison $(${VERBOSE} || echo -silent) -batch -ignorelocks -ignorearchives -force "${APP_PATH}" -perms -1
code=$?
case $code in
0) step "Initial sync finished";;
1) fail "Initial sync failed because some files were skipped";;
2) fail "Failures occurred during initial sync";;
3) fail "Fatal error occured during initial sync";;
*) fail "Unison server returned unknown exit code: ${code}";;
esac
}
docker_volume() {
if [[ -z ${DOCKER_VOLUME:-} ]]; then
project_name=${APP_PATH##*/}
[[ -z ${project_name//[a-zA-Z0-9_-]/} ]] || project_name=""
path_hash=$(path_hash $project_name)
DOCKER_VOLUME="chang-sync${project_name:+_${project_name}}_${path_hash}"
fi
echo ${DOCKER_VOLUME}
}
path_hash() {
echo ${1:?} | shasum - | head -c 8
}
docker_container() {
docker_volume
}
container_port() {
if [[ -z ${CONTAINER_PORT:-} ]]; then
CONTAINER_PORT=`docker port $(docker_container) ${CHANG_SYNC_SERVER_PORT}/tcp 2>/dev/null | sed -E 's/.*127.0.0.1://'`
[[ -n ${CONTAINER_PORT} ]] || fail "Unison server has gone away"
fi
echo ${CONTAINER_PORT}
}
server_url() {
echo socket://127.0.0.1:$(container_port)//chang
}
test_server() {
tests=${1:-1}
for _ in $(seq 1 ${tests}); do
if unison $(${VERBOSE} || echo -silent) -testserver ${APP_PATH} $(server_url) 2>/dev/null; then
return 0
fi
sleep 1
done
return 1
}
chang_unison() {
eval unison \
$(changignore) \
-root "${APP_PATH}" \
-root $(server_url) \
-perms 7 \
"${@}"
}
require_changignore() {
[[ -f .changignore || -f .chang/ignore ]] || fail "Chang-sync requires .changignore file to be present"
}
changignore() {
changignorefile=$(test -f .changignore && echo .changignore || echo .chang/ignore)
while read ignore || [ -n "${ignore}" ]; do
echo -n "-ignore='${ignore}' "
done < ${changignorefile}
}
sync() {
trap stop_server INT TERM EXIT
chang_unison $(${VERBOSE} || echo -silent) -repeat watch -prefer ${APP_PATH} -killserver -perms -1
}
sync_daemon() {
sync | read fail_fast & disown
}
create_volume_if_not_exists() {
local name=$(docker_volume)
if ! docker volume ls -q | grep -q "^${name}$"; then
docker run --rm \
--volume "${name}":/volume \
${CHANG_MIN_IMAGE} \
chown ${CHANG_UID}:${CHANG_GID} /volume
fi
}
start() {
if ! server_running; then
step "Starting chang-sync"
start_server
step "Performing initial sync"
initial_sync
sync_daemon
step "Chang-sync started"
fi
finish_step_line
}
stop() {
stop_server
}
verbose() {
VERBOSE=true
step "Starting chang-sync in verbose mode"
stop_server
step "Docker volume name: ${NO_COLOR}$(docker_volume)"
finish_step_line
step "Starting chang-sync container"
start_server
step "Performing initial sync"
finish_step_line
initial_sync
step "Running chang-sync in verbose mode"
finish_step_line
sync
}
DOCKER_IMAGE="majkel/chang-sync"
CHANG_SYNC_SERVER_PORT=5000
CHANG_UID=${CHANG_UID:-1000}
CHANG_GID=${CHANG_GID:-1000}
CHANG_PWD="${CHANG_PWD:-$(pwd -P)}"
APP_PATH="${CHANG_PWD}"
VERBOSE=false
case "${@:-}" in
""|start)
start
echo $(docker_volume)
;;
stop)
stop
;;
verbose)
verbose
;;
restart)
stop
start
;;
*)
fail "Usage: chang-sync [start|stop|restart|verbose]"
;;
esac