OLD | NEW |
| (Empty) |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library driver; | |
6 | |
7 import 'dart:async'; | |
8 import 'dart:io'; | |
9 | |
10 import 'package:analysis_server/http_server.dart'; | |
11 import 'package:analysis_server/plugin/plugin.dart'; | |
12 import 'package:analysis_server/src/analysis_server.dart'; | |
13 import 'package:analysis_server/src/plugin/plugin_impl.dart'; | |
14 import 'package:analysis_server/src/plugin/server_plugin.dart'; | |
15 import 'package:analysis_server/src/socket_server.dart'; | |
16 import 'package:analysis_server/stdio_server.dart'; | |
17 import 'package:analyzer/instrumentation/instrumentation.dart'; | |
18 import 'package:analyzer/src/generated/engine.dart'; | |
19 import 'package:analyzer/src/generated/incremental_logger.dart'; | |
20 import 'package:analyzer/src/generated/java_io.dart'; | |
21 import 'package:analyzer/src/generated/sdk.dart'; | |
22 import 'package:analyzer/src/generated/sdk_io.dart'; | |
23 import 'package:args/args.dart'; | |
24 | |
25 | |
26 /** | |
27 * Initializes incremental logger. | |
28 * | |
29 * Supports following formats of [spec]: | |
30 * | |
31 * "console" - log to the console; | |
32 * "file:/some/file/name" - log to the file, overwritten on start. | |
33 */ | |
34 void _initIncrementalLogger(String spec) { | |
35 logger = NULL_LOGGER; | |
36 if (spec == null) { | |
37 return; | |
38 } | |
39 // create logger | |
40 if (spec == 'console') { | |
41 logger = new StringSinkLogger(console.log); | |
42 } | |
43 if (spec.startsWith('file:')) { | |
44 String fileName = spec.substring('file:'.length); | |
45 File file = new File(fileName); | |
46 IOSink sink = file.openWrite(); | |
47 logger = new StringSinkLogger(sink); | |
48 } | |
49 } | |
50 | |
51 | |
52 /** | |
53 * The [Driver] class represents a single running instance of the analysis | |
54 * server application. It is responsible for parsing command line options | |
55 * and starting the HTTP and/or stdio servers. | |
56 */ | |
57 class Driver { | |
58 /** | |
59 * The name of the application that is used to start a server. | |
60 */ | |
61 static const BINARY_NAME = "server"; | |
62 | |
63 /** | |
64 * The name of the option used to set the identifier for the client. | |
65 */ | |
66 static const String CLIENT_ID = "client-id"; | |
67 | |
68 /** | |
69 * The name of the option used to enable incremental resolution of API | |
70 * changes. | |
71 */ | |
72 static const String ENABLE_INCREMENTAL_RESOLUTION_API = | |
73 "enable-incremental-resolution-api"; | |
74 | |
75 /** | |
76 * The name of the option used to describe the incremental resolution logger. | |
77 */ | |
78 static const String INCREMENTAL_RESOLUTION_LOG = "incremental-resolution-log"; | |
79 | |
80 /** | |
81 * The name of the option used to enable validation of incremental resolution | |
82 * results. | |
83 */ | |
84 static const String INCREMENTAL_RESOLUTION_VALIDATION = | |
85 "incremental-resolution-validation"; | |
86 | |
87 /** | |
88 * The name of the option used to enable instrumentation. | |
89 */ | |
90 static const String ENABLE_INSTRUMENTATION_OPTION = "enable-instrumentation"; | |
91 | |
92 /** | |
93 * The name of the option used to print usage information. | |
94 */ | |
95 static const String HELP_OPTION = "help"; | |
96 | |
97 /** | |
98 * The name of the option used to specify if [print] should print to the | |
99 * console instead of being intercepted. | |
100 */ | |
101 static const String INTERNAL_PRINT_TO_CONSOLE = "internal-print-to-console"; | |
102 | |
103 /** | |
104 * The name of the option used to specify the port to which the server will | |
105 * connect. | |
106 */ | |
107 static const String PORT_OPTION = "port"; | |
108 | |
109 /** | |
110 * The path to the SDK. | |
111 * TODO(paulberry): get rid of this once the 'analysis.updateSdks' request is | |
112 * operational. | |
113 */ | |
114 static const String SDK_OPTION = "sdk"; | |
115 | |
116 /** | |
117 * The name of the option used to disable error notifications. | |
118 */ | |
119 static const String NO_ERROR_NOTIFICATION = "no-error-notification"; | |
120 | |
121 /** | |
122 * The instrumentation server that is to be used by the analysis server. | |
123 */ | |
124 InstrumentationServer instrumentationServer; | |
125 | |
126 /** | |
127 * The plugins that are defined outside the analysis_server package. | |
128 */ | |
129 List<Plugin> _userDefinedPlugins = <Plugin>[]; | |
130 | |
131 SocketServer socketServer; | |
132 | |
133 HttpAnalysisServer httpServer; | |
134 | |
135 StdioAnalysisServer stdioServer; | |
136 | |
137 Driver(); | |
138 | |
139 /** | |
140 * Set the [plugins] that are defined outside the analysis_server package. | |
141 */ | |
142 void set userDefinedPlugins(List<Plugin> plugins) { | |
143 _userDefinedPlugins = plugins == null ? <Plugin>[] : plugins; | |
144 } | |
145 | |
146 /** | |
147 * Use the given command-line arguments to start this server. | |
148 */ | |
149 void start(List<String> args) { | |
150 ArgParser parser = new ArgParser(); | |
151 parser.addOption( | |
152 CLIENT_ID, | |
153 help: "an identifier used to identify the client"); | |
154 parser.addFlag( | |
155 ENABLE_INCREMENTAL_RESOLUTION_API, | |
156 help: "enable using incremental resolution for API changes", | |
157 defaultsTo: false, | |
158 negatable: false); | |
159 parser.addFlag( | |
160 ENABLE_INSTRUMENTATION_OPTION, | |
161 help: "enable sending instrumentation information to a server", | |
162 defaultsTo: false, | |
163 negatable: false); | |
164 parser.addFlag( | |
165 HELP_OPTION, | |
166 help: "print this help message without starting a server", | |
167 defaultsTo: false, | |
168 negatable: false); | |
169 parser.addOption( | |
170 INCREMENTAL_RESOLUTION_LOG, | |
171 help: "the description of the incremental resolution log"); | |
172 parser.addFlag( | |
173 INCREMENTAL_RESOLUTION_VALIDATION, | |
174 help: "enable validation of incremental resolution results (slow)", | |
175 defaultsTo: false, | |
176 negatable: false); | |
177 parser.addFlag( | |
178 INTERNAL_PRINT_TO_CONSOLE, | |
179 help: "enable sending `print` output to the console", | |
180 defaultsTo: false, | |
181 negatable: false); | |
182 parser.addOption( | |
183 PORT_OPTION, | |
184 help: "[port] the port on which the server will listen"); | |
185 parser.addOption(SDK_OPTION, help: "[path] the path to the sdk"); | |
186 parser.addFlag( | |
187 NO_ERROR_NOTIFICATION, | |
188 help: | |
189 "disable sending all analysis error notifications to the server (not
yet implemented)", | |
190 defaultsTo: false, | |
191 negatable: false); | |
192 | |
193 ArgResults results = parser.parse(args); | |
194 if (results[HELP_OPTION]) { | |
195 _printUsage(parser); | |
196 return; | |
197 } | |
198 | |
199 // TODO(brianwilkerson) Enable this after it is possible for an | |
200 // instrumentation server to be provided. | |
201 // if (results[ENABLE_INSTRUMENTATION_OPTION]) { | |
202 // if (instrumentationServer == null) { | |
203 // print('Exiting server: enabled instrumentation without providing an in
strumentation server'); | |
204 // print(''); | |
205 // _printUsage(parser); | |
206 // return; | |
207 // } | |
208 // } else { | |
209 // if (instrumentationServer != null) { | |
210 // print('Exiting server: providing an instrumentation server without ena
bling instrumentation'); | |
211 // print(''); | |
212 // _printUsage(parser); | |
213 // return; | |
214 // } | |
215 // } | |
216 | |
217 int port; | |
218 bool serve_http = false; | |
219 if (results[PORT_OPTION] != null) { | |
220 serve_http = true; | |
221 try { | |
222 port = int.parse(results[PORT_OPTION]); | |
223 } on FormatException { | |
224 print('Invalid port number: ${results[PORT_OPTION]}'); | |
225 print(''); | |
226 _printUsage(parser); | |
227 exitCode = 1; | |
228 return; | |
229 } | |
230 } | |
231 | |
232 AnalysisServerOptions analysisServerOptions = new AnalysisServerOptions(); | |
233 analysisServerOptions.enableIncrementalResolutionApi = | |
234 results[ENABLE_INCREMENTAL_RESOLUTION_API]; | |
235 analysisServerOptions.enableIncrementalResolutionValidation = | |
236 results[INCREMENTAL_RESOLUTION_VALIDATION]; | |
237 | |
238 _initIncrementalLogger(results[INCREMENTAL_RESOLUTION_LOG]); | |
239 | |
240 DartSdk defaultSdk; | |
241 if (results[SDK_OPTION] != null) { | |
242 defaultSdk = new DirectoryBasedDartSdk(new JavaFile(results[SDK_OPTION])); | |
243 } else { | |
244 // No path to the SDK provided; use DirectoryBasedDartSdk.defaultSdk, | |
245 // which will make a guess. | |
246 defaultSdk = DirectoryBasedDartSdk.defaultSdk; | |
247 } | |
248 | |
249 InstrumentationService service = | |
250 new InstrumentationService(instrumentationServer); | |
251 // service.logVersion(results[CLIENT_ID], defaultSdk.sdkVersion); | |
252 AnalysisEngine.instance.instrumentationService = service; | |
253 // | |
254 // Process all of the plugins so that extensions are registered. | |
255 // | |
256 ServerPlugin serverPlugin = new ServerPlugin(); | |
257 List<Plugin> plugins = <Plugin>[]; | |
258 plugins.add(serverPlugin); | |
259 plugins.addAll(_userDefinedPlugins); | |
260 ExtensionManager manager = new ExtensionManager(); | |
261 manager.processPlugins(plugins); | |
262 | |
263 socketServer = | |
264 new SocketServer(analysisServerOptions, defaultSdk, service, serverPlugi
n); | |
265 httpServer = new HttpAnalysisServer(socketServer); | |
266 stdioServer = new StdioAnalysisServer(socketServer); | |
267 | |
268 if (serve_http) { | |
269 httpServer.serveHttp(port); | |
270 } | |
271 | |
272 _captureExceptions(service, () { | |
273 stdioServer.serveStdio().then((_) { | |
274 if (serve_http) { | |
275 httpServer.close(); | |
276 } | |
277 service.shutdown(); | |
278 exit(0); | |
279 }); | |
280 }, | |
281 print: results[INTERNAL_PRINT_TO_CONSOLE] ? null : httpServer.recordPrin
t); | |
282 } | |
283 | |
284 /** | |
285 * Execute the given [callback] within a zone that will capture any unhandled | |
286 * exceptions and both report them to the client and send them to the given | |
287 * instrumentation [service]. If a [print] function is provided, then also | |
288 * capture any data printed by the callback and redirect it to the function. | |
289 */ | |
290 dynamic _captureExceptions(InstrumentationService service, dynamic callback(), | |
291 {void print(String line)}) { | |
292 Function errorFunction = | |
293 (Zone self, ZoneDelegate parent, Zone zone, dynamic exception, | |
294 StackTrace stackTrace) { | |
295 service.logPriorityException(exception, stackTrace); | |
296 socketServer.analysisServer.reportException(exception, stackTrace); | |
297 throw exception; | |
298 }; | |
299 Function printFunction = print == null ? | |
300 null : | |
301 (Zone self, ZoneDelegate parent, Zone zone, String line) { | |
302 // Note: we don't pass the line on to stdout, because that is reserved | |
303 // for communication to the client. | |
304 print(line); | |
305 }; | |
306 ZoneSpecification zoneSpecification = new ZoneSpecification( | |
307 handleUncaughtError: errorFunction, | |
308 print: printFunction); | |
309 return runZoned(callback, zoneSpecification: zoneSpecification); | |
310 } | |
311 | |
312 /** | |
313 * Print information about how to use the server. | |
314 */ | |
315 void _printUsage(ArgParser parser) { | |
316 print('Usage: $BINARY_NAME [flags]'); | |
317 print(''); | |
318 print('Supported flags are:'); | |
319 print(parser.usage); | |
320 } | |
321 } | |
OLD | NEW |