Skip to content

Instantly share code, notes, and snippets.

@pansapiens
Last active July 4, 2026 03:16
Show Gist options
  • Select an option

  • Save pansapiens/57d08c6ff616e4b2bced300dc5449d46 to your computer and use it in GitHub Desktop.

Select an option

Save pansapiens/57d08c6ff616e4b2bced300dc5449d46 to your computer and use it in GitHub Desktop.
Build a Debian/Ubuntu package for Antigravity IDE 2.x
#!/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