forked from microsoft/vscode-python
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add locator for pixi environments (microsoft#22968)
Closes microsoft#22978 This adds a locator implementation that properly detects [Pixi](https://pixi.sh/) environments. Pixi environments are essentially conda environments but placed in a specific directory inside the project/workspace. This PR properly detects these and does not do much else. This would unblock a lot of pixi users. I would prefer to use a custom pixi plugin but since the [contribution endpoints are not available yet](microsoft#22797) I think this is the next best thing. Before I put more effort into tests I just want to verify that this approach is valid. Let me know what you think! :) --------- Co-authored-by: Tim de Jager <tim@prefix.dev>
- Loading branch information
1 parent
6a54d3b
commit 8539c06
Showing
40 changed files
with
956 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* eslint-disable class-methods-use-this */ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
import { inject, injectable } from 'inversify'; | ||
import { IInterpreterService } from '../../interpreter/contracts'; | ||
import { IServiceContainer } from '../../ioc/types'; | ||
import { getEnvPath } from '../../pythonEnvironments/base/info/env'; | ||
import { EnvironmentType, ModuleInstallerType } from '../../pythonEnvironments/info'; | ||
import { ExecutionInfo, IConfigurationService } from '../types'; | ||
import { isResource } from '../utils/misc'; | ||
import { ModuleInstaller } from './moduleInstaller'; | ||
import { InterpreterUri } from './types'; | ||
import { getPixiEnvironmentFromInterpreter } from '../../pythonEnvironments/common/environmentManagers/pixi'; | ||
|
||
/** | ||
* A Python module installer for a pixi project. | ||
*/ | ||
@injectable() | ||
export class PixiInstaller extends ModuleInstaller { | ||
constructor( | ||
@inject(IServiceContainer) serviceContainer: IServiceContainer, | ||
@inject(IConfigurationService) private readonly configurationService: IConfigurationService, | ||
) { | ||
super(serviceContainer); | ||
} | ||
|
||
public get name(): string { | ||
return 'Pixi'; | ||
} | ||
|
||
public get displayName(): string { | ||
return 'pixi'; | ||
} | ||
|
||
public get type(): ModuleInstallerType { | ||
return ModuleInstallerType.Pixi; | ||
} | ||
|
||
public get priority(): number { | ||
return 20; | ||
} | ||
|
||
public async isSupported(resource?: InterpreterUri): Promise<boolean> { | ||
if (isResource(resource)) { | ||
const interpreter = await this.serviceContainer | ||
.get<IInterpreterService>(IInterpreterService) | ||
.getActiveInterpreter(resource); | ||
if (!interpreter || interpreter.envType !== EnvironmentType.Pixi) { | ||
return false; | ||
} | ||
|
||
const pixiEnv = await getPixiEnvironmentFromInterpreter(interpreter.path); | ||
return pixiEnv !== undefined; | ||
} | ||
return resource.envType === EnvironmentType.Pixi; | ||
} | ||
|
||
/** | ||
* Return the commandline args needed to install the module. | ||
*/ | ||
protected async getExecutionInfo(moduleName: string, resource?: InterpreterUri): Promise<ExecutionInfo> { | ||
const pythonPath = isResource(resource) | ||
? this.configurationService.getSettings(resource).pythonPath | ||
: getEnvPath(resource.path, resource.envPath).path ?? ''; | ||
|
||
const pixiEnv = await getPixiEnvironmentFromInterpreter(pythonPath); | ||
const execPath = pixiEnv?.pixi.command; | ||
|
||
let args = ['add', moduleName]; | ||
const manifestPath = pixiEnv?.manifestPath; | ||
if (manifestPath !== undefined) { | ||
args = args.concat(['--manifest-path', manifestPath]); | ||
} | ||
|
||
return { | ||
args, | ||
execPath, | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
src/client/common/terminal/environmentActivationProviders/pixiActivationProvider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* eslint-disable class-methods-use-this */ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
'use strict'; | ||
|
||
import { inject, injectable } from 'inversify'; | ||
import { Uri } from 'vscode'; | ||
import { IInterpreterService } from '../../../interpreter/contracts'; | ||
import { ITerminalActivationCommandProvider, TerminalShellType } from '../types'; | ||
import { traceError } from '../../../logging'; | ||
import { | ||
getPixiEnvironmentFromInterpreter, | ||
isNonDefaultPixiEnvironmentName, | ||
} from '../../../pythonEnvironments/common/environmentManagers/pixi'; | ||
import { exec } from '../../../pythonEnvironments/common/externalDependencies'; | ||
import { splitLines } from '../../stringUtils'; | ||
|
||
@injectable() | ||
export class PixiActivationCommandProvider implements ITerminalActivationCommandProvider { | ||
constructor(@inject(IInterpreterService) private readonly interpreterService: IInterpreterService) {} | ||
|
||
// eslint-disable-next-line class-methods-use-this | ||
public isShellSupported(targetShell: TerminalShellType): boolean { | ||
return shellTypeToPixiShell(targetShell) !== undefined; | ||
} | ||
|
||
public async getActivationCommands( | ||
resource: Uri | undefined, | ||
targetShell: TerminalShellType, | ||
): Promise<string[] | undefined> { | ||
const interpreter = await this.interpreterService.getActiveInterpreter(resource); | ||
if (!interpreter) { | ||
return undefined; | ||
} | ||
|
||
return this.getActivationCommandsForInterpreter(interpreter.path, targetShell); | ||
} | ||
|
||
public async getActivationCommandsForInterpreter( | ||
pythonPath: string, | ||
targetShell: TerminalShellType, | ||
): Promise<string[] | undefined> { | ||
const pixiEnv = await getPixiEnvironmentFromInterpreter(pythonPath); | ||
if (!pixiEnv) { | ||
return undefined; | ||
} | ||
|
||
const command = ['shell-hook', '--manifest-path', pixiEnv.manifestPath]; | ||
if (isNonDefaultPixiEnvironmentName(pixiEnv.envName)) { | ||
command.push('--environment'); | ||
command.push(pixiEnv.envName); | ||
} | ||
|
||
const pixiTargetShell = shellTypeToPixiShell(targetShell); | ||
if (pixiTargetShell) { | ||
command.push('--shell'); | ||
command.push(pixiTargetShell); | ||
} | ||
|
||
const shellHookOutput = await exec(pixiEnv.pixi.command, command, { | ||
throwOnStdErr: false, | ||
}).catch(traceError); | ||
if (!shellHookOutput) { | ||
return undefined; | ||
} | ||
|
||
return splitLines(shellHookOutput.stdout, { | ||
removeEmptyEntries: true, | ||
trim: true, | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* Returns the name of a terminal shell type within Pixi. | ||
*/ | ||
function shellTypeToPixiShell(targetShell: TerminalShellType): string | undefined { | ||
switch (targetShell) { | ||
case TerminalShellType.powershell: | ||
case TerminalShellType.powershellCore: | ||
return 'powershell'; | ||
case TerminalShellType.commandPrompt: | ||
return 'cmd'; | ||
|
||
case TerminalShellType.zsh: | ||
return 'zsh'; | ||
|
||
case TerminalShellType.fish: | ||
return 'fish'; | ||
|
||
case TerminalShellType.nushell: | ||
return 'nushell'; | ||
|
||
case TerminalShellType.xonsh: | ||
return 'xonsh'; | ||
|
||
case TerminalShellType.cshell: | ||
// Explicitly unsupported | ||
return undefined; | ||
|
||
case TerminalShellType.gitbash: | ||
case TerminalShellType.bash: | ||
case TerminalShellType.wsl: | ||
case TerminalShellType.tcshell: | ||
case TerminalShellType.other: | ||
default: | ||
return 'bash'; | ||
} | ||
} |
Oops, something went wrong.