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 |