@@ -26,49 +26,103 @@ abstract class IOModularStep extends ModularStep {
2626}
2727
2828class IOPipeline extends Pipeline <IOModularStep > {
29- /// A folder per step. The key is the data id produced by a specific step .
29+ /// Folder that holds the results of each step during the run of the pipeline .
3030 ///
31- /// This contains internal state used during the run of the pipeline, but is
32- /// expected to be null before and after the pipeline is executed.
33- Map <DataId , Uri > _tmpFolders;
34- Map <DataId , Uri > get tmpFoldersForTesting => _tmpFolders;
35- bool saveFoldersForTesting;
31+ /// This value is usually null before and after the pipeline runs, but will be
32+ /// non-null in two cases:
33+ ///
34+ /// * for testing purposes when using [saveIntermediateResultsForTesting] .
35+ ///
36+ /// * to share results across pipeline runs when using [cacheSharedModules] .
37+ ///
38+ /// When using [cacheSharedModules] the pipeline will only reuse data for
39+ /// modules that are known to be shared (e.g. shared packages and sdk
40+ /// libraries), and not modules that are test specific. File names will be
41+ /// specific enough so that we can keep separate the artifacts created from
42+ /// running tools under different configurations (with different flags).
43+ Uri _resultsFolderUri;
44+ Uri get resultFolderUriForTesting => _resultsFolderUri;
45+
46+ /// A unique number to denote the current modular test configuration.
47+ ///
48+ /// When using [cacheSharedModules] , a test can resuse the output of a
49+ /// previous run of this pipeline if that output was generated with the same
50+ /// configuration.
51+ int _currentConfiguration;
52+
53+ final ConfigurationRegistry _registry;
3654
37- IOPipeline (List <IOModularStep > steps, {this .saveFoldersForTesting: false })
38- : super (steps);
55+ /// Whether to keep alive the temporary folder used to store intermediate
56+ /// results in order to inspect it later in test.
57+ final bool saveIntermediateResultsForTesting;
58+
59+ IOPipeline (List <IOModularStep > steps,
60+ {this .saveIntermediateResultsForTesting: false ,
61+ bool cacheSharedModules: false })
62+ : _registry = cacheSharedModules ? new ConfigurationRegistry () : null ,
63+ super (steps, cacheSharedModules);
3964
4065 @override
4166 Future <void > run (ModularTest test) async {
42- assert (_tmpFolders == null );
43- _tmpFolders = {};
67+ var resultsDir = null ;
68+ if (_resultsFolderUri == null ) {
69+ resultsDir = await Directory .systemTemp.createTemp ('modular_test_res-' );
70+ _resultsFolderUri = resultsDir.uri;
71+ }
72+ if (cacheSharedModules) {
73+ _currentConfiguration = _registry.computeConfigurationId (test);
74+ }
4475 await super .run (test);
45- if (! saveFoldersForTesting) {
46- for (var folder in _tmpFolders.values) {
47- await Directory .fromUri (folder).delete (recursive: true );
48- }
49- _tmpFolders = null ;
76+ if (resultsDir != null &&
77+ ! saveIntermediateResultsForTesting &&
78+ ! cacheSharedModules) {
79+ await resultsDir.delete (recursive: true );
80+ _resultsFolderUri = null ;
81+ }
82+ if (! saveIntermediateResultsForTesting) {
83+ _currentConfiguration = null ;
84+ }
85+ }
86+
87+ /// Delete folders that were kept around either because of
88+ /// [saveIntermediateResultsForTesting] or because of [cacheSharedModules] .
89+ Future <void > cleanup () async {
90+ if (saveIntermediateResultsForTesting || cacheSharedModules) {
91+ await Directory .fromUri (_resultsFolderUri).delete (recursive: true );
5092 }
5193 }
5294
5395 @override
5496 Future <void > runStep (IOModularStep step, Module module,
5597 Map <Module , Set <DataId >> visibleData) async {
56- // Since data ids are unique throughout the pipeline, we use the first
57- // result data id as a hint for the name of the temporary folder of a step.
58- var stepFolder;
59- for (var dataId in step.resultData) {
60- stepFolder ?? =
61- await Directory .systemTemp.createTemp ('modular_test_${dataId }-' );
62- _tmpFolders[dataId] ?? =
63- (await Directory .systemTemp.createTemp ('modular_test_${dataId }_res-' ))
64- .uri;
98+ if (cacheSharedModules && module.isShared) {
99+ // If all expected outputs are already available, skip the step.
100+ bool allCachedResultsFound = true ;
101+ for (var dataId in step.resultData) {
102+ var cachedFile = File .fromUri (_resultsFolderUri
103+ .resolve (_toFileName (module, dataId, configSpecific: true )));
104+ if (! await cachedFile.exists ()) {
105+ allCachedResultsFound = false ;
106+ break ;
107+ }
108+ }
109+ if (allCachedResultsFound) {
110+ step.notifyCached (module);
111+ return ;
112+ }
65113 }
114+
115+ // Each step is executed in a separate folder. To make it easier to debug
116+ // issues, we include one of the step data ids in the name of the folder.
117+ var stepId = step.resultData.first;
118+ var stepFolder =
119+ await Directory .systemTemp.createTemp ('modular_test_${stepId }-' );
66120 for (var module in visibleData.keys) {
67121 for (var dataId in visibleData[module]) {
68- var filename = "${ module . name }.${ dataId . name }" ;
69- var assetUri = _tmpFolders[dataId] .resolve (filename );
70- await File .fromUri (assetUri)
71- . copy ( stepFolder.uri.resolve (filename ).toFilePath ());
122+ var assetUri = _resultsFolderUri
123+ .resolve (_toFileName (module, dataId, configSpecific : true ) );
124+ await File .fromUri (assetUri). copy (
125+ stepFolder.uri.resolve (_toFileName (module, dataId) ).toFilePath ());
72126 }
73127 }
74128 if (step.needsSources) {
@@ -81,19 +135,31 @@ class IOPipeline extends Pipeline<IOModularStep> {
81135 }
82136
83137 await step.execute (module, stepFolder.uri,
84- (Module m, DataId id) => Uri .parse ("${ m . name }.${ id . name }" ));
138+ (Module m, DataId id) => Uri .parse (_toFileName (m, id) ));
85139
86140 for (var dataId in step.resultData) {
87141 var outputFile =
88- File .fromUri (stepFolder.uri.resolve ("${ module . name }.${ dataId . name }" ));
142+ File .fromUri (stepFolder.uri.resolve (_toFileName ( module, dataId) ));
89143 if (! await outputFile.exists ()) {
90144 throw StateError (
91145 "Step '${step .runtimeType }' didn't produce an output file" );
92146 }
93- await outputFile.copy (_tmpFolders[dataId]
94- .resolve ("${ module . name }.${ dataId . name }" )
147+ await outputFile.copy (_resultsFolderUri
148+ .resolve (_toFileName ( module, dataId, configSpecific : true ) )
95149 .toFilePath ());
96150 }
97151 await stepFolder.delete (recursive: true );
98152 }
153+
154+ String _toFileName (Module module, DataId dataId,
155+ {bool configSpecific: false }) {
156+ var prefix =
157+ cacheSharedModules && configSpecific && _currentConfiguration != null
158+ ? _currentConfiguration
159+ : '' ;
160+ return "$prefix ${module .name }.${dataId .name }" ;
161+ }
162+
163+ String configSpecificResultFileNameForTesting (Module module, DataId dataId) =>
164+ _toFileName (module, dataId, configSpecific: true );
99165}
0 commit comments