Skip to content

Commit 49a653b

Browse files
committed
Refactor FileBasedAssetReader and FileBasedAssetWriter to ReaderWriter.
1 parent 8af15d3 commit 49a653b

File tree

17 files changed

+240
-199
lines changed

17 files changed

+240
-199
lines changed

_test_common/lib/in_memory_reader_writer.dart

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,56 @@ import 'dart:async';
55
import 'dart:convert';
66

77
import 'package:build/build.dart';
8+
// ignore: implementation_imports
9+
import 'package:build/src/internal.dart';
810
import 'package:build_runner_core/build_runner_core.dart';
911
import 'package:build_test/build_test.dart';
1012
// ignore: implementation_imports
1113
import 'package:build_test/src/in_memory_reader_writer.dart';
1214
import 'package:path/path.dart' as p;
1315
import 'package:watcher/watcher.dart';
1416

17+
// TODO(davidmorgan): refactor to remove this class.
1518
class InMemoryRunnerAssetReaderWriter extends InMemoryAssetReaderWriter
1619
implements AssetReader, RunnerAssetWriter {
1720
final _onCanReadController = StreamController<AssetId>.broadcast();
1821
Stream<AssetId> get onCanRead => _onCanReadController.stream;
1922
void Function(AssetId)? onDelete;
2023

21-
InMemoryRunnerAssetReaderWriter({super.rootPackage});
24+
factory InMemoryRunnerAssetReaderWriter({String? rootPackage}) {
25+
final filesystem = InMemoryFilesystem();
26+
return InMemoryRunnerAssetReaderWriter.using(
27+
rootPackage: rootPackage ?? 'unset',
28+
assetFinder: InMemoryAssetFinder(filesystem, rootPackage),
29+
assetPathProvider: const InMemoryAssetPathProvider(),
30+
filesystem: filesystem,
31+
cache: const PassthroughFilesystemCache(),
32+
inputTracker: InputTracker(),
33+
);
34+
}
35+
36+
InMemoryRunnerAssetReaderWriter.using({
37+
required super.rootPackage,
38+
required super.assetFinder,
39+
required super.assetPathProvider,
40+
required super.filesystem,
41+
required super.cache,
42+
required super.inputTracker,
43+
}) : super.using();
44+
45+
@override
46+
InMemoryRunnerAssetReaderWriter copyWith({
47+
AssetPathProvider? assetPathProvider,
48+
FilesystemCache? cache,
49+
InputTracker? inputTracker,
50+
}) => InMemoryRunnerAssetReaderWriter.using(
51+
rootPackage: rootPackage,
52+
assetFinder: assetFinder,
53+
assetPathProvider: assetPathProvider ?? this.assetPathProvider,
54+
filesystem: filesystem,
55+
cache: cache ?? this.cache,
56+
inputTracker: inputTracker ?? this.inputTracker,
57+
);
2258

2359
@override
2460
Future<bool> canRead(AssetId id) {

build/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
implementations.
1212
- Refactor `CachingAssetReader` to `FilesystemCache`.
1313
- Refactor `BuildCacheReader` to `BuildCacheAssetPathProvider`.
14+
- Refactor `FileBasedAssetReader` and `FileBasedAssetWriter` to `ReaderWriter`.
1415

1516
## 2.4.2
1617

build_runner/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- Refactor `MultiPackageAssetReader` to internal `AssetFinder`.
77
- `FinalizedReader` no longer implements `AssetReader`.
88
- Refactor `CachingAssetReader` to `FilesystemCache`.
9+
- Refactor `FileBasedAssetReader` and `FileBasedAssetWriter` to `ReaderWriter`.
910

1011
## 2.4.15
1112

build_runner/lib/src/build_script_generate/build_script_generate.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ Future<BuildScriptInfo> findBuildScriptOptions({
103103
equals: (a, b) => a.name == b.name,
104104
hashCode: (n) => n.name.hashCode,
105105
).expand((c) => c);
106-
var reader = FileBasedAssetReader(packageGraph);
106+
var reader = ReaderWriter(packageGraph);
107107
var overrides =
108108
buildConfigOverrides ??= await findBuildConfigOverrides(
109109
packageGraph,

build_runner/lib/src/entrypoint/clean.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Future<void> _cleanUpSourceOutputs(
8484
AssetGraph assetGraph,
8585
PackageGraph packageGraph,
8686
) async {
87-
var writer = FileBasedAssetWriter(packageGraph);
87+
var writer = ReaderWriter(packageGraph);
8888
for (var id in assetGraph.outputs) {
8989
if (id.package != packageGraph.root.name) continue;
9090
var node = assetGraph.get(id) as GeneratedAssetNode;

build_runner/lib/src/entrypoint/doctor.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class DoctorCommand extends BuildRunnerCommand {
6363
final packageGraph = await PackageGraph.forThisPackage();
6464
final buildConfigOverrides = await findBuildConfigOverrides(
6565
packageGraph,
66-
FileBasedAssetReader(packageGraph),
66+
ReaderWriter(packageGraph),
6767
);
6868
Future<BuildConfig> packageBuildConfig(PackageNode package) async {
6969
if (buildConfigOverrides.containsKey(package.name)) {

build_runner_core/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
implementations.
1212
- Refactor `CachingAssetReader` to `FilesystemCache`.
1313
- Refactor `BuildCacheReader` to `BuildCacheAssetPathProvider`.
14+
- Refactor `FileBasedAssetReader` and `FileBasedAssetWriter` to `ReaderWriter`.
1415

1516
## 8.0.0
1617

build_runner_core/lib/build_runner_core.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
export 'package:build/build.dart' show PostProcessBuildStep, PostProcessBuilder;
66

7-
export 'src/asset/file_based.dart';
87
export 'src/asset/finalized_reader.dart';
8+
export 'src/asset/reader_writer.dart';
99
export 'src/asset/writer.dart';
1010
export 'src/environment/build_environment.dart';
1111
export 'src/environment/io_environment.dart';
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44
import 'dart:async';
@@ -15,43 +15,63 @@ import 'package:path/path.dart' as path;
1515
import '../package_graph/package_graph.dart';
1616
import 'writer.dart';
1717

18-
/// Basic [AssetReader] which uses a [PackageGraph] to look up where to read
19-
/// files from disk.
20-
class FileBasedAssetReader extends AssetReader implements AssetReaderState {
18+
/// Pluggable [AssetReader] and [AssetWriter].
19+
class ReaderWriter extends AssetReader
20+
implements AssetReaderState, RunnerAssetWriter {
21+
/// The package the generator is running for.
22+
///
23+
/// Deletes are only allowed within this package.
24+
final String rootPackage;
25+
2126
@override
2227
final AssetPathProvider assetPathProvider;
2328
@override
2429
final Filesystem filesystem;
2530
@override
26-
late final AssetFinder assetFinder = FunctionAssetFinder(_findAssets);
31+
final AssetFinder assetFinder;
2732
@override
2833
final FilesystemCache cache;
34+
@override
35+
final InputTracker? inputTracker;
36+
37+
/// A [ReaderWriter] suitable for real builds.
38+
///
39+
/// [packageGraph] is used for mapping paths and finding assets. The
40+
/// `dart-io` filesystem is used with no cache.
41+
///
42+
/// Use [copyWith] to change settings such as caching.
43+
factory ReaderWriter(PackageGraph packageGraph) => ReaderWriter.using(
44+
rootPackage: packageGraph.root.name,
45+
assetFinder: PackageGraphAssetFinder(packageGraph),
46+
assetPathProvider: packageGraph,
47+
filesystem: IoFilesystem(),
48+
cache: const PassthroughFilesystemCache(),
49+
// In real builds input tracking is done per generator.
50+
inputTracker: null,
51+
);
2952

30-
final PackageGraph packageGraph;
31-
32-
FileBasedAssetReader(
33-
this.packageGraph, {
34-
AssetPathProvider? assetPathProvider,
35-
Filesystem? filesystem,
36-
FilesystemCache? cache,
37-
}) : filesystem = filesystem ?? IoFilesystem(),
38-
cache = cache ?? const PassthroughFilesystemCache(),
39-
assetPathProvider = assetPathProvider ?? packageGraph;
53+
ReaderWriter.using({
54+
required this.rootPackage,
55+
required this.assetFinder,
56+
required this.assetPathProvider,
57+
required this.filesystem,
58+
required this.cache,
59+
required this.inputTracker,
60+
});
4061

4162
@override
42-
FileBasedAssetReader copyWith({
63+
ReaderWriter copyWith({
4364
AssetPathProvider? assetPathProvider,
4465
FilesystemCache? cache,
45-
}) => FileBasedAssetReader(
46-
packageGraph,
66+
}) => ReaderWriter.using(
67+
rootPackage: rootPackage,
68+
assetFinder: assetFinder,
4769
assetPathProvider: assetPathProvider ?? this.assetPathProvider,
4870
filesystem: filesystem,
4971
cache: cache ?? this.cache,
72+
inputTracker: inputTracker,
5073
);
5174

52-
@override
53-
InputTracker? get inputTracker => null;
54-
5575
@override
5676
Future<bool> canRead(AssetId id) {
5777
return cache.exists(
@@ -96,44 +116,11 @@ class FileBasedAssetReader extends AssetReader implements AssetReaderState {
96116
@override
97117
Stream<AssetId> findAssets(Glob glob) => throw UnimplementedError();
98118

99-
Stream<AssetId> _findAssets(Glob glob, String? package) {
100-
var packageNode =
101-
package == null ? packageGraph.root : packageGraph[package];
102-
if (packageNode == null) {
103-
throw ArgumentError(
104-
"Could not find package '$package' which was listed as "
105-
'an input. Please ensure you have that package in your deps, or '
106-
'remove it from your input sets.',
107-
);
108-
}
109-
// TODO(davidmorgan): make this read via `filesystem`, currently it
110-
// reads directly via `dart:io`.
111-
return glob
112-
.list(followLinks: true, root: packageNode.path)
113-
.where((e) => e is File && !path.basename(e.path).startsWith('._'))
114-
.cast<File>()
115-
.map((file) => _fileToAssetId(file, packageNode));
116-
}
117-
118-
/// Creates an [AssetId] for [file], which is a part of [packageNode].
119-
AssetId _fileToAssetId(File file, PackageNode packageNode) {
120-
var filePath = path.normalize(file.absolute.path);
121-
var relativePath = path.relative(filePath, from: packageNode.path);
122-
return AssetId(packageNode.name, relativePath);
123-
}
124-
}
125-
126-
/// Basic [AssetWriter] which uses a [PackageGraph] to look up where to write
127-
/// files to disk.
128-
class FileBasedAssetWriter implements RunnerAssetWriter {
129-
final PackageGraph packageGraph;
130-
final Filesystem filesystem;
131-
132-
FileBasedAssetWriter(this.packageGraph) : filesystem = IoFilesystem();
119+
// [AssetWriter] methods.
133120

134121
@override
135122
Future<void> writeAsBytes(AssetId id, List<int> bytes) async {
136-
final path = packageGraph.pathFor(id);
123+
final path = assetPathProvider.pathFor(id);
137124
await filesystem.writeAsBytes(path, bytes);
138125
}
139126

@@ -143,19 +130,19 @@ class FileBasedAssetWriter implements RunnerAssetWriter {
143130
String contents, {
144131
Encoding encoding = utf8,
145132
}) async {
146-
final path = packageGraph.pathFor(id);
133+
final path = assetPathProvider.pathFor(id);
147134
await filesystem.writeAsString(path, contents, encoding: encoding);
148135
}
149136

150137
@override
151138
Future delete(AssetId id) async {
152-
if (id.package != packageGraph.root.name) {
139+
if (id.package != rootPackage) {
153140
throw InvalidOutputException(
154141
id,
155-
'Should not delete assets outside of ${packageGraph.root.name}',
142+
'Should not delete assets outside of $rootPackage',
156143
);
157144
}
158-
final path = packageGraph.pathFor(id);
145+
final path = assetPathProvider.pathFor(id);
159146
await filesystem.delete(path);
160147
}
161148

@@ -164,3 +151,38 @@ class FileBasedAssetWriter implements RunnerAssetWriter {
164151
// TODO(davidmorgan): add back write caching, "batching".
165152
}
166153
}
154+
155+
/// [AssetFinder] that uses [PackageGraph] to map packages to paths, then
156+
/// uses the `dart:io` filesystem to find files.
157+
///
158+
/// TODO(davidmorgan): read via `Filesystem` instead of `dart-io`.
159+
class PackageGraphAssetFinder implements AssetFinder {
160+
final PackageGraph packageGraph;
161+
162+
PackageGraphAssetFinder(this.packageGraph);
163+
164+
@override
165+
Stream<AssetId> find(Glob glob, {String? package}) {
166+
var packageNode =
167+
package == null ? packageGraph.root : packageGraph[package];
168+
if (packageNode == null) {
169+
throw ArgumentError(
170+
"Could not find package '$package' which was listed as "
171+
'an input. Please ensure you have that package in your deps, or '
172+
'remove it from your input sets.',
173+
);
174+
}
175+
return glob
176+
.list(followLinks: true, root: packageNode.path)
177+
.where((e) => e is File && !path.basename(e.path).startsWith('._'))
178+
.cast<File>()
179+
.map((file) => _fileToAssetId(file, packageNode));
180+
}
181+
182+
/// Creates an [AssetId] for [file], which is a part of [packageNode].
183+
static AssetId _fileToAssetId(File file, PackageNode packageNode) {
184+
var filePath = path.normalize(file.absolute.path);
185+
var relativePath = path.relative(filePath, from: packageNode.path);
186+
return AssetId(packageNode.name, relativePath);
187+
}
188+
}

build_runner_core/lib/src/environment/io_environment.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import 'dart:io';
88
import 'package:build/build.dart';
99
import 'package:logging/logging.dart';
1010

11-
import '../asset/file_based.dart';
11+
import '../asset/reader_writer.dart';
1212
import '../asset/writer.dart';
1313
import '../generate/build_directory.dart';
1414
import '../generate/build_result.dart';
@@ -22,7 +22,7 @@ final _logger = Logger('IOEnvironment');
2222
/// A [BuildEnvironment] writing to disk and stdout.
2323
class IOEnvironment implements BuildEnvironment {
2424
@override
25-
final AssetReader reader;
25+
final ReaderWriter reader;
2626

2727
@override
2828
final RunnerAssetWriter writer;
@@ -54,9 +54,11 @@ class IOEnvironment implements BuildEnvironment {
5454
);
5555
}
5656

57+
final readerWriter = ReaderWriter(packageGraph);
58+
5759
return IOEnvironment._(
58-
FileBasedAssetReader(packageGraph),
59-
FileBasedAssetWriter(packageGraph),
60+
readerWriter,
61+
readerWriter,
6062
assumeTty == true || _canPrompt(),
6163
outputSymlinksOnly,
6264
packageGraph,

build_runner_core/test/asset/batch_test.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@ void main() {
2121

2222
setUp(() async {
2323
packageGraph = await _createTestPackage();
24-
final fileReader = FileBasedAssetReader(packageGraph);
25-
final fileWriter = FileBasedAssetWriter(packageGraph);
24+
final readerWriter = ReaderWriter(packageGraph);
2625

27-
(reader, writer) = wrapInBatch(reader: fileReader, writer: fileWriter);
26+
(reader, writer) = wrapInBatch(reader: readerWriter, writer: readerWriter);
2827
});
2928

3029
test('delays writes until end', () async {

0 commit comments

Comments
 (0)