[flutter_tools] handle unsafe build outputs (#53601)
This commit is contained in:
parent
e71cf1cdbe
commit
7bf74c3460
@ -276,6 +276,13 @@ abstract class IosAssetBundle extends Target {
|
||||
final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework');
|
||||
final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets');
|
||||
frameworkDirectory.createSync(recursive: true);
|
||||
|
||||
// This is necessary because multiple different build configurations will
|
||||
// output different files here. Build cleaning only works when the files
|
||||
// change within a build configuration.
|
||||
if (assetDirectory.existsSync()) {
|
||||
assetDirectory.deleteSync(recursive: true);
|
||||
}
|
||||
assetDirectory.createSync();
|
||||
|
||||
// Only copy the prebuilt runtimes and kernel blob in debug mode.
|
||||
|
@ -16,8 +16,6 @@ import 'assets.dart';
|
||||
import 'dart.dart';
|
||||
import 'icon_tree_shaker.dart';
|
||||
|
||||
const String _kOutputPrefix = '{OUTPUT_DIR}/FlutterMacOS.framework';
|
||||
|
||||
/// Copy the macOS framework to the correct copy dir by invoking 'cp -R'.
|
||||
///
|
||||
/// This class is abstract to share logic between the three concrete
|
||||
@ -31,11 +29,6 @@ const String _kOutputPrefix = '{OUTPUT_DIR}/FlutterMacOS.framework';
|
||||
/// * [DebugUnpackMacOS]
|
||||
/// * [ProfileUnpackMacOS]
|
||||
/// * [ReleaseUnpackMacOS]
|
||||
///
|
||||
// TODO(jonahwilliams): remove shell out.
|
||||
// TODO(jonahwilliams): the subtypes are required to specify the different
|
||||
// input dependencies as a current limitation of the build system planning.
|
||||
// This should be resolved after https://github.com/flutter/flutter/issues/38937.
|
||||
abstract class UnpackMacOS extends Target {
|
||||
const UnpackMacOS();
|
||||
|
||||
@ -45,30 +38,14 @@ abstract class UnpackMacOS extends Target {
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[
|
||||
Source.pattern('$_kOutputPrefix/FlutterMacOS'),
|
||||
// Headers
|
||||
Source.pattern('$_kOutputPrefix/Headers/FlutterDartProject.h'),
|
||||
Source.pattern('$_kOutputPrefix/Headers/FlutterEngine.h'),
|
||||
Source.pattern('$_kOutputPrefix/Headers/FlutterViewController.h'),
|
||||
Source.pattern('$_kOutputPrefix/Headers/FlutterBinaryMessenger.h'),
|
||||
Source.pattern('$_kOutputPrefix/Headers/FlutterChannels.h'),
|
||||
Source.pattern('$_kOutputPrefix/Headers/FlutterCodecs.h'),
|
||||
Source.pattern('$_kOutputPrefix/Headers/FlutterMacros.h'),
|
||||
Source.pattern('$_kOutputPrefix/Headers/FlutterPluginMacOS.h'),
|
||||
Source.pattern('$_kOutputPrefix/Headers/FlutterPluginRegistrarMacOS.h'),
|
||||
Source.pattern('$_kOutputPrefix/Headers/FlutterMacOS.h'),
|
||||
// Modules
|
||||
Source.pattern('$_kOutputPrefix/Modules/module.modulemap'),
|
||||
// Resources
|
||||
Source.pattern('$_kOutputPrefix/Resources/icudtl.dat'),
|
||||
Source.pattern('$_kOutputPrefix/Resources/Info.plist'),
|
||||
// Ignore Versions folder for now
|
||||
];
|
||||
List<Source> get outputs => const <Source>[];
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => <Target>[];
|
||||
|
||||
@override
|
||||
List<String> get depfiles => const <String>['unpack_macos.d'];
|
||||
|
||||
@override
|
||||
Future<void> build(Environment environment) async {
|
||||
if (environment.defines[kBuildMode] == null) {
|
||||
@ -79,9 +56,20 @@ abstract class UnpackMacOS extends Target {
|
||||
final Directory targetDirectory = environment
|
||||
.outputDir
|
||||
.childDirectory('FlutterMacOS.framework');
|
||||
// This is necessary because multiple different build configurations will
|
||||
// output different files here. Build cleaning only works when the files
|
||||
// change within a build configuration.
|
||||
if (targetDirectory.existsSync()) {
|
||||
targetDirectory.deleteSync(recursive: true);
|
||||
}
|
||||
final List<File> inputs = globals.fs.directory(basePath)
|
||||
.listSync(recursive: true)
|
||||
.whereType<File>()
|
||||
.toList();
|
||||
final List<File> outputs = inputs.map((File file) {
|
||||
final String relativePath = globals.fs.path.relative(file.path, from: basePath);
|
||||
return globals.fs.file(globals.fs.path.join(targetDirectory.path, relativePath));
|
||||
}).toList();
|
||||
final ProcessResult result = await globals.processManager
|
||||
.run(<String>['cp', '-R', basePath, targetDirectory.path]);
|
||||
if (result.exitCode != 0) {
|
||||
@ -90,6 +78,15 @@ abstract class UnpackMacOS extends Target {
|
||||
'${result.stdout}\n---\n${result.stderr}',
|
||||
);
|
||||
}
|
||||
final DepfileService depfileService = DepfileService(
|
||||
logger: globals.logger,
|
||||
fileSystem: globals.fs,
|
||||
platform: globals.platform,
|
||||
);
|
||||
depfileService.writeToFile(
|
||||
Depfile(inputs, outputs),
|
||||
environment.buildDir.childFile('unpack_macos.d'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,6 +291,12 @@ abstract class MacOSBundleFlutterAssets extends Target {
|
||||
final Directory assetDirectory = outputDirectory
|
||||
.childDirectory('Resources')
|
||||
.childDirectory('flutter_assets');
|
||||
// This is necessary because multiple different build configurations will
|
||||
// output different files here. Build cleaning only works when the files
|
||||
// change within a build configuration.
|
||||
if (assetDirectory.existsSync()) {
|
||||
assetDirectory.deleteSync(recursive: true);
|
||||
}
|
||||
assetDirectory.createSync(recursive: true);
|
||||
final Depfile depfile = await copyAssets(environment, assetDirectory);
|
||||
final DepfileService depfileService = DepfileService(
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:file_testing/file_testing.dart';
|
||||
import 'package:flutter_tools/src/artifacts.dart';
|
||||
import 'package:flutter_tools/src/base/build.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
@ -67,17 +68,18 @@ void main() {
|
||||
globals.fs.file(globals.fs.path.join('bin', 'cache', 'pkg', 'sky_engine', 'sdk_ext',
|
||||
'vmservice_io.dart')).createSync(recursive: true);
|
||||
|
||||
environment = Environment.test(
|
||||
globals.fs.currentDirectory,
|
||||
defines: <String, String>{
|
||||
kBuildMode: 'debug',
|
||||
kTargetPlatform: 'darwin-x64',
|
||||
},
|
||||
artifacts: MockArtifacts(),
|
||||
processManager: FakeProcessManager.any(),
|
||||
logger: globals.logger,
|
||||
fileSystem: globals.fs,
|
||||
);
|
||||
environment = Environment.test(
|
||||
globals.fs.currentDirectory,
|
||||
defines: <String, String>{
|
||||
kBuildMode: 'debug',
|
||||
kTargetPlatform: 'darwin-x64',
|
||||
},
|
||||
artifacts: MockArtifacts(),
|
||||
processManager: FakeProcessManager.any(),
|
||||
logger: globals.logger,
|
||||
fileSystem: globals.fs,
|
||||
);
|
||||
environment.buildDir.createSync(recursive: true);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => MockProcessManager(),
|
||||
Platform: () => mockPlatform,
|
||||
@ -119,7 +121,7 @@ void main() {
|
||||
|
||||
expect(globals.fs.directory(_kOutputPrefix).existsSync(), true);
|
||||
for (final File file in inputs) {
|
||||
expect(globals.fs.file(file.path.replaceFirst(_kInputPrefix, _kOutputPrefix)).existsSync(), true);
|
||||
expect(globals.fs.file(file.path.replaceFirst(_kInputPrefix, _kOutputPrefix)), exists);
|
||||
}
|
||||
}));
|
||||
|
||||
@ -171,9 +173,57 @@ void main() {
|
||||
'flutter_assets', 'isolate_snapshot_data');
|
||||
await const ProfileMacOSBundleFlutterAssets().build(environment..defines[kBuildMode] = 'profile');
|
||||
|
||||
expect(globals.fs.file(outputKernel).existsSync(), false);
|
||||
expect(globals.fs.file(precompiledVm).existsSync(), false);
|
||||
expect(globals.fs.file(precompiledIsolate).existsSync(), false);
|
||||
expect(globals.fs.file(outputKernel), isNot(exists));
|
||||
expect(globals.fs.file(precompiledVm), isNot(exists));
|
||||
expect(globals.fs.file(precompiledIsolate), isNot(exists));
|
||||
}));
|
||||
|
||||
test('release/profile macOS application has no blob or precompiled runtime when '
|
||||
'run ontop of different configuration', () => testbed.run(() async {
|
||||
globals.fs.file(globals.fs.path.join('bin', 'cache', 'artifacts', 'engine', 'darwin-x64',
|
||||
'vm_isolate_snapshot.bin')).createSync(recursive: true);
|
||||
globals.fs.file(globals.fs.path.join('bin', 'cache', 'artifacts', 'engine', 'darwin-x64',
|
||||
'isolate_snapshot.bin')).createSync(recursive: true);
|
||||
globals.fs.file(globals.fs.path.join(environment.buildDir.path, 'App.framework', 'App'))
|
||||
.createSync(recursive: true);
|
||||
|
||||
final String inputKernel = globals.fs.path.join(environment.buildDir.path, 'app.dill');
|
||||
final String outputKernel = globals.fs.path.join('App.framework', 'Versions', 'A', 'Resources',
|
||||
'flutter_assets', 'kernel_blob.bin');
|
||||
globals.fs.file(inputKernel)
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('testing');
|
||||
|
||||
await const DebugMacOSBundleFlutterAssets().build(environment);
|
||||
|
||||
globals.fs.file(globals.fs.path.join('bin', 'cache', 'artifacts', 'engine', 'darwin-x64',
|
||||
'vm_isolate_snapshot.bin')).createSync(recursive: true);
|
||||
globals.fs.file(globals.fs.path.join('bin', 'cache', 'artifacts', 'engine', 'darwin-x64',
|
||||
'isolate_snapshot.bin')).createSync(recursive: true);
|
||||
|
||||
final Environment testEnvironment = Environment.test(
|
||||
globals.fs.currentDirectory,
|
||||
defines: <String, String>{
|
||||
kBuildMode: 'profile',
|
||||
kTargetPlatform: 'darwin-x64',
|
||||
},
|
||||
artifacts: MockArtifacts(),
|
||||
processManager: FakeProcessManager.any(),
|
||||
logger: globals.logger,
|
||||
fileSystem: globals.fs,
|
||||
);
|
||||
testEnvironment.buildDir.createSync(recursive: true);
|
||||
globals.fs.file(globals.fs.path.join(testEnvironment.buildDir.path, 'App.framework', 'App'))
|
||||
.createSync(recursive: true);
|
||||
final String precompiledVm = globals.fs.path.join('App.framework', 'Resources',
|
||||
'flutter_assets', 'vm_snapshot_data');
|
||||
final String precompiledIsolate = globals.fs.path.join('App.framework', 'Resources',
|
||||
'flutter_assets', 'isolate_snapshot_data');
|
||||
await const ProfileMacOSBundleFlutterAssets().build(testEnvironment);
|
||||
|
||||
expect(globals.fs.file(outputKernel), isNot(exists));
|
||||
expect(globals.fs.file(precompiledVm), isNot(exists));
|
||||
expect(globals.fs.file(precompiledIsolate), isNot(exists));
|
||||
}));
|
||||
|
||||
test('release/profile macOS application updates when App.framework updates', () => testbed.run(() async {
|
||||
|
Loading…
x
Reference in New Issue
Block a user