Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:io' as io; | 6 import 'dart:io' as io; |
| 7 | 7 |
| 8 import 'package:analyzer/error/error.dart'; | 8 import 'package:analyzer/error/error.dart'; |
| 9 import 'package:analyzer/file_system/file_system.dart' as file_system; | 9 import 'package:analyzer/file_system/file_system.dart' as file_system; |
| 10 import 'package:analyzer/file_system/file_system.dart'; | 10 import 'package:analyzer/file_system/file_system.dart'; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 42 import 'package:front_end/src/base/performace_logger.dart'; | 42 import 'package:front_end/src/base/performace_logger.dart'; |
| 43 import 'package:front_end/src/incremental/byte_store.dart'; | 43 import 'package:front_end/src/incremental/byte_store.dart'; |
| 44 import 'package:linter/src/rules.dart' as linter; | 44 import 'package:linter/src/rules.dart' as linter; |
| 45 import 'package:package_config/discovery.dart' as pkg_discovery; | 45 import 'package:package_config/discovery.dart' as pkg_discovery; |
| 46 import 'package:package_config/packages.dart' show Packages; | 46 import 'package:package_config/packages.dart' show Packages; |
| 47 import 'package:package_config/packages_file.dart' as pkgfile show parse; | 47 import 'package:package_config/packages_file.dart' as pkgfile show parse; |
| 48 import 'package:package_config/src/packages_impl.dart' show MapPackages; | 48 import 'package:package_config/src/packages_impl.dart' show MapPackages; |
| 49 import 'package:path/path.dart' as path; | 49 import 'package:path/path.dart' as path; |
| 50 import 'package:plugin/manager.dart'; | 50 import 'package:plugin/manager.dart'; |
| 51 import 'package:plugin/plugin.dart'; | 51 import 'package:plugin/plugin.dart'; |
| 52 import 'package:telemetry/crash_reporting.dart'; | |
| 53 import 'package:telemetry/telemetry.dart' as telemetry; | |
| 52 import 'package:yaml/yaml.dart'; | 54 import 'package:yaml/yaml.dart'; |
| 53 | 55 |
| 54 /// Shared IO sink for standard error reporting. | 56 /// Shared IO sink for standard error reporting. |
| 55 /// | 57 /// |
| 56 /// *Visible for testing.* | 58 /// *Visible for testing.* |
| 57 StringSink errorSink = io.stderr; | 59 StringSink errorSink = io.stderr; |
| 58 | 60 |
| 59 /// Shared IO sink for standard out reporting. | 61 /// Shared IO sink for standard out reporting. |
| 60 /// | 62 /// |
| 61 /// *Visible for testing.* | 63 /// *Visible for testing.* |
| 62 StringSink outSink = io.stdout; | 64 StringSink outSink = io.stdout; |
| 63 | 65 |
| 64 /// Test this option map to see if it specifies lint rules. | 66 /// Test this option map to see if it specifies lint rules. |
| 65 bool containsLintRuleEntry(Map<String, YamlNode> options) { | 67 bool containsLintRuleEntry(Map<String, YamlNode> options) { |
| 66 var linterNode = options['linter']; | 68 var linterNode = options['linter']; |
| 67 return linterNode is YamlMap && linterNode.containsKey('rules'); | 69 return linterNode is YamlMap && linterNode.containsKey('rules'); |
| 68 } | 70 } |
| 69 | 71 |
| 72 telemetry.Analytics _analytics; | |
| 73 | |
| 74 // TODO(devoncarew): Replace with the real tracking ID. | |
| 75 const _analyticsID = 'UA-001'; | |
| 76 | |
| 77 /// The analytics instance for analyzer-cli. | |
| 78 telemetry.Analytics get analytics => (_analytics ??= | |
| 79 telemetry.createAnalyticsInstance(_analyticsID, 'analyzer-cli')); | |
| 80 | |
| 81 /// Make sure that we create an analytics instance that doesn't send for this | |
| 82 /// session. | |
| 83 void disableAnalyticsForSession() { | |
| 84 _analytics = telemetry.createAnalyticsInstance(_analyticsID, 'analyzer-cli', | |
| 85 disableForSession: true); | |
| 86 } | |
| 87 | |
| 88 /// Public for testing. | |
|
Brian Wilkerson
2017/06/30 18:51:22
Please use the annotation `visibleForTesting` (fro
devoncarew
2017/06/30 21:58:13
Updated!
| |
| 89 void setAnalyticsMock(telemetry.Analytics replacementAnalytics) { | |
| 90 _analytics = replacementAnalytics; | |
| 91 } | |
| 92 | |
| 70 class Driver implements CommandLineStarter { | 93 class Driver implements CommandLineStarter { |
| 71 static final PerformanceTag _analyzeAllTag = | 94 static final PerformanceTag _analyzeAllTag = |
| 72 new PerformanceTag("Driver._analyzeAll"); | 95 new PerformanceTag("Driver._analyzeAll"); |
| 73 | 96 |
| 74 /// Cache of [AnalysisOptionsImpl] objects that correspond to directories | 97 /// Cache of [AnalysisOptionsImpl] objects that correspond to directories |
| 75 /// with analyzed files, used to reduce searching for `analysis_options.yaml` | 98 /// with analyzed files, used to reduce searching for `analysis_options.yaml` |
| 76 /// files. | 99 /// files. |
| 77 static Map<String, AnalysisOptionsImpl> _directoryToAnalysisOptions = {}; | 100 static Map<String, AnalysisOptionsImpl> _directoryToAnalysisOptions = {}; |
| 78 | 101 |
| 79 static ByteStore analysisDriverMemoryByteStore = new MemoryByteStore(); | 102 static ByteStore analysisDriverMemoryByteStore = new MemoryByteStore(); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 102 | 125 |
| 103 /** | 126 /** |
| 104 * The resource provider used to access the file system. | 127 * The resource provider used to access the file system. |
| 105 */ | 128 */ |
| 106 file_system.ResourceProvider resourceProvider = | 129 file_system.ResourceProvider resourceProvider = |
| 107 PhysicalResourceProvider.INSTANCE; | 130 PhysicalResourceProvider.INSTANCE; |
| 108 | 131 |
| 109 /// Collected analysis statistics. | 132 /// Collected analysis statistics. |
| 110 final AnalysisStats stats = new AnalysisStats(); | 133 final AnalysisStats stats = new AnalysisStats(); |
| 111 | 134 |
| 135 CrashReportSender _crashReportSender; | |
| 136 | |
| 137 // TODO(devoncarew): Replace with the real crash product ID. | |
| 138 /// The crash reporting instance for analyzer-cli. | |
| 139 CrashReportSender get crashReportSender => (_crashReportSender ??= | |
| 140 new CrashReportSender('Dart-analyzer-cli', analytics)); | |
| 141 | |
| 142 /// Create a new Driver instance. | |
| 143 /// | |
| 144 /// [isTesting] is true is we're running in a test environment. | |
|
Brian Wilkerson
2017/06/30 18:51:22
"true is" --> "true if"
devoncarew
2017/06/30 21:58:13
Done.
| |
| 145 Driver({bool isTesting: false}) { | |
| 146 if (isTesting) { | |
| 147 disableAnalyticsForSession(); | |
| 148 } | |
| 149 } | |
| 150 | |
| 112 /// This Driver's current analysis context. | 151 /// This Driver's current analysis context. |
| 113 /// | 152 /// |
| 114 /// *Visible for testing.* | 153 /// *Visible for testing.* |
| 115 AnalysisContext get context => _context; | 154 AnalysisContext get context => _context; |
| 116 | 155 |
| 117 @override | 156 @override |
| 118 void set userDefinedPlugins(List<Plugin> plugins) { | 157 void set userDefinedPlugins(List<Plugin> plugins) { |
| 119 _userDefinedPlugins = plugins ?? <Plugin>[]; | 158 _userDefinedPlugins = plugins ?? <Plugin>[]; |
| 120 } | 159 } |
| 121 | 160 |
| 122 @override | 161 @override |
| 123 Future<Null> start(List<String> args) async { | 162 Future<Null> start(List<String> args) async { |
| 124 if (_context != null) { | 163 if (_context != null) { |
| 125 throw new StateError("start() can only be called once"); | 164 throw new StateError("start() can only be called once"); |
| 126 } | 165 } |
| 127 int startTime = new DateTime.now().millisecondsSinceEpoch; | 166 int startTime = new DateTime.now().millisecondsSinceEpoch; |
| 128 | 167 |
| 129 StringUtilities.INTERNER = new MappedInterner(); | 168 StringUtilities.INTERNER = new MappedInterner(); |
| 130 | 169 |
| 131 _processPlugins(); | 170 _processPlugins(); |
| 132 | 171 |
| 133 // Parse commandline options. | 172 // Parse commandline options. |
| 134 CommandLineOptions options = CommandLineOptions.parse(args); | 173 CommandLineOptions options = CommandLineOptions.parse(args); |
| 135 | 174 |
| 175 if (options.batchMode || options.buildMode) { | |
| 176 disableAnalyticsForSession(); | |
| 177 } | |
| 178 | |
| 179 // Ping analytics with our initial call. | |
| 180 analytics.sendScreenView('home'); | |
| 181 | |
| 182 var timer = analytics.startTimer('analyze'); | |
| 183 | |
| 136 // Do analysis. | 184 // Do analysis. |
| 137 if (options.buildMode) { | 185 if (options.buildMode) { |
| 138 ErrorSeverity severity = _buildModeAnalyze(options); | 186 ErrorSeverity severity = _buildModeAnalyze(options); |
| 139 // Propagate issues to the exit code. | 187 // Propagate issues to the exit code. |
| 140 if (_shouldBeFatal(severity, options)) { | 188 if (_shouldBeFatal(severity, options)) { |
| 141 io.exitCode = severity.ordinal; | 189 io.exitCode = severity.ordinal; |
| 142 } | 190 } |
| 143 } else if (options.shouldBatch) { | 191 } else if (options.batchMode) { |
| 144 BatchRunner batchRunner = new BatchRunner(outSink, errorSink); | 192 BatchRunner batchRunner = new BatchRunner(outSink, errorSink); |
| 145 batchRunner.runAsBatch(args, (List<String> args) async { | 193 batchRunner.runAsBatch(args, (List<String> args) async { |
| 146 CommandLineOptions options = CommandLineOptions.parse(args); | 194 CommandLineOptions options = CommandLineOptions.parse(args); |
| 147 return await _analyzeAll(options); | 195 return await _analyzeAll(options); |
| 148 }); | 196 }); |
| 149 } else { | 197 } else { |
| 150 ErrorSeverity severity = await _analyzeAll(options); | 198 ErrorSeverity severity = await _analyzeAll(options); |
| 151 // Propagate issues to the exit code. | 199 // Propagate issues to the exit code. |
| 152 if (_shouldBeFatal(severity, options)) { | 200 if (_shouldBeFatal(severity, options)) { |
| 153 io.exitCode = severity.ordinal; | 201 io.exitCode = severity.ordinal; |
| 154 } | 202 } |
| 155 } | 203 } |
| 156 | 204 |
| 157 if (_context != null) { | 205 if (_context != null) { |
| 158 _analyzedFileCount += _context.sources.length; | 206 _analyzedFileCount += _context.sources.length; |
| 159 } | 207 } |
| 160 | 208 |
| 209 // Send how long analysis took. | |
| 210 timer.finish(); | |
| 211 | |
| 212 // Send how many files were analyzed. | |
| 213 analytics.sendEvent('analyze', 'analyzedFiles', value: _analyzedFileCount); | |
| 214 | |
| 161 if (options.perfReport != null) { | 215 if (options.perfReport != null) { |
| 162 String json = makePerfReport( | 216 String json = makePerfReport( |
| 163 startTime, currentTimeMillis, options, _analyzedFileCount, stats); | 217 startTime, currentTimeMillis, options, _analyzedFileCount, stats); |
| 164 new io.File(options.perfReport).writeAsStringSync(json); | 218 new io.File(options.perfReport).writeAsStringSync(json); |
| 165 } | 219 } |
| 220 | |
| 221 // Wait a brief time for any analytics calls to finish. | |
| 222 await analytics.waitForLastPing(timeout: new Duration(milliseconds: 200)); | |
| 166 } | 223 } |
| 167 | 224 |
| 168 Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async { | 225 Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async { |
| 169 PerformanceTag previous = _analyzeAllTag.makeCurrent(); | 226 PerformanceTag previous = _analyzeAllTag.makeCurrent(); |
| 170 try { | 227 try { |
| 171 return await _analyzeAllImpl(options); | 228 return await _analyzeAllImpl(options); |
| 229 } catch (e, st) { | |
| 230 crashReportSender.sendReport(e, stackTrace: st); | |
| 231 rethrow; | |
| 172 } finally { | 232 } finally { |
| 173 previous.makeCurrent(); | 233 previous.makeCurrent(); |
| 174 } | 234 } |
| 175 } | 235 } |
| 176 | 236 |
| 177 /// Perform analysis according to the given [options]. | 237 /// Perform analysis according to the given [options]. |
| 178 Future<ErrorSeverity> _analyzeAllImpl(CommandLineOptions options) async { | 238 Future<ErrorSeverity> _analyzeAllImpl(CommandLineOptions options) async { |
| 179 if (!options.machineFormat) { | 239 if (!options.machineFormat) { |
| 180 List<String> fileNames = options.sourceFiles.map((String file) { | 240 List<String> fileNames = options.sourceFiles.map((String file) { |
| 181 file = path.normalize(file); | 241 file = path.normalize(file); |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 314 return new BuildMode(resourceProvider, options, stats).analyze(); | 374 return new BuildMode(resourceProvider, options, stats).analyze(); |
| 315 } | 375 } |
| 316 }); | 376 }); |
| 317 } | 377 } |
| 318 | 378 |
| 319 /// Decide on the appropriate policy for which files need to be fully parsed | 379 /// Decide on the appropriate policy for which files need to be fully parsed |
| 320 /// and which files need to be diet parsed, based on [options], and return an | 380 /// and which files need to be diet parsed, based on [options], and return an |
| 321 /// [AnalyzeFunctionBodiesPredicate] that implements this policy. | 381 /// [AnalyzeFunctionBodiesPredicate] that implements this policy. |
| 322 AnalyzeFunctionBodiesPredicate _chooseDietParsingPolicy( | 382 AnalyzeFunctionBodiesPredicate _chooseDietParsingPolicy( |
| 323 CommandLineOptions options) { | 383 CommandLineOptions options) { |
| 324 if (options.shouldBatch) { | 384 if (options.batchMode) { |
| 325 // As analyzer is currently implemented, once a file has been diet | 385 // As analyzer is currently implemented, once a file has been diet |
| 326 // parsed, it can't easily be un-diet parsed without creating a brand new | 386 // parsed, it can't easily be un-diet parsed without creating a brand new |
| 327 // context and losing caching. In batch mode, we can't predict which | 387 // context and losing caching. In batch mode, we can't predict which |
| 328 // files we'll need to generate errors and warnings for in the future, so | 388 // files we'll need to generate errors and warnings for in the future, so |
| 329 // we can't safely diet parse anything. | 389 // we can't safely diet parse anything. |
| 330 return (Source source) => true; | 390 return (Source source) => true; |
| 331 } | 391 } |
| 332 | 392 |
| 333 return (Source source) { | 393 return (Source source) { |
| 334 if (options.sourceFiles.contains(source.fullName)) { | 394 if (options.sourceFiles.contains(source.fullName)) { |
| (...skipping 597 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 932 for (var package in packages) { | 992 for (var package in packages) { |
| 933 var packageName = path.basename(package.path); | 993 var packageName = path.basename(package.path); |
| 934 var realPath = package.resolveSymbolicLinksSync(); | 994 var realPath = package.resolveSymbolicLinksSync(); |
| 935 result[packageName] = [ | 995 result[packageName] = [ |
| 936 PhysicalResourceProvider.INSTANCE.getFolder(realPath) | 996 PhysicalResourceProvider.INSTANCE.getFolder(realPath) |
| 937 ]; | 997 ]; |
| 938 } | 998 } |
| 939 return result; | 999 return result; |
| 940 } | 1000 } |
| 941 } | 1001 } |
| OLD | NEW |