Skip to content

Commit

Permalink
Merge AssetWriterSpy functionality into SingleStepReader. (#3892)
Browse files Browse the repository at this point in the history
* Merge `AssetWriterSpy` functionality into `SingleStepReader`, make it `SingleStepReaderWriter`.

* Address review comments.
  • Loading branch information
davidmorgan authored Feb 28, 2025
1 parent e9845a4 commit 191fabc
Show file tree
Hide file tree
Showing 20 changed files with 679 additions and 635 deletions.
1 change: 1 addition & 0 deletions build/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## 2.4.3-wip

- `runBuilder` supports passing `fakeStartingAssets` for testing.
- `AssetNotFoundException` now also reports the missing `path`.
- Bump the min sdk to 3.7.0.
- Use `build_test` 3.0.0.
Expand Down
24 changes: 20 additions & 4 deletions build/lib/src/generate/run_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import 'dart:isolate';

// ignore: implementation_imports
import 'package:build_runner_core/src/generate/build_step_impl.dart';
// ignore: implementation_imports
import 'package:build_runner_core/src/generate/single_step_reader_writer.dart';
import 'package:logging/logging.dart';
import 'package:package_config/package_config.dart';

Expand Down Expand Up @@ -32,18 +34,23 @@ import 'expected_outputs.dart';
/// If [reportUnusedAssetsForInput] is provided then all calls to
/// `BuildStep.reportUnusedAssets` in [builder] will be forwarded to this
/// function with the associated primary input.
///
/// Optionally pass [fakeStartingAssets] for testing: the builder will behave as
/// if exactly those assets are available from previous phases, and will not be
/// able to access other files except for its own output.
Future<void> runBuilder(
Builder builder,
Iterable<AssetId> inputs,
AssetReader reader,
AssetWriter writer,
AssetReader assetReader,
AssetWriter assetWriter,
Resolvers? resolvers, {
Logger? logger,
ResourceManager? resourceManager,
StageTracker stageTracker = NoOpStageTracker.instance,
void Function(AssetId input, Iterable<AssetId> assets)?
reportUnusedAssetsForInput,
PackageConfig? packageConfig,
Set<AssetId>? fakeStartingAssets,
}) async {
var shouldDisposeResourceManager = resourceManager == null;
final resources = resourceManager ?? ResourceManager();
Expand Down Expand Up @@ -78,8 +85,17 @@ Future<void> runBuilder(
var buildStep = BuildStepImpl(
input,
outputs,
reader,
writer,
// If there a build running, `assetReader` and `assetWriter` are already a
// `SingleStepReaderWriter` instance integrated with the build; the `from`
// factory just passes it through.
//
// If there is no build running, this creates a fake build step,
// optionally with `fakeStartingAssets`.
SingleStepReaderWriter.from(
reader: assetReader,
writer: assetWriter,
fakeStartingAssets: fakeStartingAssets,
),
resolvers,
resources,
loadPackageConfig,
Expand Down
1 change: 1 addition & 0 deletions build/lib/src/internal.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export 'state/asset_path_provider.dart';
export 'state/filesystem.dart';
export 'state/filesystem_cache.dart';
export 'state/reader_state.dart';
export 'state/reader_writer.dart';
5 changes: 3 additions & 2 deletions build/lib/src/state/reader_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import 'asset_finder.dart';
import 'asset_path_provider.dart';
import 'filesystem.dart';
import 'filesystem_cache.dart';
import 'reader_writer.dart';

/// Provides access to the state backing an [AssetReader].
extension AssetReaderStateExtension on AssetReader {
/// Returns a new instance with optionally updated [cache].
AssetReader copyWith({
AssetReaderWriter copyWith({
AssetPathProvider? assetPathProvider,
FilesystemCache? cache,
}) {
Expand Down Expand Up @@ -55,7 +56,7 @@ extension AssetReaderStateExtension on AssetReader {
/// The state backing an [AssetReader].
abstract interface class AssetReaderState {
/// Returns a new instance with optionally updated [assetPathProvider] and/or [cache].
AssetReader copyWith({
AssetReaderWriter copyWith({
AssetPathProvider? assetPathProvider,
FilesystemCache? cache,
});
Expand Down
83 changes: 83 additions & 0 deletions build/lib/src/state/reader_writer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// 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:convert';

import 'package:crypto/crypto.dart';
import 'package:glob/glob.dart';

import '../asset/id.dart';
import '../asset/reader.dart';
import '../asset/writer.dart';
import 'asset_finder.dart';
import 'asset_path_provider.dart';
import 'filesystem.dart';
import 'filesystem_cache.dart';
import 'reader_state.dart';

/// An [AssetReader] and [AssetWriter].
abstract interface class AssetReaderWriter
implements AssetReader, AssetWriter {}

/// An [AssetReaderWriter] that delegates to an [AssetReader] and an
/// [AssetWriter].
///
/// The main `package:build` readers and writers already implement
/// `AssetReaderWriter`, this is used to support nonstandard readers/writers for
/// testing.
class DelegatingAssetReaderWriter
implements AssetReaderWriter, AssetReaderState {
final AssetReader reader;
final AssetWriter writer;

DelegatingAssetReaderWriter({required this.reader, required this.writer});

@override
AssetFinder get assetFinder => reader.assetFinder;

@override
AssetPathProvider get assetPathProvider => reader.assetPathProvider;

@override
FilesystemCache get cache => reader.cache;

@override
AssetReaderWriter copyWith({
AssetPathProvider? assetPathProvider,
FilesystemCache? cache,
}) => DelegatingAssetReaderWriter(
reader: reader.copyWith(assetPathProvider: assetPathProvider, cache: cache),
writer: writer,
);

@override
Filesystem get filesystem => reader.filesystem;

@override
Future<bool> canRead(AssetId id) => reader.canRead(id);

@override
Future<Digest> digest(AssetId id) => reader.digest(id);

@override
Stream<AssetId> findAssets(Glob glob) => reader.findAssets(glob);

@override
Future<List<int>> readAsBytes(AssetId id) => reader.readAsBytes(id);

@override
Future<String> readAsString(AssetId id, {Encoding encoding = utf8}) =>
reader.readAsString(id, encoding: encoding);

@override
Future<void> writeAsBytes(AssetId id, List<int> bytes) =>
writer.writeAsBytes(id, bytes);

@override
Future<void> writeAsString(
AssetId id,
String contents, {
Encoding encoding = utf8,
}) => writer.writeAsString(id, contents);
}
2 changes: 2 additions & 0 deletions build_runner_core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
- Refactor `FileBasedAssetReader` and `FileBasedAssetWriter` to `ReaderWriter`.
- Move `BuildStepImpl` to `build_runner_core`, use `SingleStepReader` directly.
- Remove `BuildCacheWriter`, functionality is handled by `AssetPathProvider`.
- Refactor `SingleStepReader` to `SingleStepReaderWriter`, incorporating
`AssetWriterSpy` functionality.

## 8.0.0

Expand Down
2 changes: 1 addition & 1 deletion build_runner_core/lib/src/asset/reader_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import 'writer.dart';

/// Pluggable [AssetReader] and [AssetWriter].
class ReaderWriter extends AssetReader
implements AssetReaderState, RunnerAssetWriter {
implements AssetReaderState, RunnerAssetWriter, AssetReaderWriter {
/// The package the generator is running for.
///
/// Deletes are only allowed within this package.
Expand Down
Loading

0 comments on commit 191fabc

Please sign in to comment.