返回 CodeWhale
render.sh
根目录 / packaging / aur / render.sh
1 #!/usr/bin/env bash
2 set -euo pipefail
3
4 usage() {
5 echo "usage: $0 RELEASE_ASSETS_DIR OUTPUT_DIR [PKGREL]" >&2
6 }
7
8 if [[ $# -lt 2 || $# -gt 3 ]]; then
9 usage
10 exit 2
11 fi
12
13 assets_dir="$1"
14 output_dir="$2"
15 pkgrel="${3:-1}"
16 repo_root="$(cd "$(dirname "$0")/../.." && pwd)"
17
18 if [[ ! -d "${assets_dir}" ]]; then
19 echo "release assets directory does not exist: ${assets_dir}" >&2
20 exit 1
21 fi
22 assets_dir="$(cd "${assets_dir}" && pwd)"
23
24 if [[ -e "${output_dir}" && ! -d "${output_dir}" ]]; then
25 echo "output path is not a directory: ${output_dir}" >&2
26 exit 1
27 fi
28 mkdir -p "${output_dir}"
29 if [[ -n "$(find "${output_dir}" -mindepth 1 -maxdepth 1 -print -quit)" ]]; then
30 echo "output directory must be empty: ${output_dir}" >&2
31 exit 1
32 fi
33 output_dir="$(cd "${output_dir}" && pwd)"
34
35 workspace_version="$(
36 grep -E '^version = "' "${repo_root}/Cargo.toml" \
37 | head -n 1 \
38 | sed -E 's/^version = "([^"]+)".*/\1/'
39 )"
40 if [[ ! "${workspace_version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
41 echo "workspace version must be X.Y.Z, got: ${workspace_version:-<missing>}" >&2
42 exit 1
43 fi
44 if [[ ! "${pkgrel}" =~ ^[1-9][0-9]*(\.[1-9][0-9]*)?$ ]]; then
45 echo "PKGREL must be a positive integer or positive x.y value, got: ${pkgrel}" >&2
46 exit 2
47 fi
48
49 artifact_manifest="${assets_dir}/codewhale-artifacts-sha256.txt"
50 bundle_manifest="${assets_dir}/codewhale-bundles-sha256.txt"
51 for manifest in "${artifact_manifest}" "${bundle_manifest}"; do
52 if [[ ! -f "${manifest}" ]]; then
53 echo "release assets are missing checksum manifest: ${manifest}" >&2
54 exit 1
55 fi
56 done
57
58 sha256_file() {
59 local path="$1"
60 if command -v sha256sum >/dev/null 2>&1; then
61 sha256sum "${path}" | awk '{print $1}'
62 elif command -v shasum >/dev/null 2>&1; then
63 shasum -a 256 "${path}" | awk '{print $1}'
64 else
65 echo "sha256sum or shasum is required" >&2
66 return 1
67 fi
68 }
69
70 manifest_sha() {
71 local manifest="$1"
72 local asset="$2"
73 local matches match_count checksum
74 matches="$(awk -v asset="${asset}" '$2 == asset { print $1 }' "${manifest}")"
75 match_count="$(printf '%s\n' "${matches}" | awk 'NF { count++ } END { print count + 0 }')"
76 if [[ "${match_count}" -ne 1 ]]; then
77 echo "$(basename "${manifest}") must contain exactly one checksum for ${asset}" >&2
78 return 1
79 fi
80 checksum="$(printf '%s\n' "${matches}" | awk 'NF { print; exit }')"
81 if [[ ! "${checksum}" =~ ^[0-9a-fA-F]{64}$ ]]; then
82 echo "invalid checksum for ${asset} in $(basename "${manifest}"): ${checksum}" >&2
83 return 1
84 fi
85 printf '%s' "${checksum}" | tr 'A-F' 'a-f'
86 }
87
88 verified_archive_sha() {
89 local asset="$1"
90 local archive="${assets_dir}/${asset}"
91 if [[ ! -f "${archive}" ]]; then
92 echo "release assets are missing ${asset}" >&2
93 return 1
94 fi
95
96 local artifact_sha bundle_sha actual_sha
97 artifact_sha="$(manifest_sha "${artifact_manifest}" "${asset}")"
98 bundle_sha="$(manifest_sha "${bundle_manifest}" "${asset}")"
99 if [[ "${artifact_sha}" != "${bundle_sha}" ]]; then
100 echo "checksum manifests disagree for ${asset}" >&2
101 return 1
102 fi
103 actual_sha="$(sha256_file "${archive}")"
104 if [[ "${artifact_sha}" != "${actual_sha}" ]]; then
105 echo "release asset checksum mismatch for ${asset}" >&2
106 return 1
107 fi
108
109 local release_arch="${asset#codewhale-linux-}"
110 release_arch="${release_arch%.tar.gz}"
111 local listing
112 listing="$(tar -tzf "${archive}")"
113 for entry in \
114 "codewhale-linux-${release_arch}/codewhale" \
115 "codewhale-linux-${release_arch}/codew"; do
116 if ! grep -Fqx "${entry}" <<<"${listing}"; then
117 echo "${asset} is missing required archive entry: ${entry}" >&2
118 return 1
119 fi
120 done
121
122 printf '%s' "${actual_sha}"
123 }
124
125 x86_64_sha="$(verified_archive_sha 'codewhale-linux-x64.tar.gz')"
126 aarch64_sha="$(verified_archive_sha 'codewhale-linux-arm64.tar.gz')"
127 license_sha="$(sha256_file "${repo_root}/LICENSE")"
128
129 render_template() {
130 local source="$1"
131 local destination="$2"
132 local content
133 content="$(<"${source}")"
134 content="${content//@PKGVER@/${workspace_version}}"
135 content="${content//@PKGREL@/${pkgrel}}"
136 content="${content//@LICENSE_SHA256@/${license_sha}}"
137 content="${content//@X86_64_SHA256@/${x86_64_sha}}"
138 content="${content//@AARCH64_SHA256@/${aarch64_sha}}"
139 printf '%s\n' "${content}" > "${destination}"
140 }
141
142 render_template "${repo_root}/packaging/aur/PKGBUILD.template" "${output_dir}/PKGBUILD"
143 render_template "${repo_root}/packaging/aur/SRCINFO.template" "${output_dir}/.SRCINFO"
144
145 for rendered in "${output_dir}/PKGBUILD" "${output_dir}/.SRCINFO"; do
146 if grep -Eq '@(PKGVER|PKGREL|LICENSE_SHA256|X86_64_SHA256|AARCH64_SHA256)@|SKIP' "${rendered}"; then
147 echo "rendered AUR metadata contains an unresolved or insecure checksum token: ${rendered}" >&2
148 exit 1
149 fi
150 done
151 bash -n "${output_dir}/PKGBUILD"
152
153 if command -v makepkg >/dev/null 2>&1; then
154 generated_srcinfo="$(mktemp)"
155 trap 'rm -f "${generated_srcinfo}"' EXIT
156 (cd "${output_dir}" && makepkg --printsrcinfo) > "${generated_srcinfo}"
157 if ! cmp -s "${generated_srcinfo}" "${output_dir}/.SRCINFO"; then
158 echo "rendered .SRCINFO does not match makepkg --printsrcinfo" >&2
159 diff -u "${output_dir}/.SRCINFO" "${generated_srcinfo}" >&2 || true
160 exit 1
161 fi
162 fi
163
164 echo "Rendered codewhale-bin ${workspace_version}-${pkgrel} from verified release archives:"
165 echo " ${output_dir}/PKGBUILD"
166 echo " ${output_dir}/.SRCINFO"
167
167 lines BASH