Index: pkg/analyzer_cli/lib/src/driver.dart |
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart |
deleted file mode 100644 |
index d3dc92e76f2cc379487bded60f0640f98baa4ffa..0000000000000000000000000000000000000000 |
--- a/pkg/analyzer_cli/lib/src/driver.dart |
+++ /dev/null |
@@ -1,947 +0,0 @@ |
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library analyzer_cli.src.driver; |
- |
-import 'dart:async'; |
-import 'dart:convert'; |
-import 'dart:io' as io; |
- |
-import 'package:analyzer/error/error.dart'; |
-import 'package:analyzer/file_system/file_system.dart' as file_system; |
-import 'package:analyzer/file_system/file_system.dart'; |
-import 'package:analyzer/file_system/physical_file_system.dart'; |
-import 'package:analyzer/plugin/resolver_provider.dart'; |
-import 'package:analyzer/source/package_map_provider.dart'; |
-import 'package:analyzer/source/package_map_resolver.dart'; |
-import 'package:analyzer/source/pub_package_map_provider.dart'; |
-import 'package:analyzer/source/sdk_ext.dart'; |
-import 'package:analyzer/src/context/builder.dart'; |
-import 'package:analyzer/src/dart/analysis/byte_store.dart'; |
-import 'package:analyzer/src/dart/analysis/driver.dart'; |
-import 'package:analyzer/src/dart/analysis/file_state.dart'; |
-import 'package:analyzer/src/dart/sdk/sdk.dart'; |
-import 'package:analyzer/src/generated/constant.dart'; |
-import 'package:analyzer/src/generated/engine.dart'; |
-import 'package:analyzer/src/generated/interner.dart'; |
-import 'package:analyzer/src/generated/java_engine.dart'; |
-import 'package:analyzer/src/generated/sdk.dart'; |
-import 'package:analyzer/src/generated/source.dart'; |
-import 'package:analyzer/src/generated/source_io.dart'; |
-import 'package:analyzer/src/generated/utilities_general.dart' |
- show PerformanceTag; |
-import 'package:analyzer/src/source/source_resource.dart'; |
-import 'package:analyzer/src/summary/idl.dart'; |
-import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
-import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk; |
-import 'package:analyzer_cli/src/analyzer_impl.dart'; |
-import 'package:analyzer_cli/src/build_mode.dart'; |
-import 'package:analyzer_cli/src/error_formatter.dart'; |
-import 'package:analyzer_cli/src/error_severity.dart'; |
-import 'package:analyzer_cli/src/options.dart'; |
-import 'package:analyzer_cli/src/perf_report.dart'; |
-import 'package:analyzer_cli/starter.dart' show CommandLineStarter; |
-import 'package:linter/src/rules.dart' as linter; |
-import 'package:package_config/discovery.dart' as pkg_discovery; |
-import 'package:package_config/packages.dart' show Packages; |
-import 'package:package_config/packages_file.dart' as pkgfile show parse; |
-import 'package:package_config/src/packages_impl.dart' show MapPackages; |
-import 'package:path/path.dart' as path; |
-import 'package:plugin/manager.dart'; |
-import 'package:plugin/plugin.dart'; |
-import 'package:yaml/yaml.dart'; |
- |
-/// Shared IO sink for standard error reporting. |
-/// |
-/// *Visible for testing.* |
-StringSink errorSink = io.stderr; |
- |
-/// Shared IO sink for standard out reporting. |
-/// |
-/// *Visible for testing.* |
-StringSink outSink = io.stdout; |
- |
-/// Test this option map to see if it specifies lint rules. |
-bool containsLintRuleEntry(Map<String, YamlNode> options) { |
- var linterNode = options['linter']; |
- return linterNode is YamlMap && linterNode.containsKey('rules'); |
-} |
- |
-typedef Future<ErrorSeverity> _BatchRunnerHandler(List<String> args); |
- |
-class Driver implements CommandLineStarter { |
- static final PerformanceTag _analyzeAllTag = |
- new PerformanceTag("Driver._analyzeAll"); |
- |
- static ByteStore analysisDriverMemoryByteStore = new MemoryByteStore(); |
- |
- /// The plugins that are defined outside the `analyzer_cli` package. |
- List<Plugin> _userDefinedPlugins = <Plugin>[]; |
- |
- /// The context that was most recently created by a call to [_analyzeAll], or |
- /// `null` if [_analyzeAll] hasn't been called yet. |
- InternalAnalysisContext _context; |
- |
- AnalysisDriver analysisDriver; |
- |
- /// The total number of source files loaded by an AnalysisContext. |
- int _analyzedFileCount = 0; |
- |
- /// If [_context] is not `null`, the [CommandLineOptions] that guided its |
- /// creation. |
- CommandLineOptions _previousOptions; |
- |
- @override |
- ResolverProvider packageResolverProvider; |
- |
- /// SDK instance. |
- DartSdk sdk; |
- |
- /** |
- * The resource provider used to access the file system. |
- */ |
- file_system.ResourceProvider resourceProvider = |
- PhysicalResourceProvider.INSTANCE; |
- |
- /// Collected analysis statistics. |
- final AnalysisStats stats = new AnalysisStats(); |
- |
- /// This Driver's current analysis context. |
- /// |
- /// *Visible for testing.* |
- AnalysisContext get context => _context; |
- |
- @override |
- void set userDefinedPlugins(List<Plugin> plugins) { |
- _userDefinedPlugins = plugins ?? <Plugin>[]; |
- } |
- |
- @override |
- Future<Null> start(List<String> args) async { |
- if (_context != null) { |
- throw new StateError("start() can only be called once"); |
- } |
- int startTime = new DateTime.now().millisecondsSinceEpoch; |
- |
- StringUtilities.INTERNER = new MappedInterner(); |
- |
- _processPlugins(); |
- |
- // Parse commandline options. |
- CommandLineOptions options = CommandLineOptions.parse(args); |
- |
- // Do analysis. |
- if (options.buildMode) { |
- ErrorSeverity severity = _buildModeAnalyze(options); |
- // In case of error propagate exit code. |
- if (severity == ErrorSeverity.ERROR) { |
- io.exitCode = severity.ordinal; |
- } |
- } else if (options.shouldBatch) { |
- _BatchRunner.runAsBatch(args, (List<String> args) async { |
- CommandLineOptions options = CommandLineOptions.parse(args); |
- return await _analyzeAll(options); |
- }); |
- } else { |
- ErrorSeverity severity = await _analyzeAll(options); |
- // In case of error propagate exit code. |
- if (severity == ErrorSeverity.ERROR) { |
- io.exitCode = severity.ordinal; |
- } |
- } |
- |
- if (_context != null) { |
- _analyzedFileCount += _context.sources.length; |
- } |
- |
- if (options.perfReport != null) { |
- String json = makePerfReport( |
- startTime, currentTimeMillis, options, _analyzedFileCount, stats); |
- new io.File(options.perfReport).writeAsStringSync(json); |
- } |
- } |
- |
- Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async { |
- PerformanceTag previous = _analyzeAllTag.makeCurrent(); |
- try { |
- return await _analyzeAllImpl(options); |
- } finally { |
- previous.makeCurrent(); |
- } |
- } |
- |
- /// Perform analysis according to the given [options]. |
- Future<ErrorSeverity> _analyzeAllImpl(CommandLineOptions options) async { |
- if (!options.machineFormat) { |
- List<String> fileNames = options.sourceFiles.map((String file) { |
- file = path.normalize(file); |
- if (file == '.') { |
- file = path.basename(path.current); |
- } else if (file == '..') { |
- file = path.basename(path.normalize(path.absolute(file))); |
- } |
- return file; |
- }).toList(); |
- |
- outSink.writeln("Analyzing ${fileNames.join(', ')}..."); |
- } |
- |
- // Create a context, or re-use the previous one. |
- try { |
- _createAnalysisContext(options); |
- } on _DriverError catch (error) { |
- outSink.writeln(error.msg); |
- return ErrorSeverity.ERROR; |
- } |
- |
- // Add all the files to be analyzed en masse to the context. Skip any |
- // files that were added earlier (whether explicitly or implicitly) to |
- // avoid causing those files to be unnecessarily re-read. |
- Set<Source> knownSources = context.sources.toSet(); |
- Set<Source> sourcesToAnalyze = new Set<Source>(); |
- ChangeSet changeSet = new ChangeSet(); |
- for (String sourcePath in options.sourceFiles) { |
- sourcePath = sourcePath.trim(); |
- |
- // Collect files for analysis. |
- // Note that these files will all be analyzed in the same context. |
- // This should be updated when the ContextManager re-work is complete |
- // (See: https://github.com/dart-lang/sdk/issues/24133) |
- Iterable<io.File> files = _collectFiles(sourcePath); |
- if (files.isEmpty) { |
- errorSink.writeln('No dart files found at: $sourcePath'); |
- io.exitCode = ErrorSeverity.ERROR.ordinal; |
- return ErrorSeverity.ERROR; |
- } |
- |
- for (io.File file in files) { |
- Source source = _computeLibrarySource(file.absolute.path); |
- if (!knownSources.contains(source)) { |
- changeSet.addedSource(source); |
- } |
- sourcesToAnalyze.add(source); |
- } |
- |
- if (analysisDriver == null) { |
- context.applyChanges(changeSet); |
- } |
- } |
- |
- // Analyze the libraries. |
- ErrorSeverity allResult = ErrorSeverity.NONE; |
- List<Uri> libUris = <Uri>[]; |
- Set<Source> partSources = new Set<Source>(); |
- |
- SeverityProcessor defaultSeverityProcessor = (AnalysisError error) { |
- return determineProcessedSeverity( |
- error, options, _context.analysisOptions); |
- }; |
- |
- // We currently print out to stderr to ensure that when in batch mode we |
- // print to stderr, this is because the prints from batch are made to |
- // stderr. The reason that options.shouldBatch isn't used is because when |
- // the argument flags are constructed in BatchRunner and passed in from |
- // batch mode which removes the batch flag to prevent the "cannot have the |
- // batch flag and source file" error message. |
- ErrorFormatter formatter; |
- if (options.machineFormat) { |
- formatter = new MachineErrorFormatter(errorSink, options, stats, |
- severityProcessor: defaultSeverityProcessor); |
- } else { |
- formatter = new HumanErrorFormatter(outSink, options, stats, |
- severityProcessor: defaultSeverityProcessor); |
- } |
- |
- for (Source source in sourcesToAnalyze) { |
- SourceKind sourceKind = analysisDriver != null |
- ? await analysisDriver.getSourceKind(source.fullName) |
- : context.computeKindOf(source); |
- if (sourceKind == SourceKind.PART) { |
- partSources.add(source); |
- continue; |
- } |
- ErrorSeverity status = await _runAnalyzer(source, options, formatter); |
- allResult = allResult.max(status); |
- libUris.add(source.uri); |
- } |
- |
- formatter.flush(); |
- |
- // Check that each part has a corresponding source in the input list. |
- for (Source partSource in partSources) { |
- bool found = false; |
- if (analysisDriver != null) { |
- var partFile = |
- analysisDriver.fsState.getFileForPath(partSource.fullName); |
- if (libUris.contains(partFile.library?.uri)) { |
- found = true; |
- } |
- } else { |
- for (var lib in context.getLibrariesContaining(partSource)) { |
- if (libUris.contains(lib.uri)) { |
- found = true; |
- } |
- } |
- } |
- if (!found) { |
- errorSink.writeln( |
- "${partSource.fullName} is a part and cannot be analyzed."); |
- errorSink.writeln("Please pass in a library that contains this part."); |
- io.exitCode = ErrorSeverity.ERROR.ordinal; |
- allResult = allResult.max(ErrorSeverity.ERROR); |
- } |
- } |
- |
- if (!options.machineFormat) { |
- stats.print(outSink); |
- } |
- |
- return allResult; |
- } |
- |
- /// Perform analysis in build mode according to the given [options]. |
- ErrorSeverity _buildModeAnalyze(CommandLineOptions options) { |
- return _analyzeAllTag.makeCurrentWhile(() { |
- if (options.buildModePersistentWorker) { |
- new AnalyzerWorkerLoop.std(resourceProvider, |
- dartSdkPath: options.dartSdkPath) |
- .run(); |
- } else { |
- return new BuildMode(resourceProvider, options, stats).analyze(); |
- } |
- }); |
- } |
- |
- /// Determine whether the context created during a previous call to |
- /// [_analyzeAll] can be re-used in order to analyze using [options]. |
- bool _canContextBeReused(CommandLineOptions options) { |
- // TODO(paulberry): add a command-line option that disables context re-use. |
- if (_context == null) { |
- return false; |
- } |
- if (options.packageRootPath != _previousOptions.packageRootPath) { |
- return false; |
- } |
- if (options.packageConfigPath != _previousOptions.packageConfigPath) { |
- return false; |
- } |
- if (!_equalMaps( |
- options.definedVariables, _previousOptions.definedVariables)) { |
- return false; |
- } |
- if (options.log != _previousOptions.log) { |
- return false; |
- } |
- if (options.disableHints != _previousOptions.disableHints) { |
- return false; |
- } |
- if (options.enableStrictCallChecks != |
- _previousOptions.enableStrictCallChecks) { |
- return false; |
- } |
- if (options.enableAssertInitializer != |
- _previousOptions.enableAssertInitializer) { |
- return false; |
- } |
- if (options.showPackageWarnings != _previousOptions.showPackageWarnings) { |
- return false; |
- } |
- if (options.showPackageWarningsPrefix != |
- _previousOptions.showPackageWarningsPrefix) { |
- return false; |
- } |
- if (options.showSdkWarnings != _previousOptions.showSdkWarnings) { |
- return false; |
- } |
- if (options.lints != _previousOptions.lints) { |
- return false; |
- } |
- if (options.strongMode != _previousOptions.strongMode) { |
- return false; |
- } |
- if (options.enableSuperMixins != _previousOptions.enableSuperMixins) { |
- return false; |
- } |
- if (!_equalLists( |
- options.buildSummaryInputs, _previousOptions.buildSummaryInputs)) { |
- return false; |
- } |
- if (options.disableCacheFlushing != _previousOptions.disableCacheFlushing) { |
- return false; |
- } |
- return true; |
- } |
- |
- /// Decide on the appropriate policy for which files need to be fully parsed |
- /// and which files need to be diet parsed, based on [options], and return an |
- /// [AnalyzeFunctionBodiesPredicate] that implements this policy. |
- AnalyzeFunctionBodiesPredicate _chooseDietParsingPolicy( |
- CommandLineOptions options) { |
- if (options.shouldBatch) { |
- // As analyzer is currently implemented, once a file has been diet |
- // parsed, it can't easily be un-diet parsed without creating a brand new |
- // context and losing caching. In batch mode, we can't predict which |
- // files we'll need to generate errors and warnings for in the future, so |
- // we can't safely diet parse anything. |
- return (Source source) => true; |
- } |
- |
- return (Source source) { |
- if (options.sourceFiles.contains(source.fullName)) { |
- return true; |
- } else if (source.uri.scheme == 'dart') { |
- return options.showSdkWarnings; |
- } else { |
- // TODO(paulberry): diet parse 'package:' imports when we don't want |
- // diagnostics. (Full parse is still needed for "self" packages.) |
- return true; |
- } |
- }; |
- } |
- |
- /// Decide on the appropriate method for resolving URIs based on the given |
- /// [options] and [customUrlMappings] settings, and return a |
- /// [SourceFactory] that has been configured accordingly. |
- /// When [includeSdkResolver] is `false`, return a temporary [SourceFactory] |
- /// for the purpose of resolved analysis options file `include:` directives. |
- /// In this situation, [analysisOptions] is ignored and can be `null`. |
- SourceFactory _chooseUriResolutionPolicy( |
- CommandLineOptions options, |
- Map<file_system.Folder, YamlMap> embedderMap, |
- _PackageInfo packageInfo, |
- SummaryDataStore summaryDataStore, |
- bool includeSdkResolver, |
- AnalysisOptions analysisOptions) { |
- // Create a custom package resolver if one has been specified. |
- if (packageResolverProvider != null) { |
- file_system.Folder folder = resourceProvider.getResource('.'); |
- UriResolver resolver = packageResolverProvider(folder); |
- if (resolver != null) { |
- // TODO(brianwilkerson) This doesn't handle sdk extensions. |
- List<UriResolver> resolvers = <UriResolver>[]; |
- if (includeSdkResolver) { |
- resolvers.add(new DartUriResolver(sdk)); |
- } |
- resolvers |
- .add(new InSummaryUriResolver(resourceProvider, summaryDataStore)); |
- resolvers.add(resolver); |
- resolvers.add(new file_system.ResourceUriResolver(resourceProvider)); |
- return new SourceFactory(resolvers); |
- } |
- } |
- |
- UriResolver packageUriResolver; |
- |
- if (options.packageRootPath != null) { |
- ContextBuilderOptions builderOptions = new ContextBuilderOptions(); |
- builderOptions.defaultPackagesDirectoryPath = options.packageRootPath; |
- ContextBuilder builder = new ContextBuilder(resourceProvider, null, null, |
- options: builderOptions); |
- packageUriResolver = new PackageMapUriResolver(resourceProvider, |
- builder.convertPackagesToMap(builder.createPackageMap(''))); |
- } else if (options.packageConfigPath == null) { |
- // TODO(pq): remove? |
- if (packageInfo.packageMap == null) { |
- // Fall back to pub list-package-dirs. |
- PubPackageMapProvider pubPackageMapProvider = |
- new PubPackageMapProvider(resourceProvider, sdk); |
- file_system.Resource cwd = resourceProvider.getResource('.'); |
- PackageMapInfo packageMapInfo = |
- pubPackageMapProvider.computePackageMap(cwd); |
- Map<String, List<file_system.Folder>> packageMap = |
- packageMapInfo.packageMap; |
- |
- // Only create a packageUriResolver if pub list-package-dirs succeeded. |
- // If it failed, that's not a problem; it simply means we have no way |
- // to resolve packages. |
- if (packageMapInfo.packageMap != null) { |
- packageUriResolver = |
- new PackageMapUriResolver(resourceProvider, packageMap); |
- } |
- } |
- } |
- |
- // Now, build our resolver list. |
- List<UriResolver> resolvers = []; |
- |
- // 'dart:' URIs come first. |
- |
- // Setup embedding. |
- if (includeSdkResolver) { |
- EmbedderSdk embedderSdk = new EmbedderSdk(resourceProvider, embedderMap); |
- if (embedderSdk.libraryMap.size() == 0) { |
- // The embedder uri resolver has no mappings. Use the default Dart SDK |
- // uri resolver. |
- resolvers.add(new DartUriResolver(sdk)); |
- } else { |
- // The embedder uri resolver has mappings, use it instead of the default |
- // Dart SDK uri resolver. |
- embedderSdk.analysisOptions = analysisOptions; |
- resolvers.add(new DartUriResolver(embedderSdk)); |
- } |
- } |
- |
- // Next SdkExts. |
- if (packageInfo.packageMap != null) { |
- resolvers.add(new SdkExtUriResolver(packageInfo.packageMap)); |
- } |
- |
- // Then package URIs from summaries. |
- resolvers.add(new InSummaryUriResolver(resourceProvider, summaryDataStore)); |
- |
- // Then package URIs. |
- if (packageUriResolver != null) { |
- resolvers.add(packageUriResolver); |
- } |
- |
- // Finally files. |
- resolvers.add(new file_system.ResourceUriResolver(resourceProvider)); |
- |
- return new SourceFactory(resolvers, packageInfo.packages); |
- } |
- |
- // TODO(devoncarew): This needs to respect analysis_options excludes. |
- |
- /// Collect all analyzable files at [filePath], recursively if it's a |
- /// directory, ignoring links. |
- Iterable<io.File> _collectFiles(String filePath) { |
- List<io.File> files = <io.File>[]; |
- io.File file = new io.File(filePath); |
- if (file.existsSync()) { |
- files.add(file); |
- } else { |
- io.Directory directory = new io.Directory(filePath); |
- if (directory.existsSync()) { |
- for (io.FileSystemEntity entry |
- in directory.listSync(recursive: true, followLinks: false)) { |
- String relative = path.relative(entry.path, from: directory.path); |
- if (AnalysisEngine.isDartFileName(entry.path) && |
- !_isInHiddenDir(relative)) { |
- files.add(entry); |
- } |
- } |
- } |
- } |
- return files; |
- } |
- |
- /// Convert the given [sourcePath] (which may be relative to the current |
- /// working directory) to a [Source] object that can be fed to the analysis |
- /// context. |
- Source _computeLibrarySource(String sourcePath) { |
- sourcePath = _normalizeSourcePath(sourcePath); |
- File sourceFile = resourceProvider.getFile(sourcePath); |
- Source source = sdk.fromFileUri(sourceFile.toUri()); |
- if (source != null) { |
- return source; |
- } |
- source = new FileSource(sourceFile, sourceFile.toUri()); |
- Uri uri = _context.sourceFactory.restoreUri(source); |
- if (uri == null) { |
- return source; |
- } |
- return new FileSource(sourceFile, uri); |
- } |
- |
- /// Create an analysis context that is prepared to analyze sources according |
- /// to the given [options], and store it in [_context]. |
- void _createAnalysisContext(CommandLineOptions options) { |
- if (_canContextBeReused(options)) { |
- return; |
- } |
- _previousOptions = options; |
- |
- // Save stats from previous context before clobbering it. |
- if (_context != null) { |
- _analyzedFileCount += _context.sources.length; |
- } |
- |
- // Find package info. |
- _PackageInfo packageInfo = _findPackages(options); |
- |
- // Process embedders. |
- Map<file_system.Folder, YamlMap> embedderMap = |
- new EmbedderYamlLocator(packageInfo.packageMap).embedderYamls; |
- |
- // Scan for SDK extenders. |
- bool hasSdkExt = _hasSdkExt(packageInfo.packageMap?.values); |
- |
- // No summaries in the presence of embedders or extenders. |
- bool useSummaries = embedderMap.isEmpty && !hasSdkExt; |
- |
- if (!useSummaries && options.buildSummaryInputs.isNotEmpty) { |
- throw new _DriverError( |
- 'Summaries are not yet supported when using Flutter.'); |
- } |
- |
- // Read any input summaries. |
- SummaryDataStore summaryDataStore = new SummaryDataStore( |
- useSummaries ? options.buildSummaryInputs : <String>[]); |
- |
- AnalysisOptionsImpl analysisOptions = |
- createAnalysisOptionsForCommandLineOptions(resourceProvider, options); |
- analysisOptions.analyzeFunctionBodiesPredicate = |
- _chooseDietParsingPolicy(options); |
- |
- // Once options and embedders are processed, setup the SDK. |
- _setupSdk(options, useSummaries, analysisOptions); |
- |
- PackageBundle sdkBundle = sdk.getLinkedBundle(); |
- if (sdkBundle != null) { |
- summaryDataStore.addBundle(null, sdkBundle); |
- } |
- |
- // Choose a package resolution policy and a diet parsing policy based on |
- // the command-line options. |
- SourceFactory sourceFactory = _chooseUriResolutionPolicy(options, |
- embedderMap, packageInfo, summaryDataStore, true, analysisOptions); |
- |
- // Create a context. |
- _context = AnalysisEngine.instance.createAnalysisContext(); |
- setupAnalysisContext(_context, options, analysisOptions); |
- _context.sourceFactory = sourceFactory; |
- |
- if (options.enableNewAnalysisDriver) { |
- PerformanceLog log = new PerformanceLog(null); |
- AnalysisDriverScheduler scheduler = new AnalysisDriverScheduler(log); |
- analysisDriver = new AnalysisDriver( |
- scheduler, |
- log, |
- resourceProvider, |
- analysisDriverMemoryByteStore, |
- new FileContentOverlay(), |
- null, |
- context.sourceFactory, |
- context.analysisOptions); |
- analysisDriver.results.listen((_) {}); |
- analysisDriver.exceptions.listen((_) {}); |
- scheduler.start(); |
- } else { |
- if (sdkBundle != null) { |
- _context.resultProvider = |
- new InputPackagesResultProvider(_context, summaryDataStore); |
- } |
- } |
- } |
- |
- /// Return discovered packagespec, or `null` if none is found. |
- Packages _discoverPackagespec(Uri root) { |
- try { |
- Packages packages = pkg_discovery.findPackagesFromFile(root); |
- if (packages != Packages.noPackages) { |
- return packages; |
- } |
- } catch (_) { |
- // Ignore and fall through to null. |
- } |
- |
- return null; |
- } |
- |
- _PackageInfo _findPackages(CommandLineOptions options) { |
- if (packageResolverProvider != null) { |
- // The resolver provider will do all the work later. |
- return new _PackageInfo(null, null); |
- } |
- |
- Packages packages; |
- Map<String, List<file_system.Folder>> packageMap; |
- |
- if (options.packageConfigPath != null) { |
- String packageConfigPath = options.packageConfigPath; |
- Uri fileUri = new Uri.file(packageConfigPath); |
- try { |
- io.File configFile = new io.File.fromUri(fileUri).absolute; |
- List<int> bytes = configFile.readAsBytesSync(); |
- Map<String, Uri> map = pkgfile.parse(bytes, configFile.uri); |
- packages = new MapPackages(map); |
- packageMap = _getPackageMap(packages); |
- } catch (e) { |
- printAndFail( |
- 'Unable to read package config data from $packageConfigPath: $e'); |
- } |
- } else if (options.packageRootPath != null) { |
- packageMap = _PackageRootPackageMapBuilder |
- .buildPackageMap(options.packageRootPath); |
- } else { |
- file_system.Resource cwd = resourceProvider.getResource('.'); |
- // Look for .packages. |
- packages = _discoverPackagespec(new Uri.directory(cwd.path)); |
- packageMap = _getPackageMap(packages); |
- } |
- |
- return new _PackageInfo(packages, packageMap); |
- } |
- |
- Map<String, List<file_system.Folder>> _getPackageMap(Packages packages) { |
- if (packages == null) { |
- return null; |
- } |
- |
- Map<String, List<file_system.Folder>> folderMap = |
- new Map<String, List<file_system.Folder>>(); |
- packages.asMap().forEach((String packagePath, Uri uri) { |
- folderMap[packagePath] = [resourceProvider.getFolder(path.fromUri(uri))]; |
- }); |
- return folderMap; |
- } |
- |
- bool _hasSdkExt(Iterable<List<file_system.Folder>> folders) { |
- if (folders != null) { |
- //TODO: ideally share this traversal with SdkExtUriResolver |
- for (Iterable<file_system.Folder> libDirs in folders) { |
- if (libDirs.any((file_system.Folder libDir) => |
- libDir.getChild(SdkExtUriResolver.SDK_EXT_NAME).exists)) { |
- return true; |
- } |
- } |
- } |
- return false; |
- } |
- |
- /// Returns `true` if this relative path is a hidden directory. |
- bool _isInHiddenDir(String relative) => |
- path.split(relative).any((part) => part.startsWith(".")); |
- |
- void _processPlugins() { |
- List<Plugin> plugins = <Plugin>[]; |
- plugins.addAll(AnalysisEngine.instance.requiredPlugins); |
- plugins.addAll(_userDefinedPlugins); |
- |
- ExtensionManager manager = new ExtensionManager(); |
- manager.processPlugins(plugins); |
- |
- linter.registerLintRules(); |
- } |
- |
- /// Analyze a single source. |
- Future<ErrorSeverity> _runAnalyzer(Source source, CommandLineOptions options, |
- ErrorFormatter formatter) async { |
- int startTime = currentTimeMillis; |
- AnalyzerImpl analyzer = new AnalyzerImpl(_context.analysisOptions, _context, |
- analysisDriver, source, options, stats, startTime); |
- ErrorSeverity errorSeverity = await analyzer.analyze(formatter); |
- if (errorSeverity == ErrorSeverity.ERROR) { |
- io.exitCode = errorSeverity.ordinal; |
- } |
- if (options.warningsAreFatal && errorSeverity == ErrorSeverity.WARNING) { |
- io.exitCode = errorSeverity.ordinal; |
- } |
- return errorSeverity; |
- } |
- |
- void _setupSdk(CommandLineOptions options, bool useSummaries, |
- AnalysisOptions analysisOptions) { |
- if (sdk == null) { |
- if (options.dartSdkSummaryPath != null) { |
- sdk = new SummaryBasedDartSdk( |
- options.dartSdkSummaryPath, options.strongMode); |
- } else { |
- String dartSdkPath = options.dartSdkPath; |
- FolderBasedDartSdk dartSdk = new FolderBasedDartSdk(resourceProvider, |
- resourceProvider.getFolder(dartSdkPath), options.strongMode); |
- dartSdk.useSummary = useSummaries && |
- options.sourceFiles.every((String sourcePath) { |
- sourcePath = path.absolute(sourcePath); |
- sourcePath = path.normalize(sourcePath); |
- return !path.isWithin(dartSdkPath, sourcePath); |
- }); |
- dartSdk.analysisOptions = analysisOptions; |
- sdk = dartSdk; |
- } |
- } |
- } |
- |
- static AnalysisOptionsImpl createAnalysisOptionsForCommandLineOptions( |
- ResourceProvider resourceProvider, CommandLineOptions options) { |
- if (options.analysisOptionsFile != null) { |
- file_system.File file = |
- resourceProvider.getFile(options.analysisOptionsFile); |
- if (!file.exists) { |
- printAndFail('Options file not found: ${options.analysisOptionsFile}', |
- exitCode: ErrorSeverity.ERROR.ordinal); |
- } |
- } |
- |
- String contextRoot; |
- if (options.sourceFiles.isEmpty) { |
- contextRoot = path.current; |
- } else { |
- contextRoot = options.sourceFiles[0]; |
- if (!path.isAbsolute(contextRoot)) { |
- contextRoot = path.absolute(contextRoot); |
- } |
- } |
- |
- void verbosePrint(String text) { |
- outSink.writeln(text); |
- } |
- |
- AnalysisOptionsImpl contextOptions = new ContextBuilder( |
- resourceProvider, null, null, |
- options: options.contextBuilderOptions) |
- .getAnalysisOptions(contextRoot, |
- verbosePrint: options.verbose ? verbosePrint : null); |
- |
- contextOptions.trackCacheDependencies = false; |
- contextOptions.disableCacheFlushing = options.disableCacheFlushing; |
- contextOptions.hint = !options.disableHints; |
- contextOptions.generateImplicitErrors = options.showPackageWarnings; |
- contextOptions.generateSdkErrors = options.showSdkWarnings; |
- contextOptions.enableAssertInitializer = options.enableAssertInitializer; |
- |
- return contextOptions; |
- } |
- |
- static void setAnalysisContextOptions( |
- file_system.ResourceProvider resourceProvider, |
- AnalysisContext context, |
- CommandLineOptions options, |
- void configureContextOptions(AnalysisOptionsImpl contextOptions)) { |
- AnalysisOptionsImpl analysisOptions = |
- createAnalysisOptionsForCommandLineOptions(resourceProvider, options); |
- configureContextOptions(analysisOptions); |
- setupAnalysisContext(context, options, analysisOptions); |
- } |
- |
- static void setupAnalysisContext(AnalysisContext context, |
- CommandLineOptions options, AnalysisOptionsImpl analysisOptions) { |
- Map<String, String> definedVariables = options.definedVariables; |
- if (definedVariables.isNotEmpty) { |
- DeclaredVariables declaredVariables = context.declaredVariables; |
- definedVariables.forEach((String variableName, String value) { |
- declaredVariables.define(variableName, value); |
- }); |
- } |
- |
- if (options.log) { |
- AnalysisEngine.instance.logger = new StdLogger(); |
- } |
- |
- // Set context options. |
- context.analysisOptions = analysisOptions; |
- } |
- |
- /// Perform a deep comparison of two string lists. |
- static bool _equalLists(List<String> l1, List<String> l2) { |
- if (l1.length != l2.length) { |
- return false; |
- } |
- for (int i = 0; i < l1.length; i++) { |
- if (l1[i] != l2[i]) { |
- return false; |
- } |
- } |
- return true; |
- } |
- |
- /// Perform a deep comparison of two string maps. |
- static bool _equalMaps(Map<String, String> m1, Map<String, String> m2) { |
- if (m1.length != m2.length) { |
- return false; |
- } |
- for (String key in m1.keys) { |
- if (!m2.containsKey(key) || m1[key] != m2[key]) { |
- return false; |
- } |
- } |
- return true; |
- } |
- |
- /// Convert [sourcePath] into an absolute path. |
- static String _normalizeSourcePath(String sourcePath) => |
- path.normalize(new io.File(sourcePath).absolute.path); |
-} |
- |
-/// Provides a framework to read command line options from stdin and feed them |
-/// to a callback. |
-class _BatchRunner { |
- /// Run the tool in 'batch' mode, receiving command lines through stdin and |
- /// returning pass/fail status through stdout. This feature is intended for |
- /// use in unit testing. |
- static void runAsBatch(List<String> sharedArgs, _BatchRunnerHandler handler) { |
- outSink.writeln('>>> BATCH START'); |
- Stopwatch stopwatch = new Stopwatch(); |
- stopwatch.start(); |
- int testsFailed = 0; |
- int totalTests = 0; |
- ErrorSeverity batchResult = ErrorSeverity.NONE; |
- // Read line from stdin. |
- Stream cmdLine = |
- io.stdin.transform(UTF8.decoder).transform(new LineSplitter()); |
- cmdLine.listen((String line) async { |
- // Maybe finish. |
- if (line.isEmpty) { |
- var time = stopwatch.elapsedMilliseconds; |
- outSink.writeln( |
- '>>> BATCH END (${totalTests - testsFailed}/$totalTests) ${time}ms'); |
- io.exitCode = batchResult.ordinal; |
- } |
- // Prepare arguments. |
- var lineArgs = line.split(new RegExp('\\s+')); |
- var args = new List<String>(); |
- args.addAll(sharedArgs); |
- args.addAll(lineArgs); |
- args.remove('-b'); |
- args.remove('--batch'); |
- // Analyze single set of arguments. |
- try { |
- totalTests++; |
- ErrorSeverity result = await handler(args); |
- bool resultPass = result != ErrorSeverity.ERROR; |
- if (!resultPass) { |
- testsFailed++; |
- } |
- batchResult = batchResult.max(result); |
- // Write stderr end token and flush. |
- errorSink.writeln('>>> EOF STDERR'); |
- String resultPassString = resultPass ? 'PASS' : 'FAIL'; |
- outSink.writeln( |
- '>>> TEST $resultPassString ${stopwatch.elapsedMilliseconds}ms'); |
- } catch (e, stackTrace) { |
- errorSink.writeln(e); |
- errorSink.writeln(stackTrace); |
- errorSink.writeln('>>> EOF STDERR'); |
- outSink.writeln('>>> TEST CRASH'); |
- } |
- }); |
- } |
-} |
- |
-class _DriverError implements Exception { |
- String msg; |
- _DriverError(this.msg); |
-} |
- |
-class _PackageInfo { |
- Packages packages; |
- Map<String, List<file_system.Folder>> packageMap; |
- _PackageInfo(this.packages, this.packageMap); |
-} |
- |
-/// [SdkExtUriResolver] needs a Map from package name to folder. In the case |
-/// that the analyzer is invoked with a --package-root option, we need to |
-/// manually create this mapping. Given [packageRootPath], |
-/// [_PackageRootPackageMapBuilder] creates a simple mapping from package name |
-/// to full path on disk (resolving any symbolic links). |
-class _PackageRootPackageMapBuilder { |
- static Map<String, List<file_system.Folder>> buildPackageMap( |
- String packageRootPath) { |
- var packageRoot = new io.Directory(packageRootPath); |
- if (!packageRoot.existsSync()) { |
- throw new _DriverError( |
- 'Package root directory ($packageRootPath) does not exist.'); |
- } |
- var packages = packageRoot.listSync(followLinks: false); |
- var result = new Map<String, List<file_system.Folder>>(); |
- for (var package in packages) { |
- var packageName = path.basename(package.path); |
- var realPath = package.resolveSymbolicLinksSync(); |
- result[packageName] = [ |
- PhysicalResourceProvider.INSTANCE.getFolder(realPath) |
- ]; |
- } |
- return result; |
- } |
-} |