summaryrefslogtreecommitdiff
path: root/extension/src/activation
diff options
context:
space:
mode:
authorNate Sesti <sestinj@gmail.com>2023-07-24 01:00:42 -0700
committerNate Sesti <sestinj@gmail.com>2023-07-24 01:00:42 -0700
commit85ce06beb9b2d587b0b572117a98318d226bed61 (patch)
tree76fc6232b5219d0bd61b547b26624641a99e7b9b /extension/src/activation
parent699a74250fd4cf91af930ff63077aeb81f74856f (diff)
parent885f88af1d7b35e03b1de4df3e74a60da1a777ed (diff)
downloadsncontinue-85ce06beb9b2d587b0b572117a98318d226bed61.tar.gz
sncontinue-85ce06beb9b2d587b0b572117a98318d226bed61.tar.bz2
sncontinue-85ce06beb9b2d587b0b572117a98318d226bed61.zip
Merge branch 'main' into show-react-immediately
Diffstat (limited to 'extension/src/activation')
-rw-r--r--extension/src/activation/activate.ts58
-rw-r--r--extension/src/activation/environmentSetup.ts147
2 files changed, 135 insertions, 70 deletions
diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts
index b03282e5..0c6e6009 100644
--- a/extension/src/activation/activate.ts
+++ b/extension/src/activation/activate.ts
@@ -1,7 +1,6 @@
import * as vscode from "vscode";
import { registerAllCommands } from "../commands";
import { registerAllCodeLensProviders } from "../lang-server/codeLens";
-import { sendTelemetryEvent, TelemetryEvent } from "../telemetry";
import IdeProtocolClient from "../continueIdeClient";
import { getContinueServerUrl } from "../bridge";
import { ContinueGUIWebviewViewProvider } from "../debugPanel";
@@ -10,6 +9,8 @@ import {
startContinuePythonServer,
} from "./environmentSetup";
import fetch from "node-fetch";
+import registerQuickFixProvider from "../lang-server/codeActions";
+import { get } from "http";
// import { CapturedTerminal } from "../terminal/terminalEmulator";
const PACKAGE_JSON_RAW_GITHUB_URL =
@@ -35,21 +36,40 @@ export async function activateExtension(context: vscode.ExtensionContext) {
})
.catch((e) => console.log("Error checking for extension updates: ", e));
+ // Start the server and display loader if taking > 2 seconds
const sessionIdPromise = (async () => {
- // Start the Python server
- await new Promise((resolve, reject) => {
- vscode.window.withProgress(
- {
- location: vscode.ProgressLocation.Notification,
- title:
- "Starting Continue Server... (it may take a minute to download Python packages)",
- cancellable: false,
- },
- async (progress, token) => {
- await startContinuePythonServer();
- resolve(null);
+ await new Promise((resolve) => {
+ let serverStarted = false;
+
+ // Start the server and set serverStarted to true when done
+ startContinuePythonServer().then(() => {
+ serverStarted = true;
+ resolve(null);
+ });
+
+ // Wait for 2 seconds
+ setTimeout(() => {
+ // If the server hasn't started after 2 seconds, show the notification
+ if (!serverStarted) {
+ vscode.window.withProgress(
+ {
+ location: vscode.ProgressLocation.Notification,
+ title:
+ "Starting Continue Server... (it may take a minute to download Python packages)",
+ cancellable: false,
+ },
+ async (progress, token) => {
+ // Wait for the server to start
+ while (!serverStarted) {
+ await new Promise((innerResolve) =>
+ setTimeout(innerResolve, 1000)
+ );
+ }
+ return Promise.resolve();
+ }
+ );
}
- );
+ }, 2000);
});
// Initialize IDE Protocol Client
@@ -58,11 +78,10 @@ export async function activateExtension(context: vscode.ExtensionContext) {
`${serverUrl.replace("http", "ws")}/ide/ws`,
context
);
-
- return ideProtocolClient.getSessionId();
+ return await ideProtocolClient.getSessionId();
})();
- // Register the webview
+ // Register Continue GUI as sidebar webview, and beging a new session
const provider = new ContinueGUIWebviewViewProvider(sessionIdPromise);
context.subscriptions.push(
@@ -74,9 +93,4 @@ export async function activateExtension(context: vscode.ExtensionContext) {
}
)
);
-
- // Register commands and providers
- sendTelemetryEvent(TelemetryEvent.ExtensionActivated);
- registerAllCodeLensProviders(context);
- registerAllCommands(context);
}
diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts
index 7bd08929..5a9345a6 100644
--- a/extension/src/activation/environmentSetup.ts
+++ b/extension/src/activation/environmentSetup.ts
@@ -9,7 +9,9 @@ import fetch from "node-fetch";
import * as vscode from "vscode";
import * as os from "os";
import fkill from "fkill";
-import { sendTelemetryEvent, TelemetryEvent } from "../telemetry";
+
+const WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR =
+ "A Python virtual enviroment cannot be activated because running scripts is disabled for this user. In order to use Continue, please enable signed scripts to run with this command in PowerShell: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`, reload VS Code, and then try again.";
const MAX_RETRIES = 3;
async function retryThenFail(
@@ -17,17 +19,43 @@ async function retryThenFail(
retries: number = MAX_RETRIES
): Promise<any> {
try {
+ if (retries < MAX_RETRIES && process.platform === "win32") {
+ let [stdout, stderr] = await runCommand("Get-ExecutionPolicy");
+ if (!stdout.includes("RemoteSigned")) {
+ [stdout, stderr] = await runCommand(
+ "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser"
+ );
+ console.log("Execution policy stdout: ", stdout);
+ console.log("Execution policy stderr: ", stderr);
+ }
+ }
+
return await fn();
} catch (e: any) {
if (retries > 0) {
return await retryThenFail(fn, retries - 1);
}
- vscode.window.showInformationMessage(
- "Failed to set up Continue extension. Please email nate@continue.dev and we'll get this fixed ASAP!"
- );
- sendTelemetryEvent(TelemetryEvent.ExtensionSetupError, {
- error: e.message,
- });
+
+ // Show corresponding error message depending on the platform
+ let msg =
+ "Failed to set up Continue extension. Please email hi@continue.dev and we'll get this fixed ASAP!";
+ try {
+ switch (process.platform) {
+ case "win32":
+ msg = WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR;
+ break;
+ case "darwin":
+ break;
+ case "linux":
+ const [pythonCmd] = await getPythonPipCommands();
+ msg = await getLinuxAptInstallError(pythonCmd);
+ break;
+ }
+ } finally {
+ console.log("After retries, failed to set up Continue extension", msg);
+ vscode.window.showErrorMessage(msg);
+ }
+
throw e;
}
}
@@ -51,12 +79,6 @@ async function runCommand(cmd: string): Promise<[string, string | undefined]> {
stdout = "";
}
- if (stderr) {
- sendTelemetryEvent(TelemetryEvent.ExtensionSetupError, {
- error: stderr,
- });
- }
-
return [stdout, stderr];
}
@@ -107,7 +129,7 @@ export async function getPythonPipCommands() {
if (!versionExists) {
vscode.window.showErrorMessage(
- "Continue requires Python3 version 3.8 or greater. Please update your Python3 installation, reload VS Code, and try again."
+ "Continue requires Python version 3.8 or greater. Please update your Python installation, reload VS Code, and try again."
);
throw new Error("Python3.8 or greater is not installed.");
}
@@ -186,16 +208,22 @@ async function checkRequirementsInstalled() {
return fs.existsSync(continuePath);
}
-async function setupPythonEnv() {
- console.log("Setting up python env for Continue extension...");
-
- const [pythonCmd, pipCmd] = await getPythonPipCommands();
- const [activateCmd, pipUpgradeCmd] = getActivateUpgradeCommands(
- pythonCmd,
- pipCmd
- );
+async function getLinuxAptInstallError(pythonCmd: string) {
+ // First, try to run the command to install python3-venv
+ let [stdout, stderr] = await runCommand(`${pythonCmd} --version`);
+ if (stderr) {
+ await vscode.window.showErrorMessage(
+ "Python3 is not installed. Please install from https://www.python.org/downloads, reload VS Code, and try again."
+ );
+ throw new Error(stderr);
+ }
+ const version = stdout.split(" ")[1].split(".")[1];
+ const installVenvCommand = `apt-get install python3.${version}-venv`;
+ await runCommand("apt-get update");
+ return `[Important] Continue needs to create a Python virtual environment, but python3.${version}-venv is not installed. Please run this command in your terminal: \`${installVenvCommand}\`, reload VS Code, and then try again.`;
+}
- // First, create the virtual environment
+async function createPythonVenv(pythonCmd: string) {
if (checkEnvExists()) {
console.log("Python env already exists, skipping...");
} else {
@@ -210,32 +238,38 @@ async function setupPythonEnv() {
stderr &&
stderr.includes("running scripts is disabled on this system")
) {
- await vscode.window.showErrorMessage(
- "A Python virtual enviroment cannot be activated because running scripts is disabled for this user. Please enable signed scripts to run with this command in PowerShell: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`, reload VS Code, and then try again."
- );
+ console.log("Scripts disabled error when trying to create env");
+ await vscode.window.showErrorMessage(WINDOWS_REMOTE_SIGNED_SCRIPTS_ERROR);
throw new Error(stderr);
} else if (
stderr?.includes("On Debian/Ubuntu systems") ||
stdout?.includes("On Debian/Ubuntu systems")
) {
- // First, try to run the command to install python3-venv
- let [stdout, stderr] = await runCommand(`${pythonCmd} --version`);
- if (stderr) {
- await vscode.window.showErrorMessage(
- "Python3 is not installed. Please install from https://www.python.org/downloads, reload VS Code, and try again."
- );
- throw new Error(stderr);
- }
- const version = stdout.split(" ")[1].split(".")[1];
- const installVenvCommand = `apt-get install python3.${version}-venv`;
- await runCommand("apt-get update");
- // Ask the user to run the command to install python3-venv (requires sudo, so we can't)
- // First, get the python version
- const msg = `[Important] Continue needs to create a Python virtual environment, but python3.${version}-venv is not installed. Please run this command in your terminal: \`${installVenvCommand}\`, reload VS Code, and then try again.`;
+ const msg = await getLinuxAptInstallError(pythonCmd);
console.log(msg);
await vscode.window.showErrorMessage(msg);
} else if (checkEnvExists()) {
console.log("Successfully set up python env at ", `${serverPath()}/env`);
+ } else if (
+ stderr?.includes("Permission denied") &&
+ stderr?.includes("python.exe")
+ ) {
+ // This might mean that another window is currently using the python.exe file to install requirements
+ // So we want to wait and try again
+ let i = 0;
+ await new Promise((resolve, reject) =>
+ setInterval(() => {
+ if (i > 5) {
+ reject("Timed out waiting for other window to create env...");
+ }
+ if (checkEnvExists()) {
+ resolve(null);
+ } else {
+ console.log("Waiting for other window to create env...");
+ }
+ i++;
+ }, 5000)
+ );
} else {
const msg = [
"Python environment not successfully created. Trying again. Here was the stdout + stderr: ",
@@ -246,9 +280,22 @@ async function setupPythonEnv() {
throw new Error(msg);
}
}
+}
+
+async function setupPythonEnv() {
+ console.log("Setting up python env for Continue extension...");
+
+ const [pythonCmd, pipCmd] = await getPythonPipCommands();
+ const [activateCmd, pipUpgradeCmd] = getActivateUpgradeCommands(
+ pythonCmd,
+ pipCmd
+ );
- // Install the requirements
await retryThenFail(async () => {
+ // First, create the virtual environment
+ await createPythonVenv(pythonCmd);
+
+ // Install the requirements
if (await checkRequirementsInstalled()) {
console.log("Python requirements already installed, skipping...");
} else {
@@ -343,6 +390,14 @@ function serverPath(): string {
return sPath;
}
+export function devDataPath(): string {
+ const sPath = path.join(getContinueGlobalPath(), "dev_data");
+ if (!fs.existsSync(sPath)) {
+ fs.mkdirSync(sPath);
+ }
+ return sPath;
+}
+
function serverVersionPath(): string {
return path.join(serverPath(), "server_version.txt");
}
@@ -409,21 +464,17 @@ export async function startContinuePythonServer() {
console.log(`stdout: ${data}`);
if (
data.includes("Uvicorn running on") || // Successfully started the server
- data.includes("address already in use") // The server is already running (probably a simultaneously opened VS Code window)
+ data.includes("only one usage of each socket address") || // [windows] The server is already running (probably a simultaneously opened VS Code window)
+ data.includes("address already in use") // [mac/linux] The server is already running (probably a simultaneously opened VS Code window)
) {
console.log("Successfully started Continue python server");
resolve(null);
} else if (data.includes("ERROR") || data.includes("Traceback")) {
- sendTelemetryEvent(TelemetryEvent.ExtensionSetupError, {
- error: data,
- });
+ console.log("Error starting Continue python server: ", data);
}
});
child.on("error", (error: any) => {
console.log(`error: ${error.message}`);
- sendTelemetryEvent(TelemetryEvent.ExtensionSetupError, {
- error: error.message,
- });
});
// Write the current version of vscode to a file called server_version.txt