@@ -55,7 +55,7 @@ import { selectFromCommonPackagesToInstall } from '../common/pickers';
5555import { Installable } from '../common/types' ;
5656import { shortVersion , sortEnvironments } from '../common/utils' ;
5757import { CondaEnvManager } from './condaEnvManager' ;
58- import { getLocalActivationScript } from './condaSourcingUtils' ;
58+ import { getCondaHookPs1Path , getLocalActivationScript } from './condaSourcingUtils' ;
5959
6060export const CONDA_PATH_KEY = `${ ENVS_EXTENSION_ID } :conda:CONDA_PATH` ;
6161export const CONDA_PREFIXES_KEY = `${ ENVS_EXTENSION_ID } :conda:CONDA_PREFIXES` ;
@@ -391,76 +391,117 @@ async function generateShellActivationMap2(
391391 envManager : EnvironmentManager ,
392392 name ?: string ,
393393) : Promise < ShellCommandMaps > {
394- // Determine the environment identifier to use
395- const envIdentifier = name ? name : prefix ;
394+ // Array to collect all logs
395+ const logs : string [ ] = [ ] ;
396+ let shellMaps : ShellCommandMaps ;
396397
397- traceInfo (
398- `Generating shell activation map for conda environment identifier: "${ envIdentifier } " (prefix: "${ prefix } ", name: "${
399- name ?? 'undefined'
400- } ")`,
401- ) ;
402-
403- let condaCommonActivate : PythonCommandRunConfiguration | undefined = {
404- executable : 'conda' ,
405- args : [ 'activate' , envIdentifier ] ,
406- } ;
407- let condaCommonDeactivate : PythonCommandRunConfiguration | undefined = {
408- executable : 'conda' ,
409- args : [ 'deactivate' ] ,
410- } ;
411-
412- if ( ! ( envManager instanceof CondaEnvManager ) || ! envManager . sourcingInformation ) {
413- traceError (
414- 'Conda environment manager is not available, unable to generate shell activation map correctly- returning default conda activation paths.' ,
415- ) ;
416- return generateShellActivationMapFromConfig ( [ condaCommonActivate ] , [ condaCommonDeactivate ] ) ;
417- }
418-
419- const { isActiveOnLaunch, globalSourcingScript, shellSourcingScripts } = envManager . sourcingInformation ;
420- traceVerbose (
421- `isActiveOnLaunch: ${ isActiveOnLaunch } , globalSourcingScript: ${ globalSourcingScript } , shellSourcingScripts: ${ shellSourcingScripts ?. join (
422- ', ' ,
423- ) } `,
424- ) ;
425-
426- // P1: first check to see if conda is already active in the whole VS Code workspace via sourcing info (set at startup)
427- if ( isActiveOnLaunch ) {
428- traceInfo ( 'Conda is already active on launch, using default activation commands' ) ;
429- return generateShellActivationMapFromConfig ( [ condaCommonActivate ] , [ condaCommonDeactivate ] ) ;
430- }
431-
432- // get the local activation path, if exists use this
433- let localSourcingPath : string | undefined ;
434398 try {
435- localSourcingPath = await getLocalActivationScript ( prefix ) ;
436- } catch {
437- console . log ( 'tragic error' ) ;
438- }
439- traceInfo ( `Local activation script status: ${ localSourcingPath ? 'found at ' + localSourcingPath : 'not found' } ` ) ;
399+ // Determine the environment identifier to use
400+ const envIdentifier = name ? name : prefix ;
401+
402+ logs . push ( `Environment Configuration:
403+ - Identifier: "${ envIdentifier } "
404+ - Prefix: "${ prefix } "
405+ - Name: "${ name ?? 'undefined' } "
406+ ` ) ;
407+
408+ let condaCommonActivate : PythonCommandRunConfiguration | undefined = {
409+ executable : 'conda' ,
410+ args : [ 'activate' , envIdentifier ] ,
411+ } ;
412+ let condaCommonDeactivate : PythonCommandRunConfiguration | undefined = {
413+ executable : 'conda' ,
414+ args : [ 'deactivate' ] ,
415+ } ;
416+
417+ if ( ! ( envManager instanceof CondaEnvManager ) || ! envManager . sourcingInformation ) {
418+ logs . push ( '⚠️ Error: Conda environment manager is not available, using default conda activation paths' ) ;
419+ shellMaps = await generateShellActivationMapFromConfig ( [ condaCommonActivate ] , [ condaCommonDeactivate ] ) ;
420+ return shellMaps ;
421+ }
422+
423+ const { isActiveOnLaunch, globalSourcingScript, shellSourcingScripts } = envManager . sourcingInformation ;
424+ logs . push ( `Sourcing Information:
425+ - Active on Launch: ${ isActiveOnLaunch }
426+ - Global Script: ${ globalSourcingScript ?? 'none' }
427+ - Shell Scripts: ${ shellSourcingScripts ?. join ( ', ' ) ?? 'none' }
428+ ` ) ;
429+
430+ // P1: first check to see if conda is already active in the whole VS Code workspace via sourcing info (set at startup)
431+ if ( isActiveOnLaunch ) {
432+ logs . push ( '✓ Conda already active on launch, using default activation commands' ) ;
433+ shellMaps = await generateShellActivationMapFromConfig ( [ condaCommonActivate ] , [ condaCommonDeactivate ] ) ;
434+ return shellMaps ;
435+ }
440436
441- // Determine the preferred sourcing path with preference to local
442- const preferredSourcingPath = localSourcingPath || globalSourcingScript ;
437+ // get the local activation path, if exists use this
438+ let localSourcingPath : string | undefined ;
439+ try {
440+ localSourcingPath = await getLocalActivationScript ( prefix ) ;
441+ } catch ( err ) {
442+ logs . push (
443+ `⚠️ Error getting local activation script: ${ err instanceof Error ? err . message : 'Unknown error' } ` ,
444+ ) ;
445+ }
443446
444- traceInfo ( `Selected preferred sourcing path is: ${ preferredSourcingPath ?? 'none found' } ` ) ;
447+ logs . push ( `Local Activation:
448+ - Status: ${ localSourcingPath ? 'Found' : 'Not Found' }
449+ - Path: ${ localSourcingPath ?? 'N/A' }
450+ ` ) ;
451+
452+ // Determine the preferred sourcing path with preference to local
453+ const preferredSourcingPath = localSourcingPath || globalSourcingScript ;
454+ logs . push ( `Preferred Sourcing:
455+ - Selected Path: ${ preferredSourcingPath ?? 'none found' }
456+ - Source: ${ localSourcingPath ? 'Local' : globalSourcingScript ? 'Global' : 'None' }
457+ ` ) ;
458+
459+ // P2: Return shell activation if we have no sourcing
460+ if ( ! preferredSourcingPath ) {
461+ logs . push ( '⚠️ No sourcing path found, using default conda activation' ) ;
462+ shellMaps = await generateShellActivationMapFromConfig ( [ condaCommonActivate ] , [ condaCommonDeactivate ] ) ;
463+ return shellMaps ;
464+ }
445465
446- // P2: Return shell activation if we have no sourcing
447- if ( ! preferredSourcingPath ) {
448- traceInfo ( 'No sourcing path found, falling back to default conda activation' ) ;
449- return generateShellActivationMapFromConfig ( [ condaCommonActivate ] , [ condaCommonDeactivate ] ) ;
450- }
466+ // P3: Handle Windows specifically ;this is carryover from vscode-python
467+ if ( isWindows ( ) ) {
468+ logs . push ( '✓ Using Windows-specific activation configuration' ) ;
469+ shellMaps = await windowsExceptionGenerateConfig (
470+ preferredSourcingPath ,
471+ envIdentifier ,
472+ envManager . sourcingInformation . condaFolder ,
473+ ) ;
474+ return shellMaps ;
475+ }
451476
452- // P3: Handle Windows specifically ;this is carryover from vscode-python
453- if ( isWindows ( ) ) {
454- traceInfo ( 'Using Windows-specific activation configuration' ) ;
455- return windowsExceptionGenerateConfig ( preferredSourcingPath , envIdentifier ) ;
477+ logs . push ( '✓ Using source command with preferred path' ) ;
478+ const condaSourcingPathFirst = {
479+ executable : 'source' ,
480+ args : [ preferredSourcingPath , envIdentifier ] ,
481+ } ;
482+ shellMaps = await generateShellActivationMapFromConfig ( [ condaSourcingPathFirst ] , [ condaCommonDeactivate ] ) ;
483+ return shellMaps ;
484+ } catch ( error ) {
485+ logs . push (
486+ `❌ Error in shell activation map generation: ${ error instanceof Error ? error . message : 'Unknown error' } ` ,
487+ ) ;
488+ traceError ( 'Failed to generate shell activation map. Falling back to default conda activation' ) ;
489+ // Fall back to default conda activation in case of error
490+ shellMaps = await generateShellActivationMapFromConfig (
491+ [ { executable : 'conda' , args : [ 'activate' , name || prefix ] } ] ,
492+ [ { executable : 'conda' , args : [ 'deactivate' ] } ] ,
493+ ) ;
494+ return shellMaps ;
495+ } finally {
496+ // Always print logs in a nicely formatted block, even if there was an error
497+ traceInfo (
498+ [
499+ '=== Conda Shell Activation Map Generation ===' ,
500+ ...logs ,
501+ '==========================================' ,
502+ ] . join ( '\n' ) ,
503+ ) ;
456504 }
457-
458- traceInfo ( 'Sourcing with preferred path before launching' ) ;
459- const condaSourcingPathFirst = {
460- executable : 'source' ,
461- args : [ preferredSourcingPath , envIdentifier ] ,
462- } ;
463- return generateShellActivationMapFromConfig ( [ condaSourcingPathFirst ] , [ condaCommonDeactivate ] ) ;
464505}
465506
466507async function generateShellActivationMapFromConfig (
@@ -493,7 +534,11 @@ async function generateShellActivationMapFromConfig(
493534 return { shellActivation, shellDeactivation } ;
494535}
495536
496- async function windowsExceptionGenerateConfig ( sourceInitPath : string , prefix : string ) : Promise < ShellCommandMaps > {
537+ async function windowsExceptionGenerateConfig (
538+ sourceInitPath : string ,
539+ prefix : string ,
540+ condaFolder : string ,
541+ ) : Promise < ShellCommandMaps > {
497542 const shellActivation : Map < string , PythonCommandRunConfiguration [ ] > = new Map ( ) ;
498543 const shellDeactivation : Map < string , PythonCommandRunConfiguration [ ] > = new Map ( ) ;
499544
@@ -503,22 +548,34 @@ async function windowsExceptionGenerateConfig(sourceInitPath: string, prefix: st
503548 // source pathInit ENVNAME for all NON bash
504549
505550 // not bash activate
506- const NonBashActivate = [ { executable : sourceInitPath , args : [ 'conda' , 'activate' , prefix ] } ] ;
507- // yes bash activate
508- const bashActivate = [ { executable : 'source' , args : [ sourceInitPath , prefix ] } ] ;
509- //common deactivate
510- let condaCommonActivate : PythonCommandRunConfiguration | undefined = {
551+ const ps1Hook = await getCondaHookPs1Path ( condaFolder ) ;
552+ traceVerbose ( `PS1 hook path: ${ ps1Hook ?? 'not found' } ` ) ;
553+ const activation = ps1Hook ? ps1Hook : sourceInitPath ;
554+
555+ const pwshActivate = [ { executable : activation } , { executable : 'conda' , args : [ 'activate' , prefix ] } ] ;
556+ const cmdActivate = [ { executable : sourceInitPath } , { executable : 'conda' , args : [ 'activate' , prefix ] } ] ;
557+
558+ const bashActivate = [ { executable : 'source' , args : [ sourceInitPath . replace ( / \\ / g, '/' ) , prefix ] } ] ;
559+ // TODO: for bashActivate the sep is \ but needs to be / ??? tried on gitbash
560+ traceVerbose (
561+ `Windows activation commands:
562+ PowerShell: ${ JSON . stringify ( pwshActivate ) } ,
563+ CMD: ${ JSON . stringify ( cmdActivate ) } ,
564+ Bash: ${ JSON . stringify ( bashActivate ) } ` ,
565+ ) ;
566+
567+ let condaCommonDeactivate : PythonCommandRunConfiguration | undefined = {
511568 executable : 'conda' ,
512- args : [ 'activate' , prefix ] ,
569+ args : [ 'deactivate' ] ,
513570 } ;
514571 shellActivation . set ( ShellConstants . GITBASH , bashActivate ) ;
515- shellDeactivation . set ( ShellConstants . GITBASH , [ condaCommonActivate ] ) ;
572+ shellDeactivation . set ( ShellConstants . GITBASH , [ condaCommonDeactivate ] ) ;
516573
517- shellActivation . set ( ShellConstants . CMD , NonBashActivate ) ;
518- shellDeactivation . set ( ShellConstants . CMD , [ condaCommonActivate ] ) ;
574+ shellActivation . set ( ShellConstants . CMD , cmdActivate ) ;
575+ shellDeactivation . set ( ShellConstants . CMD , [ condaCommonDeactivate ] ) ;
519576
520- shellActivation . set ( ShellConstants . PWSH , NonBashActivate ) ;
521- shellDeactivation . set ( ShellConstants . PWSH , [ condaCommonActivate ] ) ;
577+ shellActivation . set ( ShellConstants . PWSH , pwshActivate ) ;
578+ shellDeactivation . set ( ShellConstants . PWSH , [ condaCommonDeactivate ] ) ;
522579
523580 return { shellActivation, shellDeactivation } ;
524581}
0 commit comments