2ba027098f
新增 APK/IPA 轨道和 copy_artifact.sh(本地目录或 container:/dir)。 push 必须委托该脚本,禁止在 makefile 里内联 docker cp。
153 lines
4.1 KiB
Bash
Executable File
153 lines
4.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage:
|
|
COPY_DEST=/path/or/container:/dir \
|
|
copy_artifact.sh FILE [FILE ...]
|
|
|
|
Copy built artifacts to COPY_DEST. Dest is a local directory, or a Docker
|
|
copy target `container:/absolute/dir` (docker cp). Does not read `.env`.
|
|
|
|
Environment (project root .env.builder; shell values win):
|
|
COPY_DEST Required. Local dir or container:/dir
|
|
COPY_AS Optional. Extra basenames for the first file
|
|
(comma or space separated)
|
|
ALLOW_UNCOMMITTED=1 Publish despite a dirty working tree
|
|
|
|
Options:
|
|
-d DEST Override COPY_DEST
|
|
-a NAMES Override COPY_AS
|
|
--dry-run Print the copies without executing
|
|
-h Show help
|
|
|
|
The working tree must be clean to publish; set ALLOW_UNCOMMITTED=1 to override.
|
|
EOF
|
|
}
|
|
|
|
project_root=$(git rev-parse --show-toplevel 2>/dev/null || true)
|
|
|
|
if [[ -n "$project_root" && -f "$project_root/.env.builder" ]]; then
|
|
while IFS='=' read -r key value; do
|
|
key=${key%%[[:space:]]*}
|
|
[[ -z "$key" || "$key" == \#* ]] && continue
|
|
if [[ -n "${!key:-}" ]]; then
|
|
continue
|
|
fi
|
|
value=${value%\"}; value=${value#\"}; value=${value%\'}; value=${value#\'}
|
|
[[ -z "$value" ]] && continue
|
|
printf -v "$key" '%s' "$value"
|
|
export "$key"
|
|
done < <(grep -v '^[[:space:]]*$' "$project_root/.env.builder")
|
|
fi
|
|
|
|
dest=${COPY_DEST:-}
|
|
extra_as=${COPY_AS:-}
|
|
dry_run=false
|
|
|
|
while (($#)); do
|
|
case "$1" in
|
|
-d) dest=$2; shift 2 ;;
|
|
-a) extra_as=$2; shift 2 ;;
|
|
--dry-run) dry_run=true; shift ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
--) shift; break ;;
|
|
-*) echo "Error: unknown option: $1" >&2; usage >&2; exit 2 ;;
|
|
*) break ;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "$dest" || $# -eq 0 ]]; then
|
|
echo "Error: COPY_DEST and at least one file are required." >&2
|
|
echo "Set them in the environment or the project root .env.builder." >&2
|
|
usage >&2
|
|
exit 2
|
|
fi
|
|
|
|
if [[ -n "$project_root" ]] && git -C "$project_root" rev-parse HEAD >/dev/null 2>&1; then
|
|
if [[ ${ALLOW_UNCOMMITTED:-0} != 1 ]] && ! git -C "$project_root" diff-index --quiet HEAD -- 2>/dev/null; then
|
|
echo "Error: working tree has uncommitted changes; refusing to publish." >&2
|
|
echo "Commit first, or set ALLOW_UNCOMMITTED=1 to publish anyway." >&2
|
|
exit 3
|
|
fi
|
|
fi
|
|
|
|
is_docker_dest() {
|
|
local d=$1
|
|
[[ "$d" != /* && "$d" != ./* && "$d" != ../* && "$d" != ~* ]] \
|
|
&& [[ "$d" != *://* ]] \
|
|
&& [[ "$d" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]*:/ ]]
|
|
}
|
|
|
|
docker_container=
|
|
docker_dir=
|
|
local_dir=
|
|
if is_docker_dest "$dest"; then
|
|
docker_container=${dest%%:*}
|
|
docker_dir=${dest#*:}
|
|
if [[ -z "$docker_container" || -z "$docker_dir" || "$docker_dir" != /* ]]; then
|
|
echo "Error: docker dest must be container:/absolute/dir" >&2
|
|
exit 2
|
|
fi
|
|
docker_dir=${docker_dir%/}
|
|
else
|
|
local_dir=${dest%/}
|
|
fi
|
|
|
|
split_as() {
|
|
local raw=$1
|
|
raw=${raw//,/ }
|
|
# shellcheck disable=SC2086
|
|
printf '%s\n' $raw
|
|
}
|
|
|
|
copy_one() {
|
|
local src=$1 name=$2
|
|
if [[ ! -f "$src" ]]; then
|
|
echo "Error: not a file: $src" >&2
|
|
exit 2
|
|
fi
|
|
if [[ -n "$docker_container" ]]; then
|
|
local target="${docker_container}:${docker_dir}/${name}"
|
|
if $dry_run; then
|
|
echo "docker cp $src $target"
|
|
return
|
|
fi
|
|
docker cp "$src" "$target"
|
|
docker exec "$docker_container" ls -l "${docker_dir}/${name}" >/dev/null
|
|
echo "copied $(basename -- "$src") -> $target"
|
|
else
|
|
local target="${local_dir}/${name}"
|
|
if $dry_run; then
|
|
echo "cp $src $target"
|
|
return
|
|
fi
|
|
mkdir -p "$local_dir"
|
|
cp -a "$src" "$target"
|
|
test -f "$target"
|
|
echo "copied $(basename -- "$src") -> $target"
|
|
fi
|
|
}
|
|
|
|
first=true
|
|
success=0
|
|
for src in "$@"; do
|
|
copy_one "$src" "$(basename -- "$src")"
|
|
if $first; then
|
|
first=false
|
|
if [[ -n "$extra_as" ]]; then
|
|
while IFS= read -r alias; do
|
|
[[ -z "$alias" ]] && continue
|
|
copy_one "$src" "$alias"
|
|
done < <(split_as "$extra_as")
|
|
fi
|
|
fi
|
|
if ! $dry_run && command -v sha256sum >/dev/null 2>&1; then
|
|
sha256sum -- "$src"
|
|
fi
|
|
success=$((success + 1))
|
|
done
|
|
|
|
echo "copy_artifact: $success file(s) to $dest"
|