#!/bin/bash # Folosește instalarea Go standard dacă există, chiar dacă nu este în PATH. if [ -x "/usr/local/go/bin/go" ]; then export PATH="/usr/local/go/bin:$PATH" fi # Încarcă NVM dacă este disponibil export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # Forțează folosirea versiunii 22 nvm use 22 > /dev/null 2>&1 || echo "⚠️ NVM nu a putut activa Node 22 automatically." resolve_build_ref() { git describe --tags --exact-match 2>/dev/null || git describe --tags --always } require_docker_for_darwin_sqlite() { if ! command -v docker > /dev/null 2>&1; then echo "❌ Docker is required for macOS SQLite cross-builds." echo " Install the Docker CLI in this environment, or use the non-SQLite macOS build option." echo " If you are running inside a code-server container, also mount the host Docker socket." exit 1 fi if ! docker info > /dev/null 2>&1; then echo "❌ Docker is installed but the daemon is not reachable." echo " Start Docker, or expose the host Docker daemon to this container." echo " For a code-server container, mount /var/run/docker.sock from the host." if [ -n "${DOCKER_HOST:-}" ]; then echo " Current DOCKER_HOST: ${DOCKER_HOST}" else echo " Current DOCKER_HOST is unset." fi exit 1 fi } resolve_xgo_image() { local xgo_version xgo_version="$(awk '$1 == "XGO_VERSION" { print $3; exit }' Makefile 2>/dev/null)" if [ -z "$xgo_version" ]; then xgo_version="go-1.25.x" fi printf 'ghcr.io/techknowlogick/xgo:%s' "$xgo_version" } resolve_darwin_sqlite_repo_root() { local override_path override_path="${SMART_BUILD_DARWIN_HOST_REPO_PATH:-}" if [ -z "$override_path" ]; then pwd -P return fi if [ ! -d "$override_path" ] || [ ! -f "$override_path/go.mod" ]; then echo "❌ SMART_BUILD_DARWIN_HOST_REPO_PATH is set, but the path is not usable in this container:" echo " $override_path" echo " Mount the host repository path into the container at the same absolute path, then retry." exit 1 fi printf '%s' "$override_path" } validate_repo_bind_mount_for_darwin_sqlite() { local repo_path="$1" local xgo_image xgo_image="$(resolve_xgo_image)" if ! docker run --rm -v "$repo_path":/probe:ro --entrypoint sh "$xgo_image" -lc 'test -f /probe/go.mod'; then echo "❌ Docker can reach the daemon, but the daemon cannot mount this repository path correctly:" echo " $repo_path" echo " The xgo container only sees an empty or different host path, so /source/go.mod is missing there." echo " If smart-build runs inside a code-server container with the host Docker socket," echo " the repository must be mounted from a host bind path that exists at the same absolute path." exit 1 fi } write_sha256_file() { local artifact_path="$1" local artifact_dir artifact_name artifact_dir="$(dirname "$artifact_path")" artifact_name="$(basename "$artifact_path")" if command -v sha256sum > /dev/null 2>&1; then ( cd "$artifact_dir" || exit 1 sha256sum "$artifact_name" > "$artifact_name.sha256" ) return fi if command -v shasum > /dev/null 2>&1; then ( cd "$artifact_dir" || exit 1 shasum -a 256 "$artifact_name" > "$artifact_name.sha256" ) return fi echo "❌ Neither sha256sum nor shasum is available for checksum generation." exit 1 } # --- 1. VERIFICARE INTEGRITATE ȘI CURĂȚARE CACHE INIȚIALĂ --- echo "🔍 Initialization checks..." if ! command -v go > /dev/null 2>&1; then echo "❌ Go nu este disponibil în PATH. Instalează Go 1.26.2 sau adaugă binarul go în PATH." exit 1 fi notify_human_interaction() { local bell_oga="/usr/share/sounds/freedesktop/stereo/bell.oga" local bell_wav="/usr/share/sounds/alsa/Front_Center.wav" local in_vscode_terminal=0 local notification_sent=0 if [ "${TERM_PROGRAM:-}" = "vscode" ] || [ -n "${VSCODE_IPC_HOOK_CLI:-}" ] || [ -n "${VSCODE_GIT_IPC_HANDLE:-}" ]; then in_vscode_terminal=1 fi if command -v notify-send > /dev/null 2>&1; then notify-send "Gitea smart-build" "Human input required in smart-build.sh" > /dev/null 2>&1 && notification_sent=1 fi if command -v canberra-gtk-play > /dev/null 2>&1; then canberra-gtk-play -i bell > /dev/null 2>&1 && return fi if [ -f "$bell_oga" ] && command -v paplay > /dev/null 2>&1; then paplay "$bell_oga" > /dev/null 2>&1 && return fi if [ -f "$bell_wav" ] && command -v aplay > /dev/null 2>&1; then aplay -q "$bell_wav" > /dev/null 2>&1 && return fi if [ -f "$bell_wav" ] && command -v play > /dev/null 2>&1; then play -q "$bell_wav" > /dev/null 2>&1 && return fi if [ -t 1 ]; then printf '\a' fi if [ "$notification_sent" -eq 0 ] && [ "$in_vscode_terminal" -eq 1 ]; then printf '\033[1;33m%s\033[0m\n' ">>> Human input required below <<<" fi } apply_moderate_build_limits() { local go_procs="$1" local node_memory="$2" export GOMAXPROCS="$go_procs" export MAKEFLAGS="-j1" if [[ "$NODE_OPTIONS" != *"--max-old-space-size="* ]]; then export NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--max-old-space-size=$node_memory" fi } echo "" echo "⚙️ Select Build Load Profile:" echo " Normal keeps the default build behavior." echo " Moderate limits parallel jobs and keeps CPU/RAM usage lower." echo " Low Resource is slower, but safest for weaker machines." notify_human_interaction load_options=("Normal" "Moderate (GOMAXPROCS=2, make -j1)" "Low Resource (GOMAXPROCS=1, make -j1)" "Quit") select opt in "${load_options[@]}" do case $opt in "Normal") echo "✅ Selected: Normal build profile." break ;; "Moderate (GOMAXPROCS=2, make -j1)") apply_moderate_build_limits 2 2048 echo "✅ Selected: Moderate build profile." echo " GOMAXPROCS=$GOMAXPROCS MAKEFLAGS=\"$MAKEFLAGS\" NODE_OPTIONS=\"$NODE_OPTIONS\"" break ;; "Low Resource (GOMAXPROCS=1, make -j1)") apply_moderate_build_limits 1 2048 echo "✅ Selected: Low Resource build profile." echo " GOMAXPROCS=$GOMAXPROCS MAKEFLAGS=\"$MAKEFLAGS\" NODE_OPTIONS=\"$NODE_OPTIONS\"" break ;; "Quit") exit 0 ;; *) echo "Opțiune invalidă $REPLY";; esac done # Dacă compilarea anterioară a fost întreruptă, ștergem binarul parțial if [ -f "gitea" ] || [ -f "gitea.exe" ]; then echo "🧹 Garbages found. Cleanning..." rm -f gitea gitea.exe fi # Verificăm dacă node_modules există. Dacă nu, forțăm pnpm install if [ ! -d "node_modules" ]; then echo "⚠️ node_modules missing. Instaling..." if ! pnpm install --frozen-lockfile; then echo "❌ Fail to install frontend dependencies." exit 1 fi fi # --- 2. LOGICĂ FRONTEND (CHECKSUM) --- CHECKSUM_FILE=".frontend.hash" CURRENT_HASH=$(find web_src package.json tailwind.config.js -type f -print0 2>/dev/null | xargs -0 sha1sum | sha1sum | awk '{print $1}') if [ -f "$CHECKSUM_FILE" ] && [ "$CURRENT_HASH" == "$(cat $CHECKSUM_FILE)" ]; then echo "✅ Frontend is unchanged." else echo "🚀 Code changes detected. Running frontend build..." if ! make frontend; then echo "❌ Fail to build frontend assets." exit 1 fi echo "$CURRENT_HASH" > "$CHECKSUM_FILE" fi # --- 3. MENIU INTERACTIV PENTRU ARHITECTURĂ --- echo "" echo "🎯 Select Arch to build:" notify_human_interaction arch_options=("linux-amd64" "linux-armv7" "windows-amd64" "macos-amd64" "macos-arm64" "All Arch" "Quit") select opt in "${arch_options[@]}" do case $opt in "linux-amd64") TARGETS=("linux/amd64") break ;; "linux-armv7") TARGETS=("linux/arm/7") break ;; "windows-amd64") TARGETS=("windows/amd64") break ;; "macos-amd64") TARGETS=("darwin/amd64") break ;; "macos-arm64") TARGETS=("darwin/arm64") break ;; "All Arch") TARGETS=("linux/amd64" "linux/arm/7" "windows/amd64" "darwin/amd64" "darwin/arm64") break ;; "Quit") exit 0 ;; *) echo "Opțiune invalidă $REPLY";; esac done echo "" echo "🏷️ Select Build Tags:" notify_human_interaction tag_options=("bindata" "bindata sqlite sqlite_unlock_notify" "Quit") select opt in "${tag_options[@]}" do case $opt in "bindata") BUILD_TAGS="bindata" break ;; "bindata sqlite sqlite_unlock_notify") BUILD_TAGS="bindata sqlite sqlite_unlock_notify" BUILD_VARIANT="sqlite" break ;; "Quit") exit 0 ;; *) echo "Opțiune invalidă $REPLY";; esac done if [ -z "$BUILD_VARIANT" ]; then BUILD_VARIANT="default" fi BUILD_REF="$(resolve_build_ref)" BUILD_REF="${BUILD_REF//\//-}" echo "🏷️ Build tag/reference: $BUILD_REF" bindata_needs_update() { local source_dir="$1" local bindata_file="$2" if [ ! -f "$bindata_file" ]; then return 0 fi find "$source_dir" -type f -newer "$bindata_file" -print -quit 2>/dev/null | grep -q . } ensure_bindata_asset() { local label="$1" local source_dir="$2" local go_package="$3" local bindata_file="$4" if bindata_needs_update "$source_dir" "$bindata_file"; then echo "♻️ Regenerating $label bindata..." if ! CC= GOOS= GOARCH= CGO_ENABLED=0 go generate -tags bindata "$go_package"; then echo "❌ Failed to regenerate $label bindata." exit 1 fi else echo "✅ $label bindata is up to date." fi } ensure_bindata_assets() { if [[ " $BUILD_TAGS " != *" bindata "* ]]; then return fi echo "🔎 Checking embedded bindata assets..." ensure_bindata_asset "templates" "templates" "./modules/templates" "modules/templates/bindata.dat" ensure_bindata_asset "options" "options" "./modules/options" "modules/options/bindata.dat" ensure_bindata_asset "public" "public" "./modules/public" "modules/public/bindata.dat" ensure_bindata_asset "migration schemas" "modules/migration/schemas" "./modules/migration" "modules/migration/bindata.dat" } ensure_bindata_assets build_darwin_sqlite_target() { local arch="$1" local output="$2" local repo_root temp_dist built_file output_abs local built_files=() require_docker_for_darwin_sqlite repo_root="$(resolve_darwin_sqlite_repo_root)" validate_repo_bind_mount_for_darwin_sqlite "$repo_root" output_abs="$(pwd -P)/$output" temp_dist="$repo_root/dist/.smart-build-darwin-${arch}-$$" rm -rf "$temp_dist" if ! mkdir -p "$temp_dist"; then echo "❌ Failed to create a temporary macOS release directory in dist/." exit 1 fi echo "📦 Building for darwin/$arch with TAGS=\"$BUILD_TAGS\" via release-darwin..." if ! make -C "$repo_root" release-darwin TAGS="$BUILD_TAGS" DARWIN_ARCHS="darwin-10.12/$arch" DIST="$temp_dist"; then rm -rf "$temp_dist" echo "❌ Fail to build for darwin/$arch with SQLite" exit 1 fi mapfile -t built_files < <(find "$temp_dist/binaries" -maxdepth 1 -type f | sort) if [ "${#built_files[@]}" -ne 1 ]; then rm -rf "$temp_dist" echo "❌ Unexpected macOS artifact count for darwin/$arch: ${#built_files[@]}" exit 1 fi built_file="${built_files[0]}" mv "$built_file" "$output_abs" rm -rf "$temp_dist" write_sha256_file "$output_abs" echo "✅ Created: $output_abs" echo "✅ Created: $output_abs.sha256" } build_standard_target() { local os="$1" local arch="$2" local arm_ver="$3" local output="$4" local ext="$5" export GOOS=$os export GOARCH=$arch export GOARM=$arm_ver export CGO_ENABLED=0 if [ "$BUILD_VARIANT" == "sqlite" ]; then export CGO_ENABLED=1 fi if make build TAGS="$BUILD_TAGS"; then mv "gitea$ext" "$output" write_sha256_file "$output" echo "✅ Created: $output" echo "✅ Created: $output.sha256" else echo "❌ Fail to build for $os/$arch${arm_ver:+/v$arm_ver}" exit 1 fi } # --- 4. COMPILARE --- mkdir -p dist for TARGET in "${TARGETS[@]}"; do IFS="/" read -r OS ARCH ARM_VER <<< "$TARGET" EXT="" && [ "$OS" == "windows" ] && EXT=".exe" PLATFORM="$ARCH" && [ ! -z "$ARM_VER" ] && PLATFORM="armv$ARM_VER" VARIANT_SUFFIX="" && [ "$BUILD_VARIANT" == "sqlite" ] && VARIANT_SUFFIX="-sqlite" OUTPUT="dist/gitea-$BUILD_REF-$OS-$PLATFORM$VARIANT_SUFFIX$EXT" if [ "$OS" == "darwin" ] && [ "$BUILD_VARIANT" == "sqlite" ]; then build_darwin_sqlite_target "$ARCH" "$OUTPUT" else echo "📦 Building for $OS/$ARCH ${ARM_VER:+(v$ARM_VER) }with TAGS=\"$BUILD_TAGS\"..." build_standard_target "$OS" "$ARCH" "$ARM_VER" "$OUTPUT" "$EXT" fi unset GOOS GOARCH GOARM CGO_ENABLED done echo "✨ Buid finished. Get file(s) from /dist" go clean -cache # || true