From 429f52357d3cd80acef94818c579e69f178e6f4a Mon Sep 17 00:00:00 2001 From: "bobo.yang" Date: Fri, 20 Sep 2024 15:45:41 +0800 Subject: [PATCH] feat: Add configurable conda-forge URL for Python installation - Implement getCondaForgeUrl function to fetch URL from config - Use configurable URL in Python installation process - Add error handling and fallback to default URL if needed --- src/util/python_installer/python_install.ts | 141 +++++++++++--------- 1 file changed, 78 insertions(+), 63 deletions(-) diff --git a/src/util/python_installer/python_install.ts b/src/util/python_installer/python_install.ts index 61e36e4..9a079f0 100644 --- a/src/util/python_installer/python_install.ts +++ b/src/util/python_installer/python_install.ts @@ -2,6 +2,7 @@ import { exec, spawn } from 'child_process'; import * as path from 'path'; import * as os from 'os'; import { logger } from '../logger'; +import { DevChatConfig } from '../config'; const fs = require('fs'); // Check if the environment already exists @@ -96,69 +97,83 @@ function canCreateSubdirectory(dirPath: string): boolean { export async function installPythonMicromamba(mambaCommandPath: string, envName: string, pythonVersion: string): Promise { - // Set the installation directory for conda + // Set the installation directory for conda let userHome = process.platform === 'win32' ? fs.realpathSync(process.env.USERPROFILE || '') : process.env.HOME; - if (os.platform() === 'win32' && /[^\x00-\xFF]/.test(userHome)) { - if (fs.existsSync('C:/Program Files') && canCreateSubdirectory('C:/Program Files')) { - userHome = 'C:/Program Files'; - } else if (fs.existsSync('D:/Program Files') && canCreateSubdirectory('D:/Program Files')) { - userHome = 'D:/Program Files'; - } else if (fs.existsSync('E:/Program Files') && canCreateSubdirectory('E:/Program Files')) { - userHome = 'E:/Program Files'; - } - } + if (os.platform() === 'win32' && /[^\x00-\xFF]/.test(userHome)) { + if (fs.existsSync('C:/Program Files') && canCreateSubdirectory('C:/Program Files')) { + userHome = 'C:/Program Files'; + } else if (fs.existsSync('D:/Program Files') && canCreateSubdirectory('D:/Program Files')) { + userHome = 'D:/Program Files'; + } else if (fs.existsSync('E:/Program Files') && canCreateSubdirectory('E:/Program Files')) { + userHome = 'E:/Program Files'; + } + } const pathToMamba = `${userHome}/.chat/mamba`; - const envPath = path.resolve(pathToMamba, 'envs', envName); - let pythonPath; - let pythonPath2; - if (os.platform() === 'win32') { - pythonPath = path.join(envPath, 'Scripts', 'python.exe'); - pythonPath2 = path.join(envPath, 'python.exe'); - } else { - pythonPath = path.join(envPath, 'bin', 'python'); - } - - if (fs.existsSync(pythonPath)) { - return pythonPath; - } else if (pythonPath2 && fs.existsSync(pythonPath2)) { - return pythonPath2; - } - - return new Promise((resolve, reject) => { - const cmd = mambaCommandPath; - const args = ['create', '-n', envName, '-c', 'conda-forge', '-r', pathToMamba, `python=${pythonVersion}`, '--yes']; - // output command and args in line - // args to "create -n xx -c conda-forge ..." - logger.channel()?.info(`cmd: ${cmd} ${args.join(' ')}`); - const child = spawn(cmd, args); - - child.stdout.on('data', (data) => { - logger.channel()?.info(`${data}`); - }); - - child.stderr.on('data', (data) => { - console.error(`stderr: ${data}`); - }); - - child.on('error', (error) => { - logger.channel()?.error(`Error installing python ${pythonVersion} in env ${envName}`); - logger.channel()?.show(); - reject(''); - }); - - child.on('close', (code) => { - if (code !== 0) { - reject(new Error(`Command exited with code ${code}`)); - } else { - if (fs.existsSync(pythonPath)) { - resolve(pythonPath); - } else if (pythonPath2 && fs.existsSync(pythonPath2)) { - resolve(pythonPath2); - } else { - reject(new Error(`No Python found`)); - } - } - }); - }); -} \ No newline at end of file + const envPath = path.resolve(pathToMamba, 'envs', envName); + let pythonPath; + let pythonPath2; + if (os.platform() === 'win32') { + pythonPath = path.join(envPath, 'Scripts', 'python.exe'); + pythonPath2 = path.join(envPath, 'python.exe'); + } else { + pythonPath = path.join(envPath, 'bin', 'python'); + } + + if (fs.existsSync(pythonPath)) { + return pythonPath; + } else if (pythonPath2 && fs.existsSync(pythonPath2)) { + return pythonPath2; + } + + // Get conda-forge URL from config file + const condaForgeUrl = getCondaForgeUrl(); + + return new Promise((resolve, reject) => { + const cmd = mambaCommandPath; + const args = ['create', '-n', envName, '-c', condaForgeUrl, '-r', pathToMamba, `python=${pythonVersion}`, '--yes']; + logger.channel()?.info(`cmd: ${cmd} ${args.join(' ')}`); + const child = spawn(cmd, args); + + child.stdout.on('data', (data) => { + logger.channel()?.info(`${data}`); + }); + + child.stderr.on('data', (data) => { + console.error(`stderr: ${data}`); + }); + + child.on('error', (error) => { + logger.channel()?.error(`Error installing python ${pythonVersion} in env ${envName}`); + logger.channel()?.show(); + reject(''); + }); + + child.on('close', (code) => { + if (code !== 0) { + reject(new Error(`Command exited with code ${code}`)); + } else { + if (fs.existsSync(pythonPath)) { + resolve(pythonPath); + } else if (pythonPath2 && fs.existsSync(pythonPath2)) { + resolve(pythonPath2); + } else { + reject(new Error(`No Python found`)); + } + } + }); + }); +} + +export function getCondaForgeUrl(): string { + const defaultUrl = "https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/"; + try { + const config = DevChatConfig.getInstance(); + const url = config.get("conda-forge-url", defaultUrl); + return url || defaultUrl; // 如果 url 是 undefined 或空字符串,返回默认 URL + } catch (error) { + logger.channel()?.error(`Error reading conda-forge URL from config: ${error}`); + logger.channel()?.show(); + return defaultUrl; + } +}