Skip to content

Commit 069a6c1

Browse files
Merge pull request #590 from DustinCampbell/fix-global-json
Improve generation of tasks.json and launch.json assets
2 parents ff2d0b4 + 839159e commit 069a6c1

File tree

1 file changed

+120
-51
lines changed

1 file changed

+120
-51
lines changed

src/assets.ts

Lines changed: 120 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -131,27 +131,48 @@ function promptToAddAssets() {
131131
});
132132
}
133133

134-
function createLaunchConfiguration(targetFramework: string, executableName: string): ConsoleLaunchConfiguration {
134+
function computeProgramPath(projectData: TargetProjectData) {
135+
if (!projectData) {
136+
// If there's no target project data, use a placeholder for the path.
137+
return '${workspaceRoot}/bin/Debug/<target-framework>/<project-name.dll>'
138+
}
139+
140+
let result = '${workspaceRoot}';
141+
142+
if (projectData.projectPath) {
143+
result += vscode.workspace.asRelativePath(projectData.projectPath);
144+
}
145+
146+
if (!result.endsWith('/')) {
147+
result += '/';
148+
}
149+
150+
result += `bin/${projectData.configurationName}/${projectData.targetFramework}/${projectData.executableName}`;
151+
152+
return result;
153+
}
154+
155+
function createLaunchConfiguration(projectData: TargetProjectData): ConsoleLaunchConfiguration {
135156
return {
136157
name: '.NET Core Launch (console)',
137158
type: 'coreclr',
138159
request: 'launch',
139160
preLaunchTask: 'build',
140-
program: '${workspaceRoot}/bin/Debug/' + targetFramework + '/'+ executableName,
161+
program: computeProgramPath(projectData),
141162
args: [],
142163
cwd: '${workspaceRoot}',
143164
externalConsole: false,
144165
stopAtEntry: false
145166
}
146167
}
147168

148-
function createWebLaunchConfiguration(targetFramework: string, executableName: string): WebLaunchConfiguration {
169+
function createWebLaunchConfiguration(projectData: TargetProjectData): WebLaunchConfiguration {
149170
return {
150171
name: '.NET Core Launch (web)',
151172
type: 'coreclr',
152173
request: 'launch',
153174
preLaunchTask: 'build',
154-
program: '${workspaceRoot}/bin/Debug/' + targetFramework + '/'+ executableName,
175+
program: computeProgramPath(projectData),
155176
args: [],
156177
cwd: '${workspaceRoot}',
157178
stopAtEntry: false,
@@ -187,13 +208,13 @@ function createAttachConfiguration(): AttachConfiguration {
187208
}
188209
}
189210

190-
function createLaunchJson(targetFramework: string, executableName: string, isWebProject: boolean): any {
211+
function createLaunchJson(projectData: TargetProjectData, isWebProject: boolean): any {
191212
let version = '0.2.0';
192213
if (!isWebProject) {
193214
return {
194215
version: version,
195216
configurations: [
196-
createLaunchConfiguration(targetFramework, executableName),
217+
createLaunchConfiguration(projectData),
197218
createAttachConfiguration()
198219
]
199220
}
@@ -202,49 +223,123 @@ function createLaunchJson(targetFramework: string, executableName: string, isWeb
202223
return {
203224
version: version,
204225
configurations: [
205-
createWebLaunchConfiguration(targetFramework, executableName),
226+
createWebLaunchConfiguration(projectData),
206227
createAttachConfiguration()
207228
]
208229
}
209230
}
210231
}
211232

212-
function createBuildTaskDescription(): tasks.TaskDescription {
233+
function createBuildTaskDescription(projectData: TargetProjectData): tasks.TaskDescription {
234+
let buildPath = '';
235+
if (projectData) {
236+
buildPath = '${workspaceRoot}';
237+
buildPath += vscode.workspace.asRelativePath(projectData.projectJsonPath);
238+
}
239+
213240
return {
214241
taskName: 'build',
215-
args: [],
242+
args: [buildPath],
216243
isBuildCommand: true,
217244
problemMatcher: '$msCompile'
218245
};
219246
}
220247

221-
function createTasksConfiguration(): tasks.TaskConfiguration {
248+
function createTasksConfiguration(projectData: TargetProjectData): tasks.TaskConfiguration {
222249
return {
223250
version: '0.1.0',
224251
command: 'dotnet',
225252
isShellCommand: true,
226253
args: [],
227-
tasks: [ createBuildTaskDescription() ]
254+
tasks: [ createBuildTaskDescription(projectData) ]
228255
};
229256
}
230257

231-
function addTasksJsonIfNecessary(info: protocol.DotNetWorkspaceInformation, paths: Paths, operations: Operations) {
258+
function addTasksJsonIfNecessary(projectData: TargetProjectData, paths: Paths, operations: Operations) {
232259
return new Promise<void>((resolve, reject) => {
233260
if (!operations.addTasksJson) {
234261
return resolve();
235262
}
236263

237-
const tasksJson = createTasksConfiguration();
264+
const tasksJson = createTasksConfiguration(projectData);
238265
const tasksJsonText = JSON.stringify(tasksJson, null, ' ');
239266

240267
return fs.writeFileAsync(paths.tasksJsonPath, tasksJsonText);
241268
});
242269
}
243270

244-
function hasWebServerDependency(projectJsonPath: string) {
245-
let projectJson = fs.readFileSync(projectJsonPath, 'utf8');
246-
let projectJsonObject = JSON.parse(projectJson.replace(/^\uFEFF/, ''));
247-
271+
interface TargetProjectData {
272+
projectPath: string;
273+
projectJsonPath: string;
274+
targetFramework: string;
275+
executableName: string;
276+
configurationName: string;
277+
}
278+
279+
function findTargetProjectData(projects: protocol.DotNetProject[]): TargetProjectData {
280+
// TODO: For now, assume the Debug configuration. Eventually, we'll need to revisit
281+
// this when we allow selecting configurations.
282+
const configurationName = 'Debug';
283+
284+
const executableProjects = findExecutableProjects(projects, configurationName);
285+
286+
// TODO: We arbitrarily pick the first executable projec that we find. This will need
287+
// revisiting when we project a "start up project" selector.
288+
const targetProject = executableProjects.length > 0
289+
? executableProjects[0]
290+
: undefined;
291+
292+
if (targetProject && targetProject.Frameworks.length > 0) {
293+
const config = targetProject.Configurations.find(c => c.Name === configurationName);
294+
if (config) {
295+
return {
296+
projectPath: targetProject.Path,
297+
projectJsonPath: path.join(targetProject.Path, 'project.json'),
298+
targetFramework: targetProject.Frameworks[0].ShortName,
299+
executableName: path.basename(config.CompilationOutputAssemblyFile),
300+
configurationName
301+
};
302+
}
303+
}
304+
305+
return undefined;
306+
}
307+
308+
function findExecutableProjects(projects: protocol.DotNetProject[], configName: string) {
309+
let result: protocol.DotNetProject[] = [];
310+
311+
projects.forEach(project => {
312+
project.Configurations.forEach(configuration => {
313+
if (configuration.Name === configName && configuration.EmitEntryPoint === true) {
314+
if (project.Frameworks.length > 0) {
315+
result.push(project);
316+
}
317+
}
318+
});
319+
});
320+
321+
return result;
322+
}
323+
324+
function hasWebServerDependency(targetProjectData: TargetProjectData): boolean {
325+
if (!targetProjectData || !targetProjectData.projectJsonPath) {
326+
return false;
327+
}
328+
329+
let projectJson = fs.readFileSync(targetProjectData.projectJsonPath, 'utf8');
330+
projectJson = projectJson.replace(/^\uFEFF/, '');
331+
332+
let projectJsonObject: any;
333+
334+
try {
335+
// TODO: This error should be surfaced to the user. If the JSON can't be parsed
336+
// (maybe due to a syntax error like an extra comma), the user should be notified
337+
// to fix up their project.json.
338+
projectJsonObject = JSON.parse(projectJson);
339+
} catch (error) {
340+
projectJsonObject = null;
341+
}
342+
248343
if (projectJsonObject == null) {
249344
return false;
250345
}
@@ -255,38 +350,17 @@ function hasWebServerDependency(projectJsonPath: string) {
255350
}
256351
}
257352

258-
return false;
353+
return false;
259354
}
260355

261-
function addLaunchJsonIfNecessary(info: protocol.DotNetWorkspaceInformation, paths: Paths, operations: Operations, projectJsonPath: string) {
356+
function addLaunchJsonIfNecessary(projectData: TargetProjectData, paths: Paths, operations: Operations) {
262357
return new Promise<void>((resolve, reject) => {
263358
if (!operations.addLaunchJson) {
264359
return resolve();
265360
}
266-
267-
let targetFramework = '<target-framework>';
268-
let executableName = '<project-name.dll>';
269-
270-
let done = false;
271-
for (var project of info.Projects) {
272-
for (var configuration of project.Configurations) {
273-
if (configuration.Name === "Debug" && configuration.EmitEntryPoint === true) {
274-
if (project.Frameworks.length > 0) {
275-
targetFramework = project.Frameworks[0].ShortName;
276-
executableName = path.basename(configuration.CompilationOutputAssemblyFile)
277-
}
278-
279-
done = true;
280-
break;
281-
}
282-
}
283-
284-
if (done) {
285-
break;
286-
}
287-
}
288-
289-
const launchJson = createLaunchJson(targetFramework, executableName, hasWebServerDependency(projectJsonPath));
361+
362+
const isWebProject = hasWebServerDependency(projectData);
363+
const launchJson = createLaunchJson(projectData, isWebProject);
290364
const launchJsonText = JSON.stringify(launchJson, null, ' ');
291365

292366
return fs.writeFileAsync(paths.launchJsonPath, launchJsonText);
@@ -298,12 +372,6 @@ export function addAssetsIfNecessary(server: OmnisharpServer) {
298372
return;
299373
}
300374

301-
// If there is no project.json, we won't bother to prompt the user for tasks.json.
302-
const projectJsonPath = path.join(vscode.workspace.rootPath, 'project.json');
303-
if (!fs.existsSync(projectJsonPath)) {
304-
return;
305-
}
306-
307375
return serverUtils.requestWorkspaceInformation(server).then(info => {
308376
// If there are no .NET Core projects, we won't bother offering to add assets.
309377
if ('DotNet' in info && info.DotNet.Projects.length > 0) {
@@ -317,12 +385,13 @@ export function addAssetsIfNecessary(server: OmnisharpServer) {
317385
return;
318386
}
319387

388+
const data = findTargetProjectData(info.DotNet.Projects);
320389
const paths = getPaths();
321390

322391
return fs.ensureDirAsync(paths.vscodeFolder).then(() => {
323392
return Promise.all([
324-
addTasksJsonIfNecessary(info.DotNet, paths, operations),
325-
addLaunchJsonIfNecessary(info.DotNet, paths, operations, projectJsonPath)
393+
addTasksJsonIfNecessary(data, paths, operations),
394+
addLaunchJsonIfNecessary(data, paths, operations)
326395
]);
327396
});
328397
});

0 commit comments

Comments
 (0)