Files
SingBox-Gopanel/scripts/build_install.sh
CN-JS-HuiBai a703315d00
Some checks failed
build / build (api, amd64, linux) (push) Has been cancelled
build / build (api, arm64, linux) (push) Has been cancelled
build / build (api.exe, amd64, windows) (push) Has been cancelled
修改构建脚本
2026-04-17 22:37:51 +08:00

246 lines
5.6 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
GO_MOD_FILE="${ROOT_DIR}/go.mod"
DEFAULT_GO_VERSION="$(awk '/^go / { print $2; exit }' "${GO_MOD_FILE}")"
GO_VERSION="${DEFAULT_GO_VERSION}"
OUTPUT_PATH="${ROOT_DIR}/api"
TOOLS_DIR="${ROOT_DIR}/.build-tools"
CACHE_DIR="${ROOT_DIR}/.build-cache"
CLEAN_GO="false"
INSTALL_SERVICE="false"
SERVICE_NAME="singbox-gopanel"
RUN_USER="${SUDO_USER:-${USER:-root}}"
usage() {
cat <<EOF
Usage: scripts/build_install.sh [options]
Options:
--go-version <version> Go version to download, default: ${GO_VERSION}
--output <path> Build output path, default: ${OUTPUT_PATH}
--tools-dir <dir> Toolchain directory, default: ${TOOLS_DIR}
--cache-dir <dir> Go cache directory, default: ${CACHE_DIR}
--clean-go Re-download the Go toolchain even if it exists
--install-service Install and start the systemd service
--service-name <name> Systemd service name, default: ${SERVICE_NAME}
--run-user <user> Runtime user, default: ${RUN_USER}
-h, --help Show this help
Examples:
bash scripts/build_install.sh
bash scripts/build_install.sh --output ./package/api
sudo bash scripts/build_install.sh --install-service
EOF
}
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--go-version)
GO_VERSION="$2"
shift 2
;;
--output)
OUTPUT_PATH="$2"
shift 2
;;
--tools-dir)
TOOLS_DIR="$2"
shift 2
;;
--cache-dir)
CACHE_DIR="$2"
shift 2
;;
--clean-go)
CLEAN_GO="true"
shift
;;
--install-service)
INSTALL_SERVICE="true"
shift
;;
--service-name)
SERVICE_NAME="$2"
shift 2
;;
--run-user)
RUN_USER="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "error: unknown option: $1" >&2
usage
exit 1
;;
esac
done
}
require_cmd() {
if ! command -v "$1" >/dev/null 2>&1; then
echo "error: required command not found: $1" >&2
exit 1
fi
}
detect_platform() {
local uname_os uname_arch
uname_os="$(uname -s)"
uname_arch="$(uname -m)"
case "${uname_os}" in
Linux) GO_OS="linux" ;;
Darwin) GO_OS="darwin" ;;
*)
echo "error: unsupported operating system: ${uname_os}" >&2
exit 1
;;
esac
case "${uname_arch}" in
x86_64|amd64) GO_ARCH="amd64" ;;
aarch64|arm64) GO_ARCH="arm64" ;;
*)
echo "error: unsupported architecture: ${uname_arch}" >&2
exit 1
;;
esac
}
download_go() {
local archive_name archive_path download_url current_version
mkdir -p "${TOOLS_DIR}"
archive_name="go${GO_VERSION}.${GO_OS}-${GO_ARCH}.tar.gz"
archive_path="${TOOLS_DIR}/${archive_name}"
GO_ROOT="${TOOLS_DIR}/go"
if [[ -x "${GO_ROOT}/bin/go" ]]; then
current_version="$("${GO_ROOT}/bin/go" version | awk '{print $3}' | sed 's/^go//')"
if [[ "${current_version}" != "${GO_VERSION}" ]]; then
rm -rf "${GO_ROOT}"
fi
fi
if [[ "${CLEAN_GO}" == "true" ]]; then
rm -rf "${GO_ROOT}"
rm -f "${archive_path}"
fi
if [[ ! -x "${GO_ROOT}/bin/go" ]]; then
download_url="https://go.dev/dl/${archive_name}"
echo "downloading Go ${GO_VERSION} for ${GO_OS}/${GO_ARCH}..."
if [[ ! -f "${archive_path}" ]]; then
if command -v curl >/dev/null 2>&1; then
curl -fsSL "${download_url}" -o "${archive_path}"
elif command -v wget >/dev/null 2>&1; then
wget -O "${archive_path}" "${download_url}"
else
echo "error: curl or wget is required to download Go" >&2
exit 1
fi
fi
rm -rf "${GO_ROOT}"
tar -C "${TOOLS_DIR}" -xzf "${archive_path}"
fi
}
build_binary() {
local output_dir
mkdir -p "${CACHE_DIR}/gocache" "${CACHE_DIR}/gomodcache"
output_dir="$(dirname "${OUTPUT_PATH}")"
mkdir -p "${output_dir}"
echo "building ${OUTPUT_PATH}..."
(
cd "${ROOT_DIR}"
export GOROOT="${GO_ROOT}"
export PATH="${GO_ROOT}/bin:${PATH}"
export GOCACHE="${CACHE_DIR}/gocache"
export GOMODCACHE="${CACHE_DIR}/gomodcache"
"${GO_ROOT}/bin/go" build -trimpath -o "${OUTPUT_PATH}" ./cmd/api
)
chmod +x "${OUTPUT_PATH}" || true
}
install_systemd_service() {
if [[ "${INSTALL_SERVICE}" != "true" ]]; then
return
fi
if [[ "${EUID}" -ne 0 ]]; then
echo "error: systemd service installation requires root/sudo" >&2
exit 1
fi
if ! command -v systemctl >/dev/null 2>&1; then
echo "systemctl not found, skipping service installation"
return
fi
echo "installing systemd service: ${SERVICE_NAME}..."
cat >"/etc/systemd/system/${SERVICE_NAME}.service" <<EOF
[Unit]
Description=SingBox GoPanel API
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=${RUN_USER}
WorkingDirectory=${ROOT_DIR}
EnvironmentFile=-${ROOT_DIR}/.env
ExecStart=${OUTPUT_PATH}
Restart=always
RestartSec=5
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable "${SERVICE_NAME}"
systemctl restart "${SERVICE_NAME}"
echo "service ${SERVICE_NAME} installed and started."
}
print_summary() {
cat <<EOF
Build complete.
Go version: ${GO_VERSION}
Toolchain: ${GO_ROOT}
Output: ${OUTPUT_PATH}
Cache dir: ${CACHE_DIR}
To use this Go environment in your current shell:
export PATH="${GO_ROOT}/bin:\$PATH"
export GOROOT="${GO_ROOT}"
EOF
}
main() {
parse_args "$@"
require_cmd tar
detect_platform
download_go
build_binary
install_systemd_service
print_summary
}
main "$@"