blob: 8100440c24efe975e963b137943c778cf88f1075 [file] [log] [blame]
// Copyright (c) 2019, 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.
/// An implementation of [Pipeline] that runs in-memory.
///
/// To define a step, implement [MemoryModularStep].
import 'pipeline.dart';
import 'suite.dart';
/// A hook to fetch data previously computed for a dependency.
typedef ModuleDataProvider = Object? Function(Module, DataId);
typedef SourceProvider = String? Function(Uri);
abstract class MemoryModularStep extends ModularStep {
Future<Map<DataId, Object>> execute(
Module module,
SourceProvider sourceProvider,
ModuleDataProvider dataProvider,
List<String> flags);
}
class MemoryPipeline extends Pipeline<MemoryModularStep> {
final Map<Uri, String> _sources;
/// Internal state to hold the current results as they are computed by the
/// pipeline. Expected to be null before and after the pipeline runs.
Map<Module, Map<DataId, Object>>? _results;
/// A copy of [_result] at the time the pipeline last finished running.
Map<Module, Map<DataId, Object>>? resultsForTesting;
final ConfigurationRegistry? _registry;
/// Cache of results when [cacheSharedModules] is true
final List<Map<Module, Map<DataId, Object>>> _resultCache;
MemoryPipeline(this._sources, List<MemoryModularStep> steps,
{bool cacheSharedModules = false})
: _registry = cacheSharedModules ? ConfigurationRegistry() : null,
_resultCache = cacheSharedModules ? [] : const [],
super(steps, cacheSharedModules);
@override
Future<void> run(ModularTest test) async {
var results = _results = {};
Map<Module, Map<DataId, Object>>? cache = null;
if (cacheSharedModules) {
int id = _registry!.computeConfigurationId(test);
if (id < _resultCache.length) {
cache = _resultCache[id];
} else {
assert(id == _resultCache.length);
_resultCache.add(cache = {});
}
results.addAll(cache);
}
await super.run(test);
resultsForTesting = results;
if (cacheSharedModules) {
for (var module in results.keys) {
if (module.isShared) {
cache![module] = results[module]!;
}
}
}
_results = null;
}
@override
Future<void> runStep(MemoryModularStep step, Module module,
Map<Module, Set<DataId>> visibleData, List<String> flags) async {
final results = _results!;
if (cacheSharedModules && module.isShared) {
bool allCachedResultsFound = true;
for (var dataId in step.resultData) {
if (results[module] == null || results[module]![dataId] == null) {
allCachedResultsFound = false;
break;
}
}
if (allCachedResultsFound) {
step.notifyCached(module);
return;
}
}
Map<Module, Map<DataId, Object>> inputData = {};
visibleData.forEach((module, dataIdSet) {
inputData[module] = {};
for (var dataId in dataIdSet) {
inputData[module]![dataId] = results[module]![dataId]!;
}
});
Map<Uri, String> inputSources = {};
if (step.needsSources) {
module.sources.forEach((relativeUri) {
var uri = module.rootUri.resolveUri(relativeUri);
inputSources[uri] = _sources[uri]!;
});
}
Map<DataId, Object> result = await step.execute(
module,
(Uri uri) => inputSources[uri],
(Module m, DataId id) => inputData[m]![id],
flags);
for (var dataId in step.resultData) {
(results[module] ??= {})[dataId] = result[dataId]!;
}
}
}