mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +00:00
Remove Source.behavior, fix bug in depfile invalidation (#43945)
* remove Source.behavior, fix bug in depfile invalidation * more cleanup of assets * Add skip * address comments * Update build_system.dart
This commit is contained in:
parent
b815f76293
commit
0f6c093d68
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<File> inputs(Environment environment);
|
||||
|
||||
/// The outputs for a particular target.
|
||||
List<File> 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 });
|
||||
|
||||
|
|
|
@ -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<File> 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<File> results = <File>[];
|
||||
final Iterable<DevFSFileContent> files = assetBundle.entries.values.whereType<DevFSFileContent>();
|
||||
for (DevFSFileContent devFsContent in files) {
|
||||
results.add(fs.file(devFsContent.file.path));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@override
|
||||
List<File> 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<File> results = <File>[];
|
||||
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<File> 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<File> results = <File>[];
|
||||
final Iterable<DevFSFileContent> files = assetBundle.entries.values.whereType<DevFSFileContent>();
|
||||
for (DevFSFileContent devFsContent in files) {
|
||||
results.add(fs.file(fs.path.join(_pathSuffix, devFsContent.file.path)));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@override
|
||||
List<File> 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<File> results = <File>[];
|
||||
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<Depfile> 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<File> inputs = <File>[
|
||||
// An asset manifest with no assets would have zero inputs if not
|
||||
// for this pubspec file.
|
||||
pubspecFile,
|
||||
];
|
||||
final List<File> outputs = <File>[];
|
||||
await Future.wait<void>(
|
||||
assetBundle.entries.entries.map<Future<void>>((MapEntry<String, DevFSContent> 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<Source> get inputs => const <Source>[
|
||||
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<Source> get outputs => const <Source>[
|
||||
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<void>(
|
||||
assetBundle.entries.entries.map<Future<void>>((MapEntry<String, DevFSContent> 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'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<void> copyAssets(AssetBundle assetBundle, Environment environment, [String pathSuffix = '']) async {
|
||||
final Pool pool = Pool(kMaxOpenFiles);
|
||||
await Future.wait<void>(
|
||||
assetBundle.entries.entries.map<Future<void>>((MapEntry<String, DevFSContent> 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<Source> get inputs => const <Source>[
|
||||
Source.behavior(AssetOutputBehavior()),
|
||||
Source.depfile('flutter_assets.d'),
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[
|
||||
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
|
||||
|
|
|
@ -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<Source> get inputs => const <Source>[
|
||||
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<Source> get outputs => const <Source>[
|
||||
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<void>(
|
||||
assetBundle.entries.entries.map<Future<void>>((MapEntry<String, DevFSContent> 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'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<File> 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<File> results = <File>[];
|
||||
final Iterable<DevFSFileContent> files = assetBundle.entries.values.whereType<DevFSFileContent>();
|
||||
for (DevFSFileContent devFsContent in files) {
|
||||
results.add(fs.file(devFsContent.file.path));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@override
|
||||
List<File> 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<File> results = <File>[];
|
||||
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<Source> get inputs => const <Source>[
|
||||
Source.pattern('{PROJECT_DIR}/pubspec.yaml'),
|
||||
Source.pattern('{BUILD_DIR}/App.framework/App'),
|
||||
Source.behavior(MacOSAssetBehavior()),
|
||||
Source.depfile('flutter_assets.d'),
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[
|
||||
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<void>(
|
||||
assetBundle.entries.entries.map<Future<void>>((MapEntry<String, DevFSContent> 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()
|
||||
|
|
|
@ -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<Source> get inputs => const <Source>[
|
||||
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<Source> get outputs => const <Source>[
|
||||
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'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>[Source.depfile('example.d')]
|
||||
..outputs = const <Source>[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 {}
|
||||
|
|
|
@ -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<File> inputs(Environment environment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
List<File> outputs(Environment environment) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class MockPlatform extends Mock implements Platform {}
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in a new issue