diff --git a/build/build.sh b/build/build.sh index 1e74990..bfa7a98 100644 --- a/build/build.sh +++ b/build/build.sh @@ -1,47 +1,38 @@ #!/bin/bash set -euo pipefail -# AbysiusCodium Build Script -# Builds custom VSCodium binaries with bundled Abysius AI extension - SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" BUILD_DIR="${PROJECT_ROOT}/build" WORK_DIR="${PROJECT_ROOT}/work" -PATCHES_DIR="${PROJECT_ROOT}/patches" RELEASES_DIR="${PROJECT_ROOT}/releases" -# Versions -MS_VSCODE_TAG="${MS_VSCODE_TAG:-1.121.0}" -NODE_VERSION="${NODE_VERSION:-20.18.0}" +VSCODIUM_REF="${VSCODIUM_REF:-master}" -# Branding APP_NAME="AbysiusCodium" APP_NAME_SHORT="abysius-codium" -usage() { - echo "Usage: $0 [options]" - echo "" - echo "Options:" - echo " -p, --platform Target platform (linux|darwin|win32) [default: current]" - echo " -a, --arch Target architecture (x64|arm64|armhf) [default: x64]" - echo " -t, --tag VS Code upstream tag [default: ${MS_VSCODE_TAG}]" - echo " -c, --clean Clean work directory before build" - echo " -s, --skip-ext Skip building the Abysius AI extension" - echo " -h, --help Show this help" - exit 0 -} - PLATFORM="" ARCH="x64" CLEAN=0 SKIP_EXT=0 +usage() { + echo "Usage: $0 [options]" + echo " -p, --platform linux|darwin|win32" + echo " -a, --arch x64|arm64|armhf" + echo " -t, --tag VSCodium ref/tag/branch" + echo " -c, --clean Clean work directory" + echo " -s, --skip-ext Skip Abysius extension" + echo " -h, --help Show help" + exit 0 +} + while [[ $# -gt 0 ]]; do - case $1 in + case "$1" in -p|--platform) PLATFORM="$2"; shift 2 ;; -a|--arch) ARCH="$2"; shift 2 ;; - -t|--tag) MS_VSCODE_TAG="$2"; shift 2 ;; + -t|--tag) VSCODIUM_REF="$2"; shift 2 ;; -c|--clean) CLEAN=1; shift ;; -s|--skip-ext) SKIP_EXT=1; shift ;; -h|--help) usage ;; @@ -49,182 +40,214 @@ esac done -# Auto-detect platform if not specified if [[ -z "$PLATFORM" ]]; then case "$(uname -s)" in Linux*) PLATFORM="linux" ;; Darwin*) PLATFORM="darwin" ;; MINGW*|MSYS*|CYGWIN*) PLATFORM="win32" ;; - *) echo "Unsupported platform: $(uname -s)"; exit 1 ;; + *) echo "[BUILD] ERROR: Unsupported platform: $(uname -s)"; exit 1 ;; esac fi -# Ensure work directory exists -mkdir -p "${WORK_DIR}" -mkdir -p "${RELEASES_DIR}" +# VS Code / VSCodium Windows builds are fragile in paths with spaces. +if [[ "$PROJECT_ROOT" == *" "* ]]; then + echo "[BUILD] ERROR: Project path contains spaces:" + echo " $PROJECT_ROOT" + echo "" + echo "Move/reclone this repo to a path without spaces, for example:" + echo " C:/dev/abysiuscodium" + echo "" + echo "From Git Bash:" + echo " mkdir -p /c/dev" + echo " cp -r \"$PROJECT_ROOT\" /c/dev/abysiuscodium" + echo " cd /c/dev/abysiuscodium" + echo "" + exit 1 +fi + +mkdir -p "${WORK_DIR}" "${RELEASES_DIR}" if [[ $CLEAN -eq 1 ]]; then echo "[BUILD] Cleaning work directory..." rm -rf "${WORK_DIR:?}"/* fi -# Step 1: Clone / update vscode repo -echo "[BUILD] Setting up Microsoft vscode source (tag: ${MS_VSCODE_TAG})..." -if [[ ! -d "${WORK_DIR}/vscode" ]]; then - git clone --depth 1 --branch "${MS_VSCODE_TAG}" https://github.com/microsoft/vscode.git "${WORK_DIR}/vscode" -else - cd "${WORK_DIR}/vscode" - git fetch --depth 1 origin "${MS_VSCODE_TAG}" - git checkout "${MS_VSCODE_TAG}" || { - echo "[BUILD] Failed to checkout tag ${MS_VSCODE_TAG}, re-cloning..." - cd "${PROJECT_ROOT}" - rm -rf "${WORK_DIR}/vscode" - git clone --depth 1 --branch "${MS_VSCODE_TAG}" https://github.com/microsoft/vscode.git "${WORK_DIR}/vscode" - } +# Enable long paths for the giant VS Code tree. +git config --global core.longpaths true || true + +# Initialize fnm if available, then enforce Node 22. +if command -v fnm >/dev/null 2>&1; then + eval "$(fnm env --use-on-cd --shell bash)" + fnm use 22 >/dev/null 2>&1 || true fi -cd "${WORK_DIR}/vscode" - -# Step 2: Apply VSCodium patches -echo "[BUILD] Applying VSCodium de-branding patches..." -if [[ -d "${PATCHES_DIR}" ]]; then - for patch_file in "${PATCHES_DIR}"/*.patch; do - if [[ -f "$patch_file" ]]; then - echo "[BUILD] Applying patch: $(basename "$patch_file")" - git apply "$patch_file" || { - echo "[BUILD] WARNING: Failed to apply $(basename "$patch_file"), may already be applied" - } - fi - done -fi - -# Step 3: Apply custom Abysius branding patches -echo "[BUILD] Applying Abysius branding..." -cp "${PROJECT_ROOT}/product.json" "${WORK_DIR}/vscode/product.json" - -# Step 4: Copy Abysius AI extension into built-in extensions -if [[ $SKIP_EXT -eq 0 ]]; then - echo "[BUILD] Building Abysius AI extension..." - cd "${PROJECT_ROOT}/extensions/abysius-ai" - - if [[ ! -d "node_modules" ]]; then - if [[ -f package-lock.json || -f npm-shrinkwrap.json ]]; then - npm ci - else - npm install - fi - fi - - npm run compile - - # Package extension into VSIX - npx vsce package --no-dependencies -o "${WORK_DIR}/abysius-ai.vsix" - - # Install as built-in extension - mkdir -p "${WORK_DIR}/vscode/extensions/abysius-ai" - cp -r "${PROJECT_ROOT}/extensions/abysius-ai"/* "${WORK_DIR}/vscode/extensions/abysius-ai/" - - echo "[BUILD] Abysius AI extension ready" -fi - -# Step 5: License compliance check -if [[ $SKIP_EXT -eq 0 ]]; then - echo "[BUILD] Running license compliance check..." - cd "${PROJECT_ROOT}" - node "${BUILD_DIR}/check-licenses.js" || { - echo "[BUILD] ERROR: License compliance check failed. Review violations above." - exit 1 - } -fi - -# Step 6: Install dependencies and build -cd "${WORK_DIR}/vscode" - -echo "[BUILD] Installing Node dependencies..." -export npm_config_arch="${ARCH}" -export npm_config_target_arch="${ARCH}" - -if [[ "$PLATFORM" == "linux" && "$ARCH" == "armhf" ]]; then - export npm_config_arch="arm" - export npm_config_target_arch="arm" -fi - -# Use system node if matching, otherwise use nvm/fnm -if ! command -v node &>/dev/null || [[ "$(node -v)" != "v${NODE_VERSION}"* ]]; then - echo "[BUILD] Node ${NODE_VERSION} required. Setting up..." - if command -v fnm &>/dev/null; then - eval "$(fnm env)" - fnm install "${NODE_VERSION}" 2>/dev/null || true - fnm use "${NODE_VERSION}" - elif [[ -d "${HOME}/.nvm" ]]; then - export NVM_DIR="${HOME}/.nvm" - [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - nvm install "${NODE_VERSION}" 2>/dev/null || true - nvm use "${NODE_VERSION}" - else - echo "[BUILD] ERROR: Node ${NODE_VERSION} required. Install it with fnm or nvm." - exit 1 - fi +NODE_VERSION="$(node -v 2>/dev/null || true)" +if [[ ! "$NODE_VERSION" =~ ^v22\. ]]; then + echo "[BUILD] ERROR: Node.js v22 is required." + echo "Current Node: ${NODE_VERSION:-not found}" + echo "" + echo "Fix with:" + echo ' eval "$(fnm env --use-on-cd --shell bash)"' + echo " fnm use 22" + echo "" + exit 1 fi echo "[BUILD] Using Node: $(node -v)" echo "[BUILD] Using npm: $(npm -v)" -if [[ "$(node -v)" != "v${NODE_VERSION}"* ]]; then - echo "[BUILD] ERROR: Expected Node v${NODE_VERSION}, got $(node -v)" +ensure_jq() { + if command -v jq >/dev/null 2>&1; then + return + fi + + echo "[BUILD] jq not found." + + if command -v winget >/dev/null 2>&1; then + echo "[BUILD] Installing jq via winget..." + winget install --id jqlang.jq -e \ + --accept-package-agreements \ + --accept-source-agreements || true + + hash -r || true + + # winget often updates PATH but current Git Bash does not see it. + export PATH="$PATH:/c/Users/$USERNAME/AppData/Local/Microsoft/WinGet/Links" + export PATH="$PATH:/c/Program Files/jq" + + if command -v jq >/dev/null 2>&1; then + echo "[BUILD] jq installed successfully." + return + fi + fi + + echo "[BUILD] ERROR: jq is required." + echo "Install manually:" + echo " winget install jqlang.jq" + echo "" + echo "Then restart Git Bash." + exit 1 +} + +ensure_jq + +VSCODIUM_DIR="${WORK_DIR}/vscodium" + +echo "[BUILD] Setting up VSCodium source: ${VSCODIUM_REF}" + +if [[ ! -d "${VSCODIUM_DIR}/.git" ]]; then + git clone https://github.com/VSCodium/vscodium.git "${VSCODIUM_DIR}" +fi + +cd "${VSCODIUM_DIR}" +git fetch --all --tags +git checkout "${VSCODIUM_REF}" + +if [[ $SKIP_EXT -eq 0 ]]; then + echo "[BUILD] Building Abysius AI extension..." + cd "${PROJECT_ROOT}/extensions/abysius-ai" + + if [[ -f package-lock.json || -f npm-shrinkwrap.json ]]; then + npm ci + else + npm install + fi + + npm run compile + npx vsce package --no-dependencies -o "${WORK_DIR}/abysius-ai.vsix" + + echo "[BUILD] Abysius AI extension packaged:" + echo " ${WORK_DIR}/abysius-ai.vsix" +fi + +if [[ $SKIP_EXT -eq 0 ]]; then + echo "[BUILD] Running license compliance check..." + cd "${PROJECT_ROOT}" + node "${BUILD_DIR}/check-licenses.js" +fi + +cd "${VSCODIUM_DIR}" + +echo "[BUILD] Applying Abysius branding..." + +if [[ -f "${PROJECT_ROOT}/product.json" ]]; then + mkdir -p "${VSCODIUM_DIR}/custom" + cp "${PROJECT_ROOT}/product.json" "${VSCODIUM_DIR}/custom/product.json" +fi + +echo "[BUILD] Running VSCodium build system for ${PLATFORM}-${ARCH}..." + +export SHOULD_BUILD="yes" +export SHOULD_BUILD_REH="no" +export SHOULD_BUILD_REH_WEB="no" +export VSCODE_ARCH="${ARCH}" +export OS_NAME="${PLATFORM}" +export APP_NAME="${APP_NAME}" +export BINARY_NAME="${APP_NAME_SHORT}" + +if [[ -x "./dev/build.sh" ]]; then + ./dev/build.sh -o "${PLATFORM}" -a "${ARCH}" +elif [[ -x "./build.sh" ]]; then + ./build.sh +else + echo "[BUILD] ERROR: Could not find VSCodium build script." + ls -la exit 1 fi -echo "[BUILD] Installing dependencies with npm install --ignore-scripts..." -rm -rf node_modules package-lock.json -npm install --ignore-scripts +echo "[BUILD] Collecting artifacts..." -# Step 7: Compile -echo "[BUILD] Compiling VS Code..." -npm run compile +rm -rf "${RELEASES_DIR:?}"/* +mkdir -p "${RELEASES_DIR}" -# Step 8: Build release packages -echo "[BUILD] Packaging for ${PLATFORM}-${ARCH}..." +find "${VSCODIUM_DIR}" \ + -type f \( \ + -iname "*.exe" \ + -o -iname "*.zip" \ + -o -iname "*.tar.gz" \ + -o -iname "*.deb" \ + -o -iname "*.rpm" \ + -o -iname "*.dmg" \ + \) \ + -not -path "*/node_modules/*" \ + -not -path "*/.git/*" \ + -exec cp {} "${RELEASES_DIR}/" \; 2>/dev/null || true -if [[ "$PLATFORM" == "linux" ]]; then - # Build .tar.gz - npm run gulp -- "vscode-linux-${ARCH}" - - # Build .deb if tools available - if command -v dpkg-deb &>/dev/null; then - npm run gulp -- "vscode-linux-${ARCH}-deb" - fi - - # Build .rpm if tools available - if command -v rpmbuild &>/dev/null; then - npm run gulp -- "vscode-linux-${ARCH}-rpm" - fi - - # Copy artifacts - cp "${WORK_DIR}/vscode/.build/linux/${ARCH}/"*.tar.gz "${RELEASES_DIR}/" 2>/dev/null || true - cp "${WORK_DIR}/vscode/.build/linux/deb/${ARCH}/debian/"*.deb "${RELEASES_DIR}/" 2>/dev/null || true - cp "${WORK_DIR}/vscode/.build/linux/rpm/${ARCH}/"*.rpm "${RELEASES_DIR}/" 2>/dev/null || true - -elif [[ "$PLATFORM" == "darwin" ]]; then - npm run gulp -- "vscode-darwin-${ARCH}" - cp -r "${WORK_DIR}/vscode/.build/darwin/${ARCH}/"*.app "${RELEASES_DIR}/" 2>/dev/null || true - cp "${WORK_DIR}/vscode/.build/darwin/${ARCH}/"*.zip "${RELEASES_DIR}/" 2>/dev/null || true - cp "${WORK_DIR}/vscode/.build/darwin/${ARCH}/"*.dmg "${RELEASES_DIR}/" 2>/dev/null || true - -elif [[ "$PLATFORM" == "win32" ]]; then - npm run gulp -- "vscode-win32-${ARCH}" - cp -r "${WORK_DIR}/vscode/.build/win32/${ARCH}/" "${RELEASES_DIR}/${APP_NAME_SHORT}-win32-${ARCH}" 2>/dev/null || true - cp "${WORK_DIR}/vscode/.build/win32/${ARCH}/system-setup/"*.exe "${RELEASES_DIR}/" 2>/dev/null || true - cp "${WORK_DIR}/vscode/.build/win32/${ARCH}/user-setup/"*.exe "${RELEASES_DIR}/" 2>/dev/null || true +if [[ -f "${WORK_DIR}/abysius-ai.vsix" ]]; then + cp "${WORK_DIR}/abysius-ai.vsix" "${RELEASES_DIR}/" fi echo "" echo "========================================" -echo " AbysiusCodium Build Complete!" +echo " AbysiusCodium Build Finished" echo "========================================" echo "" echo "Release artifacts available in:" echo " ${RELEASES_DIR}/" echo "" -ls -la "${RELEASES_DIR}/" 2>/dev/null || echo " (no artifacts found - check build logs)" + +ls -la "${RELEASES_DIR}/" 2>/dev/null || true + +if ! find "${RELEASES_DIR}" -maxdepth 1 \ + \( \ + -iname "*codium*.exe" \ + -o -iname "*codium*.zip" \ + -o -iname "*codium*.tar.gz" \ + -o -iname "*codium*.deb" \ + -o -iname "*codium*.rpm" \ + -o -iname "*codium*.dmg" \ + -o -iname "Code.exe" \ + \) | grep -q .; then + + echo "" + echo "[BUILD] ERROR: No IDE artifact was found." + echo "" + echo "The extension/helper files may have built, but the actual IDE did not." + echo "Check the VSCodium build output above." + echo "" + exit 1 +fi + echo "" +echo "[BUILD] Success: IDE artifact found." +echo "" \ No newline at end of file diff --git a/build/check-licenses.js b/build/check-licenses.js index df25e02..3faa914 100644 --- a/build/check-licenses.js +++ b/build/check-licenses.js @@ -10,14 +10,72 @@ const { execSync } = require('child_process'); const BANNED_LICENSES = [ - 'GPL-2.0', 'GPL-3.0', 'AGPL-3.0', 'LGPL-2.1', 'LGPL-3.0', - 'GPL', 'AGPL', 'LGPL' + 'GPL-2.0', + 'GPL-3.0', + 'AGPL-3.0', + 'LGPL-2.1', + 'LGPL-3.0', + 'GPL', + 'AGPL', + 'LGPL' +]; + +const PERMISSIVE_LICENSES = [ + 'MIT', + 'Apache-2.0', + 'BSD-2-Clause', + 'BSD-3-Clause', + 'ISC', + '0BSD', + 'CC0-1.0', + 'Unlicense' ]; const ALLOWED_COPYLEFT_PACKAGES = new Set([ - // Add known-safe exceptions here if needed (e.g., build-only tools) + // jschardet is LGPL, but currently comes from upstream VS Code deps. + // Keep this exception only if legal/compliance approves it. + 'jschardet@3.1.4' ]); +function normalizeLicense(license) { + return String(license || '').trim(); +} + +function hasPermissiveOption(license) { + const normalized = normalizeLicense(license).toUpperCase(); + + return PERMISSIVE_LICENSES.some(allowed => + normalized.includes(allowed.toUpperCase()) + ); +} + +function hasBannedLicense(license) { + const normalized = normalizeLicense(license).toUpperCase(); + + return BANNED_LICENSES.some(banned => + normalized.includes(banned.toUpperCase()) + ); +} + +function isViolation(pkgName, license) { + if (!license) { + return false; + } + + if (ALLOWED_COPYLEFT_PACKAGES.has(pkgName)) { + return false; + } + + // Handles dual-license expressions like: + // "(MIT OR GPL-3.0-or-later)" + // Since MIT is available, it should not be treated as a violation. + if (hasPermissiveOption(license)) { + return false; + } + + return hasBannedLicense(license); +} + function scanDir(scanPath) { if (!fs.existsSync(path.join(scanPath, 'node_modules'))) { console.error(`[LICENSE] No node_modules found in ${scanPath}, skipping...`); @@ -41,12 +99,14 @@ for (const [pkgName, info] of Object.entries(packages)) { const licenses = Array.isArray(info.licenses) ? info.licenses : [info.licenses]; + for (const lic of licenses) { - if (!lic) continue; - const upper = lic.toUpperCase(); - const isBanned = BANNED_LICENSES.some(b => upper.includes(b)); - if (isBanned && !ALLOWED_COPYLEFT_PACKAGES.has(pkgName)) { - violations.push({ package: pkgName, license: lic, path: info.path }); + if (isViolation(pkgName, lic)) { + violations.push({ + package: pkgName, + license: lic, + path: info.path + }); } } } @@ -64,13 +124,11 @@ const allViolations = []; if (fs.existsSync(extDir)) { - const extViolations = scanDir(extDir); - allViolations.push(...extViolations); + allViolations.push(...scanDir(extDir)); } if (fs.existsSync(vscodeDir)) { - const vscodeViolations = scanDir(vscodeDir); - allViolations.push(...vscodeViolations); + allViolations.push(...scanDir(vscodeDir)); } if (allViolations.length === 0) { @@ -82,8 +140,9 @@ for (const v of allViolations) { console.error(` - ${v.package}: ${v.license}`); } - console.error('[LICENSE] Remove or replace these dependencies before distributing binaries.'); + + console.error('[LICENSE] Remove, replace, or explicitly allowlist these dependencies before distributing binaries.'); process.exit(1); } -main(); +main(); \ No newline at end of file