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.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,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
117 changes: 81 additions & 36 deletions src/binaryManager.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import axios, { AxiosResponse } from 'axios';
import * as vscode from 'vscode';
import which from 'which';
import { globalContext } from './extension';
import { MirrordAPI } from './api';
import { Utils } from 'vscode-uri';
import * as fs from 'node:fs';
import { platform } from 'os';
import { Uri, workspace, window, ProgressLocation, ExtensionMode } from 'vscode';
import { Uri, workspace, window, ProgressLocation, ExtensionMode, InputBoxOptions } from 'vscode';
import { NotificationBuilder } from './notification';
import { eq, gte, lt } from 'semver';

const mirrordBinaryEndpoint = 'https://version.mirrord.dev/v1/version';
// const binaryCheckInterval = 1000 * 60 * 3;
const baseDownloadUri = 'https://github.com/metalbear-co/mirrord/releases/download';

export let autoUpdate = true;
let userSpecifiedMirrordBinaryVersion: string | null | undefined = null;

function getExtensionMirrordPath(): Uri {
return Utils.joinPath(globalContext.globalStorageUri, 'mirrord');
}
Expand All @@ -20,34 +25,17 @@ function getExtensionMirrordPath(): Uri {
/**
* Tries to find local mirrord in path or in extension storage.
*/
export async function getLocalMirrordBinary(version?: string): Promise<string | null> {
export async function getLocalMirrordBinary(): Promise<string | null> {
try {
const mirrordPath = await which("mirrord");
if (version) {
const api = new MirrordAPI(mirrordPath);
const installedVersion = await api.getBinaryVersion();
if (installedVersion === version) {
return mirrordPath;
}
} else {
return mirrordPath;
}
return mirrordPath;
} catch (e) {
console.debug("couldn't find mirrord in path");
}
try {
const mirrordPath = getExtensionMirrordPath();
await workspace.fs.stat(mirrordPath);
if (version) {
const api = new MirrordAPI(mirrordPath.fsPath);
const installedVersion = await api.getBinaryVersion();
if (installedVersion === version) {
return mirrordPath.fsPath;
}
} else {
return mirrordPath.fsPath;
}

return mirrordPath.fsPath;
} catch (e) {
console.log("couldn't find mirrord in extension storage");
}
Expand Down Expand Up @@ -98,27 +86,44 @@ async function getConfiguredMirrordBinary(): Promise<string | null> {
export async function getMirrordBinary(): Promise<string> {
const configured = await getConfiguredMirrordBinary();
if (configured) {
await vscode.window.showInformationMessage(`Using mirrord binary specified in settings: ${configured}`);
return configured;
}

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;
const extensionMirrordPath = getExtensionMirrordPath();
const latestVersion = await getLatestSupportedVersion(10000);

if (autoUpdate) {
await downloadMirrordBinary(extensionMirrordPath, latestVersion);
return extensionMirrordPath.fsPath;
} else {
if (userSpecifiedMirrordBinaryVersion) {
await downloadMirrordBinary(extensionMirrordPath, userSpecifiedMirrordBinaryVersion);
return extensionMirrordPath.fsPath;
} else {
let localMirrord = await getLocalMirrordBinary();
if (localMirrord) {
const api = new MirrordAPI(localMirrord);
const installedVersion = await api.getBinaryVersion();

// in the release CI - the semver version is greater than the current remote semver version
// and hence, we need to use the local version

if (installedVersion !== null && installedVersion !== undefined && lt(installedVersion, latestVersion)) {
await vscode.window.showInformationMessage(`Using local mirrord binary: ${localMirrord} which is outdated. Latest supported version is ${latestVersion}`);
} else if (installedVersion !== null && installedVersion !== undefined && eq(installedVersion, latestVersion)) {
await vscode.window.showInformationMessage(`Using local mirrord binary: ${localMirrord} which is up-to-date`);
} else if (installedVersion !== null && installedVersion !== undefined && gte(installedVersion, latestVersion)) {
await vscode.window.showInformationMessage(`Using local mirrord binary: ${localMirrord} which is newer than the latest supported version ${latestVersion}. Possily a CI build`);
}

return localMirrord;
} else {
await downloadMirrordBinary(extensionMirrordPath, latestVersion);
}
}
}

const extensionMirrordPath = getExtensionMirrordPath();
await downloadMirrordBinary(extensionMirrordPath, latestVersion);

return extensionMirrordPath.fsPath;
}

Expand Down Expand Up @@ -194,4 +199,44 @@ async function downloadMirrordBinary(destPath: Uri, version: string): Promise<vo
);
fs.writeFileSync(destPath.fsPath, response.data);
fs.chmodSync(destPath.fsPath, 0o755);
}



/**
* 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 auto-update is enabled, then latest supported version is downloaded
* - if auto-update is disabled, and a version is specified, then that version is downloaded
* - if auto-update is disabled, and no version is specified, then local mirrord binary is used
* * - if auto-update is disabled, and no version is specified, and no local mirrord binary is found, then latest supported version is downloaded
* Note: typing "clear" in the input box will clear the user specified version
*/
export async function toggleAutoUpdate() {
if (autoUpdate) {
const options: vscode.InputBoxOptions = {
title: "Specify mirrord binary version",
prompt: "Auto-update will be disabled, mirrord will be updated to the specified version on restart.",
placeHolder: `Current version: ${userSpecifiedMirrordBinaryVersion ?? "unspecified (will download"}`,
};
const value = await vscode.window.showInputBox(options);

if (value) {
if (value === 'clear') {
userSpecifiedMirrordBinaryVersion = null;
} else if (/^[0-9]+\.[0-9]+\.[0-9]+$/.test(value)) {
userSpecifiedMirrordBinaryVersion = value;
} else {
vscode.window.showErrorMessage(`Invalid version format ${value}: must follow semver format`);
}
}

autoUpdate = false;
vscode.window.showInformationMessage("Auto-update disabled");
} else {
autoUpdate = true;
vscode.window.showInformationMessage("Auto-update enabled");
}
}
11 changes: 9 additions & 2 deletions src/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { MirrordConfigManager } from './config';
import { globalContext } from './extension';
import { waitlistRegisterCommand } from './waitlist';
import { NotificationBuilder } from './notification';
import { toggleAutoUpdate, autoUpdate } from './binaryManager';

export class MirrordStatus {
readonly statusBar: vscode.StatusBarItem;
static readonly toggleCommandId = 'mirrord.toggleMirroring';
static readonly settingsCommandId = 'mirrord.changeSettings';
static readonly autoUpdateCommandId = 'mirrord.autoUpdate';
static readonly submitFeedbackCommandId = 'mirrord.submitFeedback';
static readonly waitlistCommandId = 'mirrord.waitlistSignup';
static readonly selectActiveConfigId = 'mirrord.selectActiveConfig';
Expand All @@ -19,7 +21,7 @@ export class MirrordStatus {

draw() {
const {
enabled,
enabled,
statusBar,
} = this;

Expand All @@ -37,7 +39,8 @@ export class MirrordStatus {
const activeConfig = MirrordConfigManager.getInstance().activeConfig();
if (activeConfig) {
statusBar.tooltip.appendMarkdown(`\n\n[Active config: ${vscode.workspace.asRelativePath(activeConfig)}](${activeConfig})`);
}
}
statusBar.tooltip.appendMarkdown(`\n\n[Auto-update: ${autoUpdate ? 'Enabled' : 'Disabled'}](command:${MirrordStatus.autoUpdateCommandId})`);
statusBar.tooltip.appendMarkdown(`\n\n[Select active config](command:${MirrordStatus.selectActiveConfigId})`);
statusBar.tooltip.appendMarkdown(`\n\n[Settings](command:${MirrordStatus.settingsCommandId})`);
statusBar.tooltip.appendMarkdown(`\n\n[mirrord for Teams Waitlist](command:${MirrordStatus.waitlistCommandId})`);
Expand All @@ -56,6 +59,10 @@ export class MirrordStatus {
globalContext.subscriptions.push(vscode.commands.registerCommand(MirrordStatus.selectActiveConfigId, async () => {
await configManager.selectActiveConfig();
}));
globalContext.subscriptions.push(vscode.commands.registerCommand(MirrordStatus.autoUpdateCommandId, async () => {
await toggleAutoUpdate();
this.draw();
}));
globalContext.subscriptions.push(vscode.commands.registerCommand(MirrordStatus.settingsCommandId, configManager.changeSettings.bind(configManager)));
globalContext.subscriptions.push(vscode.commands.registerCommand(MirrordStatus.toggleCommandId, this.toggle.bind(this)));
globalContext.subscriptions.push(vscode.commands.registerCommand(MirrordStatus.submitFeedbackCommandId, this.submitFeedback.bind(this)));
Expand Down
2 changes: 1 addition & 1 deletion src/tests/e2e.ts
Original file line number Diff line number Diff line change
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();
}
}