Address mamba v2 incompatibilities (#368)
* look for mamba in more places and guarantee existence * parameterize mamba versions * debug locations * pass options * Pass MAMBA_ROOT_PREFIX for mamba v2 * mamba v2 doesn't create env with update * copy to condabin? * use basename * fix extension * fix path under Windows * extra verbose * is it pip? * it wasn't pip * do not compile pyc on win * temporarily remove pip section * bash wrapper goes in condabin * compile * debug a bit * fix workflow * amend paths * mark as executable? * remove which? * debug and disablew a few workflows * activate before forward? * slashes? * refactor forwarders * bash forwarder only on 1.x * fwd via cmd? * which * move to the bottom * this one too * fix executable names * revert * clean up a bit * mark as generated * restore bash forwarder * hide from local diff too * do we still need MAMBA_COMPILE_PYC?
This commit is contained in:
+2
-1
@@ -1 +1,2 @@
|
||||
*.js -diff
|
||||
dist/setup/index.js linguist-generated=true -diff
|
||||
dist/delete/index.js linguist-generated=true -diff
|
||||
|
||||
@@ -24,19 +24,22 @@ jobs:
|
||||
if:
|
||||
(github.event_name == 'schedule' && github.repository ==
|
||||
'conda-incubator/setup-miniconda') || (github.event_name != 'schedule')
|
||||
name: Ex6 (${{ matrix.os }})
|
||||
name:
|
||||
Ex6 (${{ matrix.os }}, mamba ${{ matrix.mamba-version }}, ${{
|
||||
matrix.activate-environment }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
|
||||
mamba-version: ["1.5.10", "2"]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
activate-environment: anaconda-client-env
|
||||
- os: macos-latest
|
||||
activate-environment: /tmp/anaconda-client-env
|
||||
- os: windows-latest
|
||||
activate-environment: c:\ace
|
||||
activate-environment: C:\ace
|
||||
defaults:
|
||||
run:
|
||||
shell: bash -el {0}
|
||||
@@ -47,7 +50,7 @@ jobs:
|
||||
with:
|
||||
miniforge-variant: Miniforge3
|
||||
python-version: "3.11"
|
||||
mamba-version: "*"
|
||||
mamba-version: ${{ matrix.mamba-version }}
|
||||
channels: conda-forge,nodefaults
|
||||
channel-priority: true
|
||||
activate-environment: ${{ matrix.activate-environment }}
|
||||
@@ -69,7 +72,7 @@ jobs:
|
||||
- name: Windows, .bat, from Cmd
|
||||
shell: cmd /C call {0}
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: mamba --version
|
||||
run: mamba.bat --version
|
||||
- name: Windows, no .bat, from Cmd
|
||||
shell: cmd /C call {0}
|
||||
if: matrix.os == 'windows-latest'
|
||||
|
||||
+2
-1
@@ -26473,7 +26473,7 @@ exports.isBaseEnv = isBaseEnv;
|
||||
/**
|
||||
* Run exec.exec with error handling
|
||||
*/
|
||||
function execute(command) {
|
||||
function execute(command, env = {}) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let options = {
|
||||
errStream: new stream.Writable(),
|
||||
@@ -26497,6 +26497,7 @@ function execute(command) {
|
||||
core.warning(stringData);
|
||||
},
|
||||
},
|
||||
env: Object.assign(Object.assign({}, process.env), env),
|
||||
};
|
||||
const rc = yield exec.exec(command[0], command.slice(1), options);
|
||||
if (rc !== 0) {
|
||||
|
||||
+102
-28
@@ -47043,6 +47043,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.updateMamba = void 0;
|
||||
const fs = __importStar(__nccwpck_require__(7147));
|
||||
const path = __importStar(__nccwpck_require__(1017));
|
||||
const core = __importStar(__nccwpck_require__(2186));
|
||||
const constants = __importStar(__nccwpck_require__(9042));
|
||||
const utils = __importStar(__nccwpck_require__(1314));
|
||||
@@ -47060,16 +47061,57 @@ exports.updateMamba = {
|
||||
};
|
||||
}),
|
||||
postInstall: (inputs, options) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
if (!constants.IS_WINDOWS) {
|
||||
core.info("`mamba` is already executable");
|
||||
return;
|
||||
const mambaExec = conda.condaExecutable(options);
|
||||
const condabinLocation = path.join(conda.condaBasePath(options), "condabin", path.basename(mambaExec));
|
||||
if (constants.IS_UNIX) {
|
||||
if (!fs.existsSync(condabinLocation)) {
|
||||
// This is mamba 2.x with only $PREFIX/bin/mamba,
|
||||
// we just need a symlink in condabin
|
||||
core.info(`Symlinking ${mambaExec} to ${condabinLocation}...`);
|
||||
fs.symlinkSync(mambaExec, condabinLocation);
|
||||
}
|
||||
}
|
||||
else {
|
||||
core.info(`Creating bash wrapper for 'mamba'...`);
|
||||
const mambaBat = condabinLocation.slice(0, -4) + ".bat";
|
||||
// Add bat-less forwarder for bash users on Windows
|
||||
const forwarderContents = `cmd.exe /C CALL "${mambaBat}" $* || exit 1`;
|
||||
fs.writeFileSync(condabinLocation.slice(0, -4), forwarderContents);
|
||||
core.info(`... wrote ${mambaExec.slice(0, -4)}:\n${forwarderContents}`);
|
||||
if (!fs.existsSync(mambaBat)) {
|
||||
// This is Windows and mamba 2.x, we need a mamba.bat like 1.x used to have
|
||||
const contents = `
|
||||
@REM Copyright (C) 2012 Anaconda, Inc
|
||||
@REM SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
@REM echo _CE_CONDA is %_CE_CONDA%
|
||||
@REM echo _CE_M is %_CE_M%
|
||||
@REM echo CONDA_EXE is %CONDA_EXE%
|
||||
|
||||
@IF NOT DEFINED _CE_CONDA (
|
||||
@SET _CE_M=
|
||||
@SET "CONDA_EXE=%~dp0..\\Scripts\\conda.exe"
|
||||
)
|
||||
@IF [%1]==[activate] "%~dp0_conda_activate" %*
|
||||
@IF [%1]==[deactivate] "%~dp0_conda_activate" %*
|
||||
|
||||
@SET MAMBA_EXES="%~dp0..\\Library\\bin\\mamba.exe"
|
||||
@CALL %MAMBA_EXES% %*
|
||||
|
||||
@IF %errorlevel% NEQ 0 EXIT /B %errorlevel%
|
||||
|
||||
@IF [%1]==[install] "%~dp0_conda_activate" reactivate
|
||||
@IF [%1]==[update] "%~dp0_conda_activate" reactivate
|
||||
@IF [%1]==[upgrade] "%~dp0_conda_activate" reactivate
|
||||
@IF [%1]==[remove] "%~dp0_conda_activate" reactivate
|
||||
@IF [%1]==[uninstall] "%~dp0_conda_activate" reactivate
|
||||
|
||||
@EXIT /B %errorlevel%`;
|
||||
core.info(`Creating .bat wrapper for 'mamba 2.x'...`);
|
||||
fs.writeFileSync(mambaBat, contents);
|
||||
core.info(`... wrote ${mambaBat}`);
|
||||
}
|
||||
}
|
||||
core.info("Creating bash wrapper for `mamba`...");
|
||||
// Add bat-less forwarder for bash users on Windows
|
||||
const mambaBat = conda.condaExecutable(options).replace(/\\/g, "/");
|
||||
const contents = `bash.exe -c "exec '${mambaBat}' $*" || exit 1`;
|
||||
fs.writeFileSync(mambaBat.slice(0, -4), contents);
|
||||
core.info(`... wrote ${mambaBat}:\n${contents}`);
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -47177,7 +47219,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.condaInit = exports.applyCondaConfiguration = exports.copyConfig = exports.bootstrapConfig = exports.condaCommand = exports.isMambaInstalled = exports.condaExecutable = exports.envCommandFlag = exports.condaBasePath = void 0;
|
||||
exports.condaInit = exports.applyCondaConfiguration = exports.copyConfig = exports.bootstrapConfig = exports.condaCommand = exports.isMambaInstalled = exports.condaExecutable = exports.condaExecutableLocations = exports.envCommandFlag = exports.condaBasePath = void 0;
|
||||
const fs = __importStar(__nccwpck_require__(7147));
|
||||
const path = __importStar(__nccwpck_require__(1017));
|
||||
const os = __importStar(__nccwpck_require__(2037));
|
||||
@@ -47213,25 +47255,47 @@ function envCommandFlag(inputs) {
|
||||
}
|
||||
exports.envCommandFlag = envCommandFlag;
|
||||
/**
|
||||
* Provide cross platform location of conda/mamba executable
|
||||
* Provide cross platform location of conda/mamba executable in condabin and bin
|
||||
*/
|
||||
function condaExecutable(options, subcommand) {
|
||||
function condaExecutableLocations(options, subcommand) {
|
||||
const dir = condaBasePath(options);
|
||||
let condaExe;
|
||||
let condaExes = [];
|
||||
let commandName = "conda";
|
||||
if (options.useMamba &&
|
||||
(subcommand == null || constants.MAMBA_SUBCOMMANDS.includes(subcommand))) {
|
||||
commandName = "mamba";
|
||||
}
|
||||
commandName = constants.IS_WINDOWS ? commandName + ".bat" : commandName;
|
||||
condaExe = path.join(dir, "condabin", commandName);
|
||||
return condaExe;
|
||||
condaExes.push(path.join(dir, "condabin", constants.IS_WINDOWS ? commandName + ".bat" : commandName));
|
||||
if (constants.IS_WINDOWS) {
|
||||
condaExes.push(path.join(dir, "Library", "bin", commandName + ".exe"));
|
||||
}
|
||||
else {
|
||||
condaExes.push(path.join(dir, "bin", commandName));
|
||||
}
|
||||
return condaExes;
|
||||
}
|
||||
exports.condaExecutableLocations = condaExecutableLocations;
|
||||
/**
|
||||
* Return existing conda or mamba executable
|
||||
*/
|
||||
function condaExecutable(options, subcommand) {
|
||||
const locations = condaExecutableLocations(options, subcommand);
|
||||
for (const exe of locations) {
|
||||
if (fs.existsSync(exe))
|
||||
return exe;
|
||||
}
|
||||
throw Error(`No existing ${options.useMamba ? "mamba" : "conda"} executable found at any of ${locations}`);
|
||||
}
|
||||
exports.condaExecutable = condaExecutable;
|
||||
/** Detect the presence of mamba */
|
||||
/**
|
||||
* Detect the presence of mamba
|
||||
*/
|
||||
function isMambaInstalled(options) {
|
||||
const mamba = condaExecutable(Object.assign(Object.assign({}, options), { useMamba: true }));
|
||||
return fs.existsSync(mamba);
|
||||
for (const exe of condaExecutableLocations(Object.assign(Object.assign({}, options), { useMamba: true }))) {
|
||||
if (fs.existsSync(exe))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
exports.isMambaInstalled = isMambaInstalled;
|
||||
/**
|
||||
@@ -47240,7 +47304,11 @@ exports.isMambaInstalled = isMambaInstalled;
|
||||
function condaCommand(cmd, options) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const command = [condaExecutable(options, cmd[0]), ...cmd];
|
||||
return yield utils.execute(command);
|
||||
let env = {};
|
||||
if (options.useMamba) {
|
||||
env.MAMBA_ROOT_PREFIX = condaBasePath(options);
|
||||
}
|
||||
return yield utils.execute(command, env);
|
||||
});
|
||||
}
|
||||
exports.condaCommand = condaCommand;
|
||||
@@ -48007,13 +48075,18 @@ exports.ensureYaml = {
|
||||
core.info(`Using 'environment-file: ${inputs.environmentFile}' as-is`);
|
||||
outputs.setEnvironmentFileOutputs(envFile, fs.readFileSync(inputs.environmentFile, "utf-8"));
|
||||
}
|
||||
return [
|
||||
"env",
|
||||
"update",
|
||||
...conda.envCommandFlag(inputs),
|
||||
"--file",
|
||||
envFile,
|
||||
];
|
||||
const [flag, nameOrPath] = conda.envCommandFlag(inputs);
|
||||
let subcommand;
|
||||
if (options.useMamba) {
|
||||
const envPath = flag === "--name"
|
||||
? path.join(conda.condaBasePath(options), "envs", nameOrPath)
|
||||
: nameOrPath;
|
||||
subcommand = fs.existsSync(envPath) ? "update" : "create";
|
||||
}
|
||||
else {
|
||||
subcommand = "update";
|
||||
}
|
||||
return ["env", subcommand, flag, nameOrPath, "--file", envFile];
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -49009,7 +49082,7 @@ exports.isBaseEnv = isBaseEnv;
|
||||
/**
|
||||
* Run exec.exec with error handling
|
||||
*/
|
||||
function execute(command) {
|
||||
function execute(command, env = {}) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let options = {
|
||||
errStream: new stream.Writable(),
|
||||
@@ -49033,6 +49106,7 @@ function execute(command) {
|
||||
core.warning(stringData);
|
||||
},
|
||||
},
|
||||
env: Object.assign(Object.assign({}, process.env), env),
|
||||
};
|
||||
const rc = yield exec.exec(command[0], command.slice(1), options);
|
||||
if (rc !== 0) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
|
||||
@@ -23,16 +24,59 @@ export const updateMamba: types.IToolProvider = {
|
||||
};
|
||||
},
|
||||
postInstall: async (inputs, options) => {
|
||||
if (!constants.IS_WINDOWS) {
|
||||
core.info("`mamba` is already executable");
|
||||
return;
|
||||
}
|
||||
core.info("Creating bash wrapper for `mamba`...");
|
||||
// Add bat-less forwarder for bash users on Windows
|
||||
const mambaBat = conda.condaExecutable(options).replace(/\\/g, "/");
|
||||
const mambaExec = conda.condaExecutable(options);
|
||||
const condabinLocation = path.join(
|
||||
conda.condaBasePath(options),
|
||||
"condabin",
|
||||
path.basename(mambaExec),
|
||||
);
|
||||
if (constants.IS_UNIX) {
|
||||
if (!fs.existsSync(condabinLocation)) {
|
||||
// This is mamba 2.x with only $PREFIX/bin/mamba,
|
||||
// we just need a symlink in condabin
|
||||
core.info(`Symlinking ${mambaExec} to ${condabinLocation}...`);
|
||||
fs.symlinkSync(mambaExec, condabinLocation);
|
||||
}
|
||||
} else {
|
||||
core.info(`Creating bash wrapper for 'mamba'...`);
|
||||
const mambaBat = condabinLocation.slice(0, -4) + ".bat";
|
||||
// Add bat-less forwarder for bash users on Windows
|
||||
const forwarderContents = `cmd.exe /C CALL "${mambaBat}" $* || exit 1`;
|
||||
fs.writeFileSync(condabinLocation.slice(0, -4), forwarderContents);
|
||||
core.info(`... wrote ${mambaExec.slice(0, -4)}:\n${forwarderContents}`);
|
||||
if (!fs.existsSync(mambaBat)) {
|
||||
// This is Windows and mamba 2.x, we need a mamba.bat like 1.x used to have
|
||||
const contents = `
|
||||
@REM Copyright (C) 2012 Anaconda, Inc
|
||||
@REM SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
const contents = `bash.exe -c "exec '${mambaBat}' $*" || exit 1`;
|
||||
fs.writeFileSync(mambaBat.slice(0, -4), contents);
|
||||
core.info(`... wrote ${mambaBat}:\n${contents}`);
|
||||
@REM echo _CE_CONDA is %_CE_CONDA%
|
||||
@REM echo _CE_M is %_CE_M%
|
||||
@REM echo CONDA_EXE is %CONDA_EXE%
|
||||
|
||||
@IF NOT DEFINED _CE_CONDA (
|
||||
@SET _CE_M=
|
||||
@SET "CONDA_EXE=%~dp0..\\Scripts\\conda.exe"
|
||||
)
|
||||
@IF [%1]==[activate] "%~dp0_conda_activate" %*
|
||||
@IF [%1]==[deactivate] "%~dp0_conda_activate" %*
|
||||
|
||||
@SET MAMBA_EXES="%~dp0..\\Library\\bin\\mamba.exe"
|
||||
@CALL %MAMBA_EXES% %*
|
||||
|
||||
@IF %errorlevel% NEQ 0 EXIT /B %errorlevel%
|
||||
|
||||
@IF [%1]==[install] "%~dp0_conda_activate" reactivate
|
||||
@IF [%1]==[update] "%~dp0_conda_activate" reactivate
|
||||
@IF [%1]==[upgrade] "%~dp0_conda_activate" reactivate
|
||||
@IF [%1]==[remove] "%~dp0_conda_activate" reactivate
|
||||
@IF [%1]==[uninstall] "%~dp0_conda_activate" reactivate
|
||||
|
||||
@EXIT /B %errorlevel%`;
|
||||
core.info(`Creating .bat wrapper for 'mamba 2.x'...`);
|
||||
fs.writeFileSync(mambaBat, contents);
|
||||
core.info(`... wrote ${mambaBat}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
+47
-11
@@ -40,14 +40,14 @@ export function envCommandFlag(inputs: types.IActionInputs): string[] {
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide cross platform location of conda/mamba executable
|
||||
* Provide cross platform location of conda/mamba executable in condabin and bin
|
||||
*/
|
||||
export function condaExecutable(
|
||||
export function condaExecutableLocations(
|
||||
options: types.IDynamicOptions,
|
||||
subcommand?: string,
|
||||
): string {
|
||||
): string[] {
|
||||
const dir: string = condaBasePath(options);
|
||||
let condaExe: string;
|
||||
let condaExes: string[] = [];
|
||||
let commandName = "conda";
|
||||
if (
|
||||
options.useMamba &&
|
||||
@@ -55,15 +55,47 @@ export function condaExecutable(
|
||||
) {
|
||||
commandName = "mamba";
|
||||
}
|
||||
commandName = constants.IS_WINDOWS ? commandName + ".bat" : commandName;
|
||||
condaExe = path.join(dir, "condabin", commandName);
|
||||
return condaExe;
|
||||
condaExes.push(
|
||||
path.join(
|
||||
dir,
|
||||
"condabin",
|
||||
constants.IS_WINDOWS ? commandName + ".bat" : commandName,
|
||||
),
|
||||
);
|
||||
if (constants.IS_WINDOWS) {
|
||||
condaExes.push(path.join(dir, "Library", "bin", commandName + ".exe"));
|
||||
} else {
|
||||
condaExes.push(path.join(dir, "bin", commandName));
|
||||
}
|
||||
return condaExes;
|
||||
}
|
||||
|
||||
/** Detect the presence of mamba */
|
||||
/**
|
||||
* Return existing conda or mamba executable
|
||||
*/
|
||||
export function condaExecutable(
|
||||
options: types.IDynamicOptions,
|
||||
subcommand?: string,
|
||||
) {
|
||||
const locations = condaExecutableLocations(options, subcommand);
|
||||
for (const exe of locations) {
|
||||
if (fs.existsSync(exe)) return exe;
|
||||
}
|
||||
throw Error(
|
||||
`No existing ${
|
||||
options.useMamba ? "mamba" : "conda"
|
||||
} executable found at any of ${locations}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the presence of mamba
|
||||
*/
|
||||
export function isMambaInstalled(options: types.IDynamicOptions) {
|
||||
const mamba = condaExecutable({ ...options, useMamba: true });
|
||||
return fs.existsSync(mamba);
|
||||
for (const exe of condaExecutableLocations({ ...options, useMamba: true })) {
|
||||
if (fs.existsSync(exe)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +106,11 @@ export async function condaCommand(
|
||||
options: types.IDynamicOptions,
|
||||
): Promise<void> {
|
||||
const command = [condaExecutable(options, cmd[0]), ...cmd];
|
||||
return await utils.execute(command);
|
||||
let env: { [key: string]: string } = {};
|
||||
if (options.useMamba) {
|
||||
env.MAMBA_ROOT_PREFIX = condaBasePath(options);
|
||||
}
|
||||
return await utils.execute(command, env);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Vendored
+12
-8
@@ -127,13 +127,17 @@ export const ensureYaml: types.IEnvProvider = {
|
||||
fs.readFileSync(inputs.environmentFile, "utf-8"),
|
||||
);
|
||||
}
|
||||
|
||||
return [
|
||||
"env",
|
||||
"update",
|
||||
...conda.envCommandFlag(inputs),
|
||||
"--file",
|
||||
envFile,
|
||||
];
|
||||
const [flag, nameOrPath] = conda.envCommandFlag(inputs);
|
||||
let subcommand: string;
|
||||
if (options.useMamba) {
|
||||
const envPath =
|
||||
flag === "--name"
|
||||
? path.join(conda.condaBasePath(options), "envs", nameOrPath)
|
||||
: nameOrPath;
|
||||
subcommand = fs.existsSync(envPath) ? "update" : "create";
|
||||
} else {
|
||||
subcommand = "update";
|
||||
}
|
||||
return ["env", subcommand, flag, nameOrPath, "--file", envFile];
|
||||
},
|
||||
};
|
||||
|
||||
+2
-1
@@ -21,7 +21,7 @@ export function isBaseEnv(envName: string) {
|
||||
/**
|
||||
* Run exec.exec with error handling
|
||||
*/
|
||||
export async function execute(command: string[]): Promise<void> {
|
||||
export async function execute(command: string[], env = {}): Promise<void> {
|
||||
let options: exec.ExecOptions = {
|
||||
errStream: new stream.Writable(),
|
||||
listeners: {
|
||||
@@ -44,6 +44,7 @@ export async function execute(command: string[]): Promise<void> {
|
||||
core.warning(stringData);
|
||||
},
|
||||
},
|
||||
env: { ...process.env, ...env },
|
||||
};
|
||||
|
||||
const rc = await exec.exec(command[0], command.slice(1), options);
|
||||
|
||||
Reference in New Issue
Block a user