Skip to content

Commit 2ccb89a

Browse files
authored
Merge pull request #59 from viperproject/build-version-local
Build Version 'Local'
2 parents f186c12 + 1f38c1c commit 2ccb89a

File tree

8 files changed

+345
-242
lines changed

8 files changed

+345
-242
lines changed

client/package-lock.json

Lines changed: 235 additions & 191 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/package.json

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -290,11 +290,12 @@
290290
"scope": "window",
291291
"type": "string",
292292
"enum": [
293-
"stable",
294-
"nightly"
293+
"Stable",
294+
"Nightly",
295+
"Local"
295296
],
296-
"default": "stable",
297-
"description": "Select the build version of the Gobra Tools."
297+
"default": "Stable",
298+
"description": "Select the build version of the Gobra Tools. The path specified at 'gobraDependencies.gobraToolsPaths.gobraToolsBasePath' will be used for build version 'Local'"
298299
},
299300
"gobraSettings.timeout": {
300301
"scope": "window",
@@ -323,6 +324,11 @@
323324
"gobraDependencies.gobraToolsPaths": {
324325
"type": "object",
325326
"default": {
327+
"gobraToolsBasePath": {
328+
"windows": "%APPDATA%\\Gobra\\",
329+
"linux": "$HOME/.config/Gobra",
330+
"mac": "$HOME/Library/Application Support/Gobra"
331+
},
326332
"z3Executable": {
327333
"windows": "$gobraTools$\\z3\\bin\\z3.exe",
328334
"linux": "$gobraTools$/z3/bin/z3",

client/src/Helper.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Copyright (c) 2011-2020 ETH Zurich.
66

77
import * as vscode from 'vscode';
8-
import { URI, Utils } from 'vscode-uri';
8+
import { URI } from 'vscode-uri';
99
import { VerifierConfig, OverallVerificationResult, FileData, GobraSettings, PlatformDependendPath, GobraDependencies, PreviewData, HighlightingPosition } from "./MessagePayloads";
1010
import * as locate_java_home from 'locate-java-home';
1111
import * as child_process from 'child_process';
@@ -27,8 +27,14 @@ export class Helper {
2727
}
2828
}
2929

30-
public static isNightly(): boolean {
31-
return vscode.workspace.getConfiguration("gobraSettings").get("buildVersion") == "nightly";
30+
public static getBuildChannel(): BuildChannel {
31+
const buildVersion = vscode.workspace.getConfiguration("gobraSettings").get("buildVersion");
32+
if (buildVersion === "Nightly") {
33+
return BuildChannel.Nightly;
34+
} else if (buildVersion === "Local") {
35+
return BuildChannel.Local
36+
}
37+
return BuildChannel.Stable;
3238
}
3339

3440
public static isAutoVerify(): boolean {
@@ -257,11 +263,9 @@ export class Helper {
257263
(value == "1" || value.toUpperCase() == "TRUE");
258264
}
259265

260-
/**
261-
* Get Location where Gobra Tools will be installed.
262-
*/
263-
public static getGobraToolsPath(context: vscode.ExtensionContext): string {
264-
return Utils.joinPath(context.globalStorageUri, "gobraTools").fsPath;
266+
public static getLocalGobraToolsPath(): string {
267+
const gobraToolsBasePath = Helper.getGobraDependencies().gobraToolsPaths.gobraToolsBasePath;
268+
return Helper.getPlatformPath(gobraToolsBasePath);
265269
}
266270

267271
public static getServerJarPath(location: Location): string {
@@ -442,3 +446,9 @@ export interface Output {
442446
stderr: string;
443447
code: number | null;
444448
}
449+
450+
export enum BuildChannel {
451+
Stable = "Stable",
452+
Nightly = "Nightly",
453+
Local = "Local"
454+
}

client/src/MessagePayloads.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export interface JavaSettings {
7070
}
7171

7272
export interface PathSettings {
73+
gobraToolsBasePath: PlatformDependendPath;
7374
z3Executable: PlatformDependendPath;
7475
boogieExecutable: PlatformDependendPath;
7576
serverJar: PlatformDependendPath;

client/src/VerificationService.ts

Lines changed: 75 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
// Copyright (c) 2011-2020 ETH Zurich.
66

77
import { State } from "./ExtensionState";
8-
import { Helper, Commands, ContributionCommands, Texts, Color, PreviewUris } from "./Helper";
8+
import { Helper, Commands, ContributionCommands, Texts, Color, PreviewUris, BuildChannel } from "./Helper";
99
import { ProgressBar } from "./ProgressBar";
1010
import * as vscode from 'vscode';
1111
import * as fs from 'fs';
1212
import { VerifierConfig, OverallVerificationResult, PreviewData } from "./MessagePayloads";
1313
import { IdeEvents } from "./IdeEvents";
1414

15-
import { Dependency, withProgressInWindow, Location, DependencyInstaller, RemoteZipExtractor, GitHubZipExtractor } from 'vs-verification-toolbox';
15+
import { Dependency, withProgressInWindow, Location, DependencyInstaller, RemoteZipExtractor, GitHubZipExtractor, LocalReference, ConfirmResult, Success } from 'vs-verification-toolbox';
1616

1717
export class Verifier {
1818
public static verifyItem: ProgressBar;
@@ -263,51 +263,38 @@ export class Verifier {
263263
* Update GobraTools by downloading them if necessary.
264264
*/
265265
public static async updateGobraTools(context: vscode.ExtensionContext, shouldUpdate: boolean, notificationText?: string): Promise<Location> {
266-
State.updatingGobraTools = true;
267-
268-
const gobraToolsRawProviderUrl = Helper.getGobraToolsProvider(Helper.isNightly());
269-
// note that `gobraToolsProvider` might be one of the "special" URLs as specified in the README (i.e. to a GitHub releases asset):
270-
const gobraToolsProvider = Helper.parseGitHubAssetURL(gobraToolsRawProviderUrl);
271-
272-
const folderName = "GobraTools";
273-
let dependencyInstaller: DependencyInstaller
274-
if (gobraToolsProvider.isGitHubAsset) {
275-
// provider is a GitHub release
276-
const token = Helper.getGitHubToken();
277-
dependencyInstaller = new GitHubZipExtractor(gobraToolsProvider.getUrl, folderName, token);
278-
} else {
279-
// provider is a regular resource on the Internet
280-
const url = await gobraToolsProvider.getUrl();
281-
dependencyInstaller = new RemoteZipExtractor(url, folderName);
282-
}
283-
284-
const gobraToolsPath = Helper.getGobraToolsPath(context);
285-
if (!fs.existsSync(gobraToolsPath)) {
286-
// ask user for consent to install Gobra Tools on first launch:
287-
if (!shouldUpdate && !Helper.assumeYes()) {
266+
async function confirm(): Promise<ConfirmResult> {
267+
if (shouldUpdate || Helper.assumeYes()) {
268+
// do not ask user
269+
return ConfirmResult.Continue;
270+
} else {
288271
const confirmation = await vscode.window.showInformationMessage(
289272
Texts.installingGobraToolsConfirmationMessage,
290273
Texts.installingGobraToolsConfirmationYesButton,
291274
Texts.installingGobraToolsConfirmationNoButton);
292-
if (confirmation != Texts.installingGobraToolsConfirmationYesButton) {
275+
if (confirmation === Texts.installingGobraToolsConfirmationYesButton) {
276+
return ConfirmResult.Continue;
277+
} else {
293278
// user has dismissed message without confirming
294-
return Promise.reject(Texts.gobraToolsInstallationDenied);
279+
return ConfirmResult.Cancel;
295280
}
296281
}
297-
298-
fs.mkdirSync(gobraToolsPath, { recursive: true });
299282
}
300-
301-
const gobraTools = new Dependency<"Gobra">(
302-
gobraToolsPath,
303-
["Gobra", dependencyInstaller]
304-
);
305-
306-
const { result: location, didReportProgress } = await withProgressInWindow(
283+
284+
State.updatingGobraTools = true;
285+
const selectedChannel = Helper.getBuildChannel();
286+
const dependency = await this.getDependency(context);
287+
Helper.log(`Ensuring dependencies for build channel ${selectedChannel}`);
288+
const { result: installationResult, didReportProgress } = await withProgressInWindow(
307289
shouldUpdate ? Texts.updatingGobraTools : Texts.ensuringGobraTools,
308-
listener => gobraTools.install("Gobra", shouldUpdate, listener)
290+
listener => dependency.install(selectedChannel, shouldUpdate, listener, confirm)
309291
).catch(Helper.rethrow(`Downloading and unzipping the Gobra Tools has failed`));
310292

293+
if (!(installationResult instanceof Success)) {
294+
throw new Error(Texts.gobraToolsInstallationDenied);
295+
}
296+
297+
const location = installationResult.value;
311298
if (Helper.isLinux || Helper.isMac) {
312299
const z3Path = Helper.getZ3Path(location);
313300
const boogiePath = Helper.getBoogiePath(location);
@@ -334,6 +321,58 @@ export class Verifier {
334321
return location;
335322
}
336323

324+
private static async getDependency(context: vscode.ExtensionContext): Promise<Dependency<BuildChannel>> {
325+
const buildChannelStrings = Object.keys(BuildChannel);
326+
const buildChannels = buildChannelStrings.map(c =>
327+
// Convert string to enum. See https://stackoverflow.com/a/17381004/2491528
328+
BuildChannel[c as keyof typeof BuildChannel]);
329+
330+
// note that `installDestination` is only used if tools actually have to be downloaded and installed there, i.e. it is
331+
// not used for build channel "Local":
332+
const installDestination = context.globalStorageUri.fsPath;
333+
const installers = await Promise.all(buildChannels
334+
.map<Promise<[BuildChannel, DependencyInstaller]>>(async c =>
335+
[c, await this.getDependencyInstaller(context, c)])
336+
);
337+
return new Dependency<BuildChannel>(
338+
installDestination,
339+
...installers
340+
);
341+
}
342+
343+
private static getDependencyInstaller(context: vscode.ExtensionContext, buildChannel: BuildChannel): Promise<DependencyInstaller> {
344+
if (buildChannel == BuildChannel.Local) {
345+
return this.getLocalDependencyInstaller();
346+
} else {
347+
return this.getRemoteDependencyInstaller(context, buildChannel);
348+
}
349+
}
350+
351+
private static async getLocalDependencyInstaller(): Promise<DependencyInstaller> {
352+
return new LocalReference(Helper.getLocalGobraToolsPath());
353+
}
354+
355+
private static get buildChannelSubfolderName(): string {
356+
return "GobraTools";
357+
}
358+
359+
private static async getRemoteDependencyInstaller(context: vscode.ExtensionContext, buildChannel: BuildChannel): Promise<DependencyInstaller> {
360+
const gobraToolsRawProviderUrl = Helper.getGobraToolsProvider(buildChannel === BuildChannel.Nightly);
361+
// note that `gobraToolsProvider` might be one of the "special" URLs as specified in the README (i.e. to a GitHub releases asset):
362+
const gobraToolsProvider = Helper.parseGitHubAssetURL(gobraToolsRawProviderUrl);
363+
364+
const folderName = this.buildChannelSubfolderName; // folder name to which ZIP will be unzipped to
365+
if (gobraToolsProvider.isGitHubAsset) {
366+
// provider is a GitHub release
367+
const token = Helper.getGitHubToken();
368+
return new GitHubZipExtractor(gobraToolsProvider.getUrl, folderName, token);
369+
} else {
370+
// provider is a regular resource on the Internet
371+
const url = await gobraToolsProvider.getUrl();
372+
return new RemoteZipExtractor(url, folderName);
373+
}
374+
}
375+
337376

338377
/**
339378
* Shows the preview of the selected code in the translated Viper code.

client/src/extension.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Copyright (c) 2011-2020 ETH Zurich.
66

77
import * as vscode from 'vscode';
8+
import { Utils } from 'vscode-uri';
89
import * as fs from 'fs';
910

1011
import { State } from './ExtensionState';
@@ -37,7 +38,9 @@ export function activate(context: vscode.ExtensionContext): Thenable<any> {
3738
// start of in a clean state by wiping Gobra Tools if this was requested via
3839
// environment variables. In particular, this is used for the extension tests.
3940
if (Helper.cleanInstall()) {
40-
const gobraToolsPath = Helper.getGobraToolsPath(context);
41+
const packageJson = context.extension.packageJSON;
42+
const packageId = `${packageJson.publisher}.${packageJson.name}`;
43+
const gobraToolsPath = Utils.joinPath(context.globalStorageUri, packageId).fsPath;
4144
if (fs.existsSync(gobraToolsPath)) {
4245
Helper.log(`cleanInstall has been requested and gobra tools already exist --> delete them`);
4346
// wipe gobraToolsPath if it exists:
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"gobraSettings.buildVersion": "nightly"
2+
"gobraSettings.buildVersion": "Nightly"
33
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"gobraSettings.buildVersion": "stable"
2+
"gobraSettings.buildVersion": "Stable"
33
}

0 commit comments

Comments
 (0)