flutter/packages/flutter_tools/test/general.shard/base/build_test.dart
Jonah Williams cb67513f29
[flutter_tools] Reland: simplify pub cache logic (#67589)
There have been some more additional reports of a missing 'package:characters' import after upgrading flutter. This has me concerned that our pub caching logic is incorrect. Instead of the tool attempting to guess when pub should be run, always delegate to pub.

Also takes an opportunity to fix the kernel snapshot depending on the .packages or package_config. Due to the generated: date field this causes extra rebuilds. Instead when pub get is run, write out an additional file with just the package contents and version.

Fixes #66777
Fixes #65723
2020-10-23 10:00:56 -07:00

713 lines
22 KiB
Dart

// Copyright 2014 The Flutter 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/artifacts.dart';
import 'package:flutter_tools/src/base/build.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/macos/xcode.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import '../../src/common.dart';
import '../../src/context.dart';
const FakeCommand kARMCheckCommand = FakeCommand(
command: <String>[
'sysctl',
'hw.optional.arm64',
],
exitCode: 1,
);
const FakeCommand kSdkPathCommand = FakeCommand(
command: <String>[
'xcrun',
'--sdk',
'iphoneos',
'--show-sdk-path'
]
);
const List<String> kDefaultClang = <String>[
'-miphoneos-version-min=8.0',
'-dynamiclib',
'-Xlinker',
'-rpath',
'-Xlinker',
'@executable_path/Frameworks',
'-Xlinker',
'-rpath',
'-Xlinker',
'@loader_path/Frameworks',
'-install_name',
'@rpath/App.framework/App',
'-isysroot',
'',
'-o',
'build/foo/App.framework/App',
'build/foo/snapshot_assembly.o',
];
const List<String> kBitcodeClang = <String>[
'-miphoneos-version-min=8.0',
'-dynamiclib',
'-Xlinker',
'-rpath',
'-Xlinker',
'@executable_path/Frameworks',
'-Xlinker',
'-rpath',
'-Xlinker',
'@loader_path/Frameworks',
'-install_name',
'@rpath/App.framework/App',
'-fembed-bitcode',
'-isysroot',
'',
'-o',
'build/foo/App.framework/App',
'build/foo/snapshot_assembly.o',
];
void main() {
group('SnapshotType', () {
test('throws, if build mode is null', () {
expect(
() => SnapshotType(TargetPlatform.android_x64, null),
throwsA(anything),
);
});
test('does not throw, if target platform is null', () {
expect(() => SnapshotType(null, BuildMode.release), returnsNormally);
});
});
group('GenSnapshot', () {
GenSnapshot genSnapshot;
Artifacts artifacts;
FakeProcessManager processManager;
BufferLogger logger;
setUp(() async {
artifacts = Artifacts.test();
logger = BufferLogger.test();
processManager = FakeProcessManager.list(< FakeCommand>[]);
genSnapshot = GenSnapshot(
artifacts: artifacts,
logger: logger,
processManager: processManager,
);
});
testWithoutContext('android_x64', () async {
processManager.addCommand(
FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.android_x64, mode: BuildMode.release),
'--additional_arg'
],
),
);
final int result = await genSnapshot.run(
snapshotType: SnapshotType(TargetPlatform.android_x64, BuildMode.release),
darwinArch: null,
additionalArgs: <String>['--additional_arg'],
);
expect(result, 0);
});
testWithoutContext('iOS armv7', () async {
processManager.addCommand(
FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.ios, mode: BuildMode.release) + '_armv7',
'--additional_arg'
],
),
);
final int result = await genSnapshot.run(
snapshotType: SnapshotType(TargetPlatform.ios, BuildMode.release),
darwinArch: DarwinArch.armv7,
additionalArgs: <String>['--additional_arg'],
);
expect(result, 0);
});
testWithoutContext('iOS arm64', () async {
processManager.addCommand(
FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.ios, mode: BuildMode.release) + '_arm64',
'--additional_arg',
],
),
);
final int result = await genSnapshot.run(
snapshotType: SnapshotType(TargetPlatform.ios, BuildMode.release),
darwinArch: DarwinArch.arm64,
additionalArgs: <String>['--additional_arg'],
);
expect(result, 0);
});
testWithoutContext('--strip filters error output from gen_snapshot', () async {
processManager.addCommand(FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.android_x64, mode: BuildMode.release),
'--strip',
],
stderr: 'ABC\n${GenSnapshot.kIgnoredWarnings.join('\n')}\nXYZ\n'
));
final int result = await genSnapshot.run(
snapshotType: SnapshotType(TargetPlatform.android_x64, BuildMode.release),
darwinArch: null,
additionalArgs: <String>['--strip'],
);
expect(result, 0);
expect(logger.errorText, contains('ABC'));
for (final String ignoredWarning in GenSnapshot.kIgnoredWarnings) {
expect(logger.errorText, isNot(contains(ignoredWarning)));
}
expect(logger.errorText, contains('XYZ'));
});
});
group('AOTSnapshotter', () {
MemoryFileSystem fileSystem;
AOTSnapshotter snapshotter;
Artifacts artifacts;
FakeProcessManager processManager;
Logger logger;
setUp(() async {
final Platform platform = FakePlatform(operatingSystem: 'macos');
logger = BufferLogger.test();
fileSystem = MemoryFileSystem.test();
artifacts = Artifacts.test();
processManager = FakeProcessManager.list(<FakeCommand>[]);
snapshotter = AOTSnapshotter(
fileSystem: fileSystem,
logger: logger,
xcode: Xcode(
fileSystem: fileSystem,
logger: logger,
platform: FakePlatform(operatingSystem: 'macos'),
processManager: processManager,
xcodeProjectInterpreter: XcodeProjectInterpreter(
platform: platform,
processManager: processManager,
logger: logger,
fileSystem: fileSystem,
terminal: Terminal.test(),
usage: Usage.test(),
),
),
artifacts: artifacts,
processManager: processManager,
);
});
testWithoutContext('does not build iOS with debug build mode', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
expect(await snapshotter.build(
platform: TargetPlatform.ios,
darwinArch: DarwinArch.arm64,
buildMode: BuildMode.debug,
mainPath: 'main.dill',
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
), isNot(equals(0)));
});
testWithoutContext('does not build android-arm with debug build mode', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
expect(await snapshotter.build(
platform: TargetPlatform.android_arm,
buildMode: BuildMode.debug,
mainPath: 'main.dill',
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
), isNot(0));
});
testWithoutContext('does not build android-arm64 with debug build mode', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
expect(await snapshotter.build(
platform: TargetPlatform.android_arm64,
buildMode: BuildMode.debug,
mainPath: 'main.dill',
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
), isNot(0));
});
testWithoutContext('builds iOS with bitcode', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
final String assembly = fileSystem.path.join(outputPath, 'snapshot_assembly.S');
processManager.addCommand(FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.ios, mode: BuildMode.profile) +'_armv7',
'--deterministic',
'--snapshot_kind=app-aot-assembly',
'--assembly=$assembly',
'--strip',
'--no-sim-use-hardfp',
'--no-use-integer-division',
'--no-causal-async-stacks',
'--lazy-async-stacks',
'main.dill',
]
));
processManager.addCommand(kARMCheckCommand);
processManager.addCommand(kSdkPathCommand);
processManager.addCommand(const FakeCommand(
command: <String>[
'xcrun',
'cc',
'-arch',
'armv7',
'-isysroot',
'',
'-fembed-bitcode',
'-c',
'build/foo/snapshot_assembly.S',
'-o',
'build/foo/snapshot_assembly.o',
]
));
processManager.addCommand(const FakeCommand(
command: <String>[
'xcrun',
'clang',
'-arch',
'armv7',
...kBitcodeClang,
]
));
final int genSnapshotExitCode = await snapshotter.build(
platform: TargetPlatform.ios,
buildMode: BuildMode.profile,
mainPath: 'main.dill',
outputPath: outputPath,
darwinArch: DarwinArch.armv7,
bitcode: true,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
expect(processManager.hasRemainingExpectations, false);
});
testWithoutContext('builds iOS armv7 snapshot with dwarStackTraces', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
final String assembly = fileSystem.path.join(outputPath, 'snapshot_assembly.S');
final String debugPath = fileSystem.path.join('foo', 'app.ios-armv7.symbols');
processManager.addCommand(FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.ios, mode: BuildMode.profile) +'_armv7',
'--deterministic',
'--snapshot_kind=app-aot-assembly',
'--assembly=$assembly',
'--strip',
'--no-sim-use-hardfp',
'--no-use-integer-division',
'--no-causal-async-stacks',
'--lazy-async-stacks',
'--dwarf-stack-traces',
'--save-debugging-info=$debugPath',
'main.dill',
]
));
processManager.addCommand(kARMCheckCommand);
processManager.addCommand(kSdkPathCommand);
processManager.addCommand(const FakeCommand(
command: <String>[
'xcrun',
'cc',
'-arch',
'armv7',
'-isysroot',
'',
'-c',
'build/foo/snapshot_assembly.S',
'-o',
'build/foo/snapshot_assembly.o',
]
));
processManager.addCommand(const FakeCommand(
command: <String>[
'xcrun',
'clang',
'-arch',
'armv7',
...kDefaultClang,
]
));
final int genSnapshotExitCode = await snapshotter.build(
platform: TargetPlatform.ios,
buildMode: BuildMode.profile,
mainPath: 'main.dill',
outputPath: outputPath,
darwinArch: DarwinArch.armv7,
bitcode: false,
splitDebugInfo: 'foo',
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
expect(processManager.hasRemainingExpectations, false);
});
testWithoutContext('builds iOS armv7 snapshot with obfuscate', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
final String assembly = fileSystem.path.join(outputPath, 'snapshot_assembly.S');
processManager.addCommand(FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.ios, mode: BuildMode.profile) +'_armv7',
'--deterministic',
'--snapshot_kind=app-aot-assembly',
'--assembly=$assembly',
'--strip',
'--no-sim-use-hardfp',
'--no-use-integer-division',
'--no-causal-async-stacks',
'--lazy-async-stacks',
'--obfuscate',
'main.dill',
]
));
processManager.addCommand(kARMCheckCommand);
processManager.addCommand(kSdkPathCommand);
processManager.addCommand(const FakeCommand(
command: <String>[
'xcrun',
'cc',
'-arch',
'armv7',
'-isysroot',
'',
'-c',
'build/foo/snapshot_assembly.S',
'-o',
'build/foo/snapshot_assembly.o',
]
));
processManager.addCommand(const FakeCommand(
command: <String>[
'xcrun',
'clang',
'-arch',
'armv7',
...kDefaultClang,
]
));
final int genSnapshotExitCode = await snapshotter.build(
platform: TargetPlatform.ios,
buildMode: BuildMode.profile,
mainPath: 'main.dill',
outputPath: outputPath,
darwinArch: DarwinArch.armv7,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: true,
);
expect(genSnapshotExitCode, 0);
expect(processManager.hasRemainingExpectations, false);
});
testWithoutContext('builds iOS armv7 snapshot', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
processManager.addCommand(FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.ios, mode: BuildMode.release) +'_armv7',
'--deterministic',
'--snapshot_kind=app-aot-assembly',
'--assembly=${fileSystem.path.join(outputPath, 'snapshot_assembly.S')}',
'--strip',
'--no-sim-use-hardfp',
'--no-use-integer-division',
'--no-causal-async-stacks',
'--lazy-async-stacks',
'main.dill',
]
));
processManager.addCommand(kARMCheckCommand);
processManager.addCommand(kSdkPathCommand);
processManager.addCommand(const FakeCommand(
command: <String>[
'xcrun',
'cc',
'-arch',
'armv7',
'-isysroot',
'',
'-c',
'build/foo/snapshot_assembly.S',
'-o',
'build/foo/snapshot_assembly.o',
]
));
processManager.addCommand(const FakeCommand(
command: <String>[
'xcrun',
'clang',
'-arch',
'armv7',
...kDefaultClang,
]
));
final int genSnapshotExitCode = await snapshotter.build(
platform: TargetPlatform.ios,
buildMode: BuildMode.release,
mainPath: 'main.dill',
outputPath: outputPath,
darwinArch: DarwinArch.armv7,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
expect(processManager.hasRemainingExpectations, false);
});
testWithoutContext('builds iOS arm64 snapshot', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
processManager.addCommand(FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.ios, mode: BuildMode.release) +'_arm64',
'--deterministic',
'--snapshot_kind=app-aot-assembly',
'--assembly=${fileSystem.path.join(outputPath, 'snapshot_assembly.S')}',
'--strip',
'--no-causal-async-stacks',
'--lazy-async-stacks',
'main.dill',
]
));
processManager.addCommand(kARMCheckCommand);
processManager.addCommand(kSdkPathCommand);
processManager.addCommand(const FakeCommand(
command: <String>[
'xcrun',
'cc',
'-arch',
'arm64',
'-isysroot',
'',
'-c',
'build/foo/snapshot_assembly.S',
'-o',
'build/foo/snapshot_assembly.o',
]
));
processManager.addCommand(const FakeCommand(
command: <String>[
'xcrun',
'clang',
'-arch',
'arm64',
...kDefaultClang,
]
));
final int genSnapshotExitCode = await snapshotter.build(
platform: TargetPlatform.ios,
buildMode: BuildMode.release,
mainPath: 'main.dill',
outputPath: outputPath,
darwinArch: DarwinArch.arm64,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
expect(processManager.hasRemainingExpectations, false);
});
testWithoutContext('builds shared library for android-arm (32bit)', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
processManager.addCommand(FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.android_arm, mode: BuildMode.release),
'--deterministic',
'--snapshot_kind=app-aot-elf',
'--elf=build/foo/app.so',
'--strip',
'--no-sim-use-hardfp',
'--no-use-integer-division',
'--no-causal-async-stacks',
'--lazy-async-stacks',
'main.dill',
]
));
final int genSnapshotExitCode = await snapshotter.build(
platform: TargetPlatform.android_arm,
buildMode: BuildMode.release,
mainPath: 'main.dill',
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
expect(processManager.hasRemainingExpectations, false);
});
testWithoutContext('builds shared library for android-arm with dwarf stack traces', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
final String debugPath = fileSystem.path.join('foo', 'app.android-arm.symbols');
processManager.addCommand(FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.android_arm, mode: BuildMode.release),
'--deterministic',
'--snapshot_kind=app-aot-elf',
'--elf=build/foo/app.so',
'--strip',
'--no-sim-use-hardfp',
'--no-use-integer-division',
'--no-causal-async-stacks',
'--lazy-async-stacks',
'--dwarf-stack-traces',
'--save-debugging-info=$debugPath',
'main.dill',
]
));
final int genSnapshotExitCode = await snapshotter.build(
platform: TargetPlatform.android_arm,
buildMode: BuildMode.release,
mainPath: 'main.dill',
outputPath: outputPath,
bitcode: false,
splitDebugInfo: 'foo',
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
expect(processManager.hasRemainingExpectations, false);
});
testWithoutContext('builds shared library for android-arm with obfuscate', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
processManager.addCommand(FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.android_arm, mode: BuildMode.release),
'--deterministic',
'--snapshot_kind=app-aot-elf',
'--elf=build/foo/app.so',
'--strip',
'--no-sim-use-hardfp',
'--no-use-integer-division',
'--no-causal-async-stacks',
'--lazy-async-stacks',
'--obfuscate',
'main.dill',
]
));
final int genSnapshotExitCode = await snapshotter.build(
platform: TargetPlatform.android_arm,
buildMode: BuildMode.release,
mainPath: 'main.dill',
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: true,
);
expect(genSnapshotExitCode, 0);
expect(processManager.hasRemainingExpectations, false);
});
testWithoutContext('builds shared library for android-arm without dwarf stack traces due to empty string', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
processManager.addCommand(FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.android_arm, mode: BuildMode.release),
'--deterministic',
'--snapshot_kind=app-aot-elf',
'--elf=build/foo/app.so',
'--strip',
'--no-sim-use-hardfp',
'--no-use-integer-division',
'--no-causal-async-stacks',
'--lazy-async-stacks',
'main.dill',
]
));
final int genSnapshotExitCode = await snapshotter.build(
platform: TargetPlatform.android_arm,
buildMode: BuildMode.release,
mainPath: 'main.dill',
outputPath: outputPath,
bitcode: false,
splitDebugInfo: '',
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
expect(processManager.hasRemainingExpectations, false);
});
testWithoutContext('builds shared library for android-arm64', () async {
final String outputPath = fileSystem.path.join('build', 'foo');
processManager.addCommand(FakeCommand(
command: <String>[
artifacts.getArtifactPath(Artifact.genSnapshot, platform: TargetPlatform.android_arm64, mode: BuildMode.release),
'--deterministic',
'--snapshot_kind=app-aot-elf',
'--elf=build/foo/app.so',
'--strip',
'--no-causal-async-stacks',
'--lazy-async-stacks',
'main.dill',
]
));
final int genSnapshotExitCode = await snapshotter.build(
platform: TargetPlatform.android_arm64,
buildMode: BuildMode.release,
mainPath: 'main.dill',
outputPath: outputPath,
bitcode: false,
splitDebugInfo: null,
dartObfuscation: false,
);
expect(genSnapshotExitCode, 0);
expect(processManager.hasRemainingExpectations, false);
});
});
}