[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 frameworkDirectory = environment.outputDir.childDirectory('App.framework');
|
||||||
final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets');
|
final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets');
|
||||||
frameworkDirectory.createSync(recursive: true);
|
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();
|
assetDirectory.createSync();
|
||||||
|
|
||||||
// Only copy the prebuilt runtimes and kernel blob in debug mode.
|
// Only copy the prebuilt runtimes and kernel blob in debug mode.
|
||||||
|
@ -16,8 +16,6 @@ import 'assets.dart';
|
|||||||
import 'dart.dart';
|
import 'dart.dart';
|
||||||
import 'icon_tree_shaker.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'.
|
/// Copy the macOS framework to the correct copy dir by invoking 'cp -R'.
|
||||||
///
|
///
|
||||||
/// This class is abstract to share logic between the three concrete
|
/// This class is abstract to share logic between the three concrete
|
||||||
@ -31,11 +29,6 @@ const String _kOutputPrefix = '{OUTPUT_DIR}/FlutterMacOS.framework';
|
|||||||
/// * [DebugUnpackMacOS]
|
/// * [DebugUnpackMacOS]
|
||||||
/// * [ProfileUnpackMacOS]
|
/// * [ProfileUnpackMacOS]
|
||||||
/// * [ReleaseUnpackMacOS]
|
/// * [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 {
|
abstract class UnpackMacOS extends Target {
|
||||||
const UnpackMacOS();
|
const UnpackMacOS();
|
||||||
|
|
||||||
@ -45,30 +38,14 @@ abstract class UnpackMacOS extends Target {
|
|||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Source> get outputs => const <Source>[
|
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
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Target> get dependencies => <Target>[];
|
List<Target> get dependencies => <Target>[];
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<String> get depfiles => const <String>['unpack_macos.d'];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> build(Environment environment) async {
|
Future<void> build(Environment environment) async {
|
||||||
if (environment.defines[kBuildMode] == null) {
|
if (environment.defines[kBuildMode] == null) {
|
||||||
@ -79,9 +56,20 @@ abstract class UnpackMacOS extends Target {
|
|||||||
final Directory targetDirectory = environment
|
final Directory targetDirectory = environment
|
||||||
.outputDir
|
.outputDir
|
||||||
.childDirectory('FlutterMacOS.framework');
|
.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()) {
|
if (targetDirectory.existsSync()) {
|
||||||
targetDirectory.deleteSync(recursive: true);
|
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
|
final ProcessResult result = await globals.processManager
|
||||||
.run(<String>['cp', '-R', basePath, targetDirectory.path]);
|
.run(<String>['cp', '-R', basePath, targetDirectory.path]);
|
||||||
if (result.exitCode != 0) {
|
if (result.exitCode != 0) {
|
||||||
@ -90,6 +78,15 @@ abstract class UnpackMacOS extends Target {
|
|||||||
'${result.stdout}\n---\n${result.stderr}',
|
'${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
|
final Directory assetDirectory = outputDirectory
|
||||||
.childDirectory('Resources')
|
.childDirectory('Resources')
|
||||||
.childDirectory('flutter_assets');
|
.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);
|
assetDirectory.createSync(recursive: true);
|
||||||
final Depfile depfile = await copyAssets(environment, assetDirectory);
|
final Depfile depfile = await copyAssets(environment, assetDirectory);
|
||||||
final DepfileService depfileService = DepfileService(
|
final DepfileService depfileService = DepfileService(
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:file_testing/file_testing.dart';
|
||||||
import 'package:flutter_tools/src/artifacts.dart';
|
import 'package:flutter_tools/src/artifacts.dart';
|
||||||
import 'package:flutter_tools/src/base/build.dart';
|
import 'package:flutter_tools/src/base/build.dart';
|
||||||
import 'package:flutter_tools/src/base/file_system.dart';
|
import 'package:flutter_tools/src/base/file_system.dart';
|
||||||
@ -78,6 +79,7 @@ void main() {
|
|||||||
logger: globals.logger,
|
logger: globals.logger,
|
||||||
fileSystem: globals.fs,
|
fileSystem: globals.fs,
|
||||||
);
|
);
|
||||||
|
environment.buildDir.createSync(recursive: true);
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
ProcessManager: () => MockProcessManager(),
|
ProcessManager: () => MockProcessManager(),
|
||||||
Platform: () => mockPlatform,
|
Platform: () => mockPlatform,
|
||||||
@ -119,7 +121,7 @@ void main() {
|
|||||||
|
|
||||||
expect(globals.fs.directory(_kOutputPrefix).existsSync(), true);
|
expect(globals.fs.directory(_kOutputPrefix).existsSync(), true);
|
||||||
for (final File file in inputs) {
|
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');
|
'flutter_assets', 'isolate_snapshot_data');
|
||||||
await const ProfileMacOSBundleFlutterAssets().build(environment..defines[kBuildMode] = 'profile');
|
await const ProfileMacOSBundleFlutterAssets().build(environment..defines[kBuildMode] = 'profile');
|
||||||
|
|
||||||
expect(globals.fs.file(outputKernel).existsSync(), false);
|
expect(globals.fs.file(outputKernel), isNot(exists));
|
||||||
expect(globals.fs.file(precompiledVm).existsSync(), false);
|
expect(globals.fs.file(precompiledVm), isNot(exists));
|
||||||
expect(globals.fs.file(precompiledIsolate).existsSync(), false);
|
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 {
|
test('release/profile macOS application updates when App.framework updates', () => testbed.run(() async {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user