forked from DonJayamanne/vscode-python-manager
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathinterpreter.ts
More file actions
101 lines (94 loc) · 3.89 KB
/
Copy pathinterpreter.ts
File metadata and controls
101 lines (94 loc) · 3.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import { PythonExecutableInfo, PythonVersion } from '.';
import {
interpreterInfo as getInterpreterInfoCommand,
InterpreterInfoJson,
} from '../../../common/process/internal/scripts';
import { Architecture } from '../../../common/utils/platform';
import { traceError, traceInfo } from '../../../logging';
import { shellExecute } from '../../common/externalDependencies';
import { copyPythonExecInfo, PythonExecInfo } from '../../exec';
import { parseVersion } from './pythonVersion';
export type InterpreterInformation = {
arch: Architecture;
executable: PythonExecutableInfo;
version: PythonVersion;
};
/**
* Compose full interpreter information based on the given data.
*
* The data format corresponds to the output of the `interpreterInfo.py` script.
*
* @param python - the path to the Python executable
* @param raw - the information returned by the `interpreterInfo.py` script
*/
function extractInterpreterInfo(python: string, raw: InterpreterInfoJson): InterpreterInformation {
let rawVersion = `${raw.versionInfo.slice(0, 3).join('.')}`;
// We only need additional version details if the version is 'alpha', 'beta' or 'candidate'.
// This restriction is needed to avoid sending any PII if this data is used with telemetry.
// With custom builds of python it is possible that release level and values after that can
// contain PII.
if (raw.versionInfo[3] !== undefined && ['final', 'alpha', 'beta', 'candidate'].includes(raw.versionInfo[3])) {
rawVersion = `${rawVersion}-${raw.versionInfo[3]}`;
if (raw.versionInfo[4] !== undefined) {
let serial = -1;
try {
serial = parseInt(`${raw.versionInfo[4]}`, 10);
} catch (ex) {
serial = -1;
}
rawVersion = serial >= 0 ? `${rawVersion}${serial}` : rawVersion;
}
}
return {
arch: raw.is64Bit ? Architecture.x64 : Architecture.x86,
executable: {
filename: python,
sysPrefix: raw.sysPrefix,
mtime: -1,
ctime: -1,
},
version: {
...parseVersion(rawVersion),
sysVersion: raw.sysVersion,
},
};
}
/**
* Collect full interpreter information from the given Python executable.
*
* @param python - the information to use when running Python
* @param timeout - any specific timeouts to use for getting info.
*/
export async function getInterpreterInfo(
python: PythonExecInfo,
timeout?: number,
): Promise<InterpreterInformation | undefined> {
const [args, parse] = getInterpreterInfoCommand();
const info = copyPythonExecInfo(python, args);
const argv = [info.command, ...info.args];
// Concat these together to make a set of quoted strings
const quoted = argv.reduce(
(p, c) => (p ? `${p} ${c.toCommandArgumentForPythonExt()}` : `${c.toCommandArgumentForPythonExt()}`),
'',
);
// Try shell execing the command, followed by the arguments. This will make node kill the process if it
// takes too long.
// Sometimes the python path isn't valid, timeout if that's the case.
// See these two bugs:
// https://github.com/microsoft/vscode-python/issues/7569
// https://github.com/microsoft/vscode-python/issues/7760
const result = await shellExecute(quoted, { timeout: timeout ?? 15000 });
if (result.stderr) {
traceError(
`Stderr when executing script with ${argv} stderr: ${result.stderr}, still attempting to parse output`,
);
}
const json = parse(result.stdout);
if (!json) {
return undefined;
}
traceInfo(`Found interpreter for ${argv}`);
return extractInterpreterInfo(python.pythonExecutable, json);
}