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