Skip to content

Commit 108c6ad

Browse files
authored
fix: dafny.dotnetExecutablePath works to install custom source (#287)
* fix: `dafny.dotnetExecutablePath` works to install custom source If `dotnet` is installed and placed in `dafny.dotnetExecutablePath` custom source should still be able to be built. To do this `checkSupportedDotnetVersion` needs to be the primary way to detect `dotnet`. This has the side effect of both not double installing from `brew` but also not requireing an install if `dotnet` is already installed. The `wget` call is also removed since there are already helpers to perform this get and unzip. They are updated to take a `thing` to facilitate logging. There is also a bit of update to the `Z3` section to account for this change. The largest issue with this was `Source/DafnyCore/DafnyCore.csproj` has direct `dotnet` build targets. This means that call to build will fail if `dotnet` is not on the `PATH`. This is unfortunate, but… So we add it for that specific command. Finnaly, speed up the `git clone` to both checkout the tag and not get history. Added a few things to `.gitignore` and simplified the ReadMe’s use of `vsce` * lint
1 parent 2909eb4 commit 108c6ad

File tree

3 files changed

+47
-33
lines changed

3 files changed

+47
-33
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ node_modules/
55
.DS_Store
66
/dist/*
77
!/dist/.gitkeep
8+
/.history
9+
*.vsix

README.md

+2-8
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,10 @@ Because the latest version of the plugin requires recent changes to the Dafny la
138138

139139
### Packaging
140140

141-
To create a VSIX package of the previously built sources, install the [VSCode Extension Manager](https://github.com/microsoft/vscode-vsce) globally:
141+
To create a VSIX package of the previously built sources, create the package through the CLI:
142142

143143
```sh
144-
npm install -g vsce
145-
```
146-
147-
Now create the package through the CLI:
148-
149-
```sh
150-
vsce package
144+
npx vsce package
151145
```
152146

153147
### Coding Conventions

src/language/dafnyInstallation.ts

+43-25
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import { exec } from 'child_process';
1616
import { chdir as processChdir, cwd as processCwd } from 'process';
1717
import fetch from 'cross-fetch';
1818

19+
import { checkSupportedDotnetVersion, getDotnetExecutablePath } from '../dotnet';
20+
1921
const execAsync = promisify(exec);
2022

2123
const ArchiveFileName = 'dafny.zip';
@@ -165,8 +167,8 @@ export class DafnyInstaller {
165167
this.writeStatus(`Found a non-supported architecture OSX:${os.arch()}. Going to install from source.`);
166168
return await this.installFromSource();
167169
} 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');
170172
await workspace.fs.delete(archive, { useTrash: false });
171173
this.writeStatus('Dafny installation completed');
172174
return true;
@@ -200,18 +202,23 @@ export class DafnyInstaller {
200202
const previousDirectory = processCwd();
201203
processChdir(installationPath.fsPath);
202204
try {
203-
await this.execLog('brew install dotnet-sdk');
205+
await checkSupportedDotnetVersion();
204206
} 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+
}
215222
}
216223
const configuredVersion = await getConfiguredVersion(this.context);
217224
if(versionToNumeric(configuredVersion) < versionToNumeric('3.9.0')) {
@@ -231,24 +238,35 @@ export class DafnyInstaller {
231238
return false;
232239
}
233240
}
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}`);
235244
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`);
239255
const binaries = Utils.joinPath(installationPath, 'dafny', 'Binaries').fsPath;
240256
processChdir(binaries);
241257
try {
242258
await this.execLog('brew update'); // Could help some users not get "Error: The `brew link` step did not complete successfully"
243259
} catch(error: unknown) {
244260
this.writeStatus(`Could not run \`brew update\` but this step is optional (${error})`);
245261
}
246-
await this.execLog('brew install wget');
262+
247263
const z3urlOsx = this.GetZ3DownloadUrlOSX();
248264
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`);
252270
processChdir((await this.getInstallationPath()).fsPath);
253271
await this.execLog('mkdir -p ./dafny/');
254272
await this.execLog(`cp -R ${binaries}/* ./dafny/`);
@@ -288,12 +306,12 @@ export class DafnyInstaller {
288306
}
289307
}
290308

291-
private async downloadArchive(downloadUri: string): Promise<Uri> {
309+
private async downloadArchive(downloadUri: string, downloadTarget: string): Promise<Uri> {
292310
await mkdirAsync((await this.getInstallationPath()).fsPath, { recursive: true });
293311
const archivePath = await this.getZipPath();
294312
return await new Promise<Uri>((resolve, reject) => {
295313
const archiveHandle = fs.createWriteStream(archivePath.fsPath);
296-
this.writeStatus(`downloading Dafny from ${downloadUri}`);
314+
this.writeStatus(`downloading ${downloadTarget} from ${downloadUri}`);
297315
const progressReporter = new ProgressReporter(this.statusOutput);
298316
archiveHandle
299317
.on('finish', () => resolve(archivePath))
@@ -305,9 +323,9 @@ export class DafnyInstaller {
305323
});
306324
}
307325

308-
private async extractArchive(archivePath: Uri): Promise<void> {
326+
private async extractArchive(archivePath: Uri, extractName: string): Promise<void> {
309327
const dirPath = await this.getInstallationPath();
310-
this.writeStatus(`extracting Dafny to ${dirPath.fsPath}`);
328+
this.writeStatus(`extracting ${extractName} to ${dirPath.fsPath}`);
311329
const progressReporter = new ProgressReporter(this.statusOutput);
312330
await extract(
313331
archivePath.fsPath,

0 commit comments

Comments
 (0)