1+ /*---------------------------------------------------------------------------------------------
2+ * Copyright (c) Microsoft Corporation. All rights reserved.
3+ * Licensed under the MIT License. See License.txt in the project root for license information.
4+ *--------------------------------------------------------------------------------------------*/
5+
6+ 'use strict' ;
7+
8+ import * as fs from 'fs-extra-promise' ;
9+ import * as path from 'path' ;
10+ import * as vscode from 'vscode' ;
11+ import * as tasks from 'vscode-tasks' ;
12+
13+ interface DebugConfiguration {
14+ name : string ,
15+ type : string ,
16+ request : string ,
17+ }
18+
19+ interface ConsoleLaunchConfiguration extends DebugConfiguration {
20+ preLaunchTask : string ,
21+ program : string ,
22+ args : string [ ] ,
23+ cwd : string ,
24+ stopAtEntry : boolean
25+ }
26+
27+ interface CommandLine {
28+ command : string ,
29+ args ?: string
30+ }
31+
32+ interface LaunchBrowserConfiguration {
33+ enabled : boolean ,
34+ args : string ,
35+ windows ?: CommandLine ,
36+ osx : CommandLine ,
37+ linux : CommandLine
38+ }
39+
40+ interface WebLaunchConfiguration extends ConsoleLaunchConfiguration {
41+ launchBrowser : LaunchBrowserConfiguration
42+ }
43+
44+ interface AttachConfiguration extends DebugConfiguration {
45+ processName : string
46+ }
47+
48+ interface Paths {
49+ vscodeFolder : string ;
50+ tasksJsonPath : string ;
51+ launchJsonPath : string ;
52+ }
53+
54+ function getPaths ( ) : Paths {
55+ const vscodeFolder = path . join ( vscode . workspace . rootPath , '.vscode' ) ;
56+
57+ return {
58+ vscodeFolder : vscodeFolder ,
59+ tasksJsonPath : path . join ( vscodeFolder , 'tasks.json' ) ,
60+ launchJsonPath : path . join ( vscodeFolder , 'launch.json' )
61+ }
62+ }
63+
64+ interface Operations {
65+ addTasksJson ?: boolean ,
66+ updateTasksJson ?: boolean ,
67+ addLaunchJson ?: boolean
68+ }
69+
70+ function hasOperations ( operations : Operations ) {
71+ return operations . addLaunchJson ||
72+ operations . updateTasksJson ||
73+ operations . addLaunchJson ;
74+ }
75+
76+ function getOperations ( ) {
77+ const paths = getPaths ( ) ;
78+
79+ return getBuildOperations ( paths . tasksJsonPath ) . then ( operations =>
80+ getLaunchOperations ( paths . launchJsonPath , operations ) ) ;
81+ }
82+
83+ function getBuildOperations ( tasksJsonPath : string ) {
84+ return new Promise < Operations > ( ( resolve , reject ) => {
85+ return fs . existsAsync ( tasksJsonPath ) . then ( exists => {
86+ if ( exists ) {
87+ fs . readFileAsync ( tasksJsonPath ) . then ( buffer => {
88+ const text = buffer . toString ( ) ;
89+ const tasksJson : tasks . TaskConfiguration = JSON . parse ( text ) ;
90+ const buildTask = tasksJson . tasks . find ( td => td . taskName === 'build' ) ;
91+
92+ resolve ( { updateTasksJson : ( buildTask === undefined ) } ) ;
93+ } ) ;
94+ }
95+ else {
96+ resolve ( { addTasksJson : true } ) ;
97+ }
98+ } ) ;
99+ } ) ;
100+ }
101+
102+ function getLaunchOperations ( launchJsonPath : string , operations : Operations ) {
103+ return new Promise < Operations > ( ( resolve , reject ) => {
104+ return fs . existsAsync ( launchJsonPath ) . then ( exists => {
105+ if ( exists ) {
106+ resolve ( operations ) ;
107+ }
108+ else {
109+ operations . addLaunchJson = true ;
110+ resolve ( operations ) ;
111+ }
112+ } ) ;
113+ } ) ;
114+ }
115+
116+ function promptToAddAssets ( ) {
117+ return new Promise < boolean > ( ( resolve , reject ) => {
118+ const item = { title : 'Yes' }
119+
120+ vscode . window . showInformationMessage ( 'Required assets to build and debug are missing from your project. Add them?' , item ) . then ( selection => {
121+ return selection
122+ ? resolve ( true )
123+ : resolve ( false ) ;
124+ } ) ;
125+ } ) ;
126+ }
127+
128+ function createLaunchConfiguration ( ) : ConsoleLaunchConfiguration {
129+ return {
130+ name : '.NET Core Launch (console)' ,
131+ type : 'coreclr' ,
132+ request : 'launch' ,
133+ preLaunchTask : 'build' ,
134+ program : '${workspaceRoot}/bin/Debug/<target-framework>/<project-name.dll>' ,
135+ args : [ ] ,
136+ cwd : '${workspaceRoot}' ,
137+ stopAtEntry : false
138+ }
139+ }
140+
141+ function createWebLaunchConfiguration ( ) : WebLaunchConfiguration {
142+ return {
143+ name : '.NET Core Launch (web)' ,
144+ type : 'coreclr' ,
145+ request : 'launch' ,
146+ preLaunchTask : 'build' ,
147+ program : '${workspaceRoot}/bin/Debug/<target-framework>/<project-name.dll>' ,
148+ args : [ ] ,
149+ cwd : '${workspaceRoot}' ,
150+ stopAtEntry : false ,
151+ launchBrowser : {
152+ enabled : true ,
153+ args : '${auto-detect-url}' ,
154+ windows : {
155+ command : 'cmd.exe' ,
156+ args : '/C start ${auto-detect-url}'
157+ } ,
158+ osx : {
159+ command : 'open'
160+ } ,
161+ linux : {
162+ command : 'xdg-open'
163+ }
164+ }
165+ }
166+ }
167+
168+ function createAttachConfiguration ( ) : AttachConfiguration {
169+ return {
170+ name : '.NET Core Attack' ,
171+ type : 'coreclr' ,
172+ request : 'attach' ,
173+ processName : '<example>'
174+ }
175+ }
176+
177+ function createLaunchJson ( ) : any {
178+ return {
179+ version : '0.2.0' ,
180+ configurations : [
181+ createLaunchConfiguration ( ) ,
182+ createWebLaunchConfiguration ( ) ,
183+ createAttachConfiguration ( )
184+ ]
185+ }
186+ }
187+
188+ function createBuildTaskDescription ( ) : tasks . TaskDescription {
189+ return {
190+ taskName : 'build' ,
191+ args : [ ] ,
192+ isBuildCommand : true ,
193+ problemMatcher : '$msCompile'
194+ } ;
195+ }
196+
197+ function createTasksConfiguration ( ) : tasks . TaskConfiguration {
198+ return {
199+ version : '0.1.0' ,
200+ command : 'dotnet' ,
201+ isShellCommand : true ,
202+ args : [ ] ,
203+ tasks : [ createBuildTaskDescription ( ) ]
204+ } ;
205+ }
206+
207+ function addTasksJsonIfNecessary ( paths : Paths , operations : Operations ) {
208+ return new Promise < void > ( ( resolve , reject ) => {
209+ if ( ! operations . addTasksJson ) {
210+ return resolve ( ) ;
211+ }
212+
213+ const tasksJson = createTasksConfiguration ( ) ;
214+ const tasksJsonText = JSON . stringify ( tasksJson , null , ' ' ) ;
215+
216+ return fs . writeFileAsync ( paths . tasksJsonPath , tasksJsonText ) ;
217+ } ) ;
218+ }
219+
220+ function updateTasksJsonIfNecesssary ( paths : Paths , operations : Operations ) {
221+ return new Promise < void > ( ( resolve , reject ) => {
222+ if ( ! operations . updateTasksJson ) {
223+ return resolve ( ) ;
224+ }
225+
226+ return fs . readFileAsync ( paths . tasksJsonPath ) . then ( buffer => {
227+ const bufferText = buffer . toString ( ) ;
228+ const tasksJson : tasks . TaskConfiguration = JSON . parse ( bufferText ) ;
229+ tasksJson . tasks . push ( createBuildTaskDescription ( ) ) ;
230+ const tasksJsonText = JSON . stringify ( tasksJson , null , ' ' ) ;
231+
232+ return fs . writeFileAsync ( paths . tasksJsonPath , tasksJsonText ) ;
233+ } ) ;
234+ } ) ;
235+ }
236+
237+ function addLaunchJsonIfNecessary ( paths : Paths , operations : Operations ) {
238+ return new Promise < void > ( ( resolve , reject ) => {
239+ if ( ! operations . addLaunchJson ) {
240+ return resolve ( ) ;
241+ }
242+
243+ const launchJson = createLaunchJson ( ) ;
244+ const launchJsonText = JSON . stringify ( launchJson , null , ' ' ) ;
245+
246+ return fs . writeFileAsync ( paths . launchJsonPath , launchJsonText ) ;
247+ } ) ;
248+ }
249+
250+ export function addAssetsIfNecessary ( ) {
251+ if ( ! vscode . workspace . rootPath ) {
252+ return ;
253+ }
254+
255+ // If there is no project.json, we won't bother to prompt the user for tasks.json.
256+ const projectJsonPath = path . join ( vscode . workspace . rootPath , 'project.json' ) ;
257+ if ( ! fs . existsSync ( projectJsonPath ) ) {
258+ return ;
259+ }
260+
261+ return getOperations ( ) . then ( operations => {
262+ if ( ! hasOperations ( operations ) ) {
263+ return ;
264+ }
265+
266+ promptToAddAssets ( ) . then ( addAssets => {
267+ if ( ! addAssets ) {
268+ return ;
269+ }
270+
271+ const paths = getPaths ( ) ;
272+
273+ return fs . ensureDirAsync ( paths . vscodeFolder ) . then ( ( ) => {
274+ return Promise . all ( [
275+ addTasksJsonIfNecessary ( paths , operations ) ,
276+ updateTasksJsonIfNecesssary ( paths , operations ) ,
277+ addLaunchJsonIfNecessary ( paths , operations )
278+ ] ) ;
279+ } ) ;
280+ } ) ;
281+ } ) ;
282+ }
0 commit comments