Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to disable auto-update #80

Merged
merged 25 commits into from
Nov 18, 2023
1 change: 1 addition & 0 deletions changelog.d/62.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add option to disable auto-update
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@
],
"default": null,
"description": "Path to local mirrord installation."
},
"mirrord.autoUpdate": {
"type": ["string", "boolean"],
"default": true,
"description": "Automatically update mirrord binary."
}
}
},
Expand Down Expand Up @@ -226,7 +231,7 @@
},
"dependencies": {
"axios": "^1.4.0",
"semver": "^7.3.7",
"semver": "^7.5.4",
"toml": "^3.0.0",
"vscode-uri": "^3.0.7",
"which": "^3.0.1",
Expand Down
112 changes: 81 additions & 31 deletions src/binaryManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios, { AxiosResponse } from 'axios';
import * as vscode from 'vscode';
import which from 'which';
import { globalContext } from './extension';
import { MirrordAPI } from './api';
Expand All @@ -7,6 +8,7 @@ import * as fs from 'node:fs';
import { platform } from 'os';
import { Uri, workspace, window, ProgressLocation, ExtensionMode } from 'vscode';
import { NotificationBuilder } from './notification';
import * as semver from 'semver';

const mirrordBinaryEndpoint = 'https://version.mirrord.dev/v1/version';
// const binaryCheckInterval = 1000 * 60 * 3;
Expand All @@ -19,37 +21,42 @@ function getExtensionMirrordPath(): Uri {

/**
* Tries to find local mirrord in path or in extension storage.
* @param version If specified, then the version of the binary is checked and matched path is returned if it matches.
* @returns Path to mirrord binary or null if not found
*/
export async function getLocalMirrordBinary(version?: string): Promise<string | null> {
try {
const mirrordPath = await which("mirrord");
const mirrordPath = getExtensionMirrordPath();
eyalb181 marked this conversation as resolved.
Show resolved Hide resolved
await workspace.fs.stat(mirrordPath);
eyalb181 marked this conversation as resolved.
Show resolved Hide resolved
if (version) {
const api = new MirrordAPI(mirrordPath);
const api = new MirrordAPI(mirrordPath.fsPath);
const installedVersion = await api.getBinaryVersion();
if (installedVersion === version) {
return mirrordPath;
return mirrordPath.fsPath;
}
} else {
return mirrordPath;
return mirrordPath.fsPath;
}

} catch (e) {
console.debug("couldn't find mirrord in path");
console.log("couldn't find mirrord in extension storage");
}
try {
const mirrordPath = getExtensionMirrordPath();
await workspace.fs.stat(mirrordPath);
const mirrordPath = await which("mirrord");
if (version) {
const api = new MirrordAPI(mirrordPath.fsPath);
const api = new MirrordAPI(mirrordPath);
const installedVersion = await api.getBinaryVersion();
if (installedVersion === version) {
return mirrordPath.fsPath;

// we use semver.get here because installedVersion can be greater than the latest version
// if we are running on the release CI.
if (installedVersion && semver.gte(installedVersion, version)) {
return mirrordPath;
}
} else {
return mirrordPath.fsPath;
return mirrordPath;
}

} catch (e) {
console.log("couldn't find mirrord in extension storage");
console.debug("couldn't find mirrord in path");
}
return null;
}
Expand Down Expand Up @@ -93,33 +100,76 @@ async function getConfiguredMirrordBinary(): Promise<string | null> {
}

/**
* Downloads mirrord binary (if needed) and returns its path
*/
export async function getMirrordBinary(): Promise<string> {
* Toggles auto-update of mirrord binary.
* Criteria for auto-update:
* - Auto-update is enabled by default
* - if mirrord binary path is mentioned in workspace settings, then that is used
* - if a version is specified, that version is downloaded
* - if auto-update is enabled, then latest supported version is downloaded
* - if auto-update is disabled, any local mirrord binary is used
*
* @param extensionActivate If true, then a global state is set so that any changes to the workspace settings pertaining
* to mirrord binary auto-update will prompt the user to reload the window.
* @returns Path to mirrord binary
*/
export async function getMirrordBinary(extensionActivate?: boolean): Promise<string> {
const configured = await getConfiguredMirrordBinary();

if (configured) {
vscode.window.showInformationMessage(`Using mirrord binary specified in settings: ${configured}`);
return configured;
}
const latestVersion = await getLatestSupportedVersion(10000);
eyalb181 marked this conversation as resolved.
Show resolved Hide resolved
const autoUpdateConfigured = vscode.workspace.getConfiguration().get("mirrord.autoUpdate");
const extensionPath = getExtensionMirrordPath().fsPath;

let foundLocal = await getLocalMirrordBinary();
// timeout is 1s if we have alternative or 10s if we don't
let timeout = foundLocal ? 1000 : 10000;
const latestVersion = await getLatestSupportedVersion(timeout);

// See if maybe we have it installed already, in correct version.
const localMirrord = await getLocalMirrordBinary(latestVersion);
if (localMirrord) {
const api = new MirrordAPI(localMirrord);
const installedVersion = await api.getBinaryVersion();
if (installedVersion === latestVersion) {
return localMirrord;
// if extension is activating, then set a global state to what was read in the workspace settings
eyalb181 marked this conversation as resolved.
Show resolved Hide resolved
if (extensionActivate) {
globalContext.workspaceState.update('autoUpdate', autoUpdateConfigured);
} else {
// extension is active, check if auto-update setting has changed
const autoUpdate = globalContext.workspaceState.get('autoUpdate');
if (autoUpdate !== autoUpdateConfigured) {
await new NotificationBuilder()
.withMessage("mirrord binary auto-update setting has changed, please reload the window for the change to take effect.")
.withGenericAction("Reload", async () => {
await vscode.commands.executeCommand("workbench.action.reloadWindow");
})
.warning();
}
return extensionPath;
}

const extensionMirrordPath = getExtensionMirrordPath();
await downloadMirrordBinary(extensionMirrordPath, latestVersion);
if (typeof autoUpdateConfigured === 'string') {
infiniteregrets marked this conversation as resolved.
Show resolved Hide resolved
if (semver.valid(autoUpdateConfigured)) {
const localMirrordBinary = await getLocalMirrordBinary(autoUpdateConfigured);
if (localMirrordBinary) {
return localMirrordBinary;
}
await downloadMirrordBinary(getExtensionMirrordPath(), autoUpdateConfigured);
return extensionPath;
} else {
vscode.window.showErrorMessage(`Invalid version format ${autoUpdateConfigured}: must follow semver format`);
}
}

return extensionMirrordPath.fsPath;
if (typeof autoUpdateConfigured === 'boolean') {
if (!autoUpdateConfigured) {
const localMirrordBinary = await getLocalMirrordBinary();
if (localMirrordBinary) {
return localMirrordBinary;
}
return extensionPath;
}
}

// Auto-update is enabled or no specific version specified.
infiniteregrets marked this conversation as resolved.
Show resolved Hide resolved
const localMirrordBinary = await getLocalMirrordBinary(latestVersion);
if (localMirrordBinary) {
return localMirrordBinary;
}
await downloadMirrordBinary(getExtensionMirrordPath(), latestVersion);
return extensionPath;
}

/**
Expand Down
4 changes: 4 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as vscode from 'vscode';
import { ConfigurationProvider } from './debugger';
import { MirrordStatus } from './status';
import { getMirrordBinary } from './binaryManager';

export let globalContext: vscode.ExtensionContext;

Expand All @@ -11,6 +12,9 @@ export async function activate(context: vscode.ExtensionContext) {

context.workspaceState.update('enabled', false);
vscode.debug.registerDebugConfigurationProvider('*', new ConfigurationProvider(), 2);

// start mirrord binary updates, so that we avoid downloading mid session
await getMirrordBinary(true);
eyalb181 marked this conversation as resolved.
Show resolved Hide resolved

new MirrordStatus(vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0))
.register()
Expand Down
12 changes: 6 additions & 6 deletions src/tests/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const podToSelect = process.env.POD_TO_SELECT;
* - Send traffic to the pod
* - Tests successfully exit if "GET: Request completed" is found in the terminal
*/
describe("mirrord sample flow test", function() {
describe("mirrord sample flow test", function () {

this.timeout("6 minutes"); // --> mocha tests timeout
this.bail(true); // --> stop tests on first failure
Expand All @@ -26,7 +26,7 @@ describe("mirrord sample flow test", function() {
const fileName = "app_flask.py";
const defaultTimeout = 10000; // = 10 seconds

before(async function() {
before(async function () {
console.log("podToSelect: " + podToSelect);
console.log("kubeService: " + kubeService);

Expand All @@ -48,7 +48,7 @@ describe("mirrord sample flow test", function() {
await ew.openEditor('app_flask.py');
});

it("enable mirrord button", async function() {
it("enable mirrord button", async function () {
const statusBar = new StatusBar();

await browser.driver.wait(async () => {
Expand Down Expand Up @@ -80,7 +80,7 @@ describe("mirrord sample flow test", function() {
}, defaultTimeout, "mirrord `enable` button not found -- timed out");
});

it("select pod from quickpick", async function() {
it("select pod from quickpick", async function () {
await startDebugging();
const inputBox = await InputBox.create(defaultTimeout * 2);
// assertion that podToSelect is not undefined is done in "before" block
Expand Down Expand Up @@ -108,7 +108,7 @@ describe("mirrord sample flow test", function() {
await inputBox.selectQuickPick(podToSelect!);
});

it("wait for process to write to terminal", async function() {
it("wait for process to write to terminal", async function () {
const debugToolbar = await DebugToolbar.create(2 * defaultTimeout);
const panel = new BottomBarPanel();
await browser.driver.wait(async () => {
Expand Down Expand Up @@ -153,4 +153,4 @@ async function startDebugging(configurationFile: string = "Python: Current File"
const debugView = await activityBar?.openView() as DebugView;
await debugView.selectLaunchConfiguration(configurationFile);
await debugView.start();
}
}
7 changes: 7 additions & 0 deletions test-workspace/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"mirrord.autoUpdate": {
"enabled": false,
"version": "3.70.0"
infiniteregrets marked this conversation as resolved.
Show resolved Hide resolved
},
"mirrord.binaryPath": null
}