@@ -16,6 +16,8 @@ import { exec } from 'child_process';
16
16
import { chdir as processChdir , cwd as processCwd } from 'process' ;
17
17
import fetch from 'cross-fetch' ;
18
18
19
+ import { checkSupportedDotnetVersion , getDotnetExecutablePath } from '../dotnet' ;
20
+
19
21
const execAsync = promisify ( exec ) ;
20
22
21
23
const ArchiveFileName = 'dafny.zip' ;
@@ -165,8 +167,8 @@ export class DafnyInstaller {
165
167
this . writeStatus ( `Found a non-supported architecture OSX:${ os . arch ( ) } . Going to install from source.` ) ;
166
168
return await this . installFromSource ( ) ;
167
169
} else {
168
- const archive = await this . downloadArchive ( await getDafnyDownloadAddress ( this . context ) ) ;
169
- await this . extractArchive ( archive ) ;
170
+ const archive = await this . downloadArchive ( await getDafnyDownloadAddress ( this . context ) , 'Dafny' ) ;
171
+ await this . extractArchive ( archive , 'Dafny' ) ;
170
172
await workspace . fs . delete ( archive , { useTrash : false } ) ;
171
173
this . writeStatus ( 'Dafny installation completed' ) ;
172
174
return true ;
@@ -200,18 +202,23 @@ export class DafnyInstaller {
200
202
const previousDirectory = processCwd ( ) ;
201
203
processChdir ( installationPath . fsPath ) ;
202
204
try {
203
- await this . execLog ( 'brew install dotnet-sdk' ) ;
205
+ await checkSupportedDotnetVersion ( ) ;
204
206
} catch ( error : unknown ) {
205
- this . writeStatus ( 'An error occurred while running this command.' ) ;
206
- this . writeStatus ( `${ error } ` ) ;
207
- this . writeStatus ( `If brew is installed on your system, this can usually be resolved by adding add all brew commands to your ~/.zprofile,
208
- e.g. by running the script there https://apple.stackexchange.com/a/430904 :
209
-
210
- > echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
211
- > eval "$(/opt/homebrew/bin/brew shellenv)"
212
-
213
- and restart VSCode, which may reinstall Dafny.` ) ;
214
- return false ;
207
+ try {
208
+ this . writeStatus ( 'dotnet not found in $PATH, trying to install from brew.' ) ;
209
+ await this . execLog ( 'brew install dotnet-sdk' ) ;
210
+ } catch ( error : unknown ) {
211
+ this . writeStatus ( 'An error occurred while running this command.' ) ;
212
+ this . writeStatus ( `${ error } ` ) ;
213
+ this . writeStatus ( `If brew is installed on your system, this can usually be resolved by adding add all brew commands to your ~/.zprofile,
214
+ e.g. by running the script there https://apple.stackexchange.com/a/430904 :
215
+
216
+ > echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
217
+ > eval "$(/opt/homebrew/bin/brew shellenv)"
218
+
219
+ and restart VSCode, which may reinstall Dafny.` ) ;
220
+ return false ;
221
+ }
215
222
}
216
223
const configuredVersion = await getConfiguredVersion ( this . context ) ;
217
224
if ( versionToNumeric ( configuredVersion ) < versionToNumeric ( '3.9.0' ) ) {
@@ -231,24 +238,35 @@ export class DafnyInstaller {
231
238
return false ;
232
239
}
233
240
}
234
- await this . execLog ( `git clone --recurse-submodules ${ LanguageServerConstants . DafnyGitUrl } ` ) ;
241
+
242
+ // Clone the right version
243
+ await this . execLog ( `git clone -b v${ configuredVersion } --depth 1 --recurse-submodules ${ LanguageServerConstants . DafnyGitUrl } ` ) ;
235
244
processChdir ( Utils . joinPath ( installationPath , 'dafny' ) . fsPath ) ;
236
- await this . execLog ( 'git fetch --all --tags' ) ;
237
- await this . execLog ( `git checkout v${ configuredVersion } ` ) ;
238
- await this . execLog ( 'dotnet build Source/DafnyLanguageServer/DafnyLanguageServer.csproj' ) ;
245
+
246
+ const { path : dotnet } = await getDotnetExecutablePath ( ) ;
247
+ // The DafnyCore.csproj has a few targets that call `dotnet` directly.
248
+ // If dotnet is configured in dafny.dotnetExecutablePath
249
+ // it MAY NOT be on the path.
250
+ // This will cause the build to fail.
251
+ // This works around this edge case.
252
+ const injectPath = `PATH=${ path . dirname ( dotnet ) } :$PATH` ;
253
+ // Build the DafnyLanguageServer
254
+ await this . execLog ( `${ injectPath } ${ ( await getDotnetExecutablePath ( ) ) . path } build Source/DafnyLanguageServer/DafnyLanguageServer.csproj` ) ;
239
255
const binaries = Utils . joinPath ( installationPath , 'dafny' , 'Binaries' ) . fsPath ;
240
256
processChdir ( binaries ) ;
241
257
try {
242
258
await this . execLog ( 'brew update' ) ; // Could help some users not get "Error: The `brew link` step did not complete successfully"
243
259
} catch ( error : unknown ) {
244
260
this . writeStatus ( `Could not run \`brew update\` but this step is optional (${ error } )` ) ;
245
261
}
246
- await this . execLog ( 'brew install wget' ) ;
262
+
247
263
const z3urlOsx = this . GetZ3DownloadUrlOSX ( ) ;
248
264
const z3filenameOsx = this . GetZ3FileNameOSX ( ) ;
249
- await this . execLog ( `wget ${ z3urlOsx } ` ) ;
250
- await this . execLog ( `unzip ${ z3filenameOsx } .zip` ) ;
251
- await this . execLog ( `mv ${ z3filenameOsx } z3` ) ;
265
+ const archive = await this . downloadArchive ( z3urlOsx , 'Z3' ) ;
266
+ await this . extractArchive ( archive , 'Z3' ) ;
267
+ await workspace . fs . delete ( archive , { useTrash : false } ) ;
268
+
269
+ await this . execLog ( `mv ${ ( await this . getInstallationPath ( ) ) . fsPath } /${ z3filenameOsx } z3` ) ;
252
270
processChdir ( ( await this . getInstallationPath ( ) ) . fsPath ) ;
253
271
await this . execLog ( 'mkdir -p ./dafny/' ) ;
254
272
await this . execLog ( `cp -R ${ binaries } /* ./dafny/` ) ;
@@ -288,12 +306,12 @@ export class DafnyInstaller {
288
306
}
289
307
}
290
308
291
- private async downloadArchive ( downloadUri : string ) : Promise < Uri > {
309
+ private async downloadArchive ( downloadUri : string , downloadTarget : string ) : Promise < Uri > {
292
310
await mkdirAsync ( ( await this . getInstallationPath ( ) ) . fsPath , { recursive : true } ) ;
293
311
const archivePath = await this . getZipPath ( ) ;
294
312
return await new Promise < Uri > ( ( resolve , reject ) => {
295
313
const archiveHandle = fs . createWriteStream ( archivePath . fsPath ) ;
296
- this . writeStatus ( `downloading Dafny from ${ downloadUri } ` ) ;
314
+ this . writeStatus ( `downloading ${ downloadTarget } from ${ downloadUri } ` ) ;
297
315
const progressReporter = new ProgressReporter ( this . statusOutput ) ;
298
316
archiveHandle
299
317
. on ( 'finish' , ( ) => resolve ( archivePath ) )
@@ -305,9 +323,9 @@ export class DafnyInstaller {
305
323
} ) ;
306
324
}
307
325
308
- private async extractArchive ( archivePath : Uri ) : Promise < void > {
326
+ private async extractArchive ( archivePath : Uri , extractName : string ) : Promise < void > {
309
327
const dirPath = await this . getInstallationPath ( ) ;
310
- this . writeStatus ( `extracting Dafny to ${ dirPath . fsPath } ` ) ;
328
+ this . writeStatus ( `extracting ${ extractName } to ${ dirPath . fsPath } ` ) ;
311
329
const progressReporter = new ProgressReporter ( this . statusOutput ) ;
312
330
await extract (
313
331
archivePath . fsPath ,
0 commit comments