返回 DeepSeek-TUI-2026
publish-crates.sh
根目录 / scripts / release / publish-crates.sh
1 #!/usr/bin/env bash
2 set -euo pipefail
3
4 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5 # shellcheck source=scripts/release/crates.sh
6 source "${script_dir}/crates.sh"
7
8 mode="${1:-dry-run}"
9 case "${mode}" in
10 dry-run|publish) ;;
11 *)
12 echo "usage: $0 [dry-run|publish]" >&2
13 exit 1
14 ;;
15 esac
16
17 packages=("${release_crates[@]}")
18
19 workspace_version=""
20 workspace_deepseek_packages=()
21 workspace_package_dep_flags=()
22
23 while IFS=$'\t' read -r kind name value; do
24 case "${kind}" in
25 version)
26 workspace_version="${name}"
27 ;;
28 crate)
29 workspace_deepseek_packages+=("${name}")
30 workspace_package_dep_flags+=("${value}")
31 ;;
32 esac
33 done < <(
34 python3 - <<'PY'
35 import json
36 import subprocess
37
38 metadata = json.loads(
39 subprocess.check_output(["cargo", "metadata", "--format-version", "1", "--no-deps"])
40 )
41 workspace_members = set(metadata["workspace_members"])
42 workspace_packages = [
43 pkg for pkg in metadata["packages"] if pkg["id"] in workspace_members
44 ]
45 workspace_by_name = {pkg["name"]: pkg for pkg in workspace_packages}
46
47 versions = sorted({pkg["version"] for pkg in workspace_packages})
48 if not versions:
49 raise SystemExit("workspace has no packages")
50 if len(versions) != 1:
51 raise SystemExit(f"workspace packages have mixed versions: {', '.join(versions)}")
52 print(f"version\t{versions[0]}\t")
53
54 for pkg in sorted(workspace_packages, key=lambda item: item["name"]):
55 if not pkg["name"].startswith("deepseek-"):
56 continue
57 has_workspace_dep = any(
58 dep.get("path") and dep["name"] in workspace_by_name
59 for dep in pkg["dependencies"]
60 )
61 print(f"crate\t{pkg['name']}\t{1 if has_workspace_dep else 0}")
62 PY
63 )
64
65 if [[ -z "${workspace_version}" ]]; then
66 echo "Could not determine workspace version." >&2
67 exit 1
68 fi
69
70 missing_packages=()
71 for workspace_package in "${workspace_deepseek_packages[@]}"; do
72 found=0
73 for package in "${packages[@]}"; do
74 if [[ "${package}" == "${workspace_package}" ]]; then
75 found=1
76 break
77 fi
78 done
79 if [[ "${found}" == "0" ]]; then
80 missing_packages+=("${workspace_package}")
81 fi
82 done
83
84 extra_packages=()
85 for package in "${packages[@]}"; do
86 found=0
87 for workspace_package in "${workspace_deepseek_packages[@]}"; do
88 if [[ "${package}" == "${workspace_package}" ]]; then
89 found=1
90 break
91 fi
92 done
93 if [[ "${found}" == "0" ]]; then
94 extra_packages+=("${package}")
95 fi
96 done
97
98 if (( ${#missing_packages[@]} > 0 || ${#extra_packages[@]} > 0 )); then
99 if (( ${#missing_packages[@]} > 0 )); then
100 echo "publish package list is missing workspace crates: ${missing_packages[*]}" >&2
101 fi
102 if (( ${#extra_packages[@]} > 0 )); then
103 echo "publish package list contains non-workspace crates: ${extra_packages[*]}" >&2
104 fi
105 exit 1
106 fi
107
108 package_has_workspace_deps() {
109 local package_name="$1"
110 local index
111 for ((index = 0; index < ${#workspace_deepseek_packages[@]}; index += 1)); do
112 if [[ "${workspace_deepseek_packages[$index]}" == "${package_name}" ]]; then
113 [[ "${workspace_package_dep_flags[$index]}" == "1" ]]
114 return
115 fi
116 done
117
118 echo "Unknown workspace crate: ${package_name}" >&2
119 return 1
120 }
121
122 crate_version_exists() {
123 local crate_name="$1"
124 local crate_version="$2"
125 curl -fsSL "https://crates.io/api/v1/crates/${crate_name}/${crate_version}" >/dev/null 2>&1
126 }
127
128 wait_for_crate_version() {
129 local crate_name="$1"
130 local crate_version="$2"
131 local attempts=30
132
133 for ((attempt = 1; attempt <= attempts; attempt += 1)); do
134 if crate_version_exists "${crate_name}" "${crate_version}"; then
135 return 0
136 fi
137 echo "Waiting for ${crate_name} ${crate_version} to appear on crates.io (${attempt}/${attempts})..."
138 sleep 10
139 done
140
141 echo "Timed out waiting for ${crate_name} ${crate_version} to appear on crates.io" >&2
142 return 1
143 }
144
145 for package in "${packages[@]}"; do
146 echo "::group::${mode} ${package}"
147 if [[ "${mode}" == "dry-run" ]]; then
148 if package_has_workspace_deps "${package}"; then
149 cargo package --allow-dirty --locked --list -p "${package}" >/dev/null
150 echo "Verified package contents for ${package}; full crates.io dry-run requires workspace dependencies at ${workspace_version} to be published first."
151 else
152 cargo publish --dry-run --locked --allow-dirty -p "${package}"
153 fi
154 else
155 if crate_version_exists "${package}" "${workspace_version}"; then
156 echo "Skipping ${package} ${workspace_version}; already published."
157 else
158 cargo publish --locked -p "${package}"
159 wait_for_crate_version "${package}" "${workspace_version}"
160 fi
161 fi
162 echo "::endgroup::"
163 done
164
164 lines BASH