From 44371cfb8f64a9acfc87a9a0ddcae7e74a7b20d8 Mon Sep 17 00:00:00 2001 From: Emily Soth Date: Fri, 10 Jan 2025 11:59:44 -0800 Subject: [PATCH 1/4] plugin install: create base env with git and run git commands there --- workbench/src/main/setupAddRemovePlugin.js | 37 +++++++++++++++------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/workbench/src/main/setupAddRemovePlugin.js b/workbench/src/main/setupAddRemovePlugin.js index 7a0480ad0..8bf9d30a4 100644 --- a/workbench/src/main/setupAddRemovePlugin.js +++ b/workbench/src/main/setupAddRemovePlugin.js @@ -56,15 +56,26 @@ export function setupAddPlugin() { try { logger.info('adding plugin at', pluginURL); const micromamba = settingsStore.get('micromamba'); + const rootPrefix = upath.join(process.resourcesPath, 'micromamba_envs') + const baseEnvPrefix = upath.join(rootPrefix, 'invest_base'); + // Create invest_base environment, if it doesn't already exist + // The purpose of this environment is just to ensure that git is available + if (!fs.existsSync(baseEnvPrefix)) { + await spawnWithLogging( + micromamba, + ['create', '--yes', '--prefix', `"${baseEnvPrefix}"`, '-c', 'conda-forge', 'git'] + ); + } // Create a temporary directory and check out the plugin's pyproject.toml const tmpPluginDir = fs.mkdtempSync(upath.join(tmpdir(), 'natcap-invest-')); await spawnWithLogging( - 'git', - ['clone', '--depth', '1', '--no-checkout', pluginURL, tmpPluginDir] + micromamba, + ['run', '--prefix', `"${baseEnvPrefix}"`, + 'git', 'clone', '--depth', '1', '--no-checkout', pluginURL, tmpPluginDir] ); await spawnWithLogging( - 'git', - ['checkout', 'HEAD', 'pyproject.toml'], + micromamba, + ['run', '--prefix', `"${baseEnvPrefix}"`, 'git', 'checkout', 'HEAD', 'pyproject.toml'], { cwd: tmpPluginDir } ); // Read in the plugin's pyproject.toml, then delete it @@ -80,22 +91,24 @@ export function setupAddPlugin() { // Create a conda env containing the plugin and its dependencies const envName = `invest_plugin_${pluginID}`; + const pluginEnvPrefix = upath.join(rootPrefix, envName) await spawnWithLogging( micromamba, - ['create', '--yes', '--name', envName, '-c', 'conda-forge', '"python<3.12"', '"gdal<3.6"'] + ['create', '--yes', '--prefix', `"${pluginEnvPrefix}"`, + '-c', 'conda-forge', '"python<3.12"', '"gdal<3.6"'] ); logger.info('created micromamba env for plugin'); await spawnWithLogging( micromamba, - ['run', '--name', envName, 'pip', 'install', `git+${pluginURL}`] + ['run', '--prefix', `"${pluginEnvPrefix}"`, 'pip', 'install', `git+${pluginURL}`] ); logger.info('installed plugin into its env'); // Write plugin metadata to the workbench's config.json - const envInfo = execSync(`${micromamba} info --name ${envName}`, { windowsHide: true }).toString(); - logger.info(`env info:\n${envInfo}`); - const regex = /env location : (.+)/; - const envPath = envInfo.match(regex)[1]; - logger.info(`env path:\n${envPath}`); + // const envInfo = execSync(`${micromamba} info --name ${envName}`, { windowsHide: true }).toString(); + // logger.info(`env info:\n${envInfo}`); + // const regex = /env location : (.+)/; + // const envPath = envInfo.match(regex)[1]; + // logger.info(`env path:\n${envPath}`); logger.info('writing plugin info to settings store'); settingsStore.set( `plugins.${pluginID}`, @@ -104,7 +117,7 @@ export function setupAddPlugin() { pyname: pluginPyName, type: 'plugin', source: pluginURL, - env: envPath, + env: pluginEnvPrefix, } ); logger.info('successfully added plugin'); From b9a8c7d8fc38514dc493db70d5b79e830f6aafb3 Mon Sep 17 00:00:00 2001 From: Emily Soth Date: Fri, 10 Jan 2025 14:16:44 -0800 Subject: [PATCH 2/4] clean up - remove commented code --- workbench/src/main/setupAddRemovePlugin.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/workbench/src/main/setupAddRemovePlugin.js b/workbench/src/main/setupAddRemovePlugin.js index 8bf9d30a4..90bb1b371 100644 --- a/workbench/src/main/setupAddRemovePlugin.js +++ b/workbench/src/main/setupAddRemovePlugin.js @@ -104,11 +104,6 @@ export function setupAddPlugin() { ); logger.info('installed plugin into its env'); // Write plugin metadata to the workbench's config.json - // const envInfo = execSync(`${micromamba} info --name ${envName}`, { windowsHide: true }).toString(); - // logger.info(`env info:\n${envInfo}`); - // const regex = /env location : (.+)/; - // const envPath = envInfo.match(regex)[1]; - // logger.info(`env path:\n${envPath}`); logger.info('writing plugin info to settings store'); settingsStore.set( `plugins.${pluginID}`, From 05ecf09674d9d27c914af333b3e182d13838b79d Mon Sep 17 00:00:00 2001 From: Emily Soth Date: Fri, 10 Jan 2025 15:29:08 -0800 Subject: [PATCH 3/4] read plugin's conda dependencies from pyproject.toml rather than hard-coding --- workbench/src/main/setupAddRemovePlugin.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/workbench/src/main/setupAddRemovePlugin.js b/workbench/src/main/setupAddRemovePlugin.js index 90bb1b371..b8c263e24 100644 --- a/workbench/src/main/setupAddRemovePlugin.js +++ b/workbench/src/main/setupAddRemovePlugin.js @@ -88,15 +88,16 @@ export function setupAddPlugin() { const pluginID = pyprojectTOML.tool.natcap.invest.model_id; const pluginName = pyprojectTOML.tool.natcap.invest.model_name; const pluginPyName = pyprojectTOML.tool.natcap.invest.pyname; + const condaDeps = pyprojectTOML.tool.natcap.invest.conda_dependencies; // Create a conda env containing the plugin and its dependencies const envName = `invest_plugin_${pluginID}`; const pluginEnvPrefix = upath.join(rootPrefix, envName) - await spawnWithLogging( - micromamba, - ['create', '--yes', '--prefix', `"${pluginEnvPrefix}"`, - '-c', 'conda-forge', '"python<3.12"', '"gdal<3.6"'] - ); + const createCommand = [ + 'create', '--yes', '--prefix', `"${pluginEnvPrefix}"`, + '-c', 'conda-forge']; // include dependencies read from pyproject.toml + condaDeps.forEach((dep) => createCommand.push(`"${dep}"`)) + await spawnWithLogging(micromamba, createCommand); logger.info('created micromamba env for plugin'); await spawnWithLogging( micromamba, From cfa5f159af9811cc3f5a39793754df416ec764b7 Mon Sep 17 00:00:00 2001 From: Emily Soth Date: Fri, 24 Jan 2025 13:33:57 -0800 Subject: [PATCH 4/4] include python in plugin env; allow undefined conda deps --- workbench/src/main/setupAddRemovePlugin.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/workbench/src/main/setupAddRemovePlugin.js b/workbench/src/main/setupAddRemovePlugin.js index b8c263e24..75240c920 100644 --- a/workbench/src/main/setupAddRemovePlugin.js +++ b/workbench/src/main/setupAddRemovePlugin.js @@ -56,7 +56,7 @@ export function setupAddPlugin() { try { logger.info('adding plugin at', pluginURL); const micromamba = settingsStore.get('micromamba'); - const rootPrefix = upath.join(process.resourcesPath, 'micromamba_envs') + const rootPrefix = upath.join(process.resourcesPath, 'micromamba_envs'); const baseEnvPrefix = upath.join(rootPrefix, 'invest_base'); // Create invest_base environment, if it doesn't already exist // The purpose of this environment is just to ensure that git is available @@ -71,7 +71,7 @@ export function setupAddPlugin() { await spawnWithLogging( micromamba, ['run', '--prefix', `"${baseEnvPrefix}"`, - 'git', 'clone', '--depth', '1', '--no-checkout', pluginURL, tmpPluginDir] + 'git', 'clone', '--depth', '1', '--no-checkout', pluginURL, tmpPluginDir] ); await spawnWithLogging( micromamba, @@ -92,11 +92,13 @@ export function setupAddPlugin() { // Create a conda env containing the plugin and its dependencies const envName = `invest_plugin_${pluginID}`; - const pluginEnvPrefix = upath.join(rootPrefix, envName) + const pluginEnvPrefix = upath.join(rootPrefix, envName); const createCommand = [ 'create', '--yes', '--prefix', `"${pluginEnvPrefix}"`, - '-c', 'conda-forge']; // include dependencies read from pyproject.toml - condaDeps.forEach((dep) => createCommand.push(`"${dep}"`)) + '-c', 'conda-forge', 'python']; + if (condaDeps) { // include dependencies read from pyproject.toml + condaDeps.forEach((dep) => createCommand.push(`"${dep}"`)); + } await spawnWithLogging(micromamba, createCommand); logger.info('created micromamba env for plugin'); await spawnWithLogging(