diff --git a/dist/index.js b/dist/index.js index 0d40d32..6b4bf0f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -71269,6 +71269,29 @@ var activateEnvironment = async (environment) => { }; // src/main.ts +var fileExists = async (p) => { + try { + await import_promises2.default.access(p); + return true; + } catch { + return false; + } +}; +var readInstalledPixiVersion = async (binPath) => { + try { + const { stdout, exitCode } = await executeGetOutput([binPath, "--version"], { + silent: true, + ignoreReturnCode: true + }); + if (exitCode !== 0) { + return void 0; + } + const match2 = /\b(\d+\.\d+\.\d+\S*)/.exec(stdout); + return match2?.[1]; + } catch { + return void 0; + } +}; var downloadPixi = async (source) => { const url2 = renderPixiUrl(source.urlTemplate, source.version); await group("Downloading Pixi", async () => { @@ -71276,6 +71299,22 @@ var downloadPixi = async (source) => { debug(`Downloading pixi from ${url2}`); debug(`Using headers: ${JSON.stringify(source.headers)}`); await import_promises2.default.mkdir(import_path3.default.dirname(options.pixiBinPath), { recursive: true }); + if (await fileExists(options.pixiBinPath)) { + if (source.version !== "latest") { + const installed = await readInstalledPixiVersion(options.pixiBinPath); + const requested = source.version.replace(/^v/, ""); + if (installed && installed === requested) { + info(`Pixi ${installed} already installed at ${options.pixiBinPath}, skipping download`); + return; + } + info( + `Replacing existing pixi at ${options.pixiBinPath} (installed: ${installed ?? "unknown"}, requested: ${requested})` + ); + } else { + info(`Replacing existing pixi at ${options.pixiBinPath} (requested: latest)`); + } + await import_promises2.default.rm(options.pixiBinPath, { force: true }); + } await downloadTool(url2, options.pixiBinPath, void 0, source.headers); await import_promises2.default.chmod(options.pixiBinPath, 493); info(`Pixi installed to ${options.pixiBinPath}`); diff --git a/src/main.ts b/src/main.ts index 07bc87a..9e56480 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,10 +6,38 @@ import * as core from '@actions/core' import { downloadTool } from '@actions/tool-cache' import type { PixiSource } from './options' import { options } from './options' -import { execute, pixiCmd, renderPixiUrl } from './util' +import { execute, executeGetOutput, pixiCmd, renderPixiUrl } from './util' import { tryRestoreGlobalCache, tryRestoreProjectCache, saveGlobalCache, saveProjectCache } from './cache' import { activateEnvironment } from './activate' +const fileExists = async (p: string) => { + try { + await fs.access(p) + return true + } catch { + return false + } +} + +// Returns the installed version (e.g. "0.67.2") or undefined if the binary +// cannot be executed or the output does not match the expected format. +const readInstalledPixiVersion = async (binPath: string) => { + try { + const { stdout, exitCode } = await executeGetOutput([binPath, '--version'], { + silent: true, + ignoreReturnCode: true + }) + if (exitCode !== 0) { + return undefined + } + // `pixi --version` prints something like "pixi 0.67.2" + const match = /\b(\d+\.\d+\.\d+\S*)/.exec(stdout) + return match?.[1] + } catch { + return undefined + } +} + const downloadPixi = async (source: PixiSource) => { const url = renderPixiUrl(source.urlTemplate, source.version) await core.group('Downloading Pixi', async () => { @@ -17,6 +45,29 @@ const downloadPixi = async (source: PixiSource) => { core.debug(`Downloading pixi from ${url}`) core.debug(`Using headers: ${JSON.stringify(source.headers)}`) await fs.mkdir(path.dirname(options.pixiBinPath), { recursive: true }) + + // If a previous step in this job already installed pixi at the same path, + // @actions/tool-cache's downloadTool will throw "Destination file path + // ... already exists". If the existing binary matches the requested + // version we can safely skip the download; otherwise remove it so the + // download can proceed. See prefix-dev/setup-pixi#107. + if (await fileExists(options.pixiBinPath)) { + if (source.version !== 'latest') { + const installed = await readInstalledPixiVersion(options.pixiBinPath) + const requested = source.version.replace(/^v/, '') + if (installed && installed === requested) { + core.info(`Pixi ${installed} already installed at ${options.pixiBinPath}, skipping download`) + return + } + core.info( + `Replacing existing pixi at ${options.pixiBinPath} (installed: ${installed ?? 'unknown'}, requested: ${requested})` + ) + } else { + core.info(`Replacing existing pixi at ${options.pixiBinPath} (requested: latest)`) + } + await fs.rm(options.pixiBinPath, { force: true }) + } + await downloadTool(url, options.pixiBinPath, undefined, source.headers) await fs.chmod(options.pixiBinPath, 0o755) core.info(`Pixi installed to ${options.pixiBinPath}`)