diff --git a/build_resolvers/test/resolver_test.dart b/build_resolvers/test/resolver_test.dart index a913e2334..7e63e4bd6 100644 --- a/build_resolvers/test/resolver_test.dart +++ b/build_resolvers/test/resolver_test.dart @@ -361,6 +361,8 @@ void runTests(ResolversFactory resolversFactory) { test('defaults to the current isolate package config', () async { await resolveSources({ 'a|web/main.dart': 'main() {}', + }, nonInputsToReadFromFilesystem: { + AssetId('build_resolvers', 'lib/build_resolvers.dart') }, (resolver) async { var buildResolversId = AssetId('build_resolvers', 'lib/build_resolvers.dart'); diff --git a/build_test/CHANGELOG.md b/build_test/CHANGELOG.md index 3a33f57f3..44143ebfb 100644 --- a/build_test/CHANGELOG.md +++ b/build_test/CHANGELOG.md @@ -6,6 +6,11 @@ - Breaking change: `testBuilder` no longer accepts a `reader` and a `writer`. Instead it returns a `TestBuilderResult` with the `InMemoryAssetReaderWriter` that was used. +- Breaking change: `resolveSources` no longer automatically reads non-input + files from the filesystem; specify explicitly which non-input files the + test should read in `nonInputsToReadFromFilesystem`. +- Breaking change: remove `MultiAssetReader`. Load the source into one + in-memory reader instead of providing multiple readers. - Support checks on reader state after a build action in `resolveSources`. - Start using `package:build/src/internal.dart`. diff --git a/build_test/lib/build_test.dart b/build_test/lib/build_test.dart index d0662db1a..08cb89c10 100644 --- a/build_test/lib/build_test.dart +++ b/build_test/lib/build_test.dart @@ -11,7 +11,6 @@ export 'src/globbing_builder.dart'; export 'src/in_memory_reader.dart'; export 'src/in_memory_writer.dart'; export 'src/matchers.dart'; -export 'src/multi_asset_reader.dart' show MultiAssetReader; export 'src/package_reader.dart' show PackageAssetReader; export 'src/record_logs.dart'; export 'src/resolve_source.dart' diff --git a/build_test/lib/src/multi_asset_reader.dart b/build_test/lib/src/multi_asset_reader.dart deleted file mode 100644 index 5338588c4..000000000 --- a/build_test/lib/src/multi_asset_reader.dart +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2017, 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:async/async.dart'; -import 'package:build/build.dart'; -// ignore: implementation_imports -import 'package:build/src/internal.dart'; -import 'package:glob/glob.dart'; - -/// A [MultiPackageAssetReader] that delegates to multiple other asset -/// readers. -/// -/// [MultiAssetReader] attempts to check every provided -/// [MultiPackageAssetReader] to see if they are capable of reading an -/// [AssetId], otherwise checks the next reader. -class MultiAssetReader extends AssetReader - implements MultiPackageAssetReader, AssetReaderState { - final List _readers; - - MultiAssetReader(this._readers); - - @override - InputTracker? get inputTracker { - // There should be exactly zero or one input trackers between the readers. - final results = Set.identity() - ..addAll(_readers.map((r) => r.inputTracker).nonNulls); - if (results.isEmpty) return null; - if (results.length == 1) return results.single; - throw StateError( - 'MultiAssetReader readers have more than one InputTracker: ' - '$_readers -> $results'); - } - - @override - Future canRead(AssetId id) async { - for (var reader in _readers) { - if (await reader.canRead(id)) { - return true; - } - } - return false; - } - - @override - Future> readAsBytes(AssetId id) async => - (await _readerWith(id)).readAsBytes(id); - - @override - Future readAsString(AssetId id, {Encoding encoding = utf8}) async => - (await _readerWith(id)).readAsString(id, encoding: encoding); - - /// Returns all readable assets matching [glob] under [package]. - /// - /// **NOTE**: This is a combined view of all provided readers. As such it is - /// possible that an [AssetId] will be iterated over more than once, unlike - /// other implementations of [AssetReader]. - @override - Stream findAssets(Glob glob, {String? package}) => StreamGroup.merge( - _readers.map((reader) => reader.findAssets(glob, package: package))); - - /// Returns the first [AssetReader] that contains [id]. - /// - /// Otherwise throws [AssetNotFoundException]. - Future _readerWith(AssetId id) async { - for (var reader in _readers) { - if (await reader.canRead(id)) { - return reader; - } - } - throw AssetNotFoundException(id); - } -} diff --git a/build_test/lib/src/resolve_source.dart b/build_test/lib/src/resolve_source.dart index 1e1bded09..23a65952b 100644 --- a/build_test/lib/src/resolve_source.dart +++ b/build_test/lib/src/resolve_source.dart @@ -11,7 +11,6 @@ import 'package:build_resolvers/build_resolvers.dart'; import 'package:package_config/package_config.dart'; import 'in_memory_reader.dart'; -import 'multi_asset_reader.dart'; import 'package_reader.dart'; /// Marker constant that may be used in combination with [resolveSources]. @@ -27,6 +26,7 @@ Future resolveSource( FutureOr Function(Resolver resolver) action, { AssetId? inputId, PackageConfig? packageConfig, + Set? nonInputsToReadFromFilesystem, Future? tearDown, Resolvers? resolvers, }) { @@ -38,6 +38,7 @@ Future resolveSource( inputId.package, action, packageConfig: packageConfig, + nonInputsToReadFromFilesystem: nonInputsToReadFromFilesystem, resolverFor: inputId, tearDown: tearDown, resolvers: resolvers, @@ -120,6 +121,7 @@ Future resolveSources( Map inputs, FutureOr Function(Resolver resolver) action, { PackageConfig? packageConfig, + Set? nonInputsToReadFromFilesystem, String? resolverFor, String? rootPackage, FutureOr Function(InMemoryAssetReader)? assetReaderChecks, @@ -134,6 +136,7 @@ Future resolveSources( rootPackage ?? AssetId.parse(inputs.keys.first).package, action, packageConfig: packageConfig, + nonInputsToReadFromFilesystem: nonInputsToReadFromFilesystem, resolverFor: AssetId.parse(resolverFor ?? inputs.keys.first), assetReaderChecks: assetReaderChecks, tearDown: tearDown, @@ -146,6 +149,7 @@ Future resolveAsset( AssetId inputId, FutureOr Function(Resolver resolver) action, { PackageConfig? packageConfig, + Set? nonInputsToReadFromFilesystem, Future? tearDown, Resolvers? resolvers, }) { @@ -156,6 +160,7 @@ Future resolveAsset( inputId.package, action, packageConfig: packageConfig, + nonInputsToReadFromFilesystem: nonInputsToReadFromFilesystem, resolverFor: inputId, tearDown: tearDown, resolvers: resolvers, @@ -172,6 +177,7 @@ Future _resolveAssets( String rootPackage, FutureOr Function(Resolver resolver) action, { PackageConfig? packageConfig, + Set? nonInputsToReadFromFilesystem, AssetId? resolverFor, FutureOr Function(InMemoryAssetReader)? assetReaderChecks, Future? tearDown, @@ -179,12 +185,17 @@ Future _resolveAssets( }) async { final resolvedConfig = packageConfig ?? await loadPackageConfigUri((await Isolate.packageConfig)!); - final assetReader = PackageAssetReader(resolvedConfig, rootPackage); final resolveBuilder = _ResolveSourceBuilder( action, resolverFor, tearDown, ); + + // Prepare the in-memory filesystem the build will run on. + // + // First, add directly-passed [inputs], reading from the filesystem if the + // string passed is [useAssetReader]. + final assetReader = PackageAssetReader(resolvedConfig, rootPackage); final inputAssets = {}; await Future.wait(inputs.keys.map((String rawAssetId) async { final assetId = AssetId.parse(rawAssetId); @@ -194,11 +205,19 @@ Future _resolveAssets( } inputAssets[assetId] = assetValue; })); - final inMemory = InMemoryAssetReaderWriter( + final readerWriter = InMemoryAssetReaderWriter( sourceAssets: inputAssets, rootPackage: rootPackage, ); + // Then, copy any additionally requested files from the filesystem to the + // in-memory filesystem. + if (nonInputsToReadFromFilesystem != null) { + for (final id in nonInputsToReadFromFilesystem) { + await readerWriter.writeAsBytes(id, await assetReader.readAsBytes(id)); + } + } + // Use the default resolver if no experiments are enabled. This is much // faster. resolvers ??= packageConfig == null && enabledExperiments.isEmpty @@ -216,13 +235,13 @@ Future _resolveAssets( unawaited(runBuilder( resolveBuilder, inputAssets.keys, - MultiAssetReader([inMemory, assetReader]), - inMemory, + readerWriter, + readerWriter, resolvers, ).catchError((_) {})); final result = await resolveBuilder.onDone.future; if (assetReaderChecks != null) { - await assetReaderChecks(inMemory); + await assetReaderChecks(readerWriter); } return result; } diff --git a/build_test/test/multi_asset_reader_test.dart b/build_test/test/multi_asset_reader_test.dart deleted file mode 100644 index d9b45fec6..000000000 --- a/build_test/test/multi_asset_reader_test.dart +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2017, 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/build.dart'; -import 'package:build_test/build_test.dart'; -import 'package:glob/glob.dart'; -import 'package:test/test.dart'; - -final isAssetNotFound = const TypeMatcher(); -final throwsAssetNotFound = throwsA(isAssetNotFound); - -void main() { - group('$MultiAssetReader', () { - MultiAssetReader assetReader; - - test('should throw an $AssetNotFoundException with no readers', () { - var missingId = AssetId('some_pkg', 'some_pkg.dart'); - assetReader = MultiAssetReader([]); - expect( - assetReader.readAsString(missingId), - throwsAssetNotFound, - ); - }); - - test('should read an asset from an underyling reader', () async { - var idA = AssetId('some_pkg', 'a.dart'); - var idB = AssetId('some_pkg', 'b.dart'); - var idC = AssetId('some_pkg', 'missing.dart'); - assetReader = MultiAssetReader([ - InMemoryAssetReader(sourceAssets: { - idA: 'A', - }), - InMemoryAssetReader(sourceAssets: { - idB: 'B', - }), - ]); - expect(await assetReader.readAsString(idA), 'A'); - expect(await assetReader.readAsString(idB), 'B'); - expect(assetReader.readAsString(idC), throwsAssetNotFound); - }); - - test('should combine files when using `findAssets`', () async { - var idA = AssetId('some_pkg', 'lib/a.dart'); - var idB = AssetId('some_pkg', 'lib/b.dart'); - assetReader = MultiAssetReader([ - InMemoryAssetReader( - sourceAssets: { - idA: 'A', - }, - rootPackage: 'some_pkg', - ), - InMemoryAssetReader( - sourceAssets: { - idB: 'B', - }, - rootPackage: 'some_pkg', - ), - ]); - expect(await assetReader.findAssets(Glob('lib/*.dart')).toList(), - [idA, idB]); - }); - - test('should support the `package` arg in `findAssets`', () async { - var idA = AssetId('a', 'lib/a.dart'); - var idB = AssetId('b', 'lib/b.dart'); - assetReader = MultiAssetReader([ - InMemoryAssetReader( - sourceAssets: { - idA: 'A', - }, - ), - InMemoryAssetReader( - sourceAssets: { - idB: 'B', - }, - ), - ]); - expect( - await assetReader - .findAssets(Glob('lib/*.dart'), package: 'a') - .toList(), - [idA]); - expect( - await assetReader - .findAssets(Glob('lib/*.dart'), package: 'b') - .toList(), - [idB]); - }); - - test('propagates errors from wrapped readers', () { - var idA = AssetId('a', 'lib/a.dart'); - assetReader = MultiAssetReader([ - InMemoryAssetReader( - sourceAssets: { - idA: 'A', - }, - ), - ]); - expect(() => assetReader.findAssets(Glob('lib/*.dart')), - throwsUnsupportedError); - }); - }); -} diff --git a/build_test/test/resolve_source_test.dart b/build_test/test/resolve_source_test.dart index 6aa70b782..c737b3faa 100644 --- a/build_test/test/resolve_source_test.dart +++ b/build_test/test/resolve_source_test.dart @@ -45,7 +45,10 @@ void main() { import 'package:collection/collection.dart'; abstract class Foo implements Equality {} - ''', (resolver) => resolver.findLibraryNotNull('example')); + ''', nonInputsToReadFromFilesystem: { + AssetId('collection', 'lib/collection.dart'), + AssetId('collection', 'lib/src/equality.dart'), + }, (resolver) => resolver.findLibraryNotNull('example')); var classFoo = libExample.getClass('Foo')!; expect( classFoo.allSupertypes.map(_toStringId), @@ -85,7 +88,10 @@ void main() { import 'package:collection/collection.dart'; abstract class Foo implements Equality {} - ''', (resolver) => resolver, tearDown: resolverDone.future); + ''', nonInputsToReadFromFilesystem: { + AssetId('collection', 'lib/collection.dart'), + AssetId('collection', 'lib/src/equality.dart'), + }, (resolver) => resolver, tearDown: resolverDone.future); expect( await resolver.libraries.any((library) => library.name == 'example'), true); @@ -105,7 +111,10 @@ void main() { import 'package:collection/collection.dart'; abstract class Foo implements Equality {} - ''', (resolver) async { + ''', nonInputsToReadFromFilesystem: { + AssetId('collection', 'lib/collection.dart'), + AssetId('collection', 'lib/src/equality.dart'), + }, (resolver) async { var libExample = await resolver.findLibraryNotNull('example'); var classFoo = libExample.getClass('Foo')!; expect(classFoo.allSupertypes.map(_toStringId),