re-write flutter analyze (the single-shot and --flutter-repo) to use the analysis server#16281
Conversation
…the analysis server
|
OK, this is now ready for review. Previously, we had:
This was a lot of different code paths and implementations for doing flutter analysis. Additionally, the specific package:analyzer APIs that flutter analyze was using are deprecated, and won't support the full fidelity of the changes for the Dart 2.0 type system; it's important to move flutter analyze off of them. This PR then:
Locally, I see a perf speedup in the initial (cold) repo analysis of 25% (50s to 40s), and additional (warm) analysis speedup of 3x (50s to 16s). Since we're using the analysis server, flutter analyze is analyzing the user's pubspec.yaml file, and will now catch issues in the |
| final Process process = await Process.start( | ||
| _flutter, | ||
| <String>['analyze', '--no-preamble', mainDart.path], | ||
| <String>['analyze', '--no-preamble', '--no-congratulate', mainDart.parent.path], |
There was a problem hiding this comment.
Can you not analyze just one file anymore?
There was a problem hiding this comment.
No, that is a use case that this PR removes.
There was a problem hiding this comment.
(and, it is one that I want to remove, for implementation simplicity, and to reduce the overall use case complexity here)
There was a problem hiding this comment.
FWIW, as a user, I find that not being able to analyze a single file (or rather, a single entry point, plus any files it might import directly or indirectly in the same package) is really annoying. I will often, for example, copy a file as a backup and then make backwards-incompatible changes which cause the analyzer to complain about the backup file. I also often will have a dummy package where I have multiple different "main.dart" entry points (named various things), and I only care about the one I'm editing, even though many of the others have tons of problems because I was just copying and pasting other people's code into them.
| if (entry == 'Building flutter tool...') { | ||
| await for (String entry in analysis.stderr.transform(utf8.decoder).transform(const LineSplitter())) { | ||
| print('analyzer stderr: $entry'); | ||
| if (entry.startsWith('[lint] ')) { |
There was a problem hiding this comment.
Lints show up in stderr, but info, warning, and error show up in stdout?? wat?
There was a problem hiding this comment.
How come this uses the [...] syntax but above you have the bullet point syntax?
There was a problem hiding this comment.
The [...] message is specifically generated elsewhere ([lint] $undocumentedMembers public members lack...); I'm just preserving current behavior as there's already a fair amount going on in this PR.
This single message shows in stderr (not infos, warnings, or errors as they're part of the regular tool output). It's part of the exit message if there were undoc'ed members found.
There was a problem hiding this comment.
We could choose to change this is this PR - to clarify that this is a marker message generated elsewhere - or add some comments to that effect.
| @@ -0,0 +1,8 @@ | |||
| # Take our settings from the repo's main analysis_options.yaml file, but include | |||
| # an additional rule to validate that public members are documented. | |||
There was a problem hiding this comment.
Awesome (🎉 for not having two almost-duplicated options files)!
There was a problem hiding this comment.
Yeah, all the copies have comments saying to please make changes to all files, and all the files have separate diffs...
| argParser.addOption('write', valueHelp: 'file', help: 'Also output the results to a file. This is useful with --watch if you want a file to always contain the latest results.'); | ||
| argParser.addOption('dart-sdk', valueHelp: 'path-to-sdk', help: 'The path to the Dart SDK.', hide: !verboseHelp); | ||
| AnalyzeCommand({bool verboseHelp: false, this.workingDirectory}) { | ||
| argParser.addFlag('flutter-repo', |
There was a problem hiding this comment.
This should probably be hidden
| help: 'Include all the examples and tests from the Flutter repository.', | ||
| defaultsTo: false); | ||
| argParser.addFlag('current-package', | ||
| help: 'Analyze the current project, if applicable.', defaultsTo: true); |
There was a problem hiding this comment.
Versus analyzing what? Does it even work to pass --no-current-package?
There was a problem hiding this comment.
It does work, however I would be happy to remove the option; leaving it in preserves current behavior.
| defaultsTo: false); | ||
| argParser.addFlag('current-package', | ||
| help: 'Analyze the current project, if applicable.', defaultsTo: true); | ||
| argParser.addFlag('dartdocs', |
There was a problem hiding this comment.
Does this do anything anymore?
There was a problem hiding this comment.
Yup, it should have the same behavior as before. For the flutter repo, without it, the cli tool will report the number of undocumented members. With it, it'll report and list them individually (and fail if there are any undoc'd members).
| # - analysis_options.yaml (this file) | ||
| # - analysis_options_repo.yaml | ||
| # - packages/flutter/lib/analysis_options_user.yaml | ||
| # - https://github.com/flutter/plugins/blob/master/analysis_options.yaml |
There was a problem hiding this comment.
we should probably change this back to four and point to https://github.com/flutter/engine/blob/master/analysis_options.yaml while we're at it...
|
|
||
| void _handleAnalysisErrors(FileAnalysisErrors fileErrors) { | ||
| fileErrors.errors.removeWhere(_filterError); | ||
| fileErrors.errors.removeWhere((AnalysisError error) => error.type == 'TODO'); |
There was a problem hiding this comment.
can't we turn these off in the options file?
There was a problem hiding this comment.
We now have the same options file for IDE and cli analysis. You do want to see these in the IDE (or use IDE level settings to hide them). They're not valuable on the cli; we filter them out from the dartanalyzer cli tool as well.
| if (argResults['flutter-repo']) { | ||
| // check for conflicting dependencies | ||
| final PackageDependencyTracker dependencies = | ||
| new PackageDependencyTracker(); |
devoncarew
left a comment
There was a problem hiding this comment.
Thanks for taking a pass through! PR updated
| # - analysis_options.yaml (this file) | ||
| # - analysis_options_repo.yaml | ||
| # - packages/flutter/lib/analysis_options_user.yaml | ||
| # - https://github.com/flutter/plugins/blob/master/analysis_options.yaml |
| final Process process = await Process.start( | ||
| _flutter, | ||
| <String>['analyze', '--no-preamble', mainDart.path], | ||
| <String>['analyze', '--no-preamble', '--no-congratulate', mainDart.parent.path], |
There was a problem hiding this comment.
No, that is a use case that this PR removes.
| if (entry == 'Building flutter tool...') { | ||
| await for (String entry in analysis.stderr.transform(utf8.decoder).transform(const LineSplitter())) { | ||
| print('analyzer stderr: $entry'); | ||
| if (entry.startsWith('[lint] ')) { |
There was a problem hiding this comment.
The [...] message is specifically generated elsewhere ([lint] $undocumentedMembers public members lack...); I'm just preserving current behavior as there's already a fair amount going on in this PR.
This single message shows in stderr (not infos, warnings, or errors as they're part of the regular tool output). It's part of the exit message if there were undoc'ed members found.
| @@ -0,0 +1,8 @@ | |||
| # Take our settings from the repo's main analysis_options.yaml file, but include | |||
| # an additional rule to validate that public members are documented. | |||
There was a problem hiding this comment.
Yeah, all the copies have comments saying to please make changes to all files, and all the files have separate diffs...
| argParser.addOption('write', valueHelp: 'file', help: 'Also output the results to a file. This is useful with --watch if you want a file to always contain the latest results.'); | ||
| argParser.addOption('dart-sdk', valueHelp: 'path-to-sdk', help: 'The path to the Dart SDK.', hide: !verboseHelp); | ||
| AnalyzeCommand({bool verboseHelp: false, this.workingDirectory}) { | ||
| argParser.addFlag('flutter-repo', |
| final Process process = await Process.start( | ||
| _flutter, | ||
| <String>['analyze', '--no-preamble', mainDart.path], | ||
| <String>['analyze', '--no-preamble', '--no-congratulate', mainDart.parent.path], |
There was a problem hiding this comment.
(and, it is one that I want to remove, for implementation simplicity, and to reduce the overall use case complexity here)
| help: 'Include all the examples and tests from the Flutter repository.', | ||
| defaultsTo: false); | ||
| argParser.addFlag('current-package', | ||
| help: 'Analyze the current project, if applicable.', defaultsTo: true); |
There was a problem hiding this comment.
It does work, however I would be happy to remove the option; leaving it in preserves current behavior.
| defaultsTo: false); | ||
| argParser.addFlag('current-package', | ||
| help: 'Analyze the current project, if applicable.', defaultsTo: true); | ||
| argParser.addFlag('dartdocs', |
There was a problem hiding this comment.
Yup, it should have the same behavior as before. For the flutter repo, without it, the cli tool will report the number of undocumented members. With it, it'll report and list them individually (and fail if there are any undoc'd members).
|
|
||
| void _handleAnalysisErrors(FileAnalysisErrors fileErrors) { | ||
| fileErrors.errors.removeWhere(_filterError); | ||
| fileErrors.errors.removeWhere((AnalysisError error) => error.type == 'TODO'); |
There was a problem hiding this comment.
We now have the same options file for IDE and cli analysis. You do want to see these in the IDE (or use IDE level settings to hide them). They're not valuable on the cli; we filter them out from the dartanalyzer cli tool as well.
| if (argResults['flutter-repo']) { | ||
| // check for conflicting dependencies | ||
| final PackageDependencyTracker dependencies = | ||
| new PackageDependencyTracker(); |
| argParser.addOption('write', | ||
| valueHelp: 'file', | ||
| help: | ||
| 'Also output the results to a file. This is useful with --watch if you want a file to always contain the latest results.'); |
There was a problem hiding this comment.
It looks like you're going for dartfmt style in this file, in which case let's wrap these long strings:
help:
'Also output the results to a file. This is useful with --watch if '
'you want a file to always contain the latest results.');| final PackageDependencyTracker dependencies = new PackageDependencyTracker(); | ||
| dependencies.checkForConflictingDependencies(repoPackages, dependencies); | ||
| directories = repoPackages.map((Directory dir) => dir.path).toList(); | ||
| directories = repoRoots; |
There was a problem hiding this comment.
Just remove the local variable and refer to repoRoots directly?
There was a problem hiding this comment.
I cleaned up the logic here a bit -
danrubel
left a comment
There was a problem hiding this comment.
- 1 to simplifying the "flutter analyze" implementation and reducing the number of analysis options files.
Looks like good progress to me.
…the analysis server (flutter#16281) re-write flutter analyze (the single-shot and --flutter-repo) to use the analysis server
… to use the analysis server (flutter#16281)" (flutter#16482) This reverts commit 2f41ea5.
Re-write
flutter analyze(the single-shot mode and--flutter-repo) to use the analysis server.not yet ready for review -