Last active
July 4, 2026 03:16
-
-
Save pansapiens/57d08c6ff616e4b2bced300dc5449d46 to your computer and use it in GitHub Desktop.
Build a Debian/Ubuntu package for Antigravity IDE 2.x
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -euo pipefail | |
| # Antigravity ships two distinct Linux products on https://antigravity.google/download: | |
| # - "Antigravity IDE" (id=antigravity-ide) -> classic VS Code-like editor (default, most commonly wanted) | |
| # - "Antigravity" (id=antigravity-2) -> the newer standalone app/CLI product | |
| # Their JS-driven download page lists both, so we must select the URL that | |
| # belongs to the requested product's card rather than just grabbing the first | |
| # linux-x64 tar.gz link found (which previously grabbed the wrong product). | |
| VARIANT="${VARIANT:-ide}" | |
| while [ $# -gt 0 ]; do | |
| case "$1" in | |
| -v|--variant) | |
| VARIANT="$2" | |
| shift 2 | |
| ;; | |
| --variant=*) | |
| VARIANT="${1#*=}" | |
| shift | |
| ;; | |
| *) | |
| echo "Unknown argument: $1" >&2 | |
| echo "Usage: $0 [--variant ide|app]" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| case "${VARIANT}" in | |
| ide) | |
| PACKAGE_NAME="antigravity-ide" | |
| DISPLAY_NAME="Antigravity IDE" | |
| FALLBACK_VERSION="2.1.1" | |
| FALLBACK_URL="https://edgedl.me.gvt1.com/edgedl/release2/j0qc3/antigravity/stable/2.1.1-6123990880747520/linux-x64/Antigravity%20IDE.tar.gz" | |
| ;; | |
| app) | |
| PACKAGE_NAME="antigravity" | |
| DISPLAY_NAME="Antigravity" | |
| FALLBACK_VERSION="2.2.1" | |
| FALLBACK_URL="https://storage.googleapis.com/antigravity-public/antigravity-hub/2.2.1-5287492581195776/linux-x64/Antigravity.tar.gz" | |
| ;; | |
| *) | |
| echo "Error: unknown variant '${VARIANT}' (expected 'ide' or 'app')" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| echo "Building variant: ${VARIANT} (package: ${PACKAGE_NAME})" | |
| # Allow overriding the package version and URL via environment variables | |
| VERSION="${VERSION:-}" | |
| URL="${URL:-}" | |
| if [ -z "${VERSION}" ] || [ -z "${URL}" ]; then | |
| echo "Attempting to dynamically fetch latest version and URL..." | |
| if HTML_CONTENT=$(curl -s -L -f --compressed "https://antigravity.google/download"); then | |
| if JS_FILE=$(echo "${HTML_CONTENT}" | grep -o -E "main-[a-zA-Z0-9_.-]+\.js" | head -n 1); then | |
| JS_CONTENT=$(curl -s -L -f --compressed "https://antigravity.google/${JS_FILE}") | |
| if [ "${VARIANT}" = "ide" ]; then | |
| FETCHED_URL=$(echo "${JS_CONTENT}" | perl -0777 -ne 'print $1 if /title:"Antigravity IDE".{0,4000}?(https:\/\/[^"]+\/linux-x64\/Antigravity[^"]*\.tar\.gz)/s') | |
| else | |
| FETCHED_URL=$(echo "${JS_CONTENT}" | perl -0777 -ne 'print $1 if /title:"Antigravity [0-9][^"]*".{0,4000}?(https:\/\/[^"]+\/linux-x64\/Antigravity[^"]*\.tar\.gz)/s') | |
| fi | |
| if [ -n "${FETCHED_URL}" ]; then | |
| FETCHED_URL="${FETCHED_URL// /%20}" | |
| if [[ "${FETCHED_URL}" =~ /([0-9][^/]+)/linux-x64/ ]]; then | |
| DIR_VERSION="${BASH_REMATCH[1]}" | |
| FETCHED_VERSION="${DIR_VERSION%%-*}" | |
| if [ -z "${VERSION}" ]; then | |
| VERSION="${FETCHED_VERSION}" | |
| fi | |
| if [ -z "${URL}" ]; then | |
| URL="${FETCHED_URL}" | |
| fi | |
| echo "Successfully fetched version: ${VERSION}" | |
| echo "Fetched URL: ${URL}" | |
| fi | |
| fi | |
| fi | |
| fi | |
| fi | |
| # Fallback to default values if not successfully set | |
| if [ -z "${VERSION}" ] || [ -z "${URL}" ]; then | |
| echo "Dynamic fetch failed or was bypassed. Using hardcoded fallbacks." | |
| VERSION="${VERSION:-${FALLBACK_VERSION}}" | |
| URL="${URL:-${FALLBACK_URL}}" | |
| fi | |
| WORKSPACE_DIR="$(pwd)/Antigravity_IDE" | |
| BUILD_DIR="${WORKSPACE_DIR}/build_temp" | |
| # Clean up any existing directory from previous aborted builds | |
| if [ -d "${BUILD_DIR}" ]; then | |
| rm -rf "${BUILD_DIR}" | |
| fi | |
| # Create package staging directory structures | |
| mkdir -p "${BUILD_DIR}/extracted" | |
| mkdir -p "${BUILD_DIR}/pkg/DEBIAN" | |
| mkdir -p "${BUILD_DIR}/pkg/opt/${PACKAGE_NAME}" | |
| mkdir -p "${BUILD_DIR}/pkg/usr/share/applications" | |
| mkdir -p "${BUILD_DIR}/pkg/usr/share/pixmaps" | |
| mkdir -p "${BUILD_DIR}/pkg/usr/bin" | |
| echo "Downloading ${DISPLAY_NAME}..." | |
| curl -L -o "${BUILD_DIR}/${PACKAGE_NAME}.tar.gz" "${URL}" | |
| echo "Extracting archive..." | |
| tar -xzf "${BUILD_DIR}/${PACKAGE_NAME}.tar.gz" -C "${BUILD_DIR}/extracted" | |
| # Dynamically locate the main application directory to avoid hardcoding naming variations | |
| EXTRACTED_DIR=$(find "${BUILD_DIR}/extracted" -maxdepth 2 -type f -name "${PACKAGE_NAME}" -exec dirname {} \; | head -n 1) | |
| if [ -z "${EXTRACTED_DIR}" ]; then | |
| echo "Error: Could not locate ${PACKAGE_NAME} binary in extracted archive." >&2 | |
| exit 1 | |
| fi | |
| echo "Copying application files..." | |
| cp -r "${EXTRACTED_DIR}"/* "${BUILD_DIR}/pkg/opt/${PACKAGE_NAME}/" | |
| echo "Extracting icon..." | |
| CLASSIC_ICON="${BUILD_DIR}/pkg/opt/${PACKAGE_NAME}/resources/app/resources/linux/code.png" | |
| if [ -f "${CLASSIC_ICON}" ]; then | |
| cp "${CLASSIC_ICON}" "${BUILD_DIR}/pkg/usr/share/pixmaps/${PACKAGE_NAME}.png" | |
| else | |
| (cd "${BUILD_DIR}" && npx --yes asar extract-file "${BUILD_DIR}/pkg/opt/${PACKAGE_NAME}/resources/app.asar" icon.png) | |
| mv "${BUILD_DIR}/icon.png" "${BUILD_DIR}/pkg/usr/share/pixmaps/${PACKAGE_NAME}.png" | |
| fi | |
| echo "Creating CLI symlink..." | |
| CLASSIC_CLI="${BUILD_DIR}/pkg/opt/${PACKAGE_NAME}/bin/${PACKAGE_NAME}" | |
| if [ -f "${CLASSIC_CLI}" ]; then | |
| ln -s "/opt/${PACKAGE_NAME}/bin/${PACKAGE_NAME}" "${BUILD_DIR}/pkg/usr/bin/${PACKAGE_NAME}" | |
| else | |
| ln -s "/opt/${PACKAGE_NAME}/${PACKAGE_NAME}" "${BUILD_DIR}/pkg/usr/bin/${PACKAGE_NAME}" | |
| fi | |
| echo "Creating desktop entry..." | |
| cat << EOF >"${BUILD_DIR}/pkg/usr/share/applications/${PACKAGE_NAME}.desktop" | |
| [Desktop Entry] | |
| Name=${DISPLAY_NAME} | |
| Comment=${DISPLAY_NAME} Code Editor | |
| GenericName=Text Editor | |
| Exec=/opt/${PACKAGE_NAME}/${PACKAGE_NAME} %F | |
| Icon=${PACKAGE_NAME} | |
| Type=Application | |
| StartupNotify=true | |
| StartupWMClass=${PACKAGE_NAME} | |
| Categories=Utility;TextEditor;Development;IDE; | |
| MimeType=text/plain;inode/directory; | |
| Actions=new-empty-window; | |
| [Desktop Action new-empty-window] | |
| Name=New Empty Window | |
| Exec=/opt/${PACKAGE_NAME}/${PACKAGE_NAME} --new-window %F | |
| Icon=${PACKAGE_NAME} | |
| EOF | |
| echo "Creating DEBIAN/control..." | |
| cat << EOF >"${BUILD_DIR}/pkg/DEBIAN/control" | |
| Package: ${PACKAGE_NAME} | |
| Version: ${VERSION} | |
| Section: devel | |
| Priority: optional | |
| Architecture: amd64 | |
| Depends: libasound2, libatk1.0-0, libc6, libcairo2, libcups2, libdbus-1-3, libexpat1, libfontconfig1, libfreetype6, libgbm1, libglib2.0-0, libgtk-3-0, libnspr4, libnss3, libpango-1.0-0, libpangocairo-1.0-0, libsecret-1-0, libx11-6, libx11-xcb1, libxcb1, libxcomposite1, libxcursor1, libxdamage1, libxext6, libxfixes3, libxi6, libxrandr2, libxrender1, libxss1, libxtst6, libgl1 | |
| Maintainer: Antigravity IDE Team <support@antigravity.google> | |
| Description: ${DISPLAY_NAME} - Code Editor | |
| A powerful agentic AI coding assistant and IDE. | |
| EOF | |
| # The postinst script is run as root by the package manager during installation. | |
| # This allows us to set setuid on the chrome-sandbox binary. | |
| echo "Creating DEBIAN/postinst..." | |
| cat << EOF >"${BUILD_DIR}/pkg/DEBIAN/postinst" | |
| #!/bin/bash | |
| set -e | |
| # Make chrome-sandbox setuid root to enable Chromium's SUID sandbox | |
| if [ -f "/opt/${PACKAGE_NAME}/chrome-sandbox" ]; then | |
| chown root:root "/opt/${PACKAGE_NAME}/chrome-sandbox" | |
| chmod 4755 "/opt/${PACKAGE_NAME}/chrome-sandbox" | |
| fi | |
| # Ensure executable permissions on essential binaries | |
| chmod +x "/opt/${PACKAGE_NAME}/${PACKAGE_NAME}" | |
| chmod +x "/opt/${PACKAGE_NAME}/chrome_crashpad_handler" | |
| if [ -f "/opt/${PACKAGE_NAME}/bin/${PACKAGE_NAME}" ]; then | |
| chmod +x "/opt/${PACKAGE_NAME}/bin/${PACKAGE_NAME}" | |
| fi | |
| # Update Gnome desktop entries cache | |
| if [ -x "\$(command -v update-desktop-database)" ]; then | |
| update-desktop-database -q | |
| fi | |
| EOF | |
| # Make postinst executable so dpkg can run it | |
| chmod 755 "${BUILD_DIR}/pkg/DEBIAN/postinst" | |
| # Build the package. We use --root-owner-group so the built archive structure is | |
| # owned by root:root rather than the local building user. | |
| echo "Building deb package..." | |
| dpkg-deb --root-owner-group --build "${BUILD_DIR}/pkg" "${WORKSPACE_DIR}/${PACKAGE_NAME}_${VERSION}_amd64.deb" | |
| # Clean up build artifacts | |
| rm -rf "${BUILD_DIR}" | |
| echo "Build complete: ${WORKSPACE_DIR}/${PACKAGE_NAME}_${VERSION}_amd64.deb" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment