diff --git a/build_resolvers/CHANGELOG.md b/build_resolvers/CHANGELOG.md index 56e40b4bfa..68f75708af 100644 --- a/build_resolvers/CHANGELOG.md +++ b/build_resolvers/CHANGELOG.md @@ -2,6 +2,8 @@ - Use `build` 3.0.2. - Use `build_runner` 2.7.0. +- Remove unused `TransitiveDigestsBuilder`. +- Remove unused deps: `convert`, `crypto`. ## 3.0.1 diff --git a/build_resolvers/lib/builder.dart b/build_resolvers/lib/builder.dart deleted file mode 100644 index c634b5647e..0000000000 --- a/build_resolvers/lib/builder.dart +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2023, 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. - -import 'dart:async'; - -import 'package:analyzer/dart/analysis/utilities.dart'; -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:build/build.dart'; -import 'package:convert/convert.dart'; -import 'package:crypto/crypto.dart'; - -const transitiveDigestExtension = '.transitive_digest'; - -Builder transitiveDigestsBuilder(BuilderOptions _) => - _TransitiveDigestsBuilder(); - -PostProcessBuilder transitiveDigestCleanup(BuilderOptions options) => - FileDeletingBuilder([ - transitiveDigestExtension, - ], isEnabled: options.config['enabled'] as bool? ?? true); - -/// Computes a digest comprised of the current libraries digest as well as its -/// transitive dependency digests, and writes it to a file next to the library. -/// -/// For any dependency that has a transitive digest already written, we just use -/// that and don't crawl its transitive deps, as the transitive digest includes -/// all the information we need. -/// -/// TODO(davidmorgan): this is not used by `build_resolvers` any more, consider -/// deprecating and removing. -class _TransitiveDigestsBuilder extends Builder { - @override - Future build(BuildStep buildStep) async { - final seen = {buildStep.inputId}; - final queue = [...seen]; - final digestSink = AccumulatorSink(); - final byteSink = md5.startChunkedConversion(digestSink); - - while (queue.isNotEmpty) { - final next = queue.removeLast(); - - // If we have a transitive digest ID available, just add that digest and - // continue. - final transitiveDigestId = next.addExtension(transitiveDigestExtension); - if (await buildStep.canRead(transitiveDigestId)) { - byteSink.add(await buildStep.readAsBytes(transitiveDigestId)); - continue; - } - - // We warn here but do not fail, the downside is slower builds. - if (!(await buildStep.canRead(next))) { - log.warning( - ''' -Unable to read asset, could not compute transitive deps: $next - -This may cause less efficient builds, see the following doc for help: -https://github.com/dart-lang/build/blob/master/docs/faq.md#unable-to-read-asset-could-not-compute-transitive-deps''', - ); - return; - } - - // Otherwise, add its digest and queue all its dependencies to crawl. - byteSink.add((await buildStep.digest(next)).bytes); - - // We know this isn't null since we already checked if we can read `next`. - final deps = _parseDependencies(await buildStep.readAsString(next), next); - - // Add all previously unseen deps to the queue. - for (final dep in deps) { - if (seen.add(dep)) queue.add(dep); - } - } - byteSink.close(); - await buildStep.writeAsBytes( - buildStep.inputId.addExtension(transitiveDigestExtension), - digestSink.events.single.bytes, - ); - } - - @override - Map> get buildExtensions => const { - '.dart': ['.dart$transitiveDigestExtension'], - }; -} - -const _ignoredSchemes = ['dart', 'dart-ext']; - -Iterable _parseDependencies(String content, AssetId from) => - parseString(content: content, throwIfDiagnostics: false).unit.directives - .whereType() - .map((directive) => directive.uri.stringValue) - // Filter out nulls. uri.stringValue can be null for strings that use - // interpolation. - .whereType() - .where( - (uriContent) => !_ignoredSchemes.any(Uri.parse(uriContent).isScheme), - ) - .map((content) => AssetId.resolve(Uri.parse(content), from: from)); diff --git a/build_resolvers/lib/src/crawl_async.dart b/build_resolvers/lib/src/crawl_async.dart deleted file mode 100644 index c442a5310b..0000000000 --- a/build_resolvers/lib/src/crawl_async.dart +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2025, 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. - -import 'dart:async'; -import 'dart:collection'; - -/// Finds and returns every node in a graph who's nodes and edges are -/// asynchronously resolved. -/// -/// Cycles are allowed. If this is an undirected graph the [edges] function -/// may be symmetric. In this case the [roots] may be any node in each connected -/// graph. -/// -/// [V] is the type of values in the graph nodes. [K] must be a type suitable -/// for using as a Map or Set key. [edges] should return the next reachable -/// nodes. -/// -/// There are no ordering guarantees. This is useful for ensuring some work is -/// performed at every node in an asynchronous graph, but does not give -/// guarantees that the work is done in topological order. -/// -/// If either [readNode] or [edges] throws the error will be forwarded -/// through the result stream and no further nodes will be crawled, though some -/// work may have already been started. -/// -/// Crawling is eager, so calls to [edges] may overlap with other calls that -/// have not completed. If the [edges] callback needs to be limited or throttled -/// that must be done by wrapping it before calling [crawlAsync]. -/// -/// This is a fork of the `package:graph` algorithm changed from recursive to -/// iterative; it is mostly for benchmarking, as `AnalysisDriverModel` will -/// replace the use of this method entirely. -Stream crawlAsync( - Iterable roots, - FutureOr Function(K) readNode, - FutureOr> Function(K, V) edges, -) { - final crawl = _CrawlAsync(roots, readNode, edges)..run(); - return crawl.result.stream; -} - -class _CrawlAsync { - final result = StreamController(); - - final FutureOr Function(K) readNode; - final FutureOr> Function(K, V) edges; - final Iterable roots; - - final _seen = HashSet(); - var _next = []; - - _CrawlAsync(this.roots, this.readNode, this.edges); - - /// Add all nodes in the graph to [result] and return a Future which fires - /// after all nodes have been seen. - Future run() async { - try { - _next.addAll(roots); - while (_next.isNotEmpty) { - // Take everything from `_next`, await crawling it in parallel. - final next = _next; - _next = []; - await Future.wait(next.map(_crawlNext), eagerError: true); - } - await result.close(); - } catch (e, st) { - result.addError(e, st); - await result.close(); - } - } - - /// Process [key], queue up any of its its edges that haven't been seen. - Future _crawlNext(K key) async { - final value = await readNode(key); - if (result.isClosed) return; - result.add(value); - for (final edge in await edges(key, value)) { - if (_seen.add(edge)) _next.add(edge); - } - } -} diff --git a/build_resolvers/pubspec.yaml b/build_resolvers/pubspec.yaml index 9bb2371918..58580fddb2 100644 --- a/build_resolvers/pubspec.yaml +++ b/build_resolvers/pubspec.yaml @@ -13,8 +13,6 @@ dependencies: build: '3.0.2-wip' build_runner_core: '9.3.0-wip' collection: ^1.17.0 - convert: ^3.1.1 - crypto: ^3.0.0 package_config: ^2.0.0 path: ^1.8.0 pool: ^1.5.0 diff --git a/build_resolvers/test/crawl_async_test.dart b/build_resolvers/test/crawl_async_test.dart deleted file mode 100644 index 9275b4f23d..0000000000 --- a/build_resolvers/test/crawl_async_test.dart +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2025, 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. - -import 'package:build_resolvers/src/crawl_async.dart'; -import 'package:test/test.dart'; - -// This is a fork of the `package:graph` test of the same name, there are -// no changes. TODO(davidmorgan): remove when `crawlAsync` is removed -// in favor of the new `AnalysisDriverModel`. - -void main() { - group('asyncCrawl', () { - Future> crawl( - Map?> g, - Iterable roots, - ) { - final graph = AsyncGraph(g); - return crawlAsync(roots, graph.readNode, graph.edges).toList(); - } - - test('empty result for empty graph', () async { - final result = await crawl({}, []); - expect(result, isEmpty); - }); - - test('single item for a single node', () async { - final result = await crawl({'a': []}, ['a']); - expect(result, ['a']); - }); - - test('hits every node in a graph', () async { - final result = await crawl( - { - 'a': ['b', 'c'], - 'b': ['c'], - 'c': ['d'], - 'd': [], - }, - ['a'], - ); - expect(result, hasLength(4)); - expect( - result, - allOf(contains('a'), contains('b'), contains('c'), contains('d')), - ); - }); - - test('handles cycles', () async { - final result = await crawl( - { - 'a': ['b'], - 'b': ['c'], - 'c': ['b'], - }, - ['a'], - ); - expect(result, hasLength(3)); - expect(result, allOf(contains('a'), contains('b'), contains('c'))); - }); - - test('handles self cycles', () async { - final result = await crawl( - { - 'a': ['b'], - 'b': ['b'], - }, - ['a'], - ); - expect(result, hasLength(2)); - expect(result, allOf(contains('a'), contains('b'))); - }); - - test('allows null edges', () async { - final result = await crawl( - { - 'a': ['b'], - 'b': null, - }, - ['a'], - ); - expect(result, hasLength(2)); - expect(result, allOf(contains('a'), contains('b'))); - }); - - test('allows null nodes', () async { - final result = await crawl( - { - 'a': ['b'], - }, - ['a'], - ); - expect(result, ['a', null]); - }); - - test('surfaces exceptions for crawling edges', () { - final graph = { - 'a': ['b'], - }; - final nodes = crawlAsync( - ['a'], - (n) => n, - (k, n) => k == 'b' ? throw ArgumentError() : graph[k] ?? [], - ); - expect(nodes, emitsThrough(emitsError(isArgumentError))); - }); - - test('surfaces exceptions for resolving keys', () { - final graph = { - 'a': ['b'], - }; - final nodes = crawlAsync( - ['a'], - (n) => n == 'b' ? throw ArgumentError() : n, - (k, n) => graph[k] ?? [], - ); - expect(nodes, emitsThrough(emitsError(isArgumentError))); - }); - }); -} - -/// A representation of a Graph where keys can asynchronously be resolved to -/// real values or to edges. -class AsyncGraph { - final Map?> graph; - - AsyncGraph(this.graph); - - Future readNode(String node) async => - graph.containsKey(node) ? node : null; - - Future> edges(String key, String? node) async => - graph[key] ?? []; -}