Files
gitea/.configure.sh
T
petru 43c8d014e8
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-container (push) Has been cancelled
release-tag-version / binary (push) Has been cancelled
release-tag-version / container (push) Has been cancelled
Modified - [scripts] [configure] [git-lfs] Added conditional Git LFS setup to configure.sh when repository LFS hooks are installed.
- 1 - I updated `.configure.sh` so repositories that already have Git LFS hook scripts in `.git/hooks` now treat `git-lfs` as a required dependency during verification, install the `git-lfs` system package on supported package managers, and run `git lfs install --local` during non-verify setup.

(cherry picked from commit b66ec8c19d)
2026-05-20 00:32:29 +03:00

723 lines
15 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_go_version() {
sed -n 's/^go //p' "$SCRIPT_DIR/go.mod" 2>/dev/null | head -n 1
}
repo_node_version() {
sed -n 's/.*"node": ">= *\([^"]*\)".*/\1/p' "$SCRIPT_DIR/package.json" 2>/dev/null | head -n 1
}
repo_pnpm_version() {
sed -n 's/.*"packageManager": "pnpm@\([^"]*\)".*/\1/p' "$SCRIPT_DIR/package.json" 2>/dev/null | head -n 1
}
GO_VERSION="${GO_VERSION:-$(repo_go_version)}"
GO_VERSION="${GO_VERSION:-1.26.2}"
NODE_VERSION="${NODE_VERSION:-$(repo_node_version)}"
NODE_VERSION="${NODE_VERSION:-22.18.0}"
PNPM_VERSION="${PNPM_VERSION:-$(repo_pnpm_version)}"
PNPM_VERSION="${PNPM_VERSION:-10.33.0}"
NVM_VERSION="${NVM_VERSION:-v0.40.3}"
INSTALL_SYSTEM=1
INSTALL_GO=1
INSTALL_NODE=1
INSTALL_FRONTEND_DEPS=1
VERIFY_ONLY=0
WITH_CROSS_CGO=0
SHOW_MENU=0
VERIFY_REPORT_ONLY=0
VERIFY_HAD_ISSUES=0
usage() {
cat <<EOF
Usage: ./configure.sh [options]
Installs and configures the local build requirements for this Gitea tree.
Options:
--with-cross-cgo Also install/configure cross-CGO toolchains for
sqlite builds targeting linux/armv7 and windows/amd64.
This is useful for "All Arch" + sqlite builds, but it
downloads noticeably larger packages.
--skip-system Do not install system packages.
--skip-go Do not install Go.
--skip-node Do not install NVM/Node/pnpm.
--skip-frontend-deps Do not run pnpm install --frozen-lockfile.
--verify-only Only check the current environment.
--menu Show the interactive run menu.
-h, --help Show this help.
Environment overrides:
GO_VERSION=$GO_VERSION
NODE_VERSION=$NODE_VERSION
PNPM_VERSION=$PNPM_VERSION
NVM_VERSION=$NVM_VERSION
EOF
}
show_description() {
cat <<EOF
Gitea build environment setup
This script prepares the local machine for the Gitea build used in this tree.
It can install or verify:
- the required system build packages, including gcc, make, git, pkg-config,
and the SQLite/PAM libraries;
- git-lfs when this repository has Git LFS hooks installed;
- Go $GO_VERSION, as required by go.mod;
- Node $NODE_VERSION and pnpm $PNPM_VERSION, as required by package.json;
- frontend dependencies with pnpm install --frozen-lockfile;
- optional cross-CGO compilers for SQLite builds targeting linux/armv7
and windows/amd64.
For automated runs, you can keep using CLI options, for example:
./configure.sh --verify-only
./configure.sh --with-cross-cgo
EOF
}
interactive_menu() {
show_description
cat <<EOF
Select install mode:
1) Normal mode
2) With cross cgo
3) Verify only
4) Quit
EOF
# Install the standard requirements: system packages, Go, Node, pnpm, and frontend deps.
# Normal mode plus cross-CGO toolchains for multi-arch SQLite builds.
# Install nothing; only check the current environment.
while true; do
printf 'Choose option [1-4]: '
if ! read -r choice; then
die "No menu option selected."
fi
case "$choice" in
1)
printf 'Selected: Normal\n'
return
;;
2)
WITH_CROSS_CGO=1
printf 'Selected: With cross cgo\n'
return
;;
3)
VERIFY_ONLY=1
INSTALL_SYSTEM=0
INSTALL_GO=0
INSTALL_NODE=0
INSTALL_FRONTEND_DEPS=0
VERIFY_REPORT_ONLY=1
printf 'Selected: Verify only\n'
return
;;
4)
printf 'Canceled.\n'
exit 0
;;
*)
printf 'Invalid option: %s\n' "$choice"
;;
esac
done
}
log() {
printf '\n==> %s\n' "$*"
}
warn() {
printf 'WARNING: %s\n' "$*" >&2
}
die() {
printf 'ERROR: %s\n' "$*" >&2
exit 1
}
command_exists() {
command -v "$1" >/dev/null 2>&1
}
repo_has_git_lfs_hooks() {
local hook
for hook in pre-push post-checkout post-commit post-merge; do
[ -f "$SCRIPT_DIR/.git/hooks/$hook" ] || continue
if grep -q 'git-lfs' "$SCRIPT_DIR/.git/hooks/$hook"; then
return 0
fi
done
return 1
}
repo_requires_git_lfs() {
repo_has_git_lfs_hooks
}
run_as_root() {
if [ "$(id -u)" -eq 0 ]; then
"$@"
elif command_exists sudo; then
sudo "$@"
else
die "This step needs root privileges. Install sudo or run the script as root."
fi
}
fetch_to() {
local url="$1"
local output="$2"
if command_exists curl; then
curl -fL --retry 3 --retry-delay 2 -o "$output" "$url"
elif command_exists wget; then
wget -O "$output" "$url"
else
die "curl or wget is required to download $url"
fi
}
version_ge() {
local actual="$1"
local required="$2"
[ "$(printf '%s\n%s\n' "$required" "$actual" | sort -V | head -n 1)" = "$required" ]
}
append_profile_line() {
local file="$1"
local line="$2"
touch "$file"
if ! grep -qxF "$line" "$file"; then
printf '\n%s\n' "$line" >>"$file"
fi
}
ensure_go_path() {
activate_go_path
append_profile_line "$HOME/.profile" 'export PATH="/usr/local/go/bin:$HOME/go/bin:$PATH"'
append_profile_line "$HOME/.bashrc" 'export PATH="/usr/local/go/bin:$HOME/go/bin:$PATH"'
}
activate_go_path() {
export PATH="/usr/local/go/bin:$HOME/go/bin:$PATH"
}
install_system_packages() {
log "Installing system packages"
if command_exists apt-get; then
local -a packages=(
bash
build-essential
ca-certificates
coreutils
curl
findutils
gawk
git
gzip
libpam0g-dev
libsqlite3-dev
make
openssh-client
perl
pkg-config
python3
sed
sqlite3
tar
unzip
wget
xz-utils
zip
)
repo_requires_git_lfs && packages+=(git-lfs)
if [ "$WITH_CROSS_CGO" -eq 1 ]; then
packages+=(
gcc-arm-linux-gnueabihf
g++-arm-linux-gnueabihf
gcc-mingw-w64-x86-64
g++-mingw-w64-x86-64
)
fi
run_as_root apt-get update
run_as_root env DEBIAN_FRONTEND=noninteractive apt-get install -y "${packages[@]}"
return
fi
if command_exists dnf; then
local -a packages=(
bash
ca-certificates
coreutils
curl
findutils
gawk
gcc
gcc-c++
git
gzip
make
openssh-clients
pam-devel
perl-core
pkgconf-pkg-config
python3
sed
sqlite
sqlite-devel
tar
unzip
wget
xz
zip
)
repo_requires_git_lfs && packages+=(git-lfs)
run_as_root dnf install -y "${packages[@]}"
[ "$WITH_CROSS_CGO" -eq 0 ] || warn "Cross-CGO package setup is only automated for apt-based systems."
return
fi
if command_exists yum; then
local -a packages=(
bash
ca-certificates
coreutils
curl
findutils
gawk
gcc
gcc-c++
git
gzip
make
openssh-clients
pam-devel
perl
pkgconfig
python3
sed
sqlite
sqlite-devel
tar
unzip
wget
xz
zip
)
repo_requires_git_lfs && packages+=(git-lfs)
run_as_root yum install -y "${packages[@]}"
[ "$WITH_CROSS_CGO" -eq 0 ] || warn "Cross-CGO package setup is only automated for apt-based systems."
return
fi
if command_exists pacman; then
local -a packages=(
base-devel
bash
ca-certificates
coreutils
curl
findutils
gawk
git
gzip
make
openssh
pam
perl
pkgconf
python
sed
sqlite
tar
unzip
wget
xz
zip
)
repo_requires_git_lfs && packages+=(git-lfs)
run_as_root pacman -Sy --needed --noconfirm "${packages[@]}"
[ "$WITH_CROSS_CGO" -eq 0 ] || warn "Cross-CGO package setup is only automated for apt-based systems."
return
fi
if command_exists zypper; then
local -a packages=(
bash
ca-certificates
coreutils
curl
findutils
gawk
gcc
gcc-c++
git
gzip
make
openssh
pam-devel
perl
pkg-config
python3
sed
sqlite3
sqlite3-devel
tar
unzip
wget
xz
zip
)
repo_requires_git_lfs && packages+=(git-lfs)
run_as_root zypper install -y "${packages[@]}"
[ "$WITH_CROSS_CGO" -eq 0 ] || warn "Cross-CGO package setup is only automated for apt-based systems."
return
fi
die "Unsupported package manager. Install git, make, gcc/g++, pkg-config, sqlite3 headers, curl/wget, tar, unzip, xz, python3, and then rerun with --skip-system."
}
go_download_arch() {
case "$(uname -m)" in
x86_64 | amd64)
printf 'amd64'
;;
aarch64 | arm64)
printf 'arm64'
;;
i386 | i686)
printf '386'
;;
armv6l | armv7l)
printf 'armv6l'
;;
*)
die "Unsupported CPU architecture for automatic Go install: $(uname -m)"
;;
esac
}
current_go_version() {
if command_exists go; then
go version | awk '{print $3}' | sed 's/^go//'
fi
}
install_go() {
log "Configuring Go $GO_VERSION"
ensure_go_path
if [ "$(current_go_version)" = "$GO_VERSION" ]; then
printf 'Go %s is already installed.\n' "$GO_VERSION"
return
fi
local arch
arch="$(go_download_arch)"
local archive="/tmp/go${GO_VERSION}.linux-${arch}.tar.gz"
local url="https://go.dev/dl/go${GO_VERSION}.linux-${arch}.tar.gz"
fetch_to "$url" "$archive"
run_as_root rm -rf /usr/local/go
run_as_root tar -C /usr/local -xzf "$archive"
ensure_go_path
[ "$(current_go_version)" = "$GO_VERSION" ] || die "Go install finished, but go version is not $GO_VERSION."
}
load_nvm() {
export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
# shellcheck disable=SC1091
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
}
install_nvm() {
export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
if [ -s "$NVM_DIR/nvm.sh" ]; then
load_nvm
return
fi
log "Installing NVM $NVM_VERSION"
local installer="/tmp/nvm-install-${NVM_VERSION}.sh"
fetch_to "https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh" "$installer"
bash "$installer"
load_nvm
command_exists nvm || die "NVM could not be loaded after installation."
}
current_node_version() {
if command_exists node; then
node -p 'process.versions.node'
fi
}
current_pnpm_version() {
if command_exists pnpm; then
pnpm --version
fi
}
install_node_and_pnpm() {
log "Configuring Node $NODE_VERSION and pnpm $PNPM_VERSION"
install_nvm
nvm install "$NODE_VERSION"
nvm alias default "$NODE_VERSION" >/dev/null
nvm use "$NODE_VERSION" >/dev/null
hash -r
if command_exists corepack; then
corepack enable
corepack prepare "pnpm@${PNPM_VERSION}" --activate
hash -r
fi
if ! command_exists pnpm || ! version_ge "$(current_pnpm_version)" "$PNPM_VERSION"; then
npm install -g "pnpm@${PNPM_VERSION}"
hash -r
fi
if ! version_ge "$(current_node_version)" "$NODE_VERSION"; then
die "Node $(current_node_version) is older than required $NODE_VERSION."
fi
if ! version_ge "$(current_pnpm_version)" "$PNPM_VERSION"; then
die "pnpm $(current_pnpm_version) is older than required $PNPM_VERSION."
fi
}
install_frontend_deps() {
log "Installing frontend dependencies"
cd "$SCRIPT_DIR"
pnpm install --frozen-lockfile
}
configure_git_lfs() {
repo_requires_git_lfs || return
log "Configuring Git LFS"
command_exists git-lfs || die "git-lfs is required for this repository but is not installed."
cd "$SCRIPT_DIR"
git lfs install --local >/dev/null
}
configure_cross_cgo() {
[ "$WITH_CROSS_CGO" -eq 1 ] || return
log "Configuring Makefile.local for cross-CGO sqlite builds"
cd "$SCRIPT_DIR"
if [ -f Makefile.local ] && grep -qF '# BEGIN configure.sh cross-cgo' Makefile.local; then
printf 'Makefile.local already contains configure.sh cross-CGO settings.\n'
return
fi
cat >>Makefile.local <<'EOF'
# BEGIN configure.sh cross-cgo
ifeq ($(GOOS)/$(GOARCH),windows/amd64)
CC := x86_64-w64-mingw32-gcc
CXX := x86_64-w64-mingw32-g++
export CC
export CXX
endif
ifeq ($(GOOS)/$(GOARCH)/$(GOARM),linux/arm/7)
CC := arm-linux-gnueabihf-gcc
CXX := arm-linux-gnueabihf-g++
export CC
export CXX
endif
# END configure.sh cross-cgo
EOF
}
verify_environment() {
log "Verifying build environment"
activate_go_path
load_nvm || true
hash -r
local -a missing=()
local -a problems=()
local command_name
for command_name in git make go node pnpm gcc pkg-config; do
if ! command_exists "$command_name"; then
missing+=("$command_name")
fi
done
if repo_requires_git_lfs && ! command_exists git-lfs; then
missing+=("git-lfs")
fi
if command_exists go; then
local found_go
found_go="$(current_go_version)"
[ "$found_go" = "$GO_VERSION" ] || problems+=("Go $found_go found, but $GO_VERSION is required.")
fi
if command_exists node; then
local found_node
found_node="$(current_node_version)"
version_ge "$found_node" "$NODE_VERSION" || problems+=("Node $found_node found, but >= $NODE_VERSION is required.")
fi
if command_exists pnpm; then
local found_pnpm
found_pnpm="$(current_pnpm_version)"
version_ge "$found_pnpm" "$PNPM_VERSION" || problems+=("pnpm $found_pnpm found, but >= $PNPM_VERSION is required.")
fi
cd "$SCRIPT_DIR"
if command_exists make && ! make help >/dev/null; then
problems+=("make help failed.")
fi
if [ "$WITH_CROSS_CGO" -eq 1 ]; then
for command_name in arm-linux-gnueabihf-gcc x86_64-w64-mingw32-gcc; do
if ! command_exists "$command_name"; then
missing+=("$command_name")
fi
done
fi
if [ ! -d "$SCRIPT_DIR/node_modules" ]; then
problems+=("node_modules is missing; frontend dependencies are not installed.")
fi
if [ "${#missing[@]}" -gt 0 ] || [ "${#problems[@]}" -gt 0 ]; then
VERIFY_HAD_ISSUES=1
if [ "${#missing[@]}" -gt 0 ]; then
printf '\nMissing commands:\n'
for command_name in "${missing[@]}"; do
printf ' - %s\n' "$command_name"
done
fi
if [ "${#problems[@]}" -gt 0 ]; then
printf '\nConfiguration issues:\n'
local problem
for problem in "${problems[@]}"; do
printf ' - %s\n' "$problem"
done
fi
printf '\nTo fix the standard build environment, run ./configure.sh and choose 1) Normal.\n'
printf 'For sqlite multi-arch builds, choose 2) With cross cgo.\n'
if [ "$VERIFY_REPORT_ONLY" -eq 1 ]; then
printf '\nVerify only completed; no changes were made.\n'
return 0
fi
return 1
fi
printf 'Go: %s\n' "$(go version)"
printf 'Node: %s\n' "$(node --version)"
printf 'pnpm: %s\n' "$(pnpm --version)"
printf 'gcc: %s\n' "$(gcc --version | head -n 1)"
if repo_requires_git_lfs; then
printf 'git-lfs: %s\n' "$(git lfs version)"
fi
if [ -d "$SCRIPT_DIR/node_modules" ]; then
printf 'node_modules: present\n'
else
printf 'node_modules: missing; run ./configure.sh or pnpm install --frozen-lockfile\n'
fi
}
if [ "$#" -eq 0 ] && [ -t 0 ]; then
SHOW_MENU=1
fi
while [ "$#" -gt 0 ]; do
case "$1" in
--with-cross-cgo)
WITH_CROSS_CGO=1
;;
--skip-system)
INSTALL_SYSTEM=0
;;
--skip-go)
INSTALL_GO=0
;;
--skip-node)
INSTALL_NODE=0
;;
--skip-frontend-deps)
INSTALL_FRONTEND_DEPS=0
;;
--verify-only)
VERIFY_ONLY=1
INSTALL_SYSTEM=0
INSTALL_GO=0
INSTALL_NODE=0
INSTALL_FRONTEND_DEPS=0
;;
--menu)
SHOW_MENU=1
;;
-h | --help)
usage
exit 0
;;
*)
usage
die "Unknown option: $1"
;;
esac
shift
done
if [ "$SHOW_MENU" -eq 1 ]; then
interactive_menu
fi
if [ "$(id -u)" -eq 0 ]; then
warn "You are running as root. NVM/Node will be configured for root, not for your normal user."
fi
if [ "$VERIFY_ONLY" -eq 0 ]; then
[ "$INSTALL_SYSTEM" -eq 0 ] || install_system_packages
configure_git_lfs
[ "$INSTALL_GO" -eq 0 ] || install_go
[ "$INSTALL_NODE" -eq 0 ] || install_node_and_pnpm
configure_cross_cgo
[ "$INSTALL_FRONTEND_DEPS" -eq 0 ] || install_frontend_deps
fi
verify_environment
if [ "$VERIFY_HAD_ISSUES" -eq 1 ]; then
cat <<EOF
Done. Missing requirements were reported above and no changes were made.
Run ./configure.sh again and choose:
1) Normal
For sqlite builds across all smart-build architectures, choose:
2) With cross cgo
EOF
else
cat <<EOF
Done.
Recommended next steps:
./smart-build.sh
For sqlite builds across all smart-build architectures, prepare the heavier
cross-CGO tools with:
./configure.sh --with-cross-cgo
EOF
fi