forked from DonJayamanne/pythonVSCode
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Detect ActiveState Python runtimes (#20532)
- Loading branch information
1 parent
bebf05d
commit d6ba0a7
Showing
22 changed files
with
243 additions
and
0 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
39 changes: 39 additions & 0 deletions
39
src/client/pythonEnvironments/base/locators/lowLevel/activestateLocator.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,39 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
'use strict'; | ||
|
||
import { ActiveState } from '../../../common/environmentManagers/activestate'; | ||
import { PythonEnvKind } from '../../info'; | ||
import { BasicEnvInfo, IPythonEnvsIterator } from '../../locator'; | ||
import { traceError, traceVerbose } from '../../../../logging'; | ||
import { LazyResourceBasedLocator } from '../common/resourceBasedLocator'; | ||
import { findInterpretersInDir } from '../../../common/commonUtils'; | ||
|
||
export class ActiveStateLocator extends LazyResourceBasedLocator { | ||
public readonly providerId: string = 'activestate'; | ||
|
||
// eslint-disable-next-line class-methods-use-this | ||
public async *doIterEnvs(): IPythonEnvsIterator<BasicEnvInfo> { | ||
const projects = await ActiveState.getProjects(); | ||
if (projects === undefined) { | ||
traceVerbose(`Couldn't fetch State Tool projects.`); | ||
return; | ||
} | ||
for (const project of projects) { | ||
if (project.executables) { | ||
for (const dir of project.executables) { | ||
try { | ||
traceVerbose(`Looking for Python in: ${project.name}`); | ||
for await (const exe of findInterpretersInDir(dir)) { | ||
traceVerbose(`Found Python executable: ${exe.filename}`); | ||
yield { kind: PythonEnvKind.ActiveState, executablePath: exe.filename }; | ||
} | ||
} catch (ex) { | ||
traceError(`Failed to process State Tool project: ${JSON.stringify(project)}`, ex); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
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
54 changes: 54 additions & 0 deletions
54
src/client/pythonEnvironments/common/environmentManagers/activestate.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,54 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
'use strict'; | ||
|
||
import * as path from 'path'; | ||
import { pathExists, shellExecute } from '../externalDependencies'; | ||
import { cache } from '../../../common/utils/decorators'; | ||
import { traceError, traceVerbose } from '../../../logging'; | ||
|
||
const STATE_GENERAL_TIMEOUT = 50000; | ||
|
||
export type ProjectInfo = { | ||
name: string; | ||
organization: string; | ||
local_checkouts: string[]; // eslint-disable-line camelcase | ||
executables: string[]; | ||
}; | ||
|
||
export async function isActiveStateEnvironment(interpreterPath: string): Promise<boolean> { | ||
const execDir = path.dirname(interpreterPath); | ||
const runtimeDir = path.dirname(execDir); | ||
return pathExists(path.join(runtimeDir, '_runtime_store')); | ||
} | ||
|
||
export class ActiveState { | ||
public static readonly stateCommand: string = 'state'; | ||
|
||
public static async getProjects(): Promise<ProjectInfo[] | undefined> { | ||
return this.getProjectsCached(); | ||
} | ||
|
||
@cache(30_000, true, 10_000) | ||
private static async getProjectsCached(): Promise<ProjectInfo[] | undefined> { | ||
try { | ||
const result = await shellExecute(`${this.stateCommand} projects -o editor`, { | ||
timeout: STATE_GENERAL_TIMEOUT, | ||
}); | ||
if (!result) { | ||
return undefined; | ||
} | ||
let output = result.stdout.trimEnd(); | ||
if (output[output.length - 1] === '\0') { | ||
// '\0' is a record separator. | ||
output = output.substring(0, output.length - 1); | ||
} | ||
traceVerbose(`${this.stateCommand} projects -o editor: ${output}`); | ||
return JSON.parse(output); | ||
} catch (ex) { | ||
traceError(ex); | ||
return undefined; | ||
} | ||
} | ||
} |
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
51 changes: 51 additions & 0 deletions
51
src/test/pythonEnvironments/base/locators/lowLevel/activestateLocator.unit.test.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,51 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
import * as path from 'path'; | ||
import * as sinon from 'sinon'; | ||
import { PythonEnvKind } from '../../../../../client/pythonEnvironments/base/info'; | ||
import * as externalDependencies from '../../../../../client/pythonEnvironments/common/externalDependencies'; | ||
import { getEnvs } from '../../../../../client/pythonEnvironments/base/locatorUtils'; | ||
import { ActiveStateLocator } from '../../../../../client/pythonEnvironments/base/locators/lowLevel/activestateLocator'; | ||
import { TEST_LAYOUT_ROOT } from '../../../common/commonTestConstants'; | ||
import { assertBasicEnvsEqual } from '../envTestUtils'; | ||
import { ExecutionResult } from '../../../../../client/common/process/types'; | ||
import { createBasicEnv } from '../../common'; | ||
import { getOSType, OSType } from '../../../../../client/common/utils/platform'; | ||
|
||
suite('ActiveState Locator', () => { | ||
const testActiveStateDir = path.join(TEST_LAYOUT_ROOT, 'activestate'); | ||
let shellExecute: sinon.SinonStub; | ||
let locator: ActiveStateLocator; | ||
|
||
suiteSetup(() => { | ||
locator = new ActiveStateLocator(); | ||
shellExecute = sinon.stub(externalDependencies, 'shellExecute'); | ||
shellExecute.callsFake((command: string) => { | ||
if (command === 'state projects -o editor') { | ||
return Promise.resolve<ExecutionResult<string>>({ | ||
stdout: `[{"name":"test","organization":"test-org","local_checkouts":["does-not-matter"],"executables":["${testActiveStateDir}/c09080d1/exec"]},{"name":"test2","organization":"test-org","local_checkouts":["does-not-matter2"],"executables":["${testActiveStateDir}/2af6390a/exec"]}]\n\0`, | ||
}); | ||
} | ||
return Promise.reject(new Error('Command failed')); | ||
}); | ||
}); | ||
|
||
suiteTeardown(() => sinon.restore()); | ||
|
||
test('iterEnvs()', async () => { | ||
const actualEnvs = await getEnvs(locator.iterEnvs()); | ||
const expectedEnvs = [ | ||
createBasicEnv( | ||
PythonEnvKind.ActiveState, | ||
path.join( | ||
testActiveStateDir, | ||
'c09080d1', | ||
'exec', | ||
getOSType() === OSType.Windows ? 'python3.exe' : 'python3', | ||
), | ||
), | ||
]; | ||
assertBasicEnvsEqual(actualEnvs, expectedEnvs); | ||
}); | ||
}); |
53 changes: 53 additions & 0 deletions
53
src/test/pythonEnvironments/common/environmentManagers/activestate.unit.test.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,53 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
import { expect } from 'chai'; | ||
import * as path from 'path'; | ||
import * as TypeMoq from 'typemoq'; | ||
import { IFileSystem } from '../../../../client/common/platform/types'; | ||
import { getOSType, OSType } from '../../../../client/common/utils/platform'; | ||
import { isActiveStateEnvironment } from '../../../../client/pythonEnvironments/common/environmentManagers/activestate'; | ||
import { TEST_LAYOUT_ROOT } from '../commonTestConstants'; | ||
|
||
suite('isActiveStateEnvironment Tests', () => { | ||
const testActiveStateDir = path.join(TEST_LAYOUT_ROOT, 'activestate'); | ||
let fileSystem: TypeMoq.IMock<IFileSystem>; | ||
|
||
setup(() => { | ||
fileSystem = TypeMoq.Mock.ofType<IFileSystem>(); | ||
}); | ||
|
||
test('Return true if runtime is set up', async () => { | ||
const runtimeStorePath = path.join(testActiveStateDir, 'c09080d1', '_runtime_store'); | ||
fileSystem | ||
.setup((f) => f.directoryExists(TypeMoq.It.isValue(runtimeStorePath))) | ||
.returns(() => Promise.resolve(true)); | ||
|
||
const result = await isActiveStateEnvironment( | ||
path.join( | ||
testActiveStateDir, | ||
'c09080d1', | ||
'exec', | ||
getOSType() === OSType.Windows ? 'python3.exe' : 'python3', | ||
), | ||
); | ||
expect(result).to.equal(true); | ||
}); | ||
|
||
test(`Return false if the runtime is not set up`, async () => { | ||
const runtimeStorePath = path.join(testActiveStateDir, 'b6a0705d', '_runtime_store'); | ||
fileSystem | ||
.setup((f) => f.directoryExists(TypeMoq.It.isValue(runtimeStorePath))) | ||
.returns(() => Promise.resolve(false)); | ||
|
||
const result = await isActiveStateEnvironment( | ||
path.join( | ||
testActiveStateDir, | ||
'b6a0705d', | ||
'exec', | ||
getOSType() === OSType.Windows ? 'python3.exe' : 'python3', | ||
), | ||
); | ||
expect(result).to.equal(false); | ||
}); | ||
}); |
Empty file.
Empty file.
Empty file.
1 change: 1 addition & 0 deletions
1
src/test/pythonEnvironments/common/envlayouts/activestate/b6a0705d/exec/python3
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 @@ | ||
invalid python interpreter: missing _runtime_store |
1 change: 1 addition & 0 deletions
1
src/test/pythonEnvironments/common/envlayouts/activestate/b6a0705d/exec/python3.exe
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 @@ | ||
invalid python interpreter: missing _runtime_store |
Empty file.
Empty file.
Empty file.