lvcq commited on
Commit
cb45783
·
1 Parent(s): aa1cc47

fix: Fix the endless looping problem

Browse files
Dockerfile CHANGED
@@ -1,19 +1,18 @@
1
  FROM alpine:3.21
2
 
3
  ENV TZ=Asia/Shanghai
 
4
  ENV RUNTIME_DIR=/tmp/runtime
5
  ENV SUPERVISOR_CONF=/etc/supervisord.conf
6
  ENV SUPERVISOR_CONF_TEMPLATE=/etc/supervisord.conf.template
7
  ENV STOP_WAIT_SECS=60
8
 
9
- RUN apk add --no-cache ca-certificates curl supervisor tzdata \
10
  && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
11
  && echo $TZ > /etc/timezone
12
 
13
  COPY entrypoint.sh /usr/local/bin/entrypoint.sh
14
- COPY scripts/release-common.sh /usr/local/bin/release-common.sh
15
- COPY scripts/update-loop.sh /usr/local/bin/update-loop.sh
16
  COPY supervisord.conf /etc/supervisord.conf.template
17
- RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/release-common.sh /usr/local/bin/update-loop.sh
18
 
19
  ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
 
1
  FROM alpine:3.21
2
 
3
  ENV TZ=Asia/Shanghai
4
+ ENV APP_BINARY_PATH=/app/app
5
  ENV RUNTIME_DIR=/tmp/runtime
6
  ENV SUPERVISOR_CONF=/etc/supervisord.conf
7
  ENV SUPERVISOR_CONF_TEMPLATE=/etc/supervisord.conf.template
8
  ENV STOP_WAIT_SECS=60
9
 
10
+ RUN apk add --no-cache ca-certificates supervisor tzdata \
11
  && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
12
  && echo $TZ > /etc/timezone
13
 
14
  COPY entrypoint.sh /usr/local/bin/entrypoint.sh
 
 
15
  COPY supervisord.conf /etc/supervisord.conf.template
16
+ RUN chmod +x /usr/local/bin/entrypoint.sh
17
 
18
  ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
README.md CHANGED
@@ -8,4 +8,11 @@ pinned: false
8
  app_port: 8317
9
  ---
10
 
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
8
  app_port: 8317
9
  ---
10
 
11
+ 这个镜像不再包含任何自动更新逻辑。
12
+
13
+ 运行前需要显式提供应用二进制,默认路径是 `APP_BINARY_PATH=/app/app`,也可以通过环境变量覆盖。
14
+
15
+ 最简单的用法是基于这个镜像继续构建,并把你的可执行文件复制到 `/app/app`。
16
+
17
+ Hugging Face Spaces 配置参考:
18
+ https://huggingface.co/docs/hub/spaces-config-reference
entrypoint.sh CHANGED
@@ -1,15 +1,15 @@
1
  #!/bin/sh
2
  set -eu
3
 
4
- : "${RELEASE_COMMON_SH:=/usr/local/bin/release-common.sh}"
5
  : "${SUPERVISORD_BIN:=/usr/bin/supervisord}"
6
  : "${SUPERVISOR_CONF_TEMPLATE:=/etc/supervisord.conf.template}"
 
 
 
 
7
  : "${OPEN_FILE_LIMIT:=65535}"
8
 
9
- . "$RELEASE_COMMON_SH"
10
-
11
  export RUNTIME_DIR
12
- export SUPERVISOR_CONF
13
 
14
  shell_quote() {
15
  printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\"'\"'/g")"
