diff --git a/src/features/terminal/shells/bash/bashStartup.ts b/src/features/terminal/shells/bash/bashStartup.ts index ff66d72c..b9409866 100644 --- a/src/features/terminal/shells/bash/bashStartup.ts +++ b/src/features/terminal/shells/bash/bashStartup.ts @@ -27,14 +27,14 @@ async function isGitBashInstalled(): Promise { return false; } -async function getBashProfiles(): Promise { +export async function getBashProfiles(): Promise { const homeDir = os.homedir(); const profile: string = path.join(homeDir, '.bashrc'); return profile; } -async function getZshProfiles(): Promise { +export async function getZshProfiles(): Promise { const homeDir = os.homedir(); const profile: string = path.join(homeDir, '.zshrc'); diff --git a/src/features/terminal/shells/fish/fishStartup.ts b/src/features/terminal/shells/fish/fishStartup.ts index 662d2898..dc0ca3e5 100644 --- a/src/features/terminal/shells/fish/fishStartup.ts +++ b/src/features/terminal/shells/fish/fishStartup.ts @@ -19,7 +19,7 @@ async function isFishInstalled(): Promise { } } -async function getFishProfile(): Promise { +export async function getFishProfile(): Promise { const homeDir = os.homedir(); // Fish configuration is typically at ~/.config/fish/config.fish const profilePath = path.join(homeDir, '.config', 'fish', 'config.fish'); @@ -155,4 +155,8 @@ export class FishStartupProvider implements ShellStartupScriptProvider { clearCache(): Promise { return Promise.resolve(); } + + getProfilePath(): Promise { + return getFishProfile(); + } } diff --git a/src/features/terminal/shells/pwsh/pwshStartup.ts b/src/features/terminal/shells/pwsh/pwshStartup.ts index 17347af7..8d184600 100644 --- a/src/features/terminal/shells/pwsh/pwshStartup.ts +++ b/src/features/terminal/shells/pwsh/pwshStartup.ts @@ -52,7 +52,7 @@ async function isPowerShellInstalled(shell: string): Promise { } } -async function getProfileForShell(shell: 'powershell' | 'pwsh'): Promise { +export async function getProfileForShell(shell: 'powershell' | 'pwsh'): Promise { const cachedPath = getProfilePathCache(shell); if (cachedPath) { traceInfo(`SHELL: ${shell} profile path from cache: ${cachedPath}`); diff --git a/src/features/terminal/shells/sh/shStartup.ts b/src/features/terminal/shells/sh/shStartup.ts new file mode 100644 index 00000000..43a5e913 --- /dev/null +++ b/src/features/terminal/shells/sh/shStartup.ts @@ -0,0 +1,10 @@ +import * as os from 'os'; +import * as path from 'path'; + +/** + * Returns an array of possible sh profile paths in order of preference. + */ +export async function getShProfiles(): Promise { + const home = os.homedir(); + return path.join(home, '.profile'); +} diff --git a/src/managers/conda/condaUtils.ts b/src/managers/conda/condaUtils.ts index 9fe73e01..3d503aa2 100644 --- a/src/managers/conda/condaUtils.ts +++ b/src/managers/conda/condaUtils.ts @@ -44,6 +44,9 @@ import { import { getConfiguration } from '../../common/workspace.apis'; import { ShellConstants } from '../../features/common/shellConstants'; import { quoteArgs } from '../../features/execution/execUtils'; +import { getBashProfiles, getZshProfiles } from '../../features/terminal/shells/bash/bashStartup'; +import { getProfileForShell } from '../../features/terminal/shells/pwsh/pwshStartup'; +import { getShProfiles } from '../../features/terminal/shells/sh/shStartup'; import { isNativeEnvInfo, NativeEnvInfo, @@ -293,41 +296,51 @@ async function getNamedCondaPythonInfo( if (conda.includes('/') || conda.includes('\\')) { const shActivate = path.join(path.dirname(path.dirname(conda)), 'etc', 'profile.d', 'conda.sh'); + const profileInit = await checkProfileForCondaInitialization(); if (isWindows()) { - shellActivation.set(ShellConstants.GITBASH, [ - { executable: '.', args: [pathForGitBash(shActivate)] }, - { executable: 'conda', args: ['activate', name] }, - ]); + // didn't find gitbash + const rcGitBash: PythonCommandRunConfiguration[] = [{ executable: 'conda', args: ['activate', name] }]; + if (!profileInit.get(ShellConstants.GITBASH)) { + rcGitBash.unshift({ executable: '.', args: [pathForGitBash(shActivate)] }); + } + shellActivation.set(ShellConstants.GITBASH, rcGitBash); shellDeactivation.set(ShellConstants.GITBASH, [{ executable: 'conda', args: ['deactivate'] }]); + // not sure about cmd and how to find profile const cmdActivate = path.join(path.dirname(conda), 'activate.bat'); shellActivation.set(ShellConstants.CMD, [{ executable: cmdActivate, args: [name] }]); shellDeactivation.set(ShellConstants.CMD, [{ executable: 'conda', args: ['deactivate'] }]); } else { - shellActivation.set(ShellConstants.BASH, [ - { executable: '.', args: [shActivate] }, - { executable: 'conda', args: ['activate', name] }, - ]); + // bash + const rc: PythonCommandRunConfiguration[] = [{ executable: 'conda', args: ['activate', name] }]; + if (!profileInit.get(ShellConstants.BASH)) { + rc.unshift({ executable: '.', args: [shActivate] }); + } + shellActivation.set(ShellConstants.BASH, rc); shellDeactivation.set(ShellConstants.BASH, [{ executable: 'conda', args: ['deactivate'] }]); - shellActivation.set(ShellConstants.SH, [ - { executable: '.', args: [shActivate] }, - { executable: 'conda', args: ['activate', name] }, - ]); + const rcSh: PythonCommandRunConfiguration[] = [{ executable: 'conda', args: ['activate', name] }]; + if (!profileInit.get(ShellConstants.SH)) { + rcSh.unshift({ executable: '.', args: [shActivate] }); + } + shellActivation.set(ShellConstants.SH, rcSh); shellDeactivation.set(ShellConstants.SH, [{ executable: 'conda', args: ['deactivate'] }]); - shellActivation.set(ShellConstants.ZSH, [ - { executable: '.', args: [shActivate] }, - { executable: 'conda', args: ['activate', name] }, - ]); + // zsh + const rcZsh: PythonCommandRunConfiguration[] = [{ executable: 'conda', args: ['activate', name] }]; + if (!profileInit.get(ShellConstants.ZSH)) { + rcZsh.unshift({ executable: '.', args: [shActivate] }); + } + shellActivation.set(ShellConstants.ZSH, rcZsh); shellDeactivation.set(ShellConstants.ZSH, [{ executable: 'conda', args: ['deactivate'] }]); } - const psActivate = await getCondaHookPs1Path(conda); - shellActivation.set(ShellConstants.PWSH, [ - { executable: '&', args: [psActivate] }, - { executable: 'conda', args: ['activate', name] }, - ]); + const rcPwsh: PythonCommandRunConfiguration[] = [{ executable: 'conda', args: ['activate', name] }]; + if (!profileInit.get(ShellConstants.PWSH)) { + const psActivate = await getCondaHookPs1Path(conda); + rcPwsh.unshift({ executable: '.', args: [psActivate] }); + } + shellActivation.set(ShellConstants.PWSH, rcPwsh); shellDeactivation.set(ShellConstants.PWSH, [{ executable: 'conda', args: ['deactivate'] }]); } else { shellActivation.set(ShellConstants.GITBASH, [{ executable: 'conda', args: ['activate', name] }]); @@ -374,6 +387,37 @@ async function getNamedCondaPythonInfo( }; } +async function checkProfileForCondaInitialization(): Promise> { + const profileStatusMap = new Map(); + + // bash + const bashProfiles = await getBashProfiles(); + const containsInitBash = await readProfile(bashProfiles); + profileStatusMap.set(ShellConstants.BASH, containsInitBash); + // zsh + const zshProfiles = await getZshProfiles(); + const containsInitZsh = await readProfile(zshProfiles); + profileStatusMap.set(ShellConstants.ZSH, containsInitZsh); + + // sh + const shProfiles = await getShProfiles(); + const containsInitSh = await readProfile(shProfiles); + profileStatusMap.set(ShellConstants.SH, containsInitSh); + + const pwshProfiles = await getProfileForShell('pwsh'); + const containsInitPwsh = await readProfile(pwshProfiles); + profileStatusMap.set(ShellConstants.PWSH, containsInitPwsh); + + return profileStatusMap; +} +async function readProfile(profilePath: string): Promise { + if (await fse.pathExists(profilePath)) { + const content = await fse.readFile(profilePath, 'utf8'); + return content.includes('# >>> conda initialize >>>#'); + } + return false; +} + async function getPrefixesCondaPythonInfo( prefix: string, executable: string,