diff --git a/packages/flutter_tools/lib/src/build_system/build_system.dart b/packages/flutter_tools/lib/src/build_system/build_system.dart index 19de36b31c5..3c303c6dcfb 100644 --- a/packages/flutter_tools/lib/src/build_system/build_system.dart +++ b/packages/flutter_tools/lib/src/build_system/build_system.dart @@ -526,17 +526,20 @@ class _BuildInstance { await node.target.build(environment); printTrace('${node.target.name}: Complete'); - // If we were missing the depfile, resolve files after executing the + node.inputs + ..clear() + ..addAll(node.target.resolveInputs(environment).sources); + node.outputs + ..clear() + ..addAll(node.target.resolveOutputs(environment).sources); + + // If we were missing the depfile, resolve input files after executing the // target so that all file hashes are up to date on the next run. if (node.missingDepfile) { - node.inputs.clear(); - node.outputs.clear(); - node.inputs.addAll(node.target.resolveInputs(environment).sources); - node.outputs.addAll(node.target.resolveOutputs(environment).sources); await fileCache.hashFiles(node.inputs); } - // Update hashes for output files. + // Always update hashes for output files. await fileCache.hashFiles(node.outputs); node.target._writeStamp(node.inputs, node.outputs, environment); updateGraph(); diff --git a/packages/flutter_tools/lib/src/build_system/depfile.dart b/packages/flutter_tools/lib/src/build_system/depfile.dart index a9db0e69bba..d66a87010ef 100644 --- a/packages/flutter_tools/lib/src/build_system/depfile.dart +++ b/packages/flutter_tools/lib/src/build_system/depfile.dart @@ -56,9 +56,13 @@ class Depfile { /// Given an [depfile] File, write the depfile contents. /// - /// If either [inputs] or [outputs] is empty, does not write to the file. + /// If either [inputs] or [outputs] is empty, ensures the file does not + /// exist. void writeToFile(File depfile) { if (inputs.isEmpty || outputs.isEmpty) { + if (depfile.existsSync()) { + depfile.deleteSync(); + } return; } final StringBuffer buffer = StringBuffer(); diff --git a/packages/flutter_tools/lib/src/build_system/source.dart b/packages/flutter_tools/lib/src/build_system/source.dart index 16a860ab966..3dbb92605c6 100644 --- a/packages/flutter_tools/lib/src/build_system/source.dart +++ b/packages/flutter_tools/lib/src/build_system/source.dart @@ -163,15 +163,6 @@ class SourceVisitor implements ResolvedFiles { } } - /// Visit a [Source] which contains a [SourceBehavior]. - void visitBehavior(SourceBehavior sourceBehavior) { - if (inputs) { - sources.addAll(sourceBehavior.inputs(environment)); - } else { - sources.addAll(sourceBehavior.outputs(environment)); - } - } - /// Visit a [Source] which is defined by an [Artifact] from the flutter cache. /// /// If the [Artifact] points to a directory then all child files are included. @@ -194,10 +185,6 @@ abstract class Source { /// This source is a file-uri which contains some references to magic /// environment variables. const factory Source.pattern(String pattern, { bool optional }) = _PatternSource; - - /// This source is produced by the [SourceBehavior] class. - const factory Source.behavior(SourceBehavior behavior) = _SourceBehavior; - /// The source is provided by an [Artifact]. /// /// If [artifact] points to a directory then all child files are included. @@ -222,34 +209,10 @@ abstract class Source { /// evaluated before the build. /// /// For example, [Source.pattern] and [Source.version] are not implicit - /// provided they do not use any wildcards. [Source.behavior] and - /// [Source.function] are always implicit. + /// provided they do not use any wildcards. bool get implicit; } -/// An interface for describing input and output copies together. -abstract class SourceBehavior { - const SourceBehavior(); - - /// The inputs for a particular target. - List inputs(Environment environment); - - /// The outputs for a particular target. - List outputs(Environment environment); -} - -class _SourceBehavior implements Source { - const _SourceBehavior(this.value); - - final SourceBehavior value; - - @override - void accept(SourceVisitor visitor) => visitor.visitBehavior(value); - - @override - bool get implicit => true; -} - class _PatternSource implements Source { const _PatternSource(this.value, { this.optional = false }); diff --git a/packages/flutter_tools/lib/src/build_system/targets/assets.dart b/packages/flutter_tools/lib/src/build_system/targets/assets.dart index f7832372f40..43b35292573 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/assets.dart @@ -10,81 +10,45 @@ import '../../devfs.dart'; import '../../plugins.dart'; import '../../project.dart'; import '../build_system.dart'; +import '../depfile.dart'; -/// The copying logic for flutter assets. -class AssetBehavior extends SourceBehavior { - const AssetBehavior(); - - @override - List inputs(Environment environment) { - final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); - assetBundle.build( - manifestPath: environment.projectDir.childFile('pubspec.yaml').path, - packagesPath: environment.projectDir.childFile('.packages').path, - ); - // Filter the file type to remove the files that are generated by this - // command as inputs. - final List results = []; - final Iterable files = assetBundle.entries.values.whereType(); - for (DevFSFileContent devFsContent in files) { - results.add(fs.file(devFsContent.file.path)); - } - return results; - } - - @override - List outputs(Environment environment) { - final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); - assetBundle.build( - manifestPath: environment.projectDir.childFile('pubspec.yaml').path, - packagesPath: environment.projectDir.childFile('.packages').path, - ); - final List results = []; - for (String key in assetBundle.entries.keys) { - final File file = fs.file(fs.path.join(environment.buildDir.path, 'flutter_assets', key)); - results.add(file); - } - return results; - } -} - -/// A specific asset behavior for building bundles. -class AssetOutputBehavior extends SourceBehavior { - const AssetOutputBehavior([this._pathSuffix = '']); - - final String _pathSuffix; - - @override - List inputs(Environment environment) { - final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); - assetBundle.build( - manifestPath: environment.projectDir.childFile('pubspec.yaml').path, - packagesPath: environment.projectDir.childFile('.packages').path, - ); - // Filter the file type to remove the files that are generated by this - // command as inputs. - final List results = []; - final Iterable files = assetBundle.entries.values.whereType(); - for (DevFSFileContent devFsContent in files) { - results.add(fs.file(fs.path.join(_pathSuffix, devFsContent.file.path))); - } - return results; - } - - @override - List outputs(Environment environment) { - final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); - assetBundle.build( - manifestPath: environment.projectDir.childFile('pubspec.yaml').path, - packagesPath: environment.projectDir.childFile('.packages').path, - ); - final List results = []; - for (String key in assetBundle.entries.keys) { - final File file = fs.file(fs.path.join(environment.outputDir.path, _pathSuffix, key)); - results.add(file); - } - return results; - } +/// A helper function to copy an asset bundle into an [environment]'s output +/// directory. +/// +/// Returns a [Depfile] containing all assets used in the build. +Future copyAssets(Environment environment, Directory outputDirectory) async { + final File pubspecFile = environment.projectDir.childFile('pubspec.yaml'); + final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); + await assetBundle.build( + manifestPath: pubspecFile.path, + packagesPath: environment.projectDir.childFile('.packages').path, + ); + final Pool pool = Pool(kMaxOpenFiles); + final List inputs = [ + // An asset manifest with no assets would have zero inputs if not + // for this pubspec file. + pubspecFile, + ]; + final List outputs = []; + await Future.wait( + assetBundle.entries.entries.map>((MapEntry entry) async { + final PoolResource resource = await pool.request(); + try { + final File file = fs.file(fs.path.join(outputDirectory.path, entry.key)); + outputs.add(file); + file.parent.createSync(recursive: true); + final DevFSContent content = entry.value; + if (content is DevFSFileContent && content.file is File) { + inputs.add(fs.file(content.file.path)); + await (content.file as File).copy(file.path); + } else { + await file.writeAsBytes(await entry.value.contentsAsBytes()); + } + } finally { + resource.release(); + } + })); + return Depfile(inputs, outputs); } /// Copy the assets defined in the flutter manifest into a build directory. @@ -100,16 +64,12 @@ class CopyAssets extends Target { @override List get inputs => const [ Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/assets.dart'), - Source.pattern('{PROJECT_DIR}/pubspec.yaml'), - Source.behavior(AssetBehavior()), + Source.depfile('flutter_assets.d'), ]; @override List get outputs => const [ - Source.pattern('{BUILD_DIR}/flutter_assets/AssetManifest.json'), - Source.pattern('{BUILD_DIR}/flutter_assets/FontManifest.json'), - Source.pattern('{BUILD_DIR}/flutter_assets/LICENSE'), - Source.behavior(AssetBehavior()), // <- everything in this subdirectory. + Source.depfile('flutter_assets.d'), ]; @override @@ -117,28 +77,9 @@ class CopyAssets extends Target { final Directory output = environment .buildDir .childDirectory('flutter_assets'); - if (output.existsSync()) { - output.deleteSync(recursive: true); - } output.createSync(recursive: true); - final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); - await assetBundle.build( - manifestPath: environment.projectDir.childFile('pubspec.yaml').path, - packagesPath: environment.projectDir.childFile('.packages').path, - ); - // Limit number of open files to avoid running out of file descriptors. - final Pool pool = Pool(kMaxOpenFiles); - await Future.wait( - assetBundle.entries.entries.map>((MapEntry entry) async { - final PoolResource resource = await pool.request(); - try { - final File file = fs.file(fs.path.join(output.path, entry.key)); - file.parent.createSync(recursive: true); - await file.writeAsBytes(await entry.value.contentsAsBytes()); - } finally { - resource.release(); - } - })); + final Depfile depfile = await copyAssets(environment, output); + depfile.writeToFile(environment.buildDir.childFile('flutter_assets.d')); } } diff --git a/packages/flutter_tools/lib/src/build_system/targets/dart.dart b/packages/flutter_tools/lib/src/build_system/targets/dart.dart index 2bff7d1e36e..d3f482b2dd6 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/dart.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/dart.dart @@ -2,18 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:pool/pool.dart'; - import '../../artifacts.dart'; -import '../../asset.dart'; import '../../base/build.dart'; import '../../base/file_system.dart'; import '../../build_info.dart'; import '../../compile.dart'; -import '../../devfs.dart'; import '../../globals.dart'; import '../../project.dart'; import '../build_system.dart'; +import '../depfile.dart'; import '../exceptions.dart'; import 'assets.dart'; @@ -53,7 +50,7 @@ class CopyFlutterBundle extends Target { Source.artifact(Artifact.vmSnapshotData, mode: BuildMode.debug), Source.artifact(Artifact.isolateSnapshotData, mode: BuildMode.debug), Source.pattern('{BUILD_DIR}/app.dill'), - Source.behavior(AssetOutputBehavior()), + Source.depfile('flutter_assets.d'), ]; @override @@ -61,10 +58,7 @@ class CopyFlutterBundle extends Target { Source.pattern('{OUTPUT_DIR}/vm_snapshot_data'), Source.pattern('{OUTPUT_DIR}/isolate_snapshot_data'), Source.pattern('{OUTPUT_DIR}/kernel_blob.bin'), - Source.pattern('{OUTPUT_DIR}/AssetManifest.json'), - Source.pattern('{OUTPUT_DIR}/FontManifest.json'), - Source.pattern('{OUTPUT_DIR}/LICENSE'), - Source.behavior(AssetOutputBehavior()), + Source.depfile('flutter_assets.d'), ]; @override @@ -73,12 +67,6 @@ class CopyFlutterBundle extends Target { throw MissingDefineException(kBuildMode, 'copy_flutter_bundle'); } final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); - - // We're not smart enough to only remove assets that are removed. If - // anything changes blow away the whole directory. - if (environment.outputDir.existsSync()) { - environment.outputDir.deleteSync(recursive: true); - } environment.outputDir.createSync(recursive: true); // Only copy the prebuilt runtimes and kernel blob in debug mode. @@ -92,10 +80,8 @@ class CopyFlutterBundle extends Target { fs.file(isolateSnapshotData) .copySync(environment.outputDir.childFile('isolate_snapshot_data').path); } - - final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); - await assetBundle.build(); - await copyAssets(assetBundle, environment); + final Depfile assetDepfile = await copyAssets(environment, environment.outputDir); + assetDepfile.writeToFile(environment.buildDir.childFile('flutter_assets.d')); } @override @@ -104,28 +90,6 @@ class CopyFlutterBundle extends Target { ]; } -/// A helper function to copy an [assetBundle] into an [environment]'s output directory, -/// plus an optional [pathSuffix] -Future copyAssets(AssetBundle assetBundle, Environment environment, [String pathSuffix = '']) async { - final Pool pool = Pool(kMaxOpenFiles); - await Future.wait( - assetBundle.entries.entries.map>((MapEntry entry) async { - final PoolResource resource = await pool.request(); - try { - final File file = fs.file(fs.path.join(environment.outputDir.path, pathSuffix, entry.key)); - file.parent.createSync(recursive: true); - final DevFSContent content = entry.value; - if (content is DevFSFileContent && content.file is File) { - await (content.file as File).copy(file.path); - } else { - await file.writeAsBytes(await entry.value.contentsAsBytes()); - } - } finally { - resource.release(); - } - })); -} - /// Copies the prebuilt flutter bundle for release mode. class ReleaseCopyFlutterBundle extends CopyFlutterBundle { const ReleaseCopyFlutterBundle(); @@ -135,15 +99,12 @@ class ReleaseCopyFlutterBundle extends CopyFlutterBundle { @override List get inputs => const [ - Source.behavior(AssetOutputBehavior()), + Source.depfile('flutter_assets.d'), ]; @override List get outputs => const [ - Source.pattern('{OUTPUT_DIR}/AssetManifest.json'), - Source.pattern('{OUTPUT_DIR}/FontManifest.json'), - Source.pattern('{OUTPUT_DIR}/LICENSE'), - Source.behavior(AssetOutputBehavior()), + Source.depfile('flutter_assets.d'), ]; @override diff --git a/packages/flutter_tools/lib/src/build_system/targets/linux.dart b/packages/flutter_tools/lib/src/build_system/targets/linux.dart index ab9abc9d395..28be773537e 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/linux.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/linux.dart @@ -2,13 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:pool/pool.dart'; - import '../../artifacts.dart'; -import '../../asset.dart'; import '../../base/file_system.dart'; import '../../build_info.dart'; -import '../../devfs.dart'; import '../../globals.dart'; import '../build_system.dart'; import '../depfile.dart'; @@ -120,16 +116,14 @@ class DebugBundleLinuxAssets extends Target { List get inputs => const [ Source.pattern('{BUILD_DIR}/app.dill'), Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/linux.dart'), - Source.behavior(AssetOutputBehavior('flutter_assets')), + Source.depfile('flutter_assets.d'), + Source.pattern('{PROJECT_DIR}/pubspec.yaml'), ]; @override List get outputs => const [ - Source.behavior(AssetOutputBehavior('flutter_assets')), + Source.depfile('flutter_assets.d'), Source.pattern('{OUTPUT_DIR}/flutter_assets/kernel_blob.bin'), - Source.pattern('{OUTPUT_DIR}/flutter_assets/AssetManifest.json'), - Source.pattern('{OUTPUT_DIR}/flutter_assets/FontManifest.json'), - Source.pattern('{OUTPUT_DIR}/flutter_assets/LICENSE'), ]; @override @@ -149,25 +143,7 @@ class DebugBundleLinuxAssets extends Target { environment.buildDir.childFile('app.dill') .copySync(outputDirectory.childFile('kernel_blob.bin').path); } - - final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); - await assetBundle.build(); - final Pool pool = Pool(kMaxOpenFiles); - await Future.wait( - assetBundle.entries.entries.map>((MapEntry entry) async { - final PoolResource resource = await pool.request(); - try { - final File file = fs.file(fs.path.join(outputDirectory.path, entry.key)); - file.parent.createSync(recursive: true); - final DevFSContent content = entry.value; - if (content is DevFSFileContent && content.file is File) { - await (content.file as File).copy(file.path); - } else { - await file.writeAsBytes(await entry.value.contentsAsBytes()); - } - } finally { - resource.release(); - } - })); + final Depfile depfile = await copyAssets(environment, outputDirectory); + depfile.writeToFile(environment.buildDir.childFile('flutter_assets.d')); } } diff --git a/packages/flutter_tools/lib/src/build_system/targets/macos.dart b/packages/flutter_tools/lib/src/build_system/targets/macos.dart index a448b5b6365..ca0f2cf02e0 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/macos.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/macos.dart @@ -2,65 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:pool/pool.dart'; - import '../../artifacts.dart'; -import '../../asset.dart'; import '../../base/build.dart'; import '../../base/file_system.dart'; import '../../base/io.dart'; import '../../base/process.dart'; import '../../base/process_manager.dart'; import '../../build_info.dart'; -import '../../devfs.dart'; import '../../globals.dart'; import '../../macos/xcode.dart'; import '../build_system.dart'; +import '../depfile.dart'; import '../exceptions.dart'; +import 'assets.dart'; import 'dart.dart'; const String _kOutputPrefix = '{OUTPUT_DIR}/FlutterMacOS.framework'; -/// The copying logic for flutter assets in macOS. -// TODO(jonahwilliams): remove once build planning lands. -class MacOSAssetBehavior extends SourceBehavior { - const MacOSAssetBehavior(); - - @override - List inputs(Environment environment) { - final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); - assetBundle.build( - manifestPath: environment.projectDir.childFile('pubspec.yaml').path, - packagesPath: environment.projectDir.childFile('.packages').path, - ); - // Filter the file type to remove the files that are generated by this - // command as inputs. - final List results = []; - final Iterable files = assetBundle.entries.values.whereType(); - for (DevFSFileContent devFsContent in files) { - results.add(fs.file(devFsContent.file.path)); - } - return results; - } - - @override - List outputs(Environment environment) { - final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); - assetBundle.build( - manifestPath: environment.projectDir.childFile('pubspec.yaml').path, - packagesPath: environment.projectDir.childFile('.packages').path, - ); - final String prefix = fs.path.join(environment.outputDir.path, - 'App.framework', 'Versions', 'A', 'Resources', 'flutter_assets'); - final List results = []; - for (String key in assetBundle.entries.keys) { - final File file = fs.file(fs.path.join(prefix, key)); - results.add(file); - } - return results; - } -} - /// Copy the macOS framework to the correct copy dir by invoking 'cp -R'. /// /// This class is abstract to share logic between the three concrete @@ -286,19 +244,15 @@ abstract class MacOSBundleFlutterAssets extends Target { @override List get inputs => const [ - Source.pattern('{PROJECT_DIR}/pubspec.yaml'), Source.pattern('{BUILD_DIR}/App.framework/App'), - Source.behavior(MacOSAssetBehavior()), + Source.depfile('flutter_assets.d'), ]; @override List get outputs => const [ - Source.behavior(MacOSAssetBehavior()), Source.pattern('{OUTPUT_DIR}/App.framework/Versions/A/App'), Source.pattern('{OUTPUT_DIR}/App.framework/Versions/A/Resources/Info.plist'), - Source.pattern('{OUTPUT_DIR}/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.json'), - Source.pattern('{OUTPUT_DIR}/App.framework/Versions/A/Resources/flutter_assets/FontManifest.json'), - Source.pattern('{OUTPUT_DIR}/App.framework/Versions/A/Resources/flutter_assets/LICENSE'), + Source.depfile('flutter_assets.d'), ]; @override @@ -326,31 +280,9 @@ abstract class MacOSBundleFlutterAssets extends Target { .childDirectory('Resources') .childDirectory('flutter_assets'); assetDirectory.createSync(recursive: true); - final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); - final int result = await assetBundle.build( - manifestPath: environment.projectDir.childFile('pubspec.yaml').path, - packagesPath: environment.projectDir.childFile('.packages').path, - ); - if (result != 0) { - throw Exception('Failed to create asset bundle: $result'); - } - // Limit number of open files to avoid running out of file descriptors. - try { - final Pool pool = Pool(kMaxOpenFiles); - await Future.wait( - assetBundle.entries.entries.map>((MapEntry entry) async { - final PoolResource resource = await pool.request(); - try { - final File file = fs.file(fs.path.join(assetDirectory.path, entry.key)); - file.parent.createSync(recursive: true); - await file.writeAsBytes(await entry.value.contentsAsBytes()); - } finally { - resource.release(); - } - })); - } catch (err, st) { - throw Exception('Failed to copy assets: $st'); - } + final Depfile depfile = await copyAssets(environment, assetDirectory); + depfile.writeToFile(environment.buildDir.childFile('flutter_assets.d')); + // Copy Info.plist template. assetDirectory.parent.childFile('Info.plist') ..createSync() diff --git a/packages/flutter_tools/lib/src/build_system/targets/web.dart b/packages/flutter_tools/lib/src/build_system/targets/web.dart index e7dd430a73d..4c4946f482d 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/web.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/web.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import '../../artifacts.dart'; -import '../../asset.dart'; import '../../base/file_system.dart'; import '../../base/io.dart'; import '../../base/process_manager.dart'; @@ -183,18 +182,16 @@ class WebReleaseBundle extends Target { @override List get inputs => const [ Source.pattern('{BUILD_DIR}/main.dart.js'), - Source.behavior(AssetOutputBehavior('assets')), + Source.pattern('{PROJECT_DIR}/pubspec.yaml'), Source.pattern('{PROJECT_DIR}/web/index.html'), + Source.depfile('flutter_assets.d'), ]; @override List get outputs => const [ Source.pattern('{OUTPUT_DIR}/main.dart.js'), - Source.pattern('{OUTPUT_DIR}/assets/AssetManifest.json'), - Source.pattern('{OUTPUT_DIR}/assets/FontManifest.json'), - Source.pattern('{OUTPUT_DIR}/assets/LICENSE'), Source.pattern('{OUTPUT_DIR}/index.html'), - Source.behavior(AssetOutputBehavior('assets')) + Source.depfile('flutter_assets.d'), ]; @override @@ -207,12 +204,13 @@ class WebReleaseBundle extends Target { environment.outputDir.childFile(fs.path.basename(outputFile.path)).path ); } + final Directory outputDirectory = environment.outputDir.childDirectory('assets'); + outputDirectory.createSync(recursive: true); environment.projectDir .childDirectory('web') .childFile('index.html') .copySync(fs.path.join(environment.outputDir.path, 'index.html')); - final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle(); - await assetBundle.build(); - await copyAssets(assetBundle, environment, 'assets'); + final Depfile depfile = await copyAssets(environment, environment.outputDir.childDirectory('assets')); + depfile.writeToFile(environment.buildDir.childFile('flutter_assets.d')); } } diff --git a/packages/flutter_tools/test/general.shard/build_system/build_system_test.dart b/packages/flutter_tools/test/general.shard/build_system/build_system_test.dart index ed016fb008f..fa0e9a74e19 100644 --- a/packages/flutter_tools/test/general.shard/build_system/build_system_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/build_system_test.dart @@ -339,6 +339,41 @@ void main() { expect(environmentA.buildDir.path, isNot(environmentB.buildDir.path)); })); + + test('A target with depfile dependencies can delete stale outputs on the first run', () => testbed.run(() async { + int called = 0; + final TestTarget target = TestTarget((Environment environment) async { + if (called == 0) { + environment.buildDir.childFile('example.d') + .writeAsStringSync('a.txt c.txt: b.txt'); + fs.file('a.txt').writeAsStringSync('a'); + fs.file('c.txt').writeAsStringSync('a'); + } else { + // On second run, we no longer claim c.txt as an output. + environment.buildDir.childFile('example.d') + .writeAsStringSync('a.txt: b.txt'); + fs.file('a.txt').writeAsStringSync('a'); + } + called += 1; + }) + ..inputs = const [Source.depfile('example.d')] + ..outputs = const [Source.depfile('example.d')]; + fs.file('b.txt').writeAsStringSync('b'); + + await buildSystem.build(target, environment); + + expect(fs.file('a.txt').existsSync(), true); + expect(fs.file('c.txt').existsSync(), true); + expect(called, 1); + + // rewrite an input to force a rerun, espect that the old c.txt is deleted. + fs.file('b.txt').writeAsStringSync('ba'); + await buildSystem.build(target, environment); + + expect(fs.file('a.txt').existsSync(), true); + expect(fs.file('c.txt').existsSync(), false); + expect(called, 2); + })); } class MockPlatform extends Mock implements Platform {} diff --git a/packages/flutter_tools/test/general.shard/build_system/source_test.dart b/packages/flutter_tools/test/general.shard/build_system/source_test.dart index c4ce82ee39a..6eb120dbaf6 100644 --- a/packages/flutter_tools/test/general.shard/build_system/source_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/source_test.dart @@ -41,7 +41,6 @@ void main() { test('configures implicit vs explict correctly', () => testbed.run(() { expect(const Source.pattern('{PROJECT_DIR}/foo').implicit, false); expect(const Source.pattern('{PROJECT_DIR}/*foo').implicit, true); - expect(Source.behavior(TestBehavior()).implicit, true); })); test('can substitute {PROJECT_DIR}/foo', () => testbed.run(() { @@ -217,17 +216,4 @@ void main() { })); } -class TestBehavior extends SourceBehavior { - @override - List inputs(Environment environment) { - return null; - } - - @override - List outputs(Environment environment) { - return null; - } -} - class MockPlatform extends Mock implements Platform {} - diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/assets_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/assets_test.dart index 42f1ceaece6..47ed4bfae53 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/assets_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/assets_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:io'; + import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/targets/assets.dart'; @@ -65,7 +67,7 @@ flutter: // See https://github.com/flutter/flutter/issues/35293 expect(fs.file(fs.path.join(environment.buildDir.path, 'flutter_assets', 'assets/foo/bar.png')).existsSync(), false); - })); + }), skip: Platform.isWindows); // See https://github.com/google/file.dart/issues/131 test('FlutterPlugins updates required files as needed', () => testbed.run(() async { fs.file('pubspec.yaml')