Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2015, 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 analyzer_cli.src.bootloader; | |
| 6 | |
| 7 import 'dart:io'; | |
| 8 import 'dart:isolate'; | |
| 9 | |
| 10 import 'package:analyzer/file_system/physical_file_system.dart'; | |
| 11 import 'package:analyzer/plugin/options.dart'; | |
| 12 import 'package:analyzer/source/analysis_options_provider.dart'; | |
| 13 import 'package:analyzer/src/generated/engine.dart'; | |
| 14 import 'package:analyzer/src/plugin/plugin_configuration.dart'; | |
| 15 import 'package:analyzer_cli/src/driver.dart'; | |
| 16 import 'package:analyzer_cli/src/options.dart'; | |
| 17 import 'package:analyzer_cli/src/plugin/plugin_config_processor_plugin.dart'; | |
| 18 import 'package:plugin/manager.dart'; | |
| 19 import 'package:plugin/plugin.dart'; | |
| 20 import 'package:source_span/source_span.dart'; | |
| 21 import 'package:yaml/src/yaml_node.dart'; | |
| 22 | |
| 23 const _analyzerPackageName = 'analyzer'; | |
| 24 | |
| 25 /// Source code assembler. | |
| 26 class Assembler { | |
| 27 /// Plugin configuration info. | |
| 28 final PluginConfig _config; | |
| 29 | |
| 30 /// Create an assembler for the given plugin [config]. | |
| 31 Assembler(this._config); | |
| 32 | |
| 33 /// A string enumerating required package `import`s. | |
| 34 String get enumerateImports => | |
| 35 plugins.map((PluginInfo p) => "import '${p.libraryUri}';").join('\n'); | |
| 36 | |
| 37 /// A string listing initialized plugin instances. | |
| 38 String get pluginList => | |
| 39 plugins.map((PluginInfo p) => 'new ${p.className}()').join(', '); | |
| 40 | |
| 41 /// Plugins to configure. | |
| 42 List<PluginInfo> get plugins => _config.plugins; | |
| 43 | |
| 44 /// Create a file containing a `main()` suitable for loading in spawned | |
| 45 /// isolate. | |
| 46 String createMain() => _generateMain(); | |
| 47 | |
| 48 String _generateMain() => """ | |
| 49 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
| 50 // for details. All rights reserved. Use of this source code is governed by a | |
| 51 // BSD-style license that can be found in the LICENSE file. | |
| 52 | |
| 53 // This code was auto-generated, is not intended to be edited, and is subject to | |
| 54 // significant change. Please see the README file for more information. | |
| 55 | |
| 56 import 'package:analyzer_cli/src/driver.dart'; | |
| 57 | |
| 58 $enumerateImports | |
| 59 | |
| 60 void main(List<String> args) { | |
| 61 var starter = new Driver(); | |
| 62 starter.userDefinedPlugins = [$pluginList]; | |
| 63 starter.start(args); | |
| 64 } | |
| 65 """; | |
| 66 } | |
| 67 | |
| 68 /// Given environment information extracted from command-line `args`, creates a | |
| 69 /// a loadable analyzer "image". | |
| 70 class BootLoader { | |
| 71 /// Emits an error message to [errorSink] if plugin config can't be read. | |
| 72 static final ErrorHandler _pluginConfigErrorHandler = (Exception e) { | |
| 73 String details; | |
| 74 if (e is PluginConfigFormatException) { | |
| 75 details = e.message; | |
| 76 var node = e.yamlNode; | |
| 77 if (node is YamlNode) { | |
| 78 SourceLocation location = node.span.start; | |
| 79 details += ' (line ${location.line}, column ${location.column})'; | |
| 80 } | |
| 81 } else { | |
| 82 details = e.toString(); | |
| 83 } | |
| 84 | |
| 85 errorSink.writeln('Plugin configuration skipped: $details'); | |
| 86 }; | |
| 87 | |
| 88 /// Reads plugin config info from `.analysis_options`. | |
| 89 PluginConfigProcessorPlugin _pluginConfigProcessorPlugin = | |
| 90 new PluginConfigProcessorPlugin(_pluginConfigErrorHandler); | |
| 91 | |
| 92 /// Create a loadable analyzer image confifgured with plugins derived from | |
|
Brian Wilkerson
2015/09/28 17:48:11
nit: "confifgured" --> "configured"
pquitslund
2015/09/28 18:01:29
Thanks!
| |
| 93 /// the given analyzer command-line `args`. | |
| 94 Image createImage(List<String> args) { | |
| 95 _processPlugins(); | |
| 96 | |
| 97 // Parse commandline options. | |
| 98 CommandLineOptions options = CommandLineOptions.parse(args); | |
| 99 | |
| 100 // Process analysis options file (and notify all interested parties). | |
| 101 _processAnalysisOptions(options); | |
| 102 | |
| 103 // TODO(pquitslund): Pass in .packages info | |
| 104 return new Image(_pluginConfigProcessorPlugin.pluginConfig, | |
| 105 args: args, packageRootPath: options.packageRootPath); | |
| 106 } | |
| 107 | |
| 108 void _processAnalysisOptions(CommandLineOptions options) { | |
| 109 // Determine options file path. | |
| 110 var filePath = options.analysisOptionsFile != null | |
| 111 ? options.analysisOptionsFile | |
| 112 : AnalysisOptionsProvider.ANALYSIS_OPTIONS_NAME; | |
| 113 List<OptionsProcessor> optionsProcessors = | |
|
Brian Wilkerson
2015/09/28 17:48:11
I don't think there will be any processors until a
pquitslund
2015/09/28 18:01:29
Actually, that's exactly what our PluginConfigOpti
Brian Wilkerson
2015/09/28 18:29:20
So it's an explicitly installed "plugin" that can
pquitslund
2015/09/28 21:15:03
I agree. Addressed here:
https://codereview.chro
| |
| 114 AnalysisEngine.instance.optionsPlugin.optionsProcessors; | |
| 115 try { | |
| 116 var file = PhysicalResourceProvider.INSTANCE.getFile(filePath); | |
| 117 AnalysisOptionsProvider analysisOptionsProvider = | |
| 118 new AnalysisOptionsProvider(); | |
| 119 Map<String, YamlNode> options = | |
| 120 analysisOptionsProvider.getOptionsFromFile(file); | |
| 121 optionsProcessors | |
| 122 .forEach((OptionsProcessor p) => p.optionsProcessed(options)); | |
| 123 } on Exception catch (e) { | |
| 124 optionsProcessors.forEach((OptionsProcessor p) => p.onError(e)); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 void _processPlugins() { | |
| 129 List<Plugin> plugins = <Plugin>[]; | |
| 130 plugins.add(_pluginConfigProcessorPlugin); | |
| 131 plugins.addAll(AnalysisEngine.instance.supportedPlugins); | |
| 132 ExtensionManager manager = new ExtensionManager(); | |
| 133 manager.processPlugins(plugins); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 /// A loadable "image" of a a configured analyzer instance. | |
| 138 class Image { | |
| 139 /// (Optional) package root path. | |
| 140 final String packageRootPath; | |
| 141 | |
| 142 /// (Optional) package map. | |
| 143 final Map<String, Uri> packages; | |
| 144 | |
| 145 /// Args to be passed on to the loaded main. | |
| 146 final List<String> args; | |
| 147 | |
| 148 /// Plugin configuration. | |
| 149 final PluginConfig config; | |
| 150 | |
| 151 /// Create an image with the given [config] and optionally [packages], | |
| 152 /// [packageRootPath], and command line [args]. | |
| 153 Image(this.config, {this.packages, this.packageRootPath, this.args}); | |
| 154 | |
| 155 /// Load this image. | |
| 156 /// | |
| 157 /// Loading an image consists in assembling an analyzer `main()`, configured | |
| 158 /// to include the appropriate analyzer plugins as specified in | |
| 159 /// `.analyzer_options` which is then run in a spawned isolate. | |
| 160 void load() { | |
| 161 String mainSource = new Assembler(config).createMain(); | |
| 162 | |
| 163 Uri uri = | |
| 164 Uri.parse('data:application/dart;charset=utf-8,${Uri.encodeComponent( | |
| 165 mainSource)}'); | |
| 166 | |
| 167 ReceivePort errorListener = new ReceivePort(); | |
| 168 errorListener.listen((data) { | |
| 169 //TODO(pquitslund): handle errors. | |
| 170 print('>>> ERROR: $data'); | |
| 171 }); | |
| 172 | |
| 173 ReceivePort exitListener = new ReceivePort(); | |
| 174 exitListener.listen((data) { | |
| 175 // Propagate exit code. | |
| 176 exit(exitCode); | |
| 177 }); | |
| 178 | |
| 179 // TODO(pquitslund): update once .packages are supported. | |
| 180 String packageRoot = | |
| 181 packageRootPath != null ? packageRootPath : './packages'; | |
| 182 Uri packageUri = new Uri.file(packageRoot); | |
| 183 | |
| 184 // TODO(pquitslund): add .packages support once the VM implements it. | |
| 185 Isolate.spawnUri(uri, args, null /* msg */, | |
| 186 packageRoot: packageUri, | |
| 187 onError: errorListener.sendPort, | |
| 188 onExit: exitListener.sendPort); | |
| 189 | |
| 190 // TODO(pquitslund): consider starting paused | |
| 191 // http://stackoverflow.com/questions/29247374/what-is-the-best-way-to-track -the-state-of-an-isolate-in-dart | |
| 192 } | |
| 193 } | |
| OLD | NEW |