Skip to content

Commit 7dfb3af

Browse files
Merge pull request #1842 from DustinCampbell/fix-asset-generation
Fix asset generation for multi-root workspaces
2 parents eaade81 + 6420465 commit 7dfb3af

File tree

3 files changed

+58
-27
lines changed

3 files changed

+58
-27
lines changed

.vscode/settings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"**/node_modules": true,
1212
"out/": true
1313
},
14+
15+
"csharp.suppressDotnetRestoreNotification": true,
1416

1517
"tslint.rulesDirectory": "node_modules/tslint-microsoft-contrib",
1618
"typescript.tsdk": "./node_modules/typescript/lib"

src/assets.ts

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { OmniSharpServer } from './omnisharp/server';
1515
import { tolerantParse } from './json';
1616

1717
export class AssetGenerator {
18-
public rootPath: string;
18+
public workspaceFolder: vscode.WorkspaceFolder;
1919
public vscodeFolder: string;
2020
public tasksJsonPath: string;
2121
public launchJsonPath: string;
@@ -27,13 +27,33 @@ export class AssetGenerator {
2727
private executableName: string;
2828
private configurationName: string;
2929

30-
public constructor(workspaceInfo: protocol.WorkspaceInformationResponse, rootPath: string = vscode.workspace.rootPath) {
31-
if (rootPath === null || rootPath === undefined) {
32-
throw new Error('rootPath must set.');
30+
public constructor(workspaceInfo: protocol.WorkspaceInformationResponse, workspaceFolder: vscode.WorkspaceFolder = undefined) {
31+
if (workspaceFolder) {
32+
this.workspaceFolder = workspaceFolder;
33+
}
34+
else {
35+
let resourcePath: string = undefined;
36+
37+
if (!resourcePath && workspaceInfo.Cake) {
38+
resourcePath = workspaceInfo.Cake.Path;
39+
}
40+
41+
if (!resourcePath && workspaceInfo.ScriptCs) {
42+
resourcePath = workspaceInfo.ScriptCs.Path;
43+
}
44+
45+
if (!resourcePath && workspaceInfo.DotNet && workspaceInfo.DotNet.Projects.length > 0) {
46+
resourcePath = workspaceInfo.DotNet.Projects[0].Path;
47+
}
48+
49+
if (!resourcePath && workspaceInfo.MsBuild) {
50+
resourcePath = workspaceInfo.MsBuild.SolutionPath;
51+
}
52+
53+
this.workspaceFolder = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(resourcePath));
3354
}
3455

35-
this.rootPath = rootPath;
36-
this.vscodeFolder = path.join(this.rootPath, '.vscode');
56+
this.vscodeFolder = path.join(this.workspaceFolder.uri.fsPath, '.vscode');
3757
this.tasksJsonPath = path.join(this.vscodeFolder, 'tasks.json');
3858
this.launchJsonPath = path.join(this.vscodeFolder, 'launch.json');
3959

@@ -133,15 +153,15 @@ export class AssetGenerator {
133153
let result = '${workspaceFolder}';
134154

135155
if (this.projectPath) {
136-
result = path.join(result, path.relative(this.rootPath, this.projectPath));
156+
result = path.join(result, path.relative(this.workspaceFolder.uri.fsPath, this.projectPath));
137157
}
138158

139159
result = path.join(result, `bin/${this.configurationName}/${this.targetFramework}/${this.executableName}`);
140160

141161
return result;
142162
}
143163

144-
private computeWorkingDirectory() : string {
164+
private computeWorkingDirectory(): string {
145165
if (!this.hasProject) {
146166
// If there's no target project data, use a placeholder for the path.
147167
return '${workspaceFolder}';
@@ -150,7 +170,7 @@ export class AssetGenerator {
150170
let result = '${workspaceFolder}';
151171

152172
if (this.projectPath) {
153-
result = path.join(result, path.relative(this.rootPath, this.projectPath));
173+
result = path.join(result, path.relative(this.workspaceFolder.uri.fsPath, this.projectPath));
154174
}
155175

156176
return result;
@@ -180,7 +200,7 @@ export class AssetGenerator {
180200
private createBuildTaskDescription(): tasks.TaskDescription {
181201
let buildPath = '';
182202
if (this.hasProject) {
183-
buildPath = path.join('${workspaceFolder}', path.relative(this.rootPath, this.projectFilePath));
203+
buildPath = path.join('${workspaceFolder}', path.relative(this.workspaceFolder.uri.fsPath, this.projectFilePath));
184204
}
185205

186206
return {
@@ -236,7 +256,7 @@ export function createWebLaunchConfiguration(programPath: string, workingDirecto
236256
}`;
237257
}
238258

239-
export function createLaunchConfiguration(programPath: string, workingDirectory: string): string {
259+
export function createLaunchConfiguration(programPath: string, workingDirectory: string): string {
240260
return `
241261
{
242262
"name": ".NET Core Launch (console)",
@@ -379,13 +399,13 @@ interface PromptItem extends vscode.MessageItem {
379399
result: PromptResult;
380400
}
381401

382-
function promptToAddAssets() {
402+
function promptToAddAssets(workspaceFolder: vscode.WorkspaceFolder) {
383403
return new Promise<PromptResult>((resolve, reject) => {
384404
const yesItem: PromptItem = { title: 'Yes', result: PromptResult.Yes };
385405
const noItem: PromptItem = { title: 'Not Now', result: PromptResult.No, isCloseAffordance: true };
386406
const disableItem: PromptItem = { title: "Don't Ask Again", result: PromptResult.Disable };
387407

388-
const projectName = path.basename(vscode.workspace.rootPath);
408+
const projectName = path.basename(workspaceFolder.uri.fsPath);
389409

390410
vscode.window.showWarningMessage(
391411
`Required assets to build and debug are missing from '${projectName}'. Add them?`, disableItem, noItem, yesItem)
@@ -464,7 +484,7 @@ export enum AddAssetResult {
464484

465485
export function addAssetsIfNecessary(server: OmniSharpServer): Promise<AddAssetResult> {
466486
return new Promise<AddAssetResult>((resolve, reject) => {
467-
if (!vscode.workspace.rootPath) {
487+
if (!vscode.workspace.workspaceFolders) {
468488
return resolve(AddAssetResult.NotApplicable);
469489
}
470490

@@ -477,7 +497,7 @@ export function addAssetsIfNecessary(server: OmniSharpServer): Promise<AddAssetR
477497
return resolve(AddAssetResult.NotApplicable);
478498
}
479499

480-
promptToAddAssets().then(result => {
500+
promptToAddAssets(generator.workspaceFolder).then(result => {
481501
if (result === PromptResult.Disable) {
482502
return resolve(AddAssetResult.Disable);
483503
}

test/unitTests/assets.test.ts

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,27 @@
55

66
import * as path from 'path';
77
import * as protocol from '../../src/omnisharp/protocol';
8+
import * as vscode from 'vscode';
89

910
import { AssetGenerator } from '../../src/assets';
1011
import { parse } from 'jsonc-parser';
1112
import { should } from 'chai';
1213

14+
function createMockWorkspaceFolder(rootPath: string) : vscode.WorkspaceFolder {
15+
return {
16+
uri: vscode.Uri.file(rootPath),
17+
name: undefined,
18+
index: undefined
19+
}
20+
}
21+
1322
suite("Asset generation: project.json", () => {
1423
suiteSetup(() => should());
1524

1625
test("Create tasks.json for project opened in workspace", () => {
1726
let rootPath = path.resolve('testRoot');
1827
let info = createDotNetWorkspaceInformation(rootPath, 'testApp.dll', 'netcoreapp1.0');
19-
let generator = new AssetGenerator(info, rootPath);
28+
let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath));
2029
let tasksJson = generator.createTasksConfiguration();
2130
let buildPath = tasksJson.tasks[0].args[1];
2231

@@ -28,7 +37,7 @@ suite("Asset generation: project.json", () => {
2837
test("Create tasks.json for nested project opened in workspace", () => {
2938
let rootPath = path.resolve('testRoot');
3039
let info = createDotNetWorkspaceInformation(path.join(rootPath, 'nested'), 'testApp.dll', 'netcoreapp1.0');
31-
let generator = new AssetGenerator(info, rootPath);
40+
let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath));
3241
let tasksJson = generator.createTasksConfiguration();
3342
let buildPath = tasksJson.tasks[0].args[1];
3443

@@ -40,7 +49,7 @@ suite("Asset generation: project.json", () => {
4049
test("Create launch.json for project opened in workspace", () => {
4150
let rootPath = path.resolve('testRoot');
4251
let info = createDotNetWorkspaceInformation(rootPath, 'testApp.dll', 'netcoreapp1.0');
43-
let generator = new AssetGenerator(info, rootPath);
52+
let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath));
4453
let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ false), undefined, { disallowComments: true });
4554
let programPath = launchJson[0].program;
4655

@@ -52,7 +61,7 @@ suite("Asset generation: project.json", () => {
5261
test("Create launch.json for nested project opened in workspace", () => {
5362
let rootPath = path.resolve('testRoot');
5463
let info = createDotNetWorkspaceInformation(path.join(rootPath, 'nested'), 'testApp.dll', 'netcoreapp1.0');
55-
let generator = new AssetGenerator(info, rootPath);
64+
let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath));
5665
let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ false), undefined, { disallowComments: true });
5766
let programPath = launchJson[0].program;
5867

@@ -64,7 +73,7 @@ suite("Asset generation: project.json", () => {
6473
test("Create launch.json for web project opened in workspace", () => {
6574
let rootPath = path.resolve('testRoot');
6675
let info = createDotNetWorkspaceInformation(rootPath, 'testApp.dll', 'netcoreapp1.0');
67-
let generator = new AssetGenerator(info, rootPath);
76+
let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath));
6877
let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ true), undefined, { disallowComments: true });
6978
let programPath = launchJson[0].program;
7079

@@ -76,7 +85,7 @@ suite("Asset generation: project.json", () => {
7685
test("Create launch.json for nested web project opened in workspace", () => {
7786
let rootPath = path.resolve('testRoot');
7887
let info = createDotNetWorkspaceInformation(path.join(rootPath, 'nested'), 'testApp.dll', 'netcoreapp1.0');
79-
let generator = new AssetGenerator(info, rootPath);
88+
let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath));
8089
let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ true), undefined, { disallowComments: true });
8190
let programPath = launchJson[0].program;
8291

@@ -124,7 +133,7 @@ suite("Asset generation: csproj", () => {
124133
test("Create tasks.json for project opened in workspace", () => {
125134
let rootPath = path.resolve('testRoot');
126135
let info = createMSBuildWorkspaceInformation(path.join(rootPath, 'testApp.csproj'), 'testApp', 'netcoreapp1.0');
127-
let generator = new AssetGenerator(info, rootPath);
136+
let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath));
128137
let tasksJson = generator.createTasksConfiguration();
129138
let buildPath = tasksJson.tasks[0].args[1];
130139

@@ -136,7 +145,7 @@ suite("Asset generation: csproj", () => {
136145
test("Create tasks.json for nested project opened in workspace", () => {
137146
let rootPath = path.resolve('testRoot');
138147
let info = createMSBuildWorkspaceInformation(path.join(rootPath, 'nested', 'testApp.csproj'), 'testApp', 'netcoreapp1.0');
139-
let generator = new AssetGenerator(info, rootPath);
148+
let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath));
140149
let tasksJson = generator.createTasksConfiguration();
141150
let buildPath = tasksJson.tasks[0].args[1];
142151

@@ -148,7 +157,7 @@ suite("Asset generation: csproj", () => {
148157
test("Create launch.json for project opened in workspace", () => {
149158
let rootPath = path.resolve('testRoot');
150159
let info = createMSBuildWorkspaceInformation(path.join(rootPath, 'testApp.csproj'), 'testApp', 'netcoreapp1.0');
151-
let generator = new AssetGenerator(info, rootPath);
160+
let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath));
152161
let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ false), undefined, { disallowComments: true });
153162
let programPath = launchJson[0].program;
154163

@@ -160,7 +169,7 @@ suite("Asset generation: csproj", () => {
160169
test("Create launch.json for nested project opened in workspace", () => {
161170
let rootPath = path.resolve('testRoot');
162171
let info = createMSBuildWorkspaceInformation(path.join(rootPath, 'nested', 'testApp.csproj'), 'testApp', 'netcoreapp1.0');
163-
let generator = new AssetGenerator(info, rootPath);
172+
let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath));
164173
let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ false), undefined, { disallowComments: true });
165174
let programPath = launchJson[0].program;
166175

@@ -172,7 +181,7 @@ suite("Asset generation: csproj", () => {
172181
test("Create launch.json for web project opened in workspace", () => {
173182
let rootPath = path.resolve('testRoot');
174183
let info = createMSBuildWorkspaceInformation(path.join(rootPath, 'testApp.csproj'), 'testApp', 'netcoreapp1.0');
175-
let generator = new AssetGenerator(info, rootPath);
184+
let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath));
176185
let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ true), undefined, { disallowComments: true });
177186
let programPath = launchJson[0].program;
178187

@@ -184,7 +193,7 @@ suite("Asset generation: csproj", () => {
184193
test("Create launch.json for nested web project opened in workspace", () => {
185194
let rootPath = path.resolve('testRoot');
186195
let info = createMSBuildWorkspaceInformation(path.join(rootPath, 'nested', 'testApp.csproj'), 'testApp', 'netcoreapp1.0');
187-
let generator = new AssetGenerator(info, rootPath);
196+
let generator = new AssetGenerator(info, createMockWorkspaceFolder(rootPath));
188197
let launchJson = parse(generator.createLaunchJson(/*isWebProject*/ true), undefined, { disallowComments: true });
189198
let programPath = launchJson[0].program;
190199

0 commit comments

Comments
 (0)