From 276cf49406816bca0cc3239151c9510404d8bc8b Mon Sep 17 00:00:00 2001 From: David Morgan Date: Thu, 9 Oct 2025 09:34:08 +0200 Subject: [PATCH 1/2] Try fine grained dependencies. --- .../src/build/resolver/analysis_driver.dart | 3 +- .../resolver/analysis_driver_filesystem.dart | 20 ++- .../build/resolver/analysis_driver_model.dart | 4 +- .../src/build/resolver/build_resolvers.dart | 135 ++++++++++++++++++ .../lib/src/build/resolver/resolver.dart | 3 +- build_runner/pubspec.yaml | 6 + 6 files changed, 164 insertions(+), 7 deletions(-) create mode 100644 build_runner/lib/src/build/resolver/build_resolvers.dart diff --git a/build_runner/lib/src/build/resolver/analysis_driver.dart b/build_runner/lib/src/build/resolver/analysis_driver.dart index fc7f835c43..8b5540db2b 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 a02f1bf66a..4ec6b104b3 100644 --- a/build_runner/lib/src/build/resolver/analysis_driver_filesystem.dart +++ b/build_runner/lib/src/build/resolver/analysis_driver_filesystem.dart @@ -2,6 +2,8 @@ // 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. +import 'dart:io' as io; + import 'dart:convert'; import 'dart:typed_data'; @@ -28,7 +30,12 @@ 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/')) { + return io.File(path).readAsStringSync(); + } + return _data[path]!; + } /// Deletes the data previously written to [path]. /// @@ -171,6 +178,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() { @@ -198,6 +208,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 68a3d0ba4e..61178c4d86 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 0000000000..b3ec328a1c --- /dev/null +++ b/build_runner/lib/src/build/resolver/build_resolvers.dart @@ -0,0 +1,135 @@ +// 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: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:path/path.dart' as p; + +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 runningDarkSdkPath = p.dirname(p.dirname(Platform.resolvedExecutable)); + final sdk = FolderBasedDartSdk( + resourceProvider, + resourceProvider.getFolder(runningDarkSdkPath), + ); + + //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 bcc4d70677..bf9d0ccf0b 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 0ee461fa4a..23d4c22856 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 From 91af9c995650ce160c4e813721c10ccaeea5cfb5 Mon Sep 17 00:00:00 2001 From: David Morgan Date: Mon, 13 Oct 2025 12:40:22 +0200 Subject: [PATCH 2/2] Flutter. --- .../resolver/analysis_driver_filesystem.dart | 11 +++++-- .../src/build/resolver/build_resolvers.dart | 31 +++++++++++++++++-- 2 files changed, 36 insertions(+), 6 deletions(-) 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 4ec6b104b3..c7148862d4 100644 --- a/build_runner/lib/src/build/resolver/analysis_driver_filesystem.dart +++ b/build_runner/lib/src/build/resolver/analysis_driver_filesystem.dart @@ -2,9 +2,9 @@ // 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. +import 'dart:convert'; import 'dart:io' as io; -import 'dart:convert'; import 'dart:typed_data'; import 'package:analyzer/file_system/file_system.dart'; @@ -31,10 +31,12 @@ class AnalysisDriverFilesystem implements UriResolver, ResourceProvider { /// /// Throws if ![exists]. String read(String path) { - if (path.contains('/sdk/')) { + if (path.contains('/sdk/') || path.contains('/dart-sdk/')) { return io.File(path).readAsStringSync(); } - return _data[path]!; + final result = _data[path]; + if (result == null) throw ArgumentError('Path does not exist: $path'); + return result; } /// Deletes the data previously written to [path]. @@ -193,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. // diff --git a/build_runner/lib/src/build/resolver/build_resolvers.dart b/build_runner/lib/src/build/resolver/build_resolvers.dart index b3ec328a1c..3d9be47059 100644 --- a/build_runner/lib/src/build/resolver/build_resolvers.dart +++ b/build_runner/lib/src/build/resolver/build_resolvers.dart @@ -5,6 +5,7 @@ // 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'; @@ -22,7 +23,9 @@ 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; @@ -54,11 +57,33 @@ AnalysisDriverForPackageBuild createAnalysisDriver({ final sdkBundle = PackageBundleReader(sdkSummaryBytes); final bundleSdk = SummaryBasedDartSdk.forBundle(sdkBundle); - final runningDarkSdkPath = p.dirname(p.dirname(Platform.resolvedExecutable)); - final sdk = FolderBasedDartSdk( + final runningDartSdkPath = p.dirname(p.dirname(Platform.resolvedExecutable)); + + AbstractDartSdk sdk = FolderBasedDartSdk( resourceProvider, - resourceProvider.getFolder(runningDarkSdkPath), + 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]);