55// Copyright (c) 2011-2020 ETH Zurich.
66
77import { State } from "./ExtensionState" ;
8- import { Helper , Commands , ContributionCommands , Texts , Color , PreviewUris } from "./Helper" ;
8+ import { Helper , Commands , ContributionCommands , Texts , Color , PreviewUris , BuildChannel } from "./Helper" ;
99import { ProgressBar } from "./ProgressBar" ;
1010import * as vscode from 'vscode' ;
1111import * as fs from 'fs' ;
1212import { VerifierConfig , OverallVerificationResult , PreviewData } from "./MessagePayloads" ;
1313import { 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
1717export 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.
0 commit comments