Skip to content
This repository was archived by the owner on Dec 23, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,20 @@ export enum TelemetryEventName {
MICROBIT_PERFORMANCE_DEPLOY_DEVICE = "MICROBIT.PERFORMANCE.DEPLOY.DEVICE",
MICROBIT_PERFORMANCE_NEW_FILE = "MICROBIT.PERFORMANCE.NEW.FILE",
MICROBIT_PERFORMANCE_OPEN_SIMULATOR = "MICROBIT.PERFORMANCE.OPEN.SIMULATOR",

// Venv options
SETUP_VENV_CREATION_ERR = "SETUP.VENV.CREATION.ERR",
SETUP_NO_PIP = "SETUP.NO.PIP",
SETUP_DEP_INSTALL_FAIL = "SETUP.DEP.INSTALL.FAIL",
SETUP_AUTO_RESOLVE_PYTHON_PATH = "SETUP.AUTO.RESOLVE.PYTHON.PATH",
SETUP_NO_PYTHON_PATH = "SETUP.NO.PYTHON.PATH",
SETUP_DOWNLOAD_PYTHON = "SETUP.DOWNLOAD.PYTHON",
SETUP_BAD_PYTHON_PATH = "SETUP.BAD.PYTHON.PATH",
SETUP_INVALID_PYTHON_VER = "SETUP.INVALID.PYTHON.VER",
SETUP_INSTALL_VENV = "SETUP.INSTALL.VENV",
SETUP_ORIGINAL_INTERPRETER_DEP_INSTALL = "SETUP.ORIGINAL.INTERPRETER.DEP.INSTALL",
SETUP_HAS_VENV = "SETUP.HAS.VENV",
SETUP_NO_DEPS_INSTALLED = "SETUP.NO.DEPS.INSTALLED",
}
export const DEFAULT_DEVICE = CONSTANTS.DEVICE_NAME.CPX;

