-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnas-update.sh
More file actions
executable file
·186 lines (174 loc) · 7.56 KB
/
Copy pathnas-update.sh
File metadata and controls
executable file
·186 lines (174 loc) · 7.56 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
#!/bin/sh
# Update cull on the NAS: download the latest code, rebuild, restart.
#
# TOS has no git, so this downloads the branch tarball over HTTPS. A public
# repo needs no credentials. For a private repo (or to avoid GitHub's
# unauthenticated rate limit), add a read token:
# 1. Make a GitHub Personal Access Token with read access to the repo.
# 2. echo "ghp_yourtoken" > /root/.cull-token && chmod 600 /root/.cull-token
# Then just run: sh nas-update.sh
#
# Your config.yaml is preserved (it isn't in the repo), and the index in the
# state dir persists across the rebuild, so there's no re-scan.
set -e
# Re-exec from a throwaway copy before we touch anything. This script updates
# its own directory below (rsync/cp), and /bin/sh reads a script incrementally
# as it runs — overwriting the running file mid-execution corrupts parsing.
# Running from a /tmp copy that nothing overwrites avoids that entirely, and
# the copy in APP_DIR is still refreshed for the next run.
if [ -z "${CULL_UPDATER_REEXEC:-}" ]; then
_self_copy="$(mktemp)"
cp "$0" "$_self_copy"
CULL_UPDATER_REEXEC=1 exec sh "$_self_copy" "$@"
fi
# --- deployment settings ---------------------------------------------------
# Don't edit the values below. They are placeholders, and this script rsyncs
# over itself on every update, so local edits are lost anyway. Put your real
# settings in a file OUTSIDE the repo — that also keeps your machine's paths
# and share names out of version control:
#
# cat > /root/.cull-deploy.conf <<'EOF'
# REPO="youruser/image-cull"
# APP_DIR="/home/youruser/image-cull"
# RAW_DIR="/volume1/yourshare/pictures"
# STATE_DIR="/volume1/yourshare/.cull"
# STARRED_DIR="/volume1/yourshare/starred"
# EOF
# chmod 600 /root/.cull-deploy.conf
#
# Use a different location with CULL_DEPLOY_CONF=/path/to/conf. Anything the
# conf doesn't set falls back to the defaults below, and environment variables
# override both.
#
# NOTE: volume paths are vendor-specific — TerraMaster (TOS) mounts at
# /Volume1 (capital V), Synology at /volume1. Check with `df -h` on the NAS.
DEPLOY_CONF="${CULL_DEPLOY_CONF:-/root/.cull-deploy.conf}"
if [ -f "$DEPLOY_CONF" ]; then
. "$DEPLOY_CONF"
echo "[cull] deploy config: $DEPLOY_CONF"
fi
REPO="${REPO:-youruser/image-cull}"
BRANCH="${BRANCH:-main}"
APP_DIR="${APP_DIR:-/home/youruser/image-cull}"
# Where the GitHub token lives (optional; only needed for a private repo).
# $HOME is empty in some NAS shells (su, cron, a bare `sh`), which silently
# turns "$HOME/.cull-token" into "/.cull-token" — so we search a list of
# likely spots instead of trusting one path. Override with TOKEN_FILE, or set
# TOKEN_CANDIDATES in the deploy conf.
TOKEN_CANDIDATES="${TOKEN_CANDIDATES:-${HOME:+$HOME/.cull-token} /root/.cull-token}"
RAW_DIR="${RAW_DIR:-/volume1/yourshare/pictures}"
STATE_DIR="${STATE_DIR:-/volume1/yourshare/.cull}"
STARRED_DIR="${STARRED_DIR:-/volume1/yourshare/starred}"
PORT="${PORT:-8080}"
# The image runs as a non-root user by default (uid 1000). NAS volumes are
# often root-owned (ls -n shows uid/gid 0), so the default runs the container
# as root to match. If you chown the volumes to a dedicated uid, set this to
# "uid:gid" (e.g. "1026:100") in the deploy conf instead.
CONTAINER_USER="${CONTAINER_USER:-0:0}"
# Bake onnxruntime/numpy into the image for the WD auto-tagger (~300 MB
# bigger image). The model itself lives in the state dir; see
# scripts/download_wd_model.sh and the README's auto-tagger section.
INSTALL_TAGGER="${INSTALL_TAGGER:-true}"
# --------------------------------------------------------------------------
# Refuse to run against the placeholders rather than deploying to a bogus
# path and leaving the operator to work out why nothing changed.
if [ "$APP_DIR" = "/home/youruser/image-cull" ]; then
echo "[cull] APP_DIR is still the placeholder — no deploy config in effect."
echo " Expected: $DEPLOY_CONF (see the comment block in this script)"
echo " or set CULL_DEPLOY_CONF=/path/to/conf."
exit 1
fi
# Honor an explicit TOKEN_FILE from the environment; otherwise probe the list.
if [ -n "${TOKEN_FILE:-}" ] && [ -f "$TOKEN_FILE" ]; then
:
else
TOKEN_FILE=""
for _cand in $TOKEN_CANDIDATES; do
if [ -f "$_cand" ]; then TOKEN_FILE="$_cand"; break; fi
done
fi
# A token is optional: public repos download fine without one. Missing token
# on a PRIVATE repo surfaces as a 404 from the API, so say so up front.
if [ -n "$TOKEN_FILE" ]; then
echo "[cull] using token file: $TOKEN_FILE"
TOKEN="$(cat "$TOKEN_FILE")"
else
echo "[cull] no token file found (looked in: $TOKEN_CANDIDATES, HOME='${HOME:-}')."
echo " Continuing unauthenticated — fine for a public repo. If $REPO is"
echo " private this fails with 404; create a read token, then:"
echo " echo YOUR_TOKEN > /root/.cull-token && chmod 600 /root/.cull-token"
TOKEN=""
fi
DL="https://api.github.com/repos/$REPO/tarball/$BRANCH"
TMP="$(mktemp -d)"
# Clean up the temp dir and our re-exec copy ($0 is the /tmp copy here).
trap 'rm -rf "$TMP"; rm -f "$0"' EXIT
echo "[cull] downloading $BRANCH ..."
if command -v curl >/dev/null 2>&1; then
if [ -n "$TOKEN" ]; then
curl -fSL -H "Authorization: Bearer $TOKEN" "$DL" -o "$TMP/cull.tar.gz"
else
curl -fSL "$DL" -o "$TMP/cull.tar.gz"
fi
else
if [ -n "$TOKEN" ]; then
wget -q --header="Authorization: Bearer $TOKEN" "$DL" -O "$TMP/cull.tar.gz"
else
wget -q "$DL" -O "$TMP/cull.tar.gz"
fi
fi
echo "[cull] extracting (config.yaml is preserved) ..."
mkdir -p "$APP_DIR"
tar xzf "$TMP/cull.tar.gz" -C "$TMP"
SRC="$(find "$TMP" -mindepth 1 -maxdepth 1 -type d | head -n 1)"
# Sync code into the app dir, removing files deleted upstream so stale
# modules can't linger across updates. config.yaml isn't in the tarball and
# is explicitly protected either way.
if command -v rsync >/dev/null 2>&1; then
rsync -a --delete --exclude=config.yaml "$SRC"/ "$APP_DIR"/
else
# No rsync on this box: stash config, replace the tree, put it back.
if [ -f "$APP_DIR/config.yaml" ]; then
cp "$APP_DIR/config.yaml" "$TMP/config.yaml.keep"
fi
rm -rf "$APP_DIR"
mkdir -p "$APP_DIR"
cp -a "$SRC"/. "$APP_DIR"/
if [ -f "$TMP/config.yaml.keep" ]; then
cp "$TMP/config.yaml.keep" "$APP_DIR/config.yaml"
fi
fi
if [ ! -f "$APP_DIR/config.yaml" ]; then
# Without a real file here, the bind mount below would create a DIRECTORY
# named config.yaml inside the container and break startup.
echo "[cull] no config.yaml yet — seeding from config.example.yaml, edit it!"
cp "$APP_DIR/config.example.yaml" "$APP_DIR/config.yaml"
fi
echo "[cull] building image ..."
docker build -t cull:latest \
--build-arg "INSTALL_TAGGER=$INSTALL_TAGGER" \
"$APP_DIR"
echo "[cull] restarting container ..."
docker stop cull 2>/dev/null || true
docker rm cull 2>/dev/null || true
# Same env the docker-compose path sets, so the two deploys behave alike;
# config.yaml can still override.
docker run -d --name cull --restart unless-stopped -p "$PORT:8080" \
--user "$CONTAINER_USER" \
-e CULL_CONFIG=/app/config.yaml \
-e CULL_RAW_DIR=/data/output \
-e CULL_STORE_BACKEND=indexed \
-e CULL_INDEX_PATH=/data/cull/index.db \
-e CULL_MANIFEST_PATH=/data/cull/manifest.json \
-e CULL_ACTIONLOG_PATH=/data/cull/actionlog.jsonl \
-e CULL_THUMB_CACHE_DIR=/data/cull/thumbs \
-e CULL_STARRED_DIR=/data/starred \
-e CULL_HOST=0.0.0.0 \
-e CULL_PORT=8080 \
-v "$APP_DIR/config.yaml:/app/config.yaml:ro" \
-v "$RAW_DIR:/data/output" \
-v "$STATE_DIR:/data/cull" \
-v "$STARRED_DIR:/data/starred" \
cull:latest
echo "[cull] done. Index persists in $STATE_DIR (no re-scan)."
echo "[cull] logs: docker logs -f cull"