-
Notifications
You must be signed in to change notification settings - Fork 212
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Compute and cache transitive digests as files in build_resolvers (#3556)
Spawned from discussion [here](#3555 (comment)). - Adds a builder in build_resolvers which emits a file containing the transitive digest of the library and all its imports. - When computing the transitive digest, we always first look for transitive digest files next to all of our immediate library deps, if they exist we merge that file into our digest and don't crawl any deeper. - If we can't read any transitive dependency for some reason we emit a warning and just give up in the builder, which means we will never emit a transitive digest file for that library (which is fine, just not optimal). - The resolver reads these files to establish dependencies - for each library dependency we first check for a transitive digest file, if it exists we just read that and don't crawl that libraries deps. If it doesn't exist then we do the old behavior. - There is actually an additional step here that will continue the recursive crawl for libraries that have not yet been seen in order to load them into the resource provider for the analyzer. - I also exposed a shared resource to avoid duplicate parsing of libraries between the resolver itself and the transitive digest builder. We might eventually want to migrate this to a builder as well, and serialize that information to disk instead, which would avoid some unnecessary re-parsing of libraries on rebuilds.
- Loading branch information
Showing
10 changed files
with
270 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
builders: | ||
transitive_digests: | ||
import: "package:build_resolvers/builder.dart" | ||
builder_factories: | ||
- transitiveDigestsBuilder | ||
build_extensions: | ||
.dart: | ||
- .dart.transitive_digest | ||
auto_apply: all_packages | ||
is_optional: True | ||
required_inputs: [".dart"] | ||
build_to: cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// 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:build/build.dart'; | ||
import 'package:convert/convert.dart'; | ||
import 'package:crypto/crypto.dart'; | ||
|
||
import 'src/build_asset_uri_resolver.dart'; | ||
|
||
Builder transitiveDigestsBuilder(_) => _TransitiveDigestsBuilder(); | ||
|
||
/// 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. | ||
class _TransitiveDigestsBuilder extends Builder { | ||
@override | ||
Future<void> build(BuildStep buildStep) async { | ||
final seen = <AssetId>{buildStep.inputId}; | ||
final queue = [...seen]; | ||
final digestSink = AccumulatorSink<Digest>(); | ||
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; | ||
} | ||
|
||
// Otherwise, add its digest and queue all its dependencies to crawl. | ||
byteSink.add((await buildStep.digest(next)).bytes); | ||
final deps = await dependenciesOf(next, buildStep); | ||
if (deps == null) { | ||
// We warn here but do not fail, the downside is slower builds. | ||
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; | ||
} | ||
|
||
// 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<String, List<String>> get buildExtensions => const { | ||
'.dart': ['.dart$transitiveDigestExtension'], | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.