refactor depfile usage and update linux rule (#42487)
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 cba474a..bb7d035 100644
--- a/packages/flutter_tools/lib/src/build_system/build_system.dart
+++ b/packages/flutter_tools/lib/src/build_system/build_system.dart
@@ -502,7 +502,7 @@
outputFiles[output.path] = output;
}
for (File input in node.inputs) {
- final String resolvedPath = input.resolveSymbolicLinksSync();
+ final String resolvedPath = input.absolute.path;
if (outputFiles.containsKey(resolvedPath)) {
continue;
}
@@ -704,7 +704,7 @@
/// One or more reasons why a task was invalidated.
///
/// May be empty if the task was skipped.
- final Set<InvalidedReason> invalidatedReasons = <InvalidedReason>{};
+ final Set<InvalidatedReason> invalidatedReasons = <InvalidatedReason>{};
/// Whether this node needs an action performed.
bool get dirty => _dirty;
@@ -735,7 +735,7 @@
if (fileHashStore.currentHashes.containsKey(absolutePath)) {
final String currentHash = fileHashStore.currentHashes[absolutePath];
if (currentHash != previousHash) {
- invalidatedReasons.add(InvalidedReason.inputChanged);
+ invalidatedReasons.add(InvalidatedReason.inputChanged);
_dirty = true;
}
} else {
@@ -749,13 +749,13 @@
// output paths changed.
if (!currentOutputPaths.contains(previousOutput)) {
_dirty = true;
- invalidatedReasons.add(InvalidedReason.outputSetChanged);
+ invalidatedReasons.add(InvalidatedReason.outputSetChanged);
// if this isn't a current output file there is no reason to compute the hash.
continue;
}
final File file = fs.file(previousOutput);
if (!file.existsSync()) {
- invalidatedReasons.add(InvalidedReason.outputMissing);
+ invalidatedReasons.add(InvalidatedReason.outputMissing);
_dirty = true;
continue;
}
@@ -764,7 +764,7 @@
if (fileHashStore.currentHashes.containsKey(absolutePath)) {
final String currentHash = fileHashStore.currentHashes[absolutePath];
if (currentHash != previousHash) {
- invalidatedReasons.add(InvalidedReason.outputChanged);
+ invalidatedReasons.add(InvalidatedReason.outputChanged);
_dirty = true;
}
} else {
@@ -772,9 +772,14 @@
}
}
- // If we depend on a file that doesnt exist on disk, kill the build.
+ // If we depend on a file that doesnt exist on disk, mark the build as
+ // dirty. if the rule is not correctly specified, this will result in it
+ // always being rerun.
if (missingInputs.isNotEmpty) {
- throw MissingInputException(missingInputs, target.name);
+ _dirty = true;
+ final String missingMessage = missingInputs.map((File file) => file.path).join(', ');
+ printTrace('invalidated build due to missing files: $missingMessage');
+ invalidatedReasons.add(InvalidatedReason.inputMissing);
}
// If we have files to hash, compute them asynchronously and then
@@ -782,7 +787,7 @@
if (sourcesToHash.isNotEmpty) {
final List<File> dirty = await fileHashStore.hashFiles(sourcesToHash);
if (dirty.isNotEmpty) {
- invalidatedReasons.add(InvalidedReason.inputChanged);
+ invalidatedReasons.add(InvalidatedReason.inputChanged);
_dirty = true;
}
}
@@ -790,8 +795,12 @@
}
}
-/// A description of why a task was rerun.
-enum InvalidedReason {
+/// A description of why a target was rerun.
+enum InvalidatedReason {
+ /// An input file that was expected is missing. This can occur when using
+ /// depfile dependencies, or if a target is incorrectly specified.
+ inputMissing,
+
/// An input file has an updated hash.
inputChanged,
diff --git a/packages/flutter_tools/lib/src/build_system/depfile.dart b/packages/flutter_tools/lib/src/build_system/depfile.dart
new file mode 100644
index 0000000..1df5e7d
--- /dev/null
+++ b/packages/flutter_tools/lib/src/build_system/depfile.dart
@@ -0,0 +1,78 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import '../base/file_system.dart';
+import '../base/platform.dart';
+import '../globals.dart';
+
+/// A class for representing depfile formats.
+class Depfile {
+ /// Create a [Depfile] from a list of [input] files and [output] files.
+ const Depfile(this.inputs, this.outputs);
+
+ /// Parse the depfile contents from [file].
+ ///
+ /// If the syntax is invalid, returns an empty [Depfile].
+ factory Depfile.parse(File file) {
+ final String contents = file.readAsStringSync();
+ final List<String> colonSeparated = contents.split(': ');
+ if (colonSeparated.length != 2) {
+ printError('Invalid depfile: ${file.path}');
+ return const Depfile(<File>[], <File>[]);
+ }
+ final List<File> inputs = _processList(colonSeparated[1].trim());
+ final List<File> outputs = _processList(colonSeparated[0].trim());
+ return Depfile(inputs, outputs);
+ }
+
+ /// The input files for this depfile.
+ final List<File> inputs;
+
+ /// The output files for this depfile.
+ final List<File> outputs;
+
+ /// Given an [depfile] File, write the depfile contents.
+ ///
+ /// If either [inputs] or [outputs] is empty, does not write to the file.
+ void writeToFile(File depfile) {
+ if (inputs.isEmpty || outputs.isEmpty) {
+ return;
+ }
+ final StringBuffer buffer = StringBuffer();
+ _writeFilesToBuffer(outputs, buffer);
+ buffer.write(': ');
+ _writeFilesToBuffer(inputs, buffer);
+ depfile.writeAsStringSync(buffer.toString());
+ }
+
+ void _writeFilesToBuffer(List<File> files, StringBuffer buffer) {
+ for (File outputFile in files) {
+ if (platform.isWindows) {
+ // Paths in a depfile have to be escaped on windows.
+ final String escapedPath = outputFile.path.replaceAll(r'\', r'\\');
+ buffer.write(' $escapedPath');
+ } else {
+ buffer.write(' ${outputFile.path}');
+ }
+ }
+ }
+
+ static final RegExp _separatorExpr = RegExp(r'([^\\]) ');
+ static final RegExp _escapeExpr = RegExp(r'\\(.)');
+
+ static List<File> _processList(String rawText) {
+ return rawText
+ // Put every file on right-hand side on the separate line
+ .replaceAllMapped(_separatorExpr, (Match match) => '${match.group(1)}\n')
+ .split('\n')
+ // Expand escape sequences, so that '\ ', for example,ß becomes ' '
+ .map<String>((String path) => path.replaceAllMapped(_escapeExpr, (Match match) => match.group(1)).trim())
+ .where((String path) => path.isNotEmpty)
+ // The tool doesn't write duplicates to these lists. This call is an attempt to
+ // be resillient to the outputs of other tools which write or user edits to depfiles.
+ .toSet()
+ .map((String path) => fs.file(path))
+ .toList();
+ }
+}
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 4821163..ab9abc9 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/linux.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/linux.dart
@@ -11,10 +11,22 @@
import '../../devfs.dart';
import '../../globals.dart';
import '../build_system.dart';
+import '../depfile.dart';
import '../exceptions.dart';
import 'assets.dart';
import 'dart.dart';
+/// The only files/subdirectories we care out.
+const List<String> _kLinuxArtifacts = <String>[
+ 'libflutter_linux_glfw.so',
+ 'flutter_export.h',
+ 'flutter_messenger.h',
+ 'flutter_plugin_registrar.h',
+ 'flutter_glfw.h',
+ 'icudtl.dat',
+ 'cpp_client_wrapper_glfw/',
+];
+
/// Copies the Linux desktop embedding files to the copy directory.
class UnpackLinuxDebug extends Target {
const UnpackLinuxDebug();
@@ -25,17 +37,12 @@
@override
List<Source> get inputs => const <Source>[
Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/linux.dart'),
- Source.artifact(Artifact.linuxDesktopPath, mode: BuildMode.debug),
+ Source.depfile('linux_engine_sources.d'),
];
@override
List<Source> get outputs => const <Source>[
- Source.pattern('{PROJECT_DIR}/linux/flutter/ephemeral/libflutter_linux_glfw.so'),
- Source.pattern('{PROJECT_DIR}/linux/flutter/ephemeral/flutter_export.h'),
- Source.pattern('{PROJECT_DIR}/linux/flutter/ephemeral/flutter_messenger.h'),
- Source.pattern('{PROJECT_DIR}/linux/flutter/ephemeral/flutter_plugin_registrar.h'),
- Source.pattern('{PROJECT_DIR}/linux/flutter/ephemeral/flutter_glfw.h'),
- Source.pattern('{PROJECT_DIR}/linux/flutter/ephemeral/icudtl.dat'),
+ Source.depfile('linux_engine_sources.d'),
];
@override
@@ -44,22 +51,55 @@
@override
Future<void> build(Environment environment) async {
final String basePath = artifacts.getArtifactPath(Artifact.linuxDesktopPath);
- for (File input in fs.directory(basePath)
- .listSync(recursive: true)
- .whereType<File>()) {
- final String outputPath = fs.path.join(
- environment.projectDir.path,
- 'linux',
- 'flutter',
- 'ephemeral',
- fs.path.relative(input.path, from: basePath),
- );
- final File destinationFile = fs.file(outputPath);
- if (!destinationFile.parent.existsSync()) {
- destinationFile.parent.createSync(recursive: true);
+ final List<File> inputs = <File>[];
+ final List<File> outputs = <File>[];
+ final String outputPrefix = fs.path.join(
+ environment.projectDir.path,
+ 'linux',
+ 'flutter',
+ 'ephemeral',
+ );
+ // The native linux artifacts are composed of 6 files and a directory (listed above)
+ // which need to be copied to the target directory.
+ for (String artifact in _kLinuxArtifacts) {
+ final String entityPath = fs.path.join(basePath, artifact);
+ // If this artifact is a file, just copy the source over.
+ if (fs.isFileSync(entityPath)) {
+ final String outputPath = fs.path.join(
+ outputPrefix,
+ fs.path.relative(entityPath, from: basePath),
+ );
+ final File destinationFile = fs.file(outputPath);
+ if (!destinationFile.parent.existsSync()) {
+ destinationFile.parent.createSync(recursive: true);
+ }
+ final File inputFile = fs.file(entityPath);
+ inputFile.copySync(destinationFile.path);
+ inputs.add(inputFile);
+ outputs.add(destinationFile);
+ continue;
}
- fs.file(input).copySync(destinationFile.path);
+ // If the artifact is the directory cpp_client_wrapper, recursively
+ // copy every file from it.
+ for (File input in fs.directory(entityPath)
+ .listSync(recursive: true)
+ .whereType<File>()) {
+ final String outputPath = fs.path.join(
+ outputPrefix,
+ fs.path.relative(input.path, from: basePath),
+ );
+ final File destinationFile = fs.file(outputPath);
+ if (!destinationFile.parent.existsSync()) {
+ destinationFile.parent.createSync(recursive: true);
+ }
+ final File inputFile = fs.file(input);
+ inputFile.copySync(destinationFile.path);
+ inputs.add(inputFile);
+ outputs.add(destinationFile);
+ }
}
+ final Depfile depfile = Depfile(inputs, outputs);
+ depfile.writeToFile(environment.buildDir.childFile('linux_engine_sources.d'));
}
}
diff --git a/packages/flutter_tools/lib/src/bundle.dart b/packages/flutter_tools/lib/src/bundle.dart
index 65cd920..996b166 100644
--- a/packages/flutter_tools/lib/src/bundle.dart
+++ b/packages/flutter_tools/lib/src/bundle.dart
@@ -7,15 +7,13 @@
import 'package:meta/meta.dart';
import 'package:pool/pool.dart';
-import 'artifacts.dart';
import 'asset.dart';
import 'base/common.dart';
import 'base/file_system.dart';
-import 'base/platform.dart';
import 'build_info.dart';
import 'build_system/build_system.dart';
+import 'build_system/depfile.dart';
import 'build_system/targets/dart.dart';
-import 'compile.dart';
import 'dart/package_map.dart';
import 'devfs.dart';
import 'globals.dart';
@@ -45,10 +43,6 @@
const String defaultPrivateKeyPath = 'privatekey.der';
-const String _kKernelKey = 'kernel_blob.bin';
-const String _kVMSnapshotData = 'vm_snapshot_data';
-const String _kIsolateSnapshotData = 'isolate_snapshot_data';
-
/// Provides a `build` method that builds the bundle.
class BundleBuilder {
/// Builds the bundle for the given target platform.
@@ -72,73 +66,29 @@
List<String> extraGenSnapshotOptions = const <String>[],
List<String> fileSystemRoots,
String fileSystemScheme,
- bool shouldBuildWithAssemble = false,
}) async {
mainPath ??= defaultMainPath;
depfilePath ??= defaultDepfilePath;
assetDirPath ??= getAssetBuildDirectory();
packagesPath ??= fs.path.absolute(PackageMap.globalPackagesPath);
- applicationKernelFilePath ??= getDefaultApplicationKernelPath(trackWidgetCreation: trackWidgetCreation);
final FlutterProject flutterProject = FlutterProject.current();
-
- if (shouldBuildWithAssemble) {
- await buildWithAssemble(
- buildMode: buildMode ?? BuildMode.debug,
- targetPlatform: platform,
- mainPath: mainPath,
- flutterProject: flutterProject,
- outputDir: assetDirPath,
- depfilePath: depfilePath,
- precompiled: precompiledSnapshot,
- );
- return;
- }
-
- DevFSContent kernelContent;
- if (!precompiledSnapshot) {
- if ((extraFrontEndOptions != null) && extraFrontEndOptions.isNotEmpty) {
- printTrace('Extra front-end options: $extraFrontEndOptions');
- }
- ensureDirectoryExists(applicationKernelFilePath);
- final KernelCompiler kernelCompiler = await kernelCompilerFactory.create(flutterProject);
- final CompilerOutput compilerOutput = await kernelCompiler.compile(
- sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath, mode: buildMode),
- mainPath: fs.file(mainPath).absolute.path,
- outputFilePath: applicationKernelFilePath,
- depFilePath: depfilePath,
- buildMode: buildMode,
- trackWidgetCreation: trackWidgetCreation,
- extraFrontEndOptions: extraFrontEndOptions,
- fileSystemRoots: fileSystemRoots,
- fileSystemScheme: fileSystemScheme,
- packagesPath: packagesPath,
- );
- if (compilerOutput?.outputFilename == null) {
- throwToolExit('Compiler failed on $mainPath');
- }
- kernelContent = DevFSFileContent(fs.file(compilerOutput.outputFilename));
-
- fs.directory(getBuildDirectory()).childFile('frontend_server.d')
- .writeAsStringSync('frontend_server.d: ${artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk)}\n');
- }
-
- final AssetBundle assets = await buildAssets(
- manifestPath: manifestPath,
- assetDirPath: assetDirPath,
- packagesPath: packagesPath,
- reportLicensedPackages: reportLicensedPackages,
+ await buildWithAssemble(
+ buildMode: buildMode ?? BuildMode.debug,
+ targetPlatform: platform,
+ mainPath: mainPath,
+ flutterProject: flutterProject,
+ outputDir: assetDirPath,
+ depfilePath: depfilePath,
+ precompiled: precompiledSnapshot,
);
- if (assets == null) {
- throwToolExit('Error building assets', exitCode: 1);
+ // Work around for flutter_tester placing kernel artifacts in odd places.
+ if (applicationKernelFilePath != null) {
+ final File outputDill = fs.directory(assetDirPath).childFile('kernel_blob.bin');
+ if (outputDill.existsSync()) {
+ outputDill.copySync(applicationKernelFilePath);
+ }
}
-
- await assemble(
- buildMode: buildMode,
- assetBundle: assets,
- kernelContent: kernelContent,
- privateKeyPath: privateKeyPath,
- assetDirPath: assetDirPath,
- );
+ return;
}
}
@@ -178,30 +128,13 @@
}
throwToolExit('Failed to build bundle.');
}
-
- // Output depfile format:
- final StringBuffer buffer = StringBuffer();
- buffer.write('flutter_bundle');
- _writeFilesToBuffer(result.outputFiles, buffer);
- buffer.write(': ');
- _writeFilesToBuffer(result.inputFiles, buffer);
-
- final File depfile = fs.file(depfilePath);
- if (!depfile.parent.existsSync()) {
- depfile.parent.createSync(recursive: true);
- }
- depfile.writeAsStringSync(buffer.toString());
-}
-
-void _writeFilesToBuffer(List<File> files, StringBuffer buffer) {
- for (File outputFile in files) {
- if (platform.isWindows) {
- // Paths in a depfile have to be escaped on windows.
- final String escapedPath = outputFile.path.replaceAll(r'\', r'\\');
- buffer.write(' $escapedPath');
- } else {
- buffer.write(' ${outputFile.path}');
+ if (depfilePath != null) {
+ final Depfile depfile = Depfile(result.inputFiles, result.outputFiles);
+ final File outputDepfile = fs.file(depfilePath);
+ if (!outputDepfile.parent.existsSync()) {
+ outputDepfile.parent.createSync(recursive: true);
}
+ depfile.writeToFile(outputDepfile);
}
}
@@ -231,32 +164,6 @@
return assetBundle;
}
-Future<void> assemble({
- BuildMode buildMode,
- AssetBundle assetBundle,
- DevFSContent kernelContent,
- String privateKeyPath = defaultPrivateKeyPath,
- String assetDirPath,
-}) async {
- assetDirPath ??= getAssetBuildDirectory();
- printTrace('Building bundle');
-
- final Map<String, DevFSContent> assetEntries = Map<String, DevFSContent>.from(assetBundle.entries);
- if (kernelContent != null) {
- final String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData, mode: buildMode);
- final String isolateSnapshotData = artifacts.getArtifactPath(Artifact.isolateSnapshotData, mode: buildMode);
- assetEntries[_kKernelKey] = kernelContent;
- assetEntries[_kVMSnapshotData] = DevFSFileContent(fs.file(vmSnapshotData));
- assetEntries[_kIsolateSnapshotData] = DevFSFileContent(fs.file(isolateSnapshotData));
- }
-
- printTrace('Writing asset files to $assetDirPath');
- ensureDirectoryExists(assetDirPath);
-
- await writeBundle(fs.directory(assetDirPath), assetEntries);
- printTrace('Wrote $assetDirPath');
-}
-
Future<void> writeBundle(
Directory bundleDir,
Map<String, DevFSContent> assetEntries,
diff --git a/packages/flutter_tools/lib/src/commands/build_bundle.dart b/packages/flutter_tools/lib/src/commands/build_bundle.dart
index a65803a..72e9be5 100644
--- a/packages/flutter_tools/lib/src/commands/build_bundle.dart
+++ b/packages/flutter_tools/lib/src/commands/build_bundle.dart
@@ -138,7 +138,6 @@
extraGenSnapshotOptions: argResults[FlutterOptions.kExtraGenSnapshotOptions],
fileSystemScheme: argResults['filesystem-scheme'],
fileSystemRoots: argResults['filesystem-root'],
- shouldBuildWithAssemble: true,
);
return null;
}
diff --git a/packages/flutter_tools/lib/src/tester/flutter_tester.dart b/packages/flutter_tools/lib/src/tester/flutter_tester.dart
index 9deadc0..75844c9 100644
--- a/packages/flutter_tools/lib/src/tester/flutter_tester.dart
+++ b/packages/flutter_tools/lib/src/tester/flutter_tester.dart
@@ -145,12 +145,13 @@
trackWidgetCreation: buildInfo.trackWidgetCreation,
);
await BundleBuilder().build(
+ buildMode: buildInfo.mode,
mainPath: mainPath,
assetDirPath: assetDirPath,
applicationKernelFilePath: applicationKernelFilePath,
precompiledSnapshot: false,
- buildMode: buildInfo.mode,
trackWidgetCreation: buildInfo.trackWidgetCreation,
+ platform: getTargetPlatformForName(getNameForHostPlatform(getCurrentHostPlatform())),
);
command.add('--flutter-assets-dir=$assetDirPath');
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 809ea03..b782682 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
@@ -106,13 +106,12 @@
);
});
- test('Throws exception if asked to build with missing inputs', () => testbed.run(() async {
+ test('Does not throw exception if asked to build with missing inputs', () => testbed.run(() async {
// Delete required input file.
fs.file('foo.dart').deleteSync();
final BuildResult buildResult = await buildSystem.build(fooTarget, environment);
- expect(buildResult.hasException, true);
- expect(buildResult.exceptions.values.single.exception, isInstanceOf<MissingInputException>());
+ expect(buildResult.hasException, false);
}));
test('Throws exception if it does not produce a specified output', () => testbed.run(() async {
diff --git a/packages/flutter_tools/test/general.shard/build_system/depfile_test.dart b/packages/flutter_tools/test/general.shard/build_system/depfile_test.dart
new file mode 100644
index 0000000..aa0fd38
--- /dev/null
+++ b/packages/flutter_tools/test/general.shard/build_system/depfile_test.dart
@@ -0,0 +1,106 @@
+// Copyright 2019 The Chromium Authors. 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:file/memory.dart';
+import 'package:flutter_tools/src/base/file_system.dart';
+import 'package:flutter_tools/src/build_system/depfile.dart';
+
+import '../../src/common.dart';
+import '../../src/testbed.dart';
+
+void main() {
+ Testbed testbed;
+
+ setUp(() {
+ testbed = Testbed();
+ });
+ test('Can parse depfile from file', () => testbed.run(() {
+ final File depfileSource = fs.file('example.d')..writeAsStringSync('''
+a.txt: b.txt
+''');
+ final Depfile depfile = Depfile.parse(depfileSource);
+
+ expect(depfile.inputs.single.path, 'b.txt');
+ expect(depfile.outputs.single.path, 'a.txt');
+ }));
+
+ test('Can parse depfile with multiple inputs', () => testbed.run(() {
+ final FileSystem fs = MemoryFileSystem();
+ final File depfileSource = fs.file('example.d')..writeAsStringSync('''
+a.txt: b.txt c.txt d.txt
+''');
+ final Depfile depfile = Depfile.parse(depfileSource);
+
+ expect(depfile.inputs.map((File file) => file.path), <String>[
+ 'b.txt',
+ 'c.txt',
+ 'd.txt',
+ ]);
+ expect(depfile.outputs.single.path, 'a.txt');
+ }));
+
+ test('Can parse depfile with multiple outputs', () => testbed.run(() {
+ final FileSystem fs = MemoryFileSystem();
+ final File depfileSource = fs.file('example.d')..writeAsStringSync('''
+a.txt c.txt d.txt: b.txt
+''');
+ final Depfile depfile = Depfile.parse(depfileSource);
+
+ expect(depfile.inputs.single.path, 'b.txt');
+ expect(depfile.outputs.map((File file) => file.path), <String>[
+ 'a.txt',
+ 'c.txt',
+ 'd.txt',
+ ]);
+ }));
+
+ test('Can parse depfile with windows file paths', () => testbed.run(() {
+ final FileSystem fs = MemoryFileSystem();
+ final File depfileSource = fs.file('example.d')..writeAsStringSync(r'''
+C:\\a.txt: C:\\b.txt
+''');
+ final Depfile depfile = Depfile.parse(depfileSource);
+
+ expect(depfile.inputs.single.path, r'C:\b.txt');
+ expect(depfile.outputs.single.path, r'C:\a.txt');
+ }, overrides: <Type, Generator>{
+ FileSystem: () => MemoryFileSystem(style: FileSystemStyle.windows),
+ }));
+
+ test('Resillient to weird whitespace', () => testbed.run(() {
+ final FileSystem fs = MemoryFileSystem();
+ final File depfileSource = fs.file('example.d')..writeAsStringSync(r'''
+a.txt
+ : b.txt c.txt
+
+
+''');
+ final Depfile depfile = Depfile.parse(depfileSource);
+
+ expect(depfile.inputs, hasLength(2));
+ expect(depfile.outputs.single.path, 'a.txt');
+ }));
+
+ test('Resillient to duplicate files', () => testbed.run(() {
+ final FileSystem fs = MemoryFileSystem();
+ final File depfileSource = fs.file('example.d')..writeAsStringSync(r'''
+a.txt: b.txt b.txt
+''');
+ final Depfile depfile = Depfile.parse(depfileSource);
+
+ expect(depfile.inputs.single.path, 'b.txt');
+ expect(depfile.outputs.single.path, 'a.txt');
+ }));
+
+ test('Resillient to malformed file, missing :', () => testbed.run(() {
+ final FileSystem fs = MemoryFileSystem();
+ final File depfileSource = fs.file('example.d')..writeAsStringSync(r'''
+a.text b.txt
+''');
+ final Depfile depfile = Depfile.parse(depfileSource);
+
+ expect(depfile.inputs, isEmpty);
+ expect(depfile.outputs, isEmpty);
+ }));
+}
diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/linux_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/linux_test.dart
index d707235..f4bb3dd 100644
--- a/packages/flutter_tools/test/general.shard/build_system/targets/linux_test.dart
+++ b/packages/flutter_tools/test/general.shard/build_system/targets/linux_test.dart
@@ -39,6 +39,7 @@
kBuildMode: 'debug',
}
);
+ fs.file('bin/cache/artifacts/engine/linux-x64/unrelated-stuff').createSync(recursive: true);
fs.file('bin/cache/artifacts/engine/linux-x64/libflutter_linux_glfw.so').createSync(recursive: true);
fs.file('bin/cache/artifacts/engine/linux-x64/flutter_export.h').createSync();
fs.file('bin/cache/artifacts/engine/linux-x64/flutter_messenger.h').createSync();
@@ -53,7 +54,7 @@
});
});
- test('Copies files to correct cache directory', () => testbed.run(() async {
+ test('Copies files to correct cache directory, excluding unrelated code', () => testbed.run(() async {
final BuildResult result = await buildSystem.build(const UnpackLinuxDebug(), environment);
expect(result.hasException, false);
@@ -64,6 +65,7 @@
expect(fs.file('linux/flutter/ephemeral/flutter_glfw.h').existsSync(), true);
expect(fs.file('linux/flutter/ephemeral/icudtl.dat').existsSync(), true);
expect(fs.file('linux/flutter/ephemeral/cpp_client_wrapper_glfw/foo').existsSync(), true);
+ expect(fs.file('linux/flutter/ephemeral/unrelated-stuff').existsSync(), false);
}));
test('Does not re-copy files unecessarily', () => testbed.run(() async {
diff --git a/packages/flutter_tools/test/general.shard/bundle_shim_test.dart b/packages/flutter_tools/test/general.shard/bundle_shim_test.dart
index be36d51..6b678c1 100644
--- a/packages/flutter_tools/test/general.shard/bundle_shim_test.dart
+++ b/packages/flutter_tools/test/general.shard/bundle_shim_test.dart
@@ -43,7 +43,7 @@
);
expect(fs.file(fs.path.join('example', 'kernel_blob.bin')).existsSync(), true);
expect(fs.file(fs.path.join('example', 'LICENSE')).existsSync(), true);
- expect(fs.file(fs.path.join('example.d')).existsSync(), true);
+ expect(fs.file(fs.path.join('example.d')).existsSync(), false);
}));
test('Handles build system failure', () => testbed.run(() {
diff --git a/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart b/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart
index f782d78..fa6a4f0 100644
--- a/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart
+++ b/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart
@@ -9,10 +9,8 @@
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
-import 'package:flutter_tools/src/cache.dart';
-import 'package:flutter_tools/src/compile.dart';
+import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/device.dart';
-import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/tester/flutter_tester.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
@@ -102,24 +100,23 @@
String mainPath;
MockArtifacts mockArtifacts;
- MockKernelCompiler mockKernelCompiler;
MockProcessManager mockProcessManager;
MockProcess mockProcess;
+ MockBuildSystem mockBuildSystem;
final Map<Type, Generator> startOverrides = <Type, Generator>{
Platform: () => FakePlatform(operatingSystem: 'linux'),
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
- Cache: () => Cache(rootOverride: fs.directory(flutterRoot)),
- KernelCompilerFactory: () => FakeKernelCompilerFactory(mockKernelCompiler),
Artifacts: () => mockArtifacts,
+ BuildSystem: () => mockBuildSystem,
};
setUp(() {
+ mockBuildSystem = MockBuildSystem();
flutterRoot = fs.path.join('home', 'me', 'flutter');
flutterTesterPath = fs.path.join(flutterRoot, 'bin', 'cache',
'artifacts', 'engine', 'linux-x64', 'flutter_tester');
-
final File flutterTesterFile = fs.file(flutterTesterPath);
flutterTesterFile.parent.createSync(recursive: true);
flutterTesterFile.writeAsBytesSync(const <int>[]);
@@ -139,24 +136,23 @@
mode: anyNamed('mode')
)).thenReturn(artifactPath);
- mockKernelCompiler = MockKernelCompiler();
+ when(mockBuildSystem.build(
+ any,
+ any,
+ )).thenAnswer((_) async {
+ fs.file('$mainPath.dill').createSync(recursive: true);
+ return BuildResult(success: true);
+ });
});
testUsingContext('not debug', () async {
final LaunchResult result = await device.startApp(null,
mainPath: mainPath,
debuggingOptions: DebuggingOptions.disabled(const BuildInfo(BuildMode.release, null)));
+
expect(result.started, isFalse);
}, overrides: startOverrides);
- testUsingContext('no flutter_tester', () async {
- fs.file(flutterTesterPath).deleteSync();
- expect(() async {
- await device.startApp(null,
- mainPath: mainPath,
- debuggingOptions: DebuggingOptions.disabled(const BuildInfo(BuildMode.debug, null)));
- }, throwsToolExit());
- }, overrides: startOverrides);
testUsingContext('start', () async {
final Uri observatoryUri = Uri.parse('http://127.0.0.1:6666/');
@@ -168,22 +164,6 @@
.codeUnits,
]));
- when(mockKernelCompiler.compile(
- sdkRoot: anyNamed('sdkRoot'),
- mainPath: anyNamed('mainPath'),
- outputFilePath: anyNamed('outputFilePath'),
- depFilePath: anyNamed('depFilePath'),
- buildMode: BuildMode.debug,
- trackWidgetCreation: anyNamed('trackWidgetCreation'),
- extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
- fileSystemRoots: anyNamed('fileSystemRoots'),
- fileSystemScheme: anyNamed('fileSystemScheme'),
- packagesPath: anyNamed('packagesPath'),
- )).thenAnswer((_) async {
- fs.file('$mainPath.dill').createSync(recursive: true);
- return CompilerOutput('$mainPath.dill', 0, <Uri>[]);
- });
-
final LaunchResult result = await device.startApp(null,
mainPath: mainPath,
debuggingOptions: DebuggingOptions.enabled(const BuildInfo(BuildMode.debug, null)));
@@ -195,15 +175,5 @@
});
}
+class MockBuildSystem extends Mock implements BuildSystem {}
class MockArtifacts extends Mock implements Artifacts {}
-class MockKernelCompiler extends Mock implements KernelCompiler {}
-class FakeKernelCompilerFactory implements KernelCompilerFactory {
- FakeKernelCompilerFactory(this.kernelCompiler);
-
- final KernelCompiler kernelCompiler;
-
- @override
- Future<KernelCompiler> create(FlutterProject flutterProject) async {
- return kernelCompiler;
- }
-}