Merge pull request #593 from devchat-ai/config_conda_forge

feat: Add configurable conda-forge URL for Python installation
This commit is contained in:
Tim 2024-09-20 16:56:35 +08:00 committed by GitHub
commit 4e5283556c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -2,6 +2,7 @@ import { exec, spawn } from 'child_process';
import * as path from 'path'; import * as path from 'path';
import * as os from 'os'; import * as os from 'os';
import { logger } from '../logger'; import { logger } from '../logger';
import { DevChatConfig } from '../config';
const fs = require('fs'); const fs = require('fs');
// Check if the environment already exists // 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<string> { export async function installPythonMicromamba(mambaCommandPath: string, envName: string, pythonVersion: string): Promise<string> {
// 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; let userHome = process.platform === 'win32' ? fs.realpathSync(process.env.USERPROFILE || '') : process.env.HOME;
if (os.platform() === 'win32' && /[^\x00-\xFF]/.test(userHome)) { if (os.platform() === 'win32' && /[^\x00-\xFF]/.test(userHome)) {
if (fs.existsSync('C:/Program Files') && canCreateSubdirectory('C:/Program Files')) { if (fs.existsSync('C:/Program Files') && canCreateSubdirectory('C:/Program Files')) {
userHome = 'C:/Program Files'; userHome = 'C:/Program Files';
} else if (fs.existsSync('D:/Program Files') && canCreateSubdirectory('D:/Program Files')) { } else if (fs.existsSync('D:/Program Files') && canCreateSubdirectory('D:/Program Files')) {
userHome = 'D:/Program Files'; userHome = 'D:/Program Files';
} else if (fs.existsSync('E:/Program Files') && canCreateSubdirectory('E:/Program Files')) { } else if (fs.existsSync('E:/Program Files') && canCreateSubdirectory('E:/Program Files')) {
userHome = 'E:/Program Files'; userHome = 'E:/Program Files';
} }
} }
const pathToMamba = `${userHome}/.chat/mamba`; const pathToMamba = `${userHome}/.chat/mamba`;
const envPath = path.resolve(pathToMamba, 'envs', envName); const envPath = path.resolve(pathToMamba, 'envs', envName);
let pythonPath; let pythonPath;
let pythonPath2; let pythonPath2;
if (os.platform() === 'win32') { if (os.platform() === 'win32') {
pythonPath = path.join(envPath, 'Scripts', 'python.exe'); pythonPath = path.join(envPath, 'Scripts', 'python.exe');
pythonPath2 = path.join(envPath, 'python.exe'); pythonPath2 = path.join(envPath, 'python.exe');
} else { } else {
pythonPath = path.join(envPath, 'bin', 'python'); pythonPath = path.join(envPath, 'bin', 'python');
} }
if (fs.existsSync(pythonPath)) { if (fs.existsSync(pythonPath)) {
return pythonPath; return pythonPath;
} else if (pythonPath2 && fs.existsSync(pythonPath2)) { } else if (pythonPath2 && fs.existsSync(pythonPath2)) {
return pythonPath2; return pythonPath2;
} }
return new Promise<string>((resolve, reject) => { // Get conda-forge URL from config file
const cmd = mambaCommandPath; const condaForgeUrl = getCondaForgeUrl();
const args = ['create', '-n', envName, '-c', 'conda-forge', '-r', pathToMamba, `python=${pythonVersion}`, '--yes'];
// output command and args in line return new Promise<string>((resolve, reject) => {
// args to "create -n xx -c conda-forge ..." const cmd = mambaCommandPath;
logger.channel()?.info(`cmd: ${cmd} ${args.join(' ')}`); const args = ['create', '-n', envName, '-c', condaForgeUrl, '-r', pathToMamba, `python=${pythonVersion}`, '--yes'];
const child = spawn(cmd, args); logger.channel()?.info(`cmd: ${cmd} ${args.join(' ')}`);
const child = spawn(cmd, args);
child.stdout.on('data', (data) => {
logger.channel()?.info(`${data}`); child.stdout.on('data', (data) => {
}); logger.channel()?.info(`${data}`);
});
child.stderr.on('data', (data) => {
console.error(`stderr: ${data}`); child.stderr.on('data', (data) => {
}); console.error(`stderr: ${data}`);
});
child.on('error', (error) => {
logger.channel()?.error(`Error installing python ${pythonVersion} in env ${envName}`); child.on('error', (error) => {
logger.channel()?.show(); logger.channel()?.error(`Error installing python ${pythonVersion} in env ${envName}`);
reject(''); logger.channel()?.show();
}); reject('');
});
child.on('close', (code) => {
if (code !== 0) { child.on('close', (code) => {
reject(new Error(`Command exited with code ${code}`)); if (code !== 0) {
} else { reject(new Error(`Command exited with code ${code}`));
if (fs.existsSync(pythonPath)) { } else {
resolve(pythonPath); if (fs.existsSync(pythonPath)) {
} else if (pythonPath2 && fs.existsSync(pythonPath2)) { resolve(pythonPath);
resolve(pythonPath2); } else if (pythonPath2 && fs.existsSync(pythonPath2)) {
} else { resolve(pythonPath2);
reject(new Error(`No Python found`)); } 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;
}
}