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 setAnalyticsMock(telemetry.Analytics replacementAnalytics) { | |
Brian Wilkerson
2017/07/02 15:54:26
Remove "Mock"? I don't think it's required that th
devoncarew
2017/07/04 02:35:48
Makes sense - done.
| |
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 |