Expand Down
13 changes: 10 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export async function activate(context: vscode.ExtensionContext) {
// doesn't trigger lint errors
updatePylintArgs(context);

pythonExecutablePath = await utils.setupEnv(context);
pythonExecutablePath = await utils.setupEnv(context, telemetryAI);

try {
utils.generateCPXConfig();
Expand Down Expand Up @@ -443,7 +443,11 @@ export async function activate(context: vscode.ExtensionContext) {
const installDependencies: vscode.Disposable = vscode.commands.registerCommand(
"deviceSimulatorExpress.common.installDependencies",
async () => {
pythonExecutablePath = await utils.setupEnv(context, true);
pythonExecutablePath = await utils.setupEnv(
context,
telemetryAI,
true
);
telemetryAI.trackFeatureUsage(
TelemetryEventName.COMMAND_INSTALL_EXTENSION_DEPENDENCIES
);
Expand Down Expand Up @@ -1028,7 +1032,10 @@ export async function activate(context: vscode.ExtensionContext) {
const configsChanged = vscode.workspace.onDidChangeConfiguration(
async () => {
if (utils.checkConfig(CONFIG.CONFIG_ENV_ON_SWITCH)) {
pythonExecutablePath = await utils.setupEnv(context);
pythonExecutablePath = await utils.setupEnv(
context,
telemetryAI
);
}
}
);
Expand Down
78 changes: 66 additions & 12 deletions src/extension_utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ import {
GLOBAL_ENV_VARS,
HELPER_FILES,
SERVER_INFO,
TelemetryEventName,
VERSIONS,
} from "../constants";
import { CPXWorkspace } from "../cpxWorkspace";
import { DeviceContext } from "../deviceContext";
import TelemetryAI from "../telemetry/telemetryAI";

const exec = util.promisify(cp.exec);

Expand Down Expand Up @@ -330,7 +332,8 @@ export const hasVenv = async (context: vscode.ExtensionContext) => {
export const promptInstallVenv = (
context: vscode.ExtensionContext,
pythonExecutable: string,
pythonExecutableName: string
pythonExecutableName: string,
telemetryAI: TelemetryAI
) => {
return vscode.window
.showInformationMessage(
Expand All @@ -343,7 +346,8 @@ export const promptInstallVenv = (
return installPythonVenv(
context,
pythonExecutable,
pythonExecutableName
pythonExecutableName,
telemetryAI
);
} else {
// return pythonExecutable, notifying the caller
Expand Down Expand Up @@ -371,7 +375,8 @@ export const getPythonVenv = async (
export const installPythonVenv = async (
context: vscode.ExtensionContext,
pythonExecutable: string,
pythonExecutableName: string
pythonExecutableName: string,
telemetryAI: TelemetryAI
) => {
const pathToEnv: string = getPathToScript(
context,
Expand All @@ -390,6 +395,9 @@ export const installPythonVenv = async (
// run command to download dependencies to out/python_libs
await executePythonCommand(pythonExecutable, `-m venv "${pathToEnv}"`);
} catch (err) {
telemetryAI.trackFeatureUsage(
TelemetryEventName.SETUP_VENV_CREATION_ERR
);
vscode.window
.showErrorMessage(
`Virtual environment for download could not be completed. Using original interpreter at: ${pythonExecutable}.`,
Expand All @@ -406,7 +414,12 @@ export const installPythonVenv = async (
return pythonExecutable;
}

return installDependenciesWrapper(context, pythonPath, pythonExecutable);
return installDependenciesWrapper(
context,
pythonPath,
telemetryAI,
pythonExecutable
);
};

export const areDependenciesInstalled = async (
Expand Down Expand Up @@ -436,7 +449,8 @@ export const areDependenciesInstalled = async (

export const installDependencies = async (
context: vscode.ExtensionContext,
pythonPath: string
pythonPath: string,
telemetryAI: TelemetryAI
) => {
const requirementsPath: string = getPathToScript(
context,
Expand All @@ -445,6 +459,7 @@ export const installDependencies = async (
);

if (!isPipInstalled(pythonPath)) {
telemetryAI.trackFeatureUsage(TelemetryEventName.SETUP_NO_PIP);
return false;
}

Expand All @@ -465,13 +480,14 @@ export const installDependencies = async (
export const installDependenciesWrapper = async (
context: vscode.ExtensionContext,
pythonPath: string,
telemetryAI: TelemetryAI,
backupPythonPath: string = ""
) => {
let errMessage = CONSTANTS.ERROR.DEPENDENCY_DOWNLOAD_ERROR;
if (backupPythonPath !== "") {
errMessage = `${errMessage} Using original interpreter at: ${backupPythonPath}.`;
}
if (!(await installDependencies(context, pythonPath))) {
if (!(await installDependencies(context, pythonPath, telemetryAI))) {
vscode.window
.showErrorMessage(
CONSTANTS.ERROR.DEPENDENCY_DOWNLOAD_ERROR,
Expand All @@ -482,11 +498,17 @@ export const installDependenciesWrapper = async (
open(CONSTANTS.LINKS.INSTALL);
}
});

telemetryAI.trackFeatureUsage(
TelemetryEventName.SETUP_DEP_INSTALL_FAIL
);
return backupPythonPath;
}
return pythonPath;
};
export const getCurrentpythonExecutablePath = async () => {
export const getCurrentpythonExecutablePath = async (
telemetryAI: TelemetryAI
) => {
let originalpythonExecutablePath = "";

// try to get name from interpreter
Expand All @@ -500,13 +522,19 @@ export const getCurrentpythonExecutablePath = async () => {
originalpythonExecutablePath === GLOBAL_ENV_VARS.PYTHON ||
originalpythonExecutablePath === ""
) {
telemetryAI.trackFeatureUsage(
TelemetryEventName.SETUP_AUTO_RESOLVE_PYTHON_PATH
);
try {
const { stdout } = await executePythonCommand(
GLOBAL_ENV_VARS.PYTHON,
`-c "import sys; print(sys.executable)"`
);
originalpythonExecutablePath = stdout.trim();
} catch (err) {
telemetryAI.trackFeatureUsage(
TelemetryEventName.SETUP_NO_PYTHON_PATH
);
vscode.window
.showErrorMessage(
CONSTANTS.ERROR.NO_PYTHON_PATH,
Expand All @@ -515,6 +543,9 @@ export const getCurrentpythonExecutablePath = async () => {
.then((selection: vscode.MessageItem | undefined) => {
if (selection === DialogResponses.INSTALL_PYTHON) {
const okAction = () => {
telemetryAI.trackFeatureUsage(
TelemetryEventName.SETUP_DOWNLOAD_PYTHON
);
open(CONSTANTS.LINKS.DOWNLOAD_PYTHON);
};
showPrivacyModal(
Expand All @@ -523,7 +554,6 @@ export const getCurrentpythonExecutablePath = async () => {
);
}
});

// no python installed, cannot get path
return "";
}
Expand All @@ -538,20 +568,27 @@ export const getCurrentpythonExecutablePath = async () => {

if (!fs.existsSync(originalpythonExecutablePath)) {
await vscode.window.showErrorMessage(CONSTANTS.ERROR.BAD_PYTHON_PATH);
telemetryAI.trackFeatureUsage(TelemetryEventName.SETUP_BAD_PYTHON_PATH);
return "";
}

if (!(await validatePythonVersion(originalpythonExecutablePath))) {
telemetryAI.trackFeatureUsage(
TelemetryEventName.SETUP_INVALID_PYTHON_VER
);
return "";
}

return originalpythonExecutablePath;
};
export const setupEnv = async (
context: vscode.ExtensionContext,
telemetryAI: TelemetryAI,
needsResponse: boolean = false
) => {
const originalpythonExecutablePath = await getCurrentpythonExecutablePath();
const originalpythonExecutablePath = await getCurrentpythonExecutablePath(
telemetryAI
);
let pythonExecutablePath = originalpythonExecutablePath;
let pythonExecutableName: string =
os.platform() === "win32"
Expand All @@ -567,6 +604,7 @@ export const setupEnv = async (
);
if (await hasVenv(context)) {
// venv in extention exists with wrong dependencies

if (
!(await areDependenciesInstalled(
context,
Expand All @@ -576,6 +614,7 @@ export const setupEnv = async (
pythonExecutablePath = await installDependenciesWrapper(
context,
pythonExecutablePathVenv,
telemetryAI,
pythonExecutablePath
);
} else {
Expand All @@ -585,7 +624,11 @@ export const setupEnv = async (
pythonExecutablePath = await promptInstallVenv(
context,
originalpythonExecutablePath,
pythonExecutableName
pythonExecutableName,
telemetryAI
);
telemetryAI.trackFeatureUsage(
TelemetryEventName.SETUP_INSTALL_VENV
);
}

Expand All @@ -597,6 +640,8 @@ export const setupEnv = async (
.getConfiguration()
.update(CONFIG.PYTHON_PATH, pythonExecutablePath);
}
} else {
telemetryAI.trackFeatureUsage(TelemetryEventName.SETUP_HAS_VENV);
}
if (pythonExecutablePath === originalpythonExecutablePath) {
// going with original interpreter, either because
Expand All @@ -613,9 +658,13 @@ export const setupEnv = async (
installChoice: vscode.MessageItem | undefined
) => {
if (installChoice === DialogResponses.INSTALL_NOW) {
telemetryAI.trackFeatureUsage(
TelemetryEventName.SETUP_ORIGINAL_INTERPRETER_DEP_INSTALL
);
await installDependenciesWrapper(
context,
pythonExecutablePath
pythonExecutablePath,
telemetryAI
);
} else {
await vscode.window
Expand All @@ -636,7 +685,12 @@ export const setupEnv = async (
) {
await installDependenciesWrapper(
context,
pythonExecutablePath
pythonExecutablePath,
telemetryAI
);
} else {
telemetryAI.trackFeatureUsage(
TelemetryEventName.SETUP_NO_DEPS_INSTALLED
);
}
}
Expand Down