diff --git a/build_runner/lib/src/build/resolver/analysis_driver.dart b/build_runner/lib/src/build/resolver/analysis_driver.dart index fc7f835c4..8b5540db2 100644 --- a/build_runner/lib/src/build/resolver/analysis_driver.dart +++ b/build_runner/lib/src/build/resolver/analysis_driver.dart @@ -5,14 +5,13 @@ import 'dart:io'; import 'package:analyzer/file_system/file_system.dart' show ResourceProvider; -// ignore: implementation_imports -import 'package:analyzer/src/clients/build_resolvers/build_resolvers.dart'; import 'package:package_config/package_config.dart' show PackageConfig; import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; import 'analysis_driver_filesystem.dart'; import 'analysis_driver_model.dart'; +import 'build_resolvers.dart'; /// Builds an [AnalysisDriverForPackageBuild] backed by a summary SDK. /// diff --git a/build_runner/lib/src/build/resolver/analysis_driver_filesystem.dart b/build_runner/lib/src/build/resolver/analysis_driver_filesystem.dart index a02f1bf66..c7148862d 100644 --- a/build_runner/lib/src/build/resolver/analysis_driver_filesystem.dart +++ b/build_runner/lib/src/build/resolver/analysis_driver_filesystem.dart @@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:convert'; +import 'dart:io' as io; + import 'dart:typed_data'; import 'package:analyzer/file_system/file_system.dart'; @@ -28,7 +30,14 @@ class AnalysisDriverFilesystem implements UriResolver, ResourceProvider { /// Reads the data previously written to [path]. /// /// Throws if ![exists]. - String read(String path) => _data[path]!; + String read(String path) { + if (path.contains('/sdk/') || path.contains('/dart-sdk/')) { + return io.File(path).readAsStringSync(); + } + final result = _data[path]; + if (result == null) throw ArgumentError('Path does not exist: $path'); + return result; + } /// Deletes the data previously written to [path]. /// @@ -171,6 +180,9 @@ class _Resource implements File, Folder { @override String get shortName => filesystem.pathContext.basename(path); + @override + Folder get parent => _Resource(filesystem, p.dirname(path)); + // `File` methods. @override Uint8List readAsBytesSync() { @@ -183,6 +195,9 @@ class _Resource implements File, Folder { @override String readAsStringSync() => filesystem.read(path); + @override + String canonicalizePath(String path) => path; + // Analyzer methods such as `CompilationUnitElement.source` provide access to // source and return a `TimestampedData` with this value. // @@ -198,6 +213,14 @@ class _Resource implements File, Folder { bool contains(String path) => filesystem.pathContext.isWithin(this.path, path); + @override + File getChildAssumingFile(String relPath) => + _Resource(filesystem, '$path/$relPath'); + + @override + Folder getChildAssumingFolder(String relPath) => + _Resource(filesystem, '$path/$relPath'); + // Most `File` and/or `Folder` methods are not needed. @override diff --git a/build_runner/lib/src/build/resolver/analysis_driver_model.dart b/build_runner/lib/src/build/resolver/analysis_driver_model.dart index 68a3d0ba4..61178c4d8 100644 --- a/build_runner/lib/src/build/resolver/analysis_driver_model.dart +++ b/build_runner/lib/src/build/resolver/analysis_driver_model.dart @@ -4,8 +4,6 @@ import 'dart:async'; -// ignore: implementation_imports -import 'package:analyzer/src/clients/build_resolvers/build_resolvers.dart'; import 'package:build/build.dart'; import '../../logging/timed_activities.dart'; @@ -15,6 +13,8 @@ import '../library_cycle_graph/library_cycle_graph_loader.dart'; import '../library_cycle_graph/phased_asset_deps.dart'; import 'analysis_driver_filesystem.dart'; +import 'build_resolvers.dart'; + /// Manages analysis driver and related build state. /// /// - Tracks the import graph of all sources needed for analysis. diff --git a/build_runner/lib/src/build/resolver/build_resolvers.dart b/build_runner/lib/src/build/resolver/build_resolvers.dart new file mode 100644 index 000000000..3d9be4705 --- /dev/null +++ b/build_runner/lib/src/build/resolver/build_resolvers.dart @@ -0,0 +1,160 @@ +// Copyright (c) 2021, 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. + +// ignore_for_file: implementation_imports + +import 'dart:io'; +import 'dart:io' as io; +import 'dart:typed_data'; + +import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; +import 'package:analyzer/dart/analysis/analysis_options.dart'; +import 'package:analyzer/dart/analysis/session.dart'; +import 'package:analyzer/file_system/file_system.dart'; +import 'package:analyzer/src/context/packages.dart'; +import 'package:analyzer/src/dart/analysis/analysis_options.dart'; +import 'package:analyzer/src/dart/analysis/analysis_options_map.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_content_cache.dart'; +import 'package:analyzer/src/dart/analysis/performance_logger.dart'; +import 'package:analyzer/src/dart/sdk/sdk.dart'; +import 'package:analyzer/src/generated/source.dart'; +import 'package:analyzer/src/summary/summary_sdk.dart'; +import 'package:analyzer/src/summary2/package_bundle_format.dart'; +import 'package:package_config/package_config_types.dart'; +import 'package:path/path.dart' as p; +import 'package:yaml/yaml.dart'; + +export 'package:analyzer/dart/analysis/analysis_options.dart' + show AnalysisOptions; +export 'package:analyzer/source/source.dart' show Source; +export 'package:analyzer/src/context/packages.dart' show Package, Packages; +export 'package:analyzer/src/dart/analysis/analysis_options.dart' + show AnalysisOptionsImpl; +export 'package:analyzer/src/dart/analysis/byte_store.dart' show ByteStore; +export 'package:analyzer/src/dart/analysis/experiments.dart' + show ExperimentStatus; +export 'package:analyzer/src/generated/source.dart' show UriResolver; + +/// A somewhat low level API to create [AnalysisSession]. +/// +/// Ideally we want clients to use [AnalysisContextCollection], which +/// encapsulates any internals and is driven by `package_config.json` and +/// `analysis_options.yaml` files. But so far it looks that `build_resolvers` +/// wants to provide [UriResolver], and push [Packages] created by other means +/// than parsing `package_config.json`. +AnalysisDriverForPackageBuild createAnalysisDriver({ + required ResourceProvider resourceProvider, + required Uint8List sdkSummaryBytes, + required AnalysisOptions analysisOptions, + FileContentCache? fileContentCache, + required List uriResolvers, + required Packages packages, + ByteStore? byteStore, +}) { + final sdkBundle = PackageBundleReader(sdkSummaryBytes); + final bundleSdk = SummaryBasedDartSdk.forBundle(sdkBundle); + + final runningDartSdkPath = p.dirname(p.dirname(Platform.resolvedExecutable)); + + AbstractDartSdk sdk = FolderBasedDartSdk( + resourceProvider, + resourceProvider.getFolder(runningDartSdkPath), + ); + + final dartUiPath = p.normalize( + p.join(runningDartSdkPath, '..', 'pkg', 'sky_engine', 'lib'), + ); + final isFlutter = + Platform.version.contains('flutter') || + Directory(dartUiPath).existsSync(); + if (isFlutter) { + final embedderYamlPath = p.join(dartUiPath, '_embedder.yaml'); + final content = io.File(embedderYamlPath).readAsStringSync(); + final map = loadYaml(content) as YamlMap; + final embedderSdk = EmbedderSdk(resourceProvider, { + resourceProvider.getFolder(p.dirname(embedderYamlPath)): map, + }, languageVersion: sdk.languageVersion); + for (final library in embedderSdk.sdkLibraries) { + final uriStr = library.shortName; + if (sdk.libraryMap.getLibrary(uriStr) == null) { + sdk.libraryMap.setLibrary(uriStr, library); + } + } + } + + //final sourceFactory = SourceFactory([DartUriResolver(sdk), ...uriResolvers]); + final sourceFactory = SourceFactory([DartUriResolver(sdk), ...uriResolvers]); + + //final dataStore = SummaryDataStore(); + //dataStore.addBundle('', sdkBundle); + + final logger = PerformanceLog(null); + byteStore ??= MemoryByteStore(); + + final scheduler = AnalysisDriverScheduler(logger); + scheduler.events.drain().ignore(); + + final sharedOptions = analysisOptions as AnalysisOptionsImpl; + final optionsMap = AnalysisOptionsMap.forSharedOptions(sharedOptions); + final driver = AnalysisDriver( + scheduler: scheduler, + logger: logger, + resourceProvider: resourceProvider, + byteStore: byteStore, + sourceFactory: sourceFactory, + analysisOptionsMap: optionsMap, + fileContentCache: fileContentCache, + // externalSummaries: dataStore, + packages: packages, + withFineDependencies: true, + shouldReportInconsistentAnalysisException: false, + ); + + scheduler.start(); + + return AnalysisDriverForPackageBuild._(bundleSdk.libraryUris, driver); +} + +/// [AnalysisSession] plus a tiny bit more. +class AnalysisDriverForPackageBuild { + final List _sdkLibraryUris; + final AnalysisDriver _driver; + + AnalysisDriverForPackageBuild._(this._sdkLibraryUris, this._driver); + + AnalysisSession get currentSession { + return _driver.currentSession; + } + + /// Returns URIs of libraries in the given SDK. + List get sdkLibraryUris { + return _sdkLibraryUris; + } + + /// Return a [Future] that completes after pending file changes are applied, + /// so that [currentSession] can be used to compute results. + Future applyPendingFileChanges() { + return _driver.applyPendingFileChanges(); + } + + /// The file with the given [path] might have changed - updated, added or + /// removed. Or not, we don't know. Or it might have, but then changed back. + /// + /// The [path] must be absolute and normalized. + /// + /// The [currentSession] most probably will be invalidated. + /// Note, is does NOT at the time of writing this comment. + /// But we are going to fix this. + void changeFile(String path) { + _driver.changeFile(path); + } + + /// Return `true` if the [uri] can be resolved to an existing file. + bool isUriOfExistingFile(Uri uri) { + final source = _driver.sourceFactory.forUri2(uri); + return source != null && source.exists(); + } +} diff --git a/build_runner/lib/src/build/resolver/resolver.dart b/build_runner/lib/src/build/resolver/resolver.dart index bcc4d7067..bf9d0ccf0 100644 --- a/build_runner/lib/src/build/resolver/resolver.dart +++ b/build_runner/lib/src/build/resolver/resolver.dart @@ -12,8 +12,6 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/diagnostic/diagnostic.dart'; import 'package:analyzer/error/error.dart'; -// ignore: implementation_imports -import 'package:analyzer/src/clients/build_resolvers/build_resolvers.dart'; import 'package:async/async.dart'; import 'package:build/build.dart'; import 'package:build/experiments.dart'; @@ -27,6 +25,7 @@ import '../../logging/timed_activities.dart'; import 'analysis_driver.dart'; import 'analysis_driver_filesystem.dart'; import 'analysis_driver_model.dart'; +import 'build_resolvers.dart'; import 'sdk_summary.dart'; import 'shared_resource_pool.dart'; diff --git a/build_runner/pubspec.yaml b/build_runner/pubspec.yaml index 0ee461fa4..23d4c2285 100644 --- a/build_runner/pubspec.yaml +++ b/build_runner/pubspec.yaml @@ -52,5 +52,11 @@ dev_dependencies: test: ^1.25.5 test_descriptor: ^2.0.0 +dependency_overrides: + analyzer: + path: ../../dart-sdk/sdk/pkg/analyzer + _fe_analyzer_shared: + path: ../../dart-sdk/sdk/pkg/_fe_analyzer_shared + topics: - build-runner