Skip to content

Commit 3e83217

Browse files
authored
Refactor PathProvidingAssetReader to AssetPathProvider. (#3858)
1 parent aa2e1fe commit 3e83217

17 files changed

+111
-89
lines changed

build/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
- Add `package:build/src/internal.dart` for use by `build_resolvers`,
44
`build_runner_core` and `build_test`.
55
- Use `build_test` 3.0.0.
6+
- Refactor `PathProvidingAssetReader` to `AssetPathProvider`.
67

78
## 2.4.2
89

build/lib/src/builder/build_step_impl.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import '../asset/id.dart';
1818
import '../asset/reader.dart';
1919
import '../asset/writer.dart';
2020
import '../resource/resource.dart';
21+
import '../state/asset_path_provider.dart';
2122
import '../state/input_tracker.dart';
2223
import '../state/reader_state.dart';
2324
import 'build_step.dart';
@@ -80,6 +81,9 @@ class BuildStepImpl implements BuildStep, AssetReaderState {
8081
_stageTracker = stageTracker ?? NoOpStageTracker.instance,
8182
_reportUnusedAssets = reportUnusedAssets;
8283

84+
@override
85+
AssetPathProvider? get assetPathProvider => _reader.assetPathProvider;
86+
8387
@override
8488
InputTracker? get inputTracker => _reader.inputTracker;
8589

build/lib/src/internal.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
/// `build_test` only.
77
library;
88

9+
export 'state/asset_path_provider.dart';
910
export 'state/input_tracker.dart';
1011
export 'state/reader_state.dart';
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import '../asset/id.dart';
6+
7+
/// Converts [AssetId] to paths.
8+
abstract interface class AssetPathProvider {
9+
String pathFor(AssetId id);
10+
}
11+
12+
/// Applies a function to an existing [AssetPathProvider].
13+
class OverlayAssetPathProvider implements AssetPathProvider {
14+
AssetPathProvider delegate;
15+
AssetId Function(AssetId) overlay;
16+
17+
OverlayAssetPathProvider({required this.delegate, required this.overlay});
18+
19+
@override
20+
String pathFor(AssetId id) => delegate.pathFor(overlay(id));
21+
}

build/lib/src/state/reader_state.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import '../asset/reader.dart';
6+
import 'asset_path_provider.dart';
67
import 'input_tracker.dart';
78

89
/// Provides access to the state backing an [AssetReader].
@@ -21,6 +22,10 @@ extension AssetReaderStateExtension on AssetReader {
2122
return result;
2223
}
2324

25+
AssetPathProvider? get assetPathProvider => this is AssetReaderState
26+
? (this as AssetReaderState).assetPathProvider
27+
: null;
28+
2429
/// Throws if `this` is not an [AssetReaderState].
2530
void _requireIsAssetReaderState() {
2631
if (this is! AssetReaderState) {
@@ -35,4 +40,8 @@ abstract interface class AssetReaderState {
3540
/// The [InputTracker] that this reader records reads to; or `null` if it does
3641
/// not have one.
3742
InputTracker? get inputTracker;
43+
44+
/// The [AssetPathProvider] associated with this reader, or `null` if it does
45+
/// not have one.
46+
AssetPathProvider? get assetPathProvider;
3847
}

build_runner_core/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
- Fix crash when running on assets ending in a dot.
44
- Start using `package:build/src/internal.dart'.
55
- Use `build_test` 3.0.0.
6+
- Refactor `PathProvidingAssetReader` to `AssetPathProvider`.
67

78
## 8.0.0
89

build_runner_core/lib/src/asset/batch.dart

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import 'dart:async';
66
import 'dart:convert';
77

88
import 'package:build/build.dart';
9+
// ignore: implementation_imports
10+
import 'package:build/src/internal.dart';
911
import 'package:glob/glob.dart';
1012
import 'package:meta/meta.dart';
1113

@@ -53,13 +55,12 @@ final class _FileSystemWriteBatch {
5355
/// they are flushed to the file system.
5456
(RunnerAssetReader, RunnerAssetWriter) wrapInBatch({
5557
required RunnerAssetReader reader,
56-
required PathProvidingAssetReader pathProvidingReader,
5758
required RunnerAssetWriter writer,
5859
}) {
5960
final batch = _FileSystemWriteBatch._();
6061

6162
return (
62-
BatchReader(reader, pathProvidingReader, batch),
63+
BatchReader(reader, batch),
6364
BatchWriter(writer, batch),
6465
);
6566
}
@@ -74,12 +75,17 @@ final class _PendingFileState {
7475

7576
@internal
7677
final class BatchReader extends AssetReader
77-
implements RunnerAssetReader, PathProvidingAssetReader {
78+
implements AssetReaderState, RunnerAssetReader {
7879
final RunnerAssetReader _inner;
79-
final PathProvidingAssetReader _innerPathProviding;
8080
final _FileSystemWriteBatch _batch;
8181

82-
BatchReader(this._inner, this._innerPathProviding, this._batch);
82+
BatchReader(this._inner, this._batch);
83+
84+
@override
85+
AssetPathProvider? get assetPathProvider => _inner.assetPathProvider;
86+
87+
@override
88+
InputTracker? get inputTracker => _inner.inputTracker;
8389

8490
_PendingFileState? _stateFor(AssetId id) {
8591
return _batch._pendingWrites[id];
@@ -101,11 +107,6 @@ final class BatchReader extends AssetReader
101107
.where((asset) => _stateFor(asset)?.isDeleted != true);
102108
}
103109

104-
@override
105-
String pathTo(AssetId id) {
106-
return _innerPathProviding.pathTo(id);
107-
}
108-
109110
@override
110111
Future<List<int>> readAsBytes(AssetId id) async {
111112
if (_stateFor(id) case final state?) {

build_runner_core/lib/src/asset/build_cache.dart

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,39 @@ import 'dart:async';
22
import 'dart:convert';
33

44
import 'package:build/build.dart';
5+
// ignore: implementation_imports
6+
import 'package:build/src/internal.dart';
57
import 'package:crypto/crypto.dart';
68
import 'package:glob/glob.dart';
79

810
import '../asset_graph/graph.dart';
911
import '../asset_graph/node.dart';
1012
import '../util/constants.dart';
11-
import 'reader.dart';
1213
import 'writer.dart';
1314

1415
/// Wraps an [AssetReader] and translates reads for generated files into reads
1516
/// from the build cache directory
16-
class BuildCacheReader implements AssetReader {
17-
final AssetGraph _assetGraph;
17+
class BuildCacheReader implements AssetReader, AssetReaderState {
18+
@override
19+
final AssetPathProvider? assetPathProvider;
20+
1821
final AssetReader _delegate;
22+
final AssetGraph _assetGraph;
1923
final String _rootPackage;
2024

21-
BuildCacheReader._(this._delegate, this._assetGraph, this._rootPackage);
25+
BuildCacheReader(
26+
AssetReader delegate, AssetGraph assetGraph, String rootPackage)
27+
: _delegate = delegate,
28+
_assetGraph = assetGraph,
29+
_rootPackage = rootPackage,
30+
assetPathProvider = delegate.assetPathProvider == null
31+
? null
32+
: OverlayAssetPathProvider(
33+
delegate: delegate.assetPathProvider!,
34+
overlay: (id) => _cacheLocation(id, assetGraph, rootPackage));
2235

23-
factory BuildCacheReader(
24-
AssetReader delegate, AssetGraph assetGraph, String rootPackage) =>
25-
delegate is PathProvidingAssetReader
26-
? _PathProvidingBuildCacheReader._(delegate, assetGraph, rootPackage)
27-
: BuildCacheReader._(delegate, assetGraph, rootPackage);
36+
@override
37+
InputTracker? get inputTracker => _delegate.inputTracker;
2838

2939
@override
3040
Future<bool> canRead(AssetId id) =>
@@ -48,21 +58,6 @@ class BuildCacheReader implements AssetReader {
4858
'Asset globbing should be done per phase with the AssetGraph');
4959
}
5060

51-
class _PathProvidingBuildCacheReader extends BuildCacheReader
52-
implements PathProvidingAssetReader {
53-
@override
54-
PathProvidingAssetReader get _delegate =>
55-
super._delegate as PathProvidingAssetReader;
56-
57-
_PathProvidingBuildCacheReader._(PathProvidingAssetReader super.delegate,
58-
super.assetGraph, super.rootPackage)
59-
: super._();
60-
61-
@override
62-
String pathTo(AssetId id) =>
63-
_delegate.pathTo(_cacheLocation(id, _assetGraph, _rootPackage));
64-
}
65-
6661
class BuildCacheWriter implements RunnerAssetWriter {
6762
final AssetGraph _assetGraph;
6863
final RunnerAssetWriter _delegate;

build_runner_core/lib/src/asset/cache.dart

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,19 @@ import 'dart:convert';
77
import 'dart:typed_data';
88

99
import 'package:build/build.dart';
10+
// ignore: implementation_imports
11+
import 'package:build/src/internal.dart';
1012
import 'package:crypto/crypto.dart';
1113
import 'package:glob/glob.dart';
1214

1315
import 'lru_cache.dart';
14-
import 'reader.dart';
1516

1617
/// An [AssetReader] that caches all results from the delegate.
1718
///
1819
/// Assets are cached until [invalidate] is invoked.
1920
///
2021
/// Does not implement [findAssets].
21-
class CachingAssetReader implements AssetReader {
22+
class CachingAssetReader implements AssetReader, AssetReaderState {
2223
/// Cached results of [readAsBytes].
2324
final _bytesContentCache = LruCache<AssetId, List<int>>(
2425
1024 * 1024,
@@ -46,12 +47,13 @@ class CachingAssetReader implements AssetReader {
4647

4748
final AssetReader _delegate;
4849

49-
CachingAssetReader._(this._delegate);
50+
CachingAssetReader(this._delegate);
5051

51-
factory CachingAssetReader(AssetReader delegate) =>
52-
delegate is PathProvidingAssetReader
53-
? _PathProvidingCachingAssetReader._(delegate)
54-
: CachingAssetReader._(delegate);
52+
@override
53+
AssetPathProvider? get assetPathProvider => _delegate.assetPathProvider;
54+
55+
@override
56+
InputTracker? get inputTracker => _delegate.inputTracker;
5557

5658
@override
5759
Future<bool> canRead(AssetId id) =>
@@ -111,17 +113,3 @@ class CachingAssetReader implements AssetReader {
111113
}
112114
}
113115
}
114-
115-
/// A version of a [CachingAssetReader] that implements
116-
/// [PathProvidingAssetReader].
117-
class _PathProvidingCachingAssetReader extends CachingAssetReader
118-
implements PathProvidingAssetReader {
119-
@override
120-
PathProvidingAssetReader get _delegate =>
121-
super._delegate as PathProvidingAssetReader;
122-
123-
_PathProvidingCachingAssetReader._(super.delegate) : super._();
124-
125-
@override
126-
String pathTo(AssetId id) => _delegate.pathTo(id);
127-
}

build_runner_core/lib/src/asset/file_based.dart

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import 'dart:convert';
66
import 'dart:io';
77

88
import 'package:build/build.dart';
9+
// ignore: implementation_imports
10+
import 'package:build/src/internal.dart';
911
import 'package:glob/glob.dart';
1012
import 'package:glob/list_local_fs.dart';
1113
import 'package:path/path.dart' as path;
@@ -21,11 +23,17 @@ final _descriptorPool = Pool(32);
2123
/// Basic [AssetReader] which uses a [PackageGraph] to look up where to read
2224
/// files from disk.
2325
class FileBasedAssetReader extends AssetReader
24-
implements RunnerAssetReader, PathProvidingAssetReader {
26+
implements AssetReaderState, RunnerAssetReader {
2527
final PackageGraph packageGraph;
2628

2729
FileBasedAssetReader(this.packageGraph);
2830

31+
@override
32+
AssetPathProvider? get assetPathProvider => packageGraph;
33+
34+
@override
35+
InputTracker? get inputTracker => null;
36+
2937
@override
3038
Future<bool> canRead(AssetId id) =>
3139
_descriptorPool.withResource(() => _fileFor(id, packageGraph).exists());
@@ -55,9 +63,6 @@ class FileBasedAssetReader extends AssetReader
5563
.cast<File>()
5664
.map((file) => _fileToAssetId(file, packageNode));
5765
}
58-
59-
@override
60-
String pathTo(AssetId id) => _filePathFor(id, packageGraph);
6166
}
6267

6368
/// Creates an [AssetId] for [file], which is a part of [packageNode].
@@ -112,18 +117,9 @@ class FileBasedAssetWriter implements RunnerAssetWriter {
112117
Future<void> completeBuild() async {}
113118
}
114119

115-
/// Returns the path to [id] for a given [packageGraph].
116-
String _filePathFor(AssetId id, PackageGraph packageGraph) {
117-
var package = packageGraph[id.package];
118-
if (package == null) {
119-
throw PackageNotFoundException(id.package);
120-
}
121-
return path.join(package.path, id.path);
122-
}
123-
124120
/// Returns a [File] for [id] given [packageGraph].
125121
File _fileFor(AssetId id, PackageGraph packageGraph) {
126-
return File(_filePathFor(id, packageGraph));
122+
return File(packageGraph.pathFor(id));
127123
}
128124

129125
/// Returns a `File` for the asset reference by [id] given [packageGraph].

build_runner_core/lib/src/asset/reader.dart

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@ import '../util/async.dart';
1919
/// A [RunnerAssetReader] must implement [MultiPackageAssetReader].
2020
abstract class RunnerAssetReader implements MultiPackageAssetReader {}
2121

22-
/// An [AssetReader] that can provide actual paths to assets on disk.
23-
abstract class PathProvidingAssetReader implements AssetReader {
24-
String pathTo(AssetId id);
25-
}
26-
2722
/// Describes if and how a [SingleStepReader] should read an [AssetId].
2823
class Readability {
2924
final bool canRead;
@@ -80,6 +75,9 @@ class SingleStepReader implements AssetReader, AssetReaderState {
8075
this._primaryPackage, this._isReadableNode, this._checkInvalidInput,
8176
[this._getGlobNode, this._writtenAssets]);
8277

78+
@override
79+
AssetPathProvider? get assetPathProvider => _delegate.assetPathProvider;
80+
8381
/// Checks whether [id] can be read by this step - attempting to build the
8482
/// asset if necessary.
8583
///

build_runner_core/lib/src/environment/create_merged_dir.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import 'dart:convert';
77
import 'dart:io';
88

99
import 'package:build/build.dart';
10+
// ignore: implementation_imports
11+
import 'package:build/src/internal.dart';
1012
import 'package:logging/logging.dart';
1113
import 'package:path/path.dart' as p;
1214
import 'package:pool/pool.dart';
1315

14-
import '../asset/reader.dart';
1516
import '../environment/build_environment.dart';
1617
import '../generate/build_directory.dart';
1718
import '../generate/finalized_assets_view.dart';
@@ -35,7 +36,7 @@ Future<bool> createMergedOutputDirectories(
3536
AssetReader reader,
3637
FinalizedAssetsView finalizedAssetsView,
3738
bool outputSymlinksOnly) async {
38-
if (outputSymlinksOnly && reader is! PathProvidingAssetReader) {
39+
if (outputSymlinksOnly && reader.assetPathProvider == null) {
3940
_logger.severe(
4041
'The current environment does not support symlinks, but symlinks were '
4142
'requested.');
@@ -229,7 +230,7 @@ Future<AssetId> _writeAsset(
229230
await Link(_filePathFor(outputDir, outputId)).create(
230231
// We assert at the top of `createMergedOutputDirectories` that the
231232
// reader implements this type when requesting symlinks.
232-
(reader as PathProvidingAssetReader).pathTo(id),
233+
reader.assetPathProvider!.pathFor(id),
233234
recursive: true);
234235
} else {
235236
await _writeAsBytes(outputDir, outputId, await reader.readAsBytes(id));

0 commit comments

Comments
 (0)