@@ -22,11 +22,9 @@ escape_sed_replacement() {
22
  write_supervisord_conf() {
23
  mkdir -p "$(dirname "$SUPERVISOR_CONF")"
24
  app_program_name=$(escape_sed_replacement "$SUPERVISOR_PROGRAM_NAME")
25
- updater_program_name=$(escape_sed_replacement "$SUPERVISOR_UPDATER_PROGRAM_NAME")
26
 
27
  sed \
28
  -e "s/__APP_PROGRAM__/$app_program_name/g" \
29
- -e "s/__UPDATER_PROGRAM__/$updater_program_name/g" \
30
  "$SUPERVISOR_CONF_TEMPLATE" > "$SUPERVISOR_CONF"
31
  }
32
 
@@ -36,7 +34,7 @@ write_run_app_script() {
36
  {
37
  printf '#!/bin/sh\n'
38
  printf 'set -eu\n'
39
- printf 'exec "%s"' "$(current_binary_path)"
40
  for arg in "$@"; do
41
  printf ' %s' "$(shell_quote "$arg")"
42
  done
@@ -48,13 +46,13 @@ write_run_app_script() {
48
 
49
  prepare_runtime_environment() {
50
  ulimit -n "$OPEN_FILE_LIMIT"
51
- ensure_runtime_dirs
52
  rm -f "$RUNTIME_DIR/supervisor.sock" "$RUNTIME_DIR/supervisord.pid"
53
  }
54
 
55
- bootstrap_release_or_exit() {
56
- if ! ensure_initial_release; then
57
- echo "错误: 初次启动时无法准备可运行版本" >&2
58
  exit 1
59
  fi
60
  }
@@ -65,8 +63,8 @@ start_supervisord() {
65
 
66
  main() {
67
  prepare_runtime_environment
 
68
  write_supervisord_conf
69
- bootstrap_release_or_exit
70
  write_run_app_script "$@"
71
  start_supervisord
72
  }
 
1
  #!/bin/sh
2
  set -eu
3
 
 
4
  : "${SUPERVISORD_BIN:=/usr/bin/supervisord}"
5
  : "${SUPERVISOR_CONF_TEMPLATE:=/etc/supervisord.conf.template}"
6
+ : "${APP_BINARY_PATH:=/app/app}"
7
+ : "${RUNTIME_DIR:=/tmp/runtime}"
8
+ : "${SUPERVISOR_CONF:=/etc/supervisord.conf}"
9
+ : "${SUPERVISOR_PROGRAM_NAME:=app}"
10
  : "${OPEN_FILE_LIMIT:=65535}"
11
 
 
 
12
  export RUNTIME_DIR
 
13
 
14
  shell_quote() {
15
  printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\"'\"'/g")"
 
22
  write_supervisord_conf() {
23
  mkdir -p "$(dirname "$SUPERVISOR_CONF")"
24
  app_program_name=$(escape_sed_replacement "$SUPERVISOR_PROGRAM_NAME")
 
25
 
26
  sed \
27
  -e "s/__APP_PROGRAM__/$app_program_name/g" \
 
28
  "$SUPERVISOR_CONF_TEMPLATE" > "$SUPERVISOR_CONF"
29
  }
30
 
 
34
  {
35
  printf '#!/bin/sh\n'
36
  printf 'set -eu\n'
37
+ printf 'exec "%s"' "$APP_BINARY_PATH"
38
  for arg in "$@"; do
39
  printf ' %s' "$(shell_quote "$arg")"
40
  done
 
46
 
47
  prepare_runtime_environment() {
48
  ulimit -n "$OPEN_FILE_LIMIT"
49
+ mkdir -p "$RUNTIME_DIR"
50
  rm -f "$RUNTIME_DIR/supervisor.sock" "$RUNTIME_DIR/supervisord.pid"
51
  }
52
 
53
+ validate_app_binary_or_exit() {
54
+ if [ ! -x "$APP_BINARY_PATH" ]; then
55
+ echo "错误: APP_BINARY_PATH 指向的文件不存在或不可执行: $APP_BINARY_PATH" >&2
56
  exit 1
57
  fi
58
  }
 
63
 
64
  main() {
65
  prepare_runtime_environment
66
+ validate_app_binary_or_exit
67
  write_supervisord_conf
 
68
  write_run_app_script "$@"
69
  start_supervisord
70
  }
release-common.sh DELETED
@@ -1,240 +0,0 @@
1
- #!/bin/sh
2
-
3
- : "${REPO_API_URL:=https://api.github.com/repos/caidaoli/CLIProxyAPI/releases/latest}"
4
- : "${RUNTIME_DIR:=/tmp/runtime}"
5
- : "${RELEASES_DIR:=$RUNTIME_DIR/releases}"
6
- : "${CURRENT_LINK:=$RUNTIME_DIR/current}"
7
- : "${CURRENT_TAG_FILE:=$RUNTIME_DIR/current.tag}"
8
- : "${DOWNLOADS_DIR:=$RUNTIME_DIR/downloads}"
9
- : "${SUPERVISOR_CONF:=/etc/supervisord.conf}"
10
- : "${SUPERVISOR_PROGRAM_NAME:=app}"
11
- : "${SUPERVISOR_UPDATER_PROGRAM_NAME:=${SUPERVISOR_PROGRAM_NAME}-updater}"
12
- : "${CURRENT_BINARY_NAME:=app}"
13
- : "${APP_BINARY_NAMES:=}"
14
-
15
- log() {
16
- timestamp=$(date '+%Y-%m-%d %H:%M:%S %z')
17
- printf '[%s] %s\n' "$timestamp" "$*" >&2
18
- }
19
-
20
- tag_to_dir_name() {
21
- printf '%s\n' "$1" | tr '/:' '__'
22
- }
23
-
24
- release_dir_for_tag() {
25
- printf '%s/%s\n' "$RELEASES_DIR" "$(tag_to_dir_name "$1")"
26
- }
27
-
28
- ensure_runtime_dirs() {
29
- mkdir -p "$RUNTIME_DIR" "$RELEASES_DIR" "$DOWNLOADS_DIR"
30
- }
31
-
32
- current_tag() {
33
- if [ -f "$CURRENT_TAG_FILE" ]; then
34
- tr -d '\n' < "$CURRENT_TAG_FILE"
35
- fi
36
- }
37
-
38
- current_binary_path() {
39
- printf '%s/%s\n' "$CURRENT_LINK" "$CURRENT_BINARY_NAME"
40
- }
41
-
42
- fetch_latest_release_info() {
43
- response=$(curl -fsSL "$REPO_API_URL") || return 1
44
-
45
- tag_name=$(
46
- printf '%s\n' "$response" \
47
- | grep -Eo '"tag_name"[[:space:]]*:[[:space:]]*"[^"]+"' \
48
- | head -n 1 \
49
- | cut -d '"' -f 4 \
50
- || true
51
- )
52
- asset_url=$(
53
- printf '%s\n' "$response" \
54
- | grep -Eo '"browser_download_url"[[:space:]]*:[[:space:]]*"[^"]*"' \
55
- | cut -d '"' -f 4 \
56
- | grep -E '/[^/]*linux[-_]amd64(\.tar\.gz)?$' \
57
- | head -n 1 \
58
- || true
59
- )
60
-
61
- if [ -z "$tag_name" ] || [ -z "$asset_url" ]; then
62
- return 1
63
- fi
64
-
65
- printf '%s|%s\n' "$tag_name" "$asset_url"
66
- }
67
-
68
- load_latest_release() {
69
- release_info=$(fetch_latest_release_info) || return 1
70
- LATEST_TAG=${release_info%%|*}
71
- LATEST_ASSET_URL=${release_info#*|}
72
- }
73
-
74
- find_release_binary() {
75
- release_dir=$1
76
-
77
- for name in $APP_BINARY_NAMES; do
78
- if [ -f "$release_dir/$name" ]; then
79
- printf '%s\n' "$release_dir/$name"
80
- return 0
81
- fi
82
- done
83
-
84
- for name in $APP_BINARY_NAMES; do
85
- binary_path=$(find "$release_dir" -maxdepth 3 -type f -name "$name" | head -n 1)
86
- if [ -n "$binary_path" ]; then
87
- printf '%s\n' "$binary_path"
88
- return 0
89
- fi
90
- done
91
-
92
- file_list=$(find "$release_dir" -maxdepth 3 -type f ! -name '._*' ! -path '*/__MACOSX/*' | sort)
93
- first_file=$(printf '%s\n' "$file_list" | sed -n '1p')
94
- second_file=$(printf '%s\n' "$file_list" | sed -n '2p')
95
- if [ -n "$first_file" ] && [ -z "$second_file" ]; then
96
- printf '%s\n' "$first_file"
97
- return 0
98
- fi
99
-
100
- return 1
101
- }
102
-
103
- activate_release() {
104
- tag_name=$1
105
- release_dir=$2
106
-
107
- rm -f "$CURRENT_LINK"
108
- ln -s "$release_dir" "$CURRENT_LINK"
109
- printf '%s\n' "$tag_name" > "$CURRENT_TAG_FILE"
110
- }
111
-
112
- extract_release_binary() {
113
- source_dir=$1
114
- target_path=$2
115
- binary_path=$(find_release_binary "$source_dir" || true)
116
-
117
- if [ -z "$binary_path" ]; then
118
- return 1
119
- fi
120
-
121
- if [ "$binary_path" != "$target_path" ]; then
122
- cp "$binary_path" "$target_path"
123
- fi
124
- chmod +x "$target_path"
125
- }
126
-
127
- cleanup_workspace() {
128
- workspace=$1
129
- if [ -n "$workspace" ] && [ -d "$workspace" ]; then
130
- rm -rf "$workspace"
131
- fi
132
- }
133
-
134
- install_release() {
135
- tag_name=$1
136
- asset_url=$2
137
-
138
- ensure_runtime_dirs
139
- release_dir=$(release_dir_for_tag "$tag_name")
140
- release_binary="$release_dir/$CURRENT_BINARY_NAME"
141
-
142
- if [ -x "$release_binary" ]; then
143
- activate_release "$tag_name" "$release_dir"
144
- return 0
145
- fi
146
-
147
- workspace=$(mktemp -d "$RUNTIME_DIR/install.XXXXXX") || return 1
148
- download_name=$(basename "$asset_url")
149
- if [ -z "$download_name" ] || [ "$download_name" = "/" ] || [ "$download_name" = "." ]; then
150
- download_name="release.asset"
151
- fi
152
- download_path="$DOWNLOADS_DIR/$download_name"
153
- stage_dir="$workspace/stage"
154
-
155
- rm -f "$download_path" || {
156
- cleanup_workspace "$workspace"
157
- return 1
158
- }
159
- mkdir -p "$stage_dir" || {
160
- cleanup_workspace "$workspace"
161
- return 1
162
- }
163
- curl -fsSL "$asset_url" -o "$download_path" || {
164
- cleanup_workspace "$workspace"
165
- return 1
166
- }
167
-
168
- case "$download_path" in
169
- *.tar.gz)
170
- tar -xzf "$download_path" -C "$stage_dir" || {
171
- cleanup_workspace "$workspace"
172
- return 1
173
- }
174
- extract_release_binary "$stage_dir" "$stage_dir/$CURRENT_BINARY_NAME" || {
175
- cleanup_workspace "$workspace"
176
- return 1
177
- }
178
- ;;
179
- *)
180
- cp "$download_path" "$stage_dir/$CURRENT_BINARY_NAME" || {
181
- cleanup_workspace "$workspace"
182
- return 1
183
- }
184
- chmod +x "$stage_dir/$CURRENT_BINARY_NAME" || {
185
- cleanup_workspace "$workspace"
186
- return 1
187
- }
188
- ;;
189
- esac
190
-
191
- rm -rf "$release_dir" || {
192
- cleanup_workspace "$workspace"
193
- return 1
194
- }
195
- mv "$stage_dir" "$release_dir" || {
196
- cleanup_workspace "$workspace"
197
- return 1
198
- }
199
- cleanup_workspace "$workspace"
200
-
201
- activate_release "$tag_name" "$release_dir"
202
- }
203
-
204
- ensure_initial_release() {
205
- if load_latest_release; then
206
- if install_release "$LATEST_TAG" "$LATEST_ASSET_URL"; then
207
- return 0
208
- fi
209
- log "警告: 安装最新版本失败,尝试使用已有版本继续启动"
210
- fi
211
-
212
- [ -x "$(current_binary_path)" ]
213
- }
214
-
215
- restart_managed_service() {
216
- supervisorctl -c "$SUPERVISOR_CONF" restart "$SUPERVISOR_PROGRAM_NAME"
217
- }
218
-
219
- update_if_needed() {
220
- load_latest_release || {
221
- log "检查最新版本失败"
222
- return 1
223
- }
224
-
225
- installed_tag=$(current_tag)
226
- if [ "$LATEST_TAG" = "$installed_tag" ]; then
227
- log "当前已是最新版本: $LATEST_TAG"
228
- return 0
229
- fi
230
-
231
- log "发现新版本: ${installed_tag:-<none>} -> $LATEST_TAG"
232
- install_release "$LATEST_TAG" "$LATEST_ASSET_URL" || {
233
- log "安装新版本失败: $LATEST_TAG"
234
- return 1
235
- }
236
-
237
- if [ -n "$installed_tag" ]; then
238
- restart_managed_service
239
- fi
240
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/release-common.sh DELETED
@@ -1,240 +0,0 @@
1
- #!/bin/sh
2
-
3
- : "${REPO_API_URL:=https://api.github.com/repos/caidaoli/CLIProxyAPI/releases/latest}"
4
- : "${RUNTIME_DIR:=/tmp/runtime}"
5
- : "${RELEASES_DIR:=$RUNTIME_DIR/releases}"
6
- : "${CURRENT_LINK:=$RUNTIME_DIR/current}"
7
- : "${CURRENT_TAG_FILE:=$RUNTIME_DIR/current.tag}"
8
- : "${DOWNLOADS_DIR:=$RUNTIME_DIR/downloads}"
9
- : "${SUPERVISOR_CONF:=/etc/supervisord.conf}"
10
- : "${SUPERVISOR_PROGRAM_NAME:=app}"
11
- : "${SUPERVISOR_UPDATER_PROGRAM_NAME:=${SUPERVISOR_PROGRAM_NAME}-updater}"
12
- : "${CURRENT_BINARY_NAME:=app}"
13
- : "${APP_BINARY_NAMES:=}"
14
-
15
- log() {
16
- timestamp=$(date '+%Y-%m-%d %H:%M:%S %z')
17
- printf '[%s] %s\n' "$timestamp" "$*" >&2
18
- }
19
-
20
- tag_to_dir_name() {
21
- printf '%s\n' "$1" | tr '/:' '__'
22
- }
23
-
24
- release_dir_for_tag() {
25
- printf '%s/%s\n' "$RELEASES_DIR" "$(tag_to_dir_name "$1")"
26
- }
27
-
28
- ensure_runtime_dirs() {
29
- mkdir -p "$RUNTIME_DIR" "$RELEASES_DIR" "$DOWNLOADS_DIR"
30
- }
31
-
32
- current_tag() {
33
- if [ -f "$CURRENT_TAG_FILE" ]; then
34
- tr -d '\n' < "$CURRENT_TAG_FILE"
35
- fi
36
- }
37
-
38
- current_binary_path() {
39
- printf '%s/%s\n' "$CURRENT_LINK" "$CURRENT_BINARY_NAME"
40
- }
41
-
42
- fetch_latest_release_info() {
43
- response=$(curl -fsSL "$REPO_API_URL") || return 1
44
-
45
- tag_name=$(
46
- printf '%s\n' "$response" \
47
- | grep -Eo '"tag_name"[[:space:]]*:[[:space:]]*"[^"]+"' \
48
- | head -n 1 \
49
- | cut -d '"' -f 4 \
50
- || true
51
- )
52
- asset_url=$(
53
- printf '%s\n' "$response" \
54
- | grep -Eo '"browser_download_url"[[:space:]]*:[[:space:]]*"[^"]*"' \
55
- | cut -d '"' -f 4 \
56
- | grep -E '/[^/]*linux[-_]amd64(\.tar\.gz)?$' \
57
- | head -n 1 \
58
- || true
59
- )
60
-
61
- if [ -z "$tag_name" ] || [ -z "$asset_url" ]; then
62
- return 1
63
- fi
64
-
65
- printf '%s|%s\n' "$tag_name" "$asset_url"
66
- }
67
-
68
- load_latest_release() {
69
- release_info=$(fetch_latest_release_info) || return 1
70
- LATEST_TAG=${release_info%%|*}
71
- LATEST_ASSET_URL=${release_info#*|}
72
- }
73
-
74
- find_release_binary() {
75
- release_dir=$1
76
-
77
- for name in $APP_BINARY_NAMES; do
78
- if [ -f "$release_dir/$name" ]; then
79
- printf '%s\n' "$release_dir/$name"
80
- return 0
81
- fi
82
- done
83
-
84
- for name in $APP_BINARY_NAMES; do
85
- binary_path=$(find "$release_dir" -maxdepth 3 -type f -name "$name" | head -n 1)
86
- if [ -n "$binary_path" ]; then
87
- printf '%s\n' "$binary_path"
88
- return 0
89
- fi
90
- done
91
-
92
- file_list=$(find "$release_dir" -maxdepth 3 -type f ! -name '._*' ! -path '*/__MACOSX/*' | sort)
93
- first_file=$(printf '%s\n' "$file_list" | sed -n '1p')
94
- second_file=$(printf '%s\n' "$file_list" | sed -n '2p')
95
- if [ -n "$first_file" ] && [ -z "$second_file" ]; then
96
- printf '%s\n' "$first_file"
97
- return 0
98
- fi
99
-
100
- return 1
101
- }
102
-
103
- activate_release() {
104
- tag_name=$1
105
- release_dir=$2
106
-
107
- rm -f "$CURRENT_LINK"
108
- ln -s "$release_dir" "$CURRENT_LINK"
109
- printf '%s\n' "$tag_name" > "$CURRENT_TAG_FILE"
110
- }
111
-
112
- extract_release_binary() {
113
- source_dir=$1
114
- target_path=$2
115
- binary_path=$(find_release_binary "$source_dir" || true)
116
-
117
- if [ -z "$binary_path" ]; then
118
- return 1
119
- fi
120
-
121
- if [ "$binary_path" != "$target_path" ]; then
122
- cp "$binary_path" "$target_path"
123
- fi
124
- chmod +x "$target_path"
125
- }
126
-
127
- cleanup_workspace() {
128
- workspace=$1
129
- if [ -n "$workspace" ] && [ -d "$workspace" ]; then
130
- rm -rf "$workspace"
131
- fi
132
- }
133
-
134
- install_release() {
135
- tag_name=$1
136
- asset_url=$2
137
-
138
- ensure_runtime_dirs
139
- release_dir=$(release_dir_for_tag "$tag_name")
140
- release_binary="$release_dir/$CURRENT_BINARY_NAME"
141
-
142
- if [ -x "$release_binary" ]; then
143
- activate_release "$tag_name" "$release_dir"
144
- return 0
145
- fi
146
-
147
- workspace=$(mktemp -d "$RUNTIME_DIR/install.XXXXXX") || return 1
148
- download_name=$(basename "$asset_url")
149
- if [ -z "$download_name" ] || [ "$download_name" = "/" ] || [ "$download_name" = "." ]; then
150
- download_name="release.asset"
151
- fi
152
- download_path="$DOWNLOADS_DIR/$download_name"
153
- stage_dir="$workspace/stage"
154
-
155
- rm -f "$download_path" || {
156
- cleanup_workspace "$workspace"
157
- return 1
158
- }
159
- mkdir -p "$stage_dir" || {
160
- cleanup_workspace "$workspace"
161
- return 1
162
- }
163
- curl -fsSL "$asset_url" -o "$download_path" || {
164
- cleanup_workspace "$workspace"
165
- return 1
166
- }
167
-
168
- case "$download_path" in
169
- *.tar.gz)
170
- tar -xzf "$download_path" -C "$stage_dir" || {
171
- cleanup_workspace "$workspace"
172
- return 1
173
- }
174
- extract_release_binary "$stage_dir" "$stage_dir/$CURRENT_BINARY_NAME" || {
175
- cleanup_workspace "$workspace"
176
- return 1
177
- }
178
- ;;
179
- *)
180
- cp "$download_path" "$stage_dir/$CURRENT_BINARY_NAME" || {
181
- cleanup_workspace "$workspace"
182
- return 1
183
- }
184
- chmod +x "$stage_dir/$CURRENT_BINARY_NAME" || {
185
- cleanup_workspace "$workspace"
186
- return 1
187
- }
188
- ;;
189
- esac
190
-
191
- rm -rf "$release_dir" || {
192
- cleanup_workspace "$workspace"
193
- return 1
194
- }
195
- mv "$stage_dir" "$release_dir" || {
196
- cleanup_workspace "$workspace"
197
- return 1
198
- }
199
- cleanup_workspace "$workspace"
200
-
201
- activate_release "$tag_name" "$release_dir"
202
- }
203
-
204
- ensure_initial_release() {
205
- if load_latest_release; then
206
- if install_release "$LATEST_TAG" "$LATEST_ASSET_URL"; then
207
- return 0
208
- fi
209
- log "警告: 安装最新版本失败,尝试使用已有版本继续启动"
210
- fi
211
-
212
- [ -x "$(current_binary_path)" ]
213
- }
214
-
215
- restart_managed_service() {
216
- supervisorctl -c "$SUPERVISOR_CONF" restart "$SUPERVISOR_PROGRAM_NAME"
217
- }
218
-
219
- update_if_needed() {
220
- load_latest_release || {
221
- log "检查最新版本失败"
222
- return 1
223
- }
224
-
225
- installed_tag=$(current_tag)
226
- if [ "$LATEST_TAG" = "$installed_tag" ]; then
227
- log "当前已是最新版本: $LATEST_TAG"
228
- return 0
229
- fi
230
-
231
- log "发现新版本: ${installed_tag:-<none>} -> $LATEST_TAG"
232
- install_release "$LATEST_TAG" "$LATEST_ASSET_URL" || {
233
- log "安装新版本失败: $LATEST_TAG"
234
- return 1
235
- }
236
-
237
- if [ -n "$installed_tag" ]; then
238
- restart_managed_service
239
- fi
240
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/update-loop.sh DELETED
@@ -1,15 +0,0 @@
1
- #!/bin/sh
2
- set -eu
3
-
4
- : "${UPDATE_INTERVAL_SECONDS:=3600}"
5
- : "${RELEASE_COMMON_SH:=/usr/local/bin/release-common.sh}"
6
-
7
- . "$RELEASE_COMMON_SH"
8
-
9
- while true; do
10
- sleep "$UPDATE_INTERVAL_SECONDS"
11
- log "开始定时版本检查"
12
- if ! update_if_needed; then
13
- log "警告: 自动更新检查失败,继续运行当前版本"
14
- fi
15
- done
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
supervisord.conf CHANGED
@@ -27,15 +27,3 @@ stdout_logfile=/dev/fd/1
27
  stdout_logfile_maxbytes=0
28
  stderr_logfile=/dev/fd/2
29
  stderr_logfile_maxbytes=0
30
-
31
- [program:__UPDATER_PROGRAM__]
32
- command=/usr/local/bin/update-loop.sh
33
- autostart=true
34
- autorestart=true
35
- startsecs=0
36
- stopasgroup=true
37
- killasgroup=true
38
- stdout_logfile=/dev/fd/1
39
- stdout_logfile_maxbytes=0
40
- stderr_logfile=/dev/fd/2
41
- stderr_logfile_maxbytes=0
 
27
  stdout_logfile_maxbytes=0
28
  stderr_logfile=/dev/fd/2
29
  stderr_logfile_maxbytes=0
 
 
 
 
 
 
 
 
 
 
 
 
tests/no-auto-update.sh ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ REPO_ROOT=$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)
5
+ TMPDIR=$(mktemp -d)
6
+ trap 'rm -rf "$TMPDIR"' EXIT
7
+
8
+ RUNTIME_DIR="$TMPDIR/runtime"
9
+ SUPERVISOR_CONF="$TMPDIR/supervisord.conf"
10
+ APP_BINARY_PATH="$TMPDIR/app"
11
+ STUB_RELEASE_COMMON="$TMPDIR/release-common.sh"
12
+ TRUE_BIN=$(command -v true)
13
+
14
+ cat > "$APP_BINARY_PATH" <<'EOF'
15
+ #!/bin/sh
16
+ exit 0
17
+ EOF
18
+ chmod +x "$APP_BINARY_PATH"
19
+
20
+ cat > "$STUB_RELEASE_COMMON" <<'EOF'
21
+ #!/bin/sh
22
+
23
+ ensure_runtime_dirs() {
24
+ mkdir -p "$RUNTIME_DIR"
25
+ }
26
+
27
+ current_binary_path() {
28
+ printf '%s\n' "$APP_BINARY_PATH"
29
+ }
30
+
31
+ ensure_initial_release() {
32
+ mkdir -p "$RUNTIME_DIR"
33
+ : > "$RUNTIME_DIR/bootstrap-called"
34
+ return 0
35
+ }
36
+ EOF
37
+ chmod +x "$STUB_RELEASE_COMMON"
38
+
39
+ RELEASE_COMMON_SH="$STUB_RELEASE_COMMON" \
40
+ SUPERVISORD_BIN="$TRUE_BIN" \
41
+ SUPERVISOR_CONF_TEMPLATE="$REPO_ROOT/supervisord.conf" \
42
+ SUPERVISOR_CONF="$SUPERVISOR_CONF" \
43
+ RUNTIME_DIR="$RUNTIME_DIR" \
44
+ APP_BINARY_PATH="$APP_BINARY_PATH" \
45
+ SUPERVISOR_PROGRAM_NAME=app \
46
+ SUPERVISOR_UPDATER_PROGRAM_NAME=app-updater \
47
+ sh "$REPO_ROOT/entrypoint.sh" --probe
48
+
49
+ if [ -e "$RUNTIME_DIR/bootstrap-called" ]; then
50
+ echo "失败: entrypoint 仍然触发了启动时自动拉取逻辑" >&2
51
+ exit 1
52
+ fi
53
+
54
+ if grep -Eq '^\[program:.*-updater\]$' "$SUPERVISOR_CONF"; then
55
+ echo "失败: supervisord 配置仍然包含 updater 进程" >&2
56
+ exit 1
57
+ fi
58
+
59
+ if ! grep -F "exec \"$APP_BINARY_PATH\" '--probe'" "$RUNTIME_DIR/run-app.sh" >/dev/null; then
60
+ echo "失败: run-app.sh 没有直接执行显式提供的二进制" >&2
61
+ exit 1
62
+ fi
update-loop.sh DELETED
@@ -1,15 +0,0 @@
1
- #!/bin/sh
2
- set -eu
3
-
4
- : "${UPDATE_INTERVAL_SECONDS:=3600}"
5
- : "${RELEASE_COMMON_SH:=/usr/local/bin/release-common.sh}"
6
-
7
- . "$RELEASE_COMMON_SH"
8
-
9
- while true; do
10
- sleep "$UPDATE_INTERVAL_SECONDS"
11
- log "开始定时版本检查"
12
- if ! update_if_needed; then
13
- log "警告: 自动更新检查失败,继续运行当前版本"
14
- fi
15
- done