diff --git a/scripts/build_sandbox.js b/scripts/build_sandbox.js index 7eece434..ef6b0686 100644 --- a/scripts/build_sandbox.js +++ b/scripts/build_sandbox.js @@ -20,6 +20,7 @@ import { execSync } from 'child_process'; import { chmodSync, existsSync, readFileSync, rmSync, writeFileSync } from 'fs'; import { join } from 'path'; +import os from 'os'; import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; import cliPkgJson from '../packages/cli/package.json' with { type: 'json' }; @@ -117,12 +118,28 @@ chmodSync( const buildStdout = process.env.VERBOSE ? 'inherit' : 'ignore'; +// Determine the appropriate shell based on OS +const isWindows = os.platform() === 'win32'; +const shellToUse = isWindows ? 'powershell.exe' : '/bin/bash'; + function buildImage(imageName, dockerfile) { console.log(`building ${imageName} ... (can be slow first time)`); - const buildCommand = - sandboxCommand === 'podman' - ? `${sandboxCommand} build --authfile=<(echo '{}')` - : `${sandboxCommand} build`; + + let buildCommandArgs = ''; + let tempAuthFile = ''; + + if (sandboxCommand === 'podman') { + if (isWindows) { + // PowerShell doesn't support <() process substitution. + // Create a temporary auth file that we will clean up after. + tempAuthFile = join(os.tmpdir(), `gemini-auth-${Date.now()}.json`); + writeFileSync(tempAuthFile, '{}'); + buildCommandArgs = `--authfile="${tempAuthFile}"`; + } else { + // Use bash-specific syntax for Linux/macOS + buildCommandArgs = `--authfile=<(echo '{}')`; + } + } const npmPackageVersion = JSON.parse( readFileSync(join(process.cwd(), 'package.json'), 'utf-8'), @@ -132,27 +149,34 @@ function buildImage(imageName, dockerfile) { process.env.GEMINI_SANDBOX_IMAGE_TAG || imageName.split(':')[1]; const finalImageName = `${imageName.split(':')[0]}:${imageTag}`; - execSync( - `${buildCommand} ${ - process.env.BUILD_SANDBOX_FLAGS || '' - } --build-arg CLI_VERSION_ARG=${npmPackageVersion} -f "${dockerfile}" -t "${finalImageName}" .`, - { stdio: buildStdout, shell: '/bin/bash' }, - ); - console.log(`built ${finalImageName}`); - - // If an output file path was provided via command-line, write the final image URI to it. - if (argv.outputFile) { - console.log( - `Writing final image URI for CI artifact to: ${argv.outputFile}`, + try { + execSync( + `${sandboxCommand} build ${buildCommandArgs} ${ + process.env.BUILD_SANDBOX_FLAGS || '' + } --build-arg CLI_VERSION_ARG=${npmPackageVersion} -f "${dockerfile}" -t "${imageName}" .`, + { stdio: buildStdout, shell: shellToUse }, ); - // The publish step only supports one image. If we build multiple, only the last one - // will be published. Throw an error to make this failure explicit if the file already exists. - if (existsSync(argv.outputFile)) { - throw new Error( - `CI artifact file ${argv.outputFile} already exists. Refusing to overwrite.`, + console.log(`built ${finalImageName}`); + + // If an output file path was provided via command-line, write the final image URI to it. + if (argv.outputFile) { + console.log( + `Writing final image URI for CI artifact to: ${argv.outputFile}`, ); + // The publish step only supports one image. If we build multiple, only the last one + // will be published. Throw an error to make this failure explicit if the file already exists. + if (existsSync(argv.outputFile)) { + throw new Error( + `CI artifact file ${argv.outputFile} already exists. Refusing to overwrite.`, + ); + } + writeFileSync(argv.outputFile, finalImageName); + } + } finally { + // If we created a temp file, delete it now. + if (tempAuthFile) { + rmSync(tempAuthFile, { force: true }); } - writeFileSync(argv.outputFile, finalImageName); } }