mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
flutter build aar
regenerates tooling between each build-mode step (#162705)
Closes https://github.com/flutter/flutter/issues/162703. I still need to do a similar change for `ios|macos`-`framework` in https://github.com/flutter/flutter/issues/162704. I added two unit tests, as well as opted in an integration test to the flag (it will become the default in https://github.com/flutter/flutter/pull/160289). /cc @reidbaker @gmackall.
This commit is contained in:
parent
f219bbac55
commit
0e59f0f64c
@ -21,6 +21,11 @@ Future<void> main() async {
|
|||||||
}
|
}
|
||||||
print('\nUsing JAVA_HOME=$javaHome');
|
print('\nUsing JAVA_HOME=$javaHome');
|
||||||
|
|
||||||
|
// TODO(matanlurey): Remove after default.
|
||||||
|
// https://github.com/flutter/flutter/issues/160257
|
||||||
|
section('Opt-in to --explicit-package-dependencies');
|
||||||
|
await flutter('config', options: <String>['--explicit-package-dependencies']);
|
||||||
|
|
||||||
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.');
|
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.');
|
||||||
final Directory projectDir = Directory(path.join(tempDir.path, 'hello'));
|
final Directory projectDir = Directory(path.join(tempDir.path, 'hello'));
|
||||||
try {
|
try {
|
||||||
|
@ -19,6 +19,7 @@ abstract class AndroidBuilder {
|
|||||||
required FlutterProject project,
|
required FlutterProject project,
|
||||||
required Set<AndroidBuildInfo> androidBuildInfo,
|
required Set<AndroidBuildInfo> androidBuildInfo,
|
||||||
required String target,
|
required String target,
|
||||||
|
required Future<void> Function(FlutterProject, {required bool releaseMode}) generateTooling,
|
||||||
String? outputDirectoryPath,
|
String? outputDirectoryPath,
|
||||||
required String buildNumber,
|
required String buildNumber,
|
||||||
});
|
});
|
||||||
|
@ -191,6 +191,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
|
|||||||
required FlutterProject project,
|
required FlutterProject project,
|
||||||
required Set<AndroidBuildInfo> androidBuildInfo,
|
required Set<AndroidBuildInfo> androidBuildInfo,
|
||||||
required String target,
|
required String target,
|
||||||
|
required Future<void> Function(FlutterProject, {required bool releaseMode}) generateTooling,
|
||||||
String? outputDirectoryPath,
|
String? outputDirectoryPath,
|
||||||
required String buildNumber,
|
required String buildNumber,
|
||||||
}) async {
|
}) async {
|
||||||
@ -208,6 +209,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
|
|||||||
_logger.printWarning(androidX86DeprecationWarning);
|
_logger.printWarning(androidX86DeprecationWarning);
|
||||||
}
|
}
|
||||||
for (final AndroidBuildInfo androidBuildInfo in androidBuildInfo) {
|
for (final AndroidBuildInfo androidBuildInfo in androidBuildInfo) {
|
||||||
|
await generateTooling(project, releaseMode: androidBuildInfo.buildInfo.isRelease);
|
||||||
await buildGradleAar(
|
await buildGradleAar(
|
||||||
project: project,
|
project: project,
|
||||||
androidBuildInfo: androidBuildInfo,
|
androidBuildInfo: androidBuildInfo,
|
||||||
|
@ -111,6 +111,9 @@ class BuildAarCommand extends BuildSubCommand {
|
|||||||
await super.validateCommand();
|
await super.validateCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get regeneratePlatformSpecificToolingDurifyVerify => false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<FlutterCommandResult> runCommand() async {
|
Future<FlutterCommandResult> runCommand() async {
|
||||||
if (_androidSdk == null) {
|
if (_androidSdk == null) {
|
||||||
@ -149,10 +152,12 @@ class BuildAarCommand extends BuildSubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
displayNullSafetyMode(androidBuildInfo.first.buildInfo);
|
displayNullSafetyMode(androidBuildInfo.first.buildInfo);
|
||||||
|
|
||||||
await androidBuilder?.buildAar(
|
await androidBuilder?.buildAar(
|
||||||
project: project,
|
project: project,
|
||||||
target: targetFile.path,
|
target: targetFile.path,
|
||||||
androidBuildInfo: androidBuildInfo,
|
androidBuildInfo: androidBuildInfo,
|
||||||
|
generateTooling: regeneratePlatformSpecificToolingIfApplicable,
|
||||||
outputDirectoryPath: stringArg('output'),
|
outputDirectoryPath: stringArg('output'),
|
||||||
buildNumber: buildNumber,
|
buildNumber: buildNumber,
|
||||||
);
|
);
|
||||||
|
@ -1893,22 +1893,15 @@ Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and
|
|||||||
buildSystem: globals.buildSystem,
|
buildSystem: globals.buildSystem,
|
||||||
buildTargets: globals.buildTargets,
|
buildTargets: globals.buildTargets,
|
||||||
);
|
);
|
||||||
|
|
||||||
// null implicitly means all plugins are allowed
|
|
||||||
List<String>? allowedPlugins;
|
|
||||||
if (stringArg(FlutterGlobalOptions.kDeviceIdOption, global: true) == 'preview') {
|
|
||||||
// The preview device does not currently support any plugins.
|
|
||||||
allowedPlugins = PreviewDevice.supportedPubPlugins;
|
|
||||||
}
|
|
||||||
await project.regeneratePlatformSpecificTooling(
|
|
||||||
allowedPlugins: allowedPlugins,
|
|
||||||
releaseMode: featureFlags.isExplicitPackageDependenciesEnabled && getBuildMode().isRelease,
|
|
||||||
);
|
|
||||||
if (reportNullSafety) {
|
if (reportNullSafety) {
|
||||||
await _sendNullSafetyAnalyticsEvents(project);
|
await _sendNullSafetyAnalyticsEvents(project);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (regeneratePlatformSpecificToolingDurifyVerify) {
|
||||||
|
await regeneratePlatformSpecificToolingIfApplicable(project);
|
||||||
|
}
|
||||||
|
|
||||||
setupApplicationPackages();
|
setupApplicationPackages();
|
||||||
|
|
||||||
if (commandPath != null) {
|
if (commandPath != null) {
|
||||||
@ -1918,6 +1911,66 @@ Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and
|
|||||||
return runCommand();
|
return runCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether to run [regeneratePlatformSpecificTooling] in [verifyThenRunCommand].
|
||||||
|
///
|
||||||
|
/// By default `true`, but sub-commands that do _meta_ builds (make multiple different
|
||||||
|
/// builds sequentially in one-go) may choose to override this and provide `false`, instead
|
||||||
|
/// calling [regeneratePlatformSpecificTooling] manually when applicable.
|
||||||
|
@visibleForOverriding
|
||||||
|
bool get regeneratePlatformSpecificToolingDurifyVerify => true;
|
||||||
|
|
||||||
|
/// Runs [FlutterProject.regeneratePlatformSpecificTooling] for [project] with appropriate configuration.
|
||||||
|
///
|
||||||
|
/// By default, this uses [getBuildMode] to determine and provide whether a release build is being made,
|
||||||
|
/// but sub-commands (such as commands that do _meta_ builds, or builds that make multiple different builds
|
||||||
|
/// sequentially in one-go) may choose to overide this and make the call at a different point in time.
|
||||||
|
///
|
||||||
|
/// This method should only be called when [shouldRunPub] is `true`:
|
||||||
|
/// ```dart
|
||||||
|
/// if (shouldRunPub) {
|
||||||
|
/// await regeneratePlatformSpecificTooling(project);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// - <https://github.com/flutter/flutter/issues/162649>.
|
||||||
|
@protected
|
||||||
|
@nonVirtual
|
||||||
|
Future<void> regeneratePlatformSpecificToolingIfApplicable(
|
||||||
|
FlutterProject project, {
|
||||||
|
bool? releaseMode,
|
||||||
|
}) async {
|
||||||
|
if (!shouldRunPub) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(matanlurey): Determine if PreviewDevice should be kept.
|
||||||
|
// https://github.com/flutter/flutter/issues/162693
|
||||||
|
final List<String>? allowedPlugins;
|
||||||
|
if (stringArg(FlutterGlobalOptions.kDeviceIdOption, global: true) == 'preview') {
|
||||||
|
// The preview device does not currently support any plugins.
|
||||||
|
allowedPlugins = PreviewDevice.supportedPubPlugins;
|
||||||
|
} else {
|
||||||
|
// null means all plugins are allowed
|
||||||
|
allowedPlugins = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
await project.regeneratePlatformSpecificTooling(
|
||||||
|
allowedPlugins: allowedPlugins,
|
||||||
|
// TODO(matanlurey): Move this up, i.e. releaseMode ??= getBuildMode().release.
|
||||||
|
//
|
||||||
|
// As it stands, this is a breaking change until https://github.com/flutter/flutter/issues/162704 is
|
||||||
|
// implemented, as the build_ios_framework command (and similar) will start querying
|
||||||
|
// for getBuildMode(), causing an error (meta-build commands like build ios-framework do not have
|
||||||
|
// a single build mode). Once ios-framework and macos-framework are migrated, then this can be
|
||||||
|
// cleaned up.
|
||||||
|
releaseMode:
|
||||||
|
featureFlags.isExplicitPackageDependenciesEnabled &&
|
||||||
|
(releaseMode ?? getBuildMode().isRelease),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _sendNullSafetyAnalyticsEvents(FlutterProject project) async {
|
Future<void> _sendNullSafetyAnalyticsEvents(FlutterProject project) async {
|
||||||
final BuildInfo buildInfo = await getBuildInfo();
|
final BuildInfo buildInfo = await getBuildInfo();
|
||||||
NullSafetyAnalysisEvent(
|
NullSafetyAnalysisEvent(
|
||||||
|
@ -13,6 +13,7 @@ import 'package:flutter_tools/src/base/logger.dart';
|
|||||||
import 'package:flutter_tools/src/build_info.dart';
|
import 'package:flutter_tools/src/build_info.dart';
|
||||||
import 'package:flutter_tools/src/cache.dart';
|
import 'package:flutter_tools/src/cache.dart';
|
||||||
import 'package:flutter_tools/src/commands/build_aar.dart';
|
import 'package:flutter_tools/src/commands/build_aar.dart';
|
||||||
|
import 'package:flutter_tools/src/dart/pub.dart';
|
||||||
import 'package:flutter_tools/src/features.dart';
|
import 'package:flutter_tools/src/features.dart';
|
||||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||||
import 'package:flutter_tools/src/project.dart';
|
import 'package:flutter_tools/src/project.dart';
|
||||||
@ -24,24 +25,42 @@ import '../../src/android_common.dart';
|
|||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
import '../../src/context.dart';
|
import '../../src/context.dart';
|
||||||
import '../../src/fake_process_manager.dart';
|
import '../../src/fake_process_manager.dart';
|
||||||
|
import '../../src/fake_pub_deps.dart';
|
||||||
import '../../src/fakes.dart' hide FakeFlutterProjectFactory;
|
import '../../src/fakes.dart' hide FakeFlutterProjectFactory;
|
||||||
import '../../src/test_flutter_command_runner.dart';
|
import '../../src/test_flutter_command_runner.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
Cache.disableLocking();
|
Cache.disableLocking();
|
||||||
|
|
||||||
Future<BuildAarCommand> runCommandIn(String target, {List<String>? arguments}) async {
|
/// Runs the equivalent of `flutter build aar`.
|
||||||
|
///
|
||||||
|
/// If [arguments] are provided, they are appended to the end, i.e.:
|
||||||
|
/// ```sh
|
||||||
|
/// flutter build aar [arguments]
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// If [androidSdk] is provided, it is used, otherwise defaults to [FakeAndroidSdk].
|
||||||
|
Future<BuildAarCommand> runBuildAar(
|
||||||
|
String target, {
|
||||||
|
AndroidSdk? androidSdk = const _FakeAndroidSdk(),
|
||||||
|
List<String>? arguments,
|
||||||
|
}) async {
|
||||||
final BuildAarCommand command = BuildAarCommand(
|
final BuildAarCommand command = BuildAarCommand(
|
||||||
androidSdk: FakeAndroidSdk(),
|
androidSdk: androidSdk,
|
||||||
fileSystem: globals.fs,
|
fileSystem: globals.fs,
|
||||||
logger: BufferLogger.test(),
|
logger: BufferLogger.test(),
|
||||||
verboseHelp: false,
|
verboseHelp: false,
|
||||||
);
|
);
|
||||||
final CommandRunner<void> runner = createTestCommandRunner(command);
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
await runner.run(<String>['aar', '--no-pub', ...?arguments, target]);
|
await runner.run(<String>['aar', ...?arguments, target]);
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(matanlurey): Remove after `explicit-package-dependencies` is enabled by default.
|
||||||
|
FeatureFlags enableExplicitPackageDependencies() {
|
||||||
|
return TestFeatureFlags(isExplicitPackageDependenciesEnabled: true);
|
||||||
|
}
|
||||||
|
|
||||||
group('Usage', () {
|
group('Usage', () {
|
||||||
late Directory tempDir;
|
late Directory tempDir;
|
||||||
late FakeAnalytics analytics;
|
late FakeAnalytics analytics;
|
||||||
@ -66,7 +85,7 @@ void main() {
|
|||||||
arguments: <String>['--no-pub', '--template=module'],
|
arguments: <String>['--no-pub', '--template=module'],
|
||||||
);
|
);
|
||||||
|
|
||||||
await runCommandIn(projectPath);
|
await runBuildAar(projectPath, arguments: <String>['--no-pub']);
|
||||||
expect(
|
expect(
|
||||||
analytics.sentEvents,
|
analytics.sentEvents,
|
||||||
contains(
|
contains(
|
||||||
@ -80,7 +99,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
overrides: <Type, Generator>{
|
overrides: <Type, Generator>{
|
||||||
AndroidBuilder: () => FakeAndroidBuilder(),
|
AndroidBuilder: () => _CapturingFakeAndroidBuilder(),
|
||||||
Analytics: () => analytics,
|
Analytics: () => analytics,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -93,7 +112,10 @@ void main() {
|
|||||||
arguments: <String>['--no-pub', '--template=module'],
|
arguments: <String>['--no-pub', '--template=module'],
|
||||||
);
|
);
|
||||||
|
|
||||||
await runCommandIn(projectPath, arguments: <String>['--target-platform=android-arm']);
|
await runBuildAar(
|
||||||
|
projectPath,
|
||||||
|
arguments: <String>['--no-pub', '--target-platform=android-arm'],
|
||||||
|
);
|
||||||
expect(
|
expect(
|
||||||
analytics.sentEvents,
|
analytics.sentEvents,
|
||||||
contains(
|
contains(
|
||||||
@ -107,11 +129,36 @@ void main() {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
overrides: <Type, Generator>{
|
overrides: <Type, Generator>{
|
||||||
AndroidBuilder: () => FakeAndroidBuilder(),
|
AndroidBuilder: () => _CapturingFakeAndroidBuilder(),
|
||||||
Analytics: () => analytics,
|
Analytics: () => analytics,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Regression test for https://github.com/flutter/flutter/issues/162649.
|
||||||
|
testUsingContext(
|
||||||
|
'triggers builds even with --pub',
|
||||||
|
() async {
|
||||||
|
final String projectPath = await createProject(
|
||||||
|
tempDir,
|
||||||
|
arguments: <String>['--no-pub', '--template=module'],
|
||||||
|
);
|
||||||
|
|
||||||
|
await runBuildAar(
|
||||||
|
projectPath,
|
||||||
|
arguments: <String>['--target-platform=android-arm'],
|
||||||
|
// If we use --no-pub, it bypasses validation that occurs only on a
|
||||||
|
// build with --pub, which as a consequence means that we aren't
|
||||||
|
// testing every code branch.
|
||||||
|
);
|
||||||
|
},
|
||||||
|
overrides: <Type, Generator>{
|
||||||
|
AndroidBuilder: () => _CapturingFakeAndroidBuilder(),
|
||||||
|
Analytics: () => analytics,
|
||||||
|
FeatureFlags: enableExplicitPackageDependencies,
|
||||||
|
Pub: () => FakePubWithPrimedDeps(allowGet: true),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
testUsingContext(
|
testUsingContext(
|
||||||
'logs success',
|
'logs success',
|
||||||
() async {
|
() async {
|
||||||
@ -120,7 +167,10 @@ void main() {
|
|||||||
arguments: <String>['--no-pub', '--template=module'],
|
arguments: <String>['--no-pub', '--template=module'],
|
||||||
);
|
);
|
||||||
|
|
||||||
await runCommandIn(projectPath, arguments: <String>['--target-platform=android-arm']);
|
await runBuildAar(
|
||||||
|
projectPath,
|
||||||
|
arguments: <String>['--no-pub', '--target-platform=android-arm'],
|
||||||
|
);
|
||||||
|
|
||||||
final Iterable<Event> successEvent = analytics.sentEvents.where(
|
final Iterable<Event> successEvent = analytics.sentEvents.where(
|
||||||
(Event e) =>
|
(Event e) =>
|
||||||
@ -131,7 +181,7 @@ void main() {
|
|||||||
expect(successEvent, isNotEmpty, reason: 'Tool should send create success event');
|
expect(successEvent, isNotEmpty, reason: 'Tool should send create success event');
|
||||||
},
|
},
|
||||||
overrides: <Type, Generator>{
|
overrides: <Type, Generator>{
|
||||||
AndroidBuilder: () => FakeAndroidBuilder(),
|
AndroidBuilder: () => _CapturingFakeAndroidBuilder(),
|
||||||
Analytics: () => analytics,
|
Analytics: () => analytics,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -139,10 +189,10 @@ void main() {
|
|||||||
|
|
||||||
group('flag parsing', () {
|
group('flag parsing', () {
|
||||||
late Directory tempDir;
|
late Directory tempDir;
|
||||||
late FakeAndroidBuilder fakeAndroidBuilder;
|
late _CapturingFakeAndroidBuilder fakeAndroidBuilder;
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
fakeAndroidBuilder = FakeAndroidBuilder();
|
fakeAndroidBuilder = _CapturingFakeAndroidBuilder();
|
||||||
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_build_aar_test.');
|
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_build_aar_test.');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -155,13 +205,19 @@ void main() {
|
|||||||
tempDir,
|
tempDir,
|
||||||
arguments: <String>['--no-pub', '--template=module'],
|
arguments: <String>['--no-pub', '--template=module'],
|
||||||
);
|
);
|
||||||
await runCommandIn(projectPath);
|
await runBuildAar(projectPath, arguments: <String>['--no-pub']);
|
||||||
|
|
||||||
expect(fakeAndroidBuilder.buildNumber, '1.0');
|
expect(
|
||||||
expect(fakeAndroidBuilder.androidBuildInfo.length, 3);
|
fakeAndroidBuilder.capturedBuildAarCalls,
|
||||||
|
hasLength(1),
|
||||||
|
reason: 'A single call to buildAar was expected.',
|
||||||
|
);
|
||||||
|
final Invocation buildAarCall = fakeAndroidBuilder.capturedBuildAarCalls.single;
|
||||||
|
expect(buildAarCall.namedArguments[#buildNumber], '1.0');
|
||||||
|
|
||||||
final List<BuildMode> buildModes = <BuildMode>[];
|
final List<BuildMode> buildModes = <BuildMode>[];
|
||||||
for (final AndroidBuildInfo androidBuildInfo in fakeAndroidBuilder.androidBuildInfo) {
|
for (final AndroidBuildInfo androidBuildInfo
|
||||||
|
in buildAarCall.namedArguments[#androidBuildInfo] as Set<AndroidBuildInfo>) {
|
||||||
final BuildInfo buildInfo = androidBuildInfo.buildInfo;
|
final BuildInfo buildInfo = androidBuildInfo.buildInfo;
|
||||||
buildModes.add(buildInfo.mode);
|
buildModes.add(buildInfo.mode);
|
||||||
if (buildInfo.mode.isPrecompiled) {
|
if (buildInfo.mode.isPrecompiled) {
|
||||||
@ -180,7 +236,7 @@ void main() {
|
|||||||
AndroidArch.x86_64,
|
AndroidArch.x86_64,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
expect(buildModes.length, 3);
|
expect(buildModes, hasLength(3));
|
||||||
expect(
|
expect(
|
||||||
buildModes,
|
buildModes,
|
||||||
containsAll(<BuildMode>[BuildMode.debug, BuildMode.profile, BuildMode.release]),
|
containsAll(<BuildMode>[BuildMode.debug, BuildMode.profile, BuildMode.release]),
|
||||||
@ -192,9 +248,10 @@ void main() {
|
|||||||
tempDir,
|
tempDir,
|
||||||
arguments: <String>['--no-pub', '--template=module'],
|
arguments: <String>['--no-pub', '--template=module'],
|
||||||
);
|
);
|
||||||
await runCommandIn(
|
await runBuildAar(
|
||||||
projectPath,
|
projectPath,
|
||||||
arguments: <String>[
|
arguments: <String>[
|
||||||
|
'--no-pub',
|
||||||
'--no-debug',
|
'--no-debug',
|
||||||
'--no-profile',
|
'--no-profile',
|
||||||
'--target-platform',
|
'--target-platform',
|
||||||
@ -211,9 +268,16 @@ void main() {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(fakeAndroidBuilder.buildNumber, '200');
|
expect(
|
||||||
|
fakeAndroidBuilder.capturedBuildAarCalls,
|
||||||
|
hasLength(1),
|
||||||
|
reason: 'A single call to buildAar was expected.',
|
||||||
|
);
|
||||||
|
final Invocation buildAarCall = fakeAndroidBuilder.capturedBuildAarCalls.single;
|
||||||
|
expect(buildAarCall.namedArguments[#buildNumber], '200');
|
||||||
|
|
||||||
final AndroidBuildInfo androidBuildInfo = fakeAndroidBuilder.androidBuildInfo.single;
|
final AndroidBuildInfo androidBuildInfo =
|
||||||
|
(buildAarCall.namedArguments[#androidBuildInfo] as Set<AndroidBuildInfo>).single;
|
||||||
expect(androidBuildInfo.targetArchs, <AndroidArch>[AndroidArch.x86]);
|
expect(androidBuildInfo.targetArchs, <AndroidArch>[AndroidArch.x86]);
|
||||||
|
|
||||||
final BuildInfo buildInfo = androidBuildInfo.buildInfo;
|
final BuildInfo buildInfo = androidBuildInfo.buildInfo;
|
||||||
@ -229,7 +293,6 @@ void main() {
|
|||||||
|
|
||||||
group('Gradle', () {
|
group('Gradle', () {
|
||||||
late Directory tempDir;
|
late Directory tempDir;
|
||||||
late AndroidSdk mockAndroidSdk;
|
|
||||||
late String gradlew;
|
late String gradlew;
|
||||||
late FakeProcessManager processManager;
|
late FakeProcessManager processManager;
|
||||||
late String flutterRoot;
|
late String flutterRoot;
|
||||||
@ -241,7 +304,6 @@ void main() {
|
|||||||
fs: MemoryFileSystem.test(),
|
fs: MemoryFileSystem.test(),
|
||||||
fakeFlutterVersion: FakeFlutterVersion(),
|
fakeFlutterVersion: FakeFlutterVersion(),
|
||||||
);
|
);
|
||||||
mockAndroidSdk = FakeAndroidSdk();
|
|
||||||
gradlew = globals.fs.path.join(
|
gradlew = globals.fs.path.join(
|
||||||
tempDir.path,
|
tempDir.path,
|
||||||
'flutter_project',
|
'flutter_project',
|
||||||
@ -267,7 +329,7 @@ void main() {
|
|||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
() async {
|
() async {
|
||||||
await runBuildAarCommand(projectPath, null, arguments: <String>['--no-pub']);
|
await runBuildAar(projectPath, androidSdk: null, arguments: <String>['--no-pub']);
|
||||||
},
|
},
|
||||||
throwsToolExit(
|
throwsToolExit(
|
||||||
message: 'No Android SDK found. Try setting the ANDROID_HOME environment variable',
|
message: 'No Android SDK found. Try setting the ANDROID_HOME environment variable',
|
||||||
@ -284,17 +346,19 @@ void main() {
|
|||||||
group('throws ToolExit', () {
|
group('throws ToolExit', () {
|
||||||
testUsingContext('main.dart not found', () async {
|
testUsingContext('main.dart not found', () async {
|
||||||
await expectLater(() async {
|
await expectLater(() async {
|
||||||
await runBuildAarCommand(
|
await runBuildAar(
|
||||||
'missing_project',
|
'missing_project',
|
||||||
mockAndroidSdk,
|
arguments: <String>[
|
||||||
arguments: <String>['--no-pub'],
|
'--no-pub',
|
||||||
|
globals.fs.path.join('missing_project', 'lib', 'main.dart'),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}, throwsToolExit(message: 'main.dart does not exist'));
|
}, throwsToolExit(message: 'main.dart does not exist'));
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('flutter project not valid', () async {
|
testUsingContext('flutter project not valid', () async {
|
||||||
await expectLater(() async {
|
await expectLater(() async {
|
||||||
await runCommandIn(tempDir.path, arguments: <String>['--no-pub']);
|
await runBuildAar(tempDir.path, arguments: <String>['--no-pub']);
|
||||||
}, throwsToolExit(message: 'is not a valid flutter project'));
|
}, throwsToolExit(message: 'is not a valid flutter project'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -330,10 +394,10 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
() => runBuildAarCommand(
|
() => runBuildAar(
|
||||||
projectPath,
|
projectPath,
|
||||||
mockAndroidSdk,
|
|
||||||
arguments: <String>[
|
arguments: <String>[
|
||||||
|
'--no-pub',
|
||||||
'--no-debug',
|
'--no-debug',
|
||||||
'--no-profile',
|
'--no-profile',
|
||||||
'--extra-front-end-options=foo',
|
'--extra-front-end-options=foo',
|
||||||
@ -349,7 +413,7 @@ void main() {
|
|||||||
Java: () => null,
|
Java: () => null,
|
||||||
ProcessManager: () => processManager,
|
ProcessManager: () => processManager,
|
||||||
FeatureFlags: () => TestFeatureFlags(isIOSEnabled: false),
|
FeatureFlags: () => TestFeatureFlags(isIOSEnabled: false),
|
||||||
AndroidStudio: () => FakeAndroidStudio(),
|
AndroidStudio: () => _FakeAndroidStudio(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -393,7 +457,7 @@ void main() {
|
|||||||
arguments: <String>['--no-pub', '--template=module'],
|
arguments: <String>['--no-pub', '--template=module'],
|
||||||
);
|
);
|
||||||
|
|
||||||
await runBuildAarCommand(projectPath, mockAndroidSdk);
|
await runBuildAar(projectPath, arguments: <String>['--no-pub']);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
fakeAnalytics.sentEvents,
|
fakeAnalytics.sentEvents,
|
||||||
@ -404,7 +468,7 @@ void main() {
|
|||||||
},
|
},
|
||||||
overrides: <Type, Generator>{
|
overrides: <Type, Generator>{
|
||||||
Analytics: () => fakeAnalytics,
|
Analytics: () => fakeAnalytics,
|
||||||
AndroidBuilder: () => FakeAndroidBuilder(),
|
AndroidBuilder: () => _CapturingFakeAndroidBuilder(),
|
||||||
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
|
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -427,7 +491,7 @@ void main() {
|
|||||||
value: 'true',
|
value: 'true',
|
||||||
);
|
);
|
||||||
|
|
||||||
await runBuildAarCommand(projectPath, mockAndroidSdk);
|
await runBuildAar(projectPath, arguments: <String>['--no-pub']);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
fakeAnalytics.sentEvents,
|
fakeAnalytics.sentEvents,
|
||||||
@ -438,7 +502,7 @@ void main() {
|
|||||||
},
|
},
|
||||||
overrides: <Type, Generator>{
|
overrides: <Type, Generator>{
|
||||||
Analytics: () => fakeAnalytics,
|
Analytics: () => fakeAnalytics,
|
||||||
AndroidBuilder: () => FakeAndroidBuilder(),
|
AndroidBuilder: () => _CapturingFakeAndroidBuilder(),
|
||||||
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
|
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -461,7 +525,7 @@ void main() {
|
|||||||
value: 'false',
|
value: 'false',
|
||||||
);
|
);
|
||||||
|
|
||||||
await runBuildAarCommand(projectPath, mockAndroidSdk);
|
await runBuildAar(projectPath, arguments: <String>['--no-pub']);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
fakeAnalytics.sentEvents,
|
fakeAnalytics.sentEvents,
|
||||||
@ -472,7 +536,7 @@ void main() {
|
|||||||
},
|
},
|
||||||
overrides: <Type, Generator>{
|
overrides: <Type, Generator>{
|
||||||
Analytics: () => fakeAnalytics,
|
Analytics: () => fakeAnalytics,
|
||||||
AndroidBuilder: () => FakeAndroidBuilder(),
|
AndroidBuilder: () => _CapturingFakeAndroidBuilder(),
|
||||||
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
|
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -480,53 +544,27 @@ void main() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<BuildAarCommand> runBuildAarCommand(
|
/// A fake implementation of [AndroidBuilder] that allows [buildAar] calls.
|
||||||
String target,
|
///
|
||||||
AndroidSdk? androidSdk, {
|
/// Calls to [buildAar] are stored as [capturedBuildAarCalls], other calls are rejected.
|
||||||
List<String>? arguments,
|
final class _CapturingFakeAndroidBuilder extends Fake implements AndroidBuilder {
|
||||||
}) async {
|
final List<Invocation> capturedBuildAarCalls = <Invocation>[];
|
||||||
final BuildAarCommand command = BuildAarCommand(
|
|
||||||
androidSdk: androidSdk,
|
|
||||||
fileSystem: globals.fs,
|
|
||||||
logger: BufferLogger.test(),
|
|
||||||
verboseHelp: false,
|
|
||||||
);
|
|
||||||
final CommandRunner<void> runner = createTestCommandRunner(command);
|
|
||||||
await runner.run(<String>[
|
|
||||||
'aar',
|
|
||||||
'--no-pub',
|
|
||||||
...?arguments,
|
|
||||||
globals.fs.path.join(target, 'lib', 'main.dart'),
|
|
||||||
]);
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
|
|
||||||
class FakeAndroidBuilder extends Fake implements AndroidBuilder {
|
|
||||||
late FlutterProject project;
|
|
||||||
late Set<AndroidBuildInfo> androidBuildInfo;
|
|
||||||
late String target;
|
|
||||||
String? outputDirectoryPath;
|
|
||||||
late String buildNumber;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> buildAar({
|
Object? noSuchMethod(Invocation invocation) {
|
||||||
required FlutterProject project,
|
if (invocation.memberName != #buildAar) {
|
||||||
required Set<AndroidBuildInfo> androidBuildInfo,
|
return super.noSuchMethod(invocation);
|
||||||
required String target,
|
}
|
||||||
String? outputDirectoryPath,
|
capturedBuildAarCalls.add(invocation);
|
||||||
required String buildNumber,
|
return Future<void>.value();
|
||||||
}) async {
|
|
||||||
this.project = project;
|
|
||||||
this.androidBuildInfo = androidBuildInfo;
|
|
||||||
this.target = target;
|
|
||||||
this.outputDirectoryPath = outputDirectoryPath;
|
|
||||||
this.buildNumber = buildNumber;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FakeAndroidSdk extends Fake implements AndroidSdk {}
|
final class _FakeAndroidSdk with Fake implements AndroidSdk {
|
||||||
|
const _FakeAndroidSdk();
|
||||||
|
}
|
||||||
|
|
||||||
class FakeAndroidStudio extends Fake implements AndroidStudio {
|
final class _FakeAndroidStudio extends Fake implements AndroidStudio {
|
||||||
@override
|
@override
|
||||||
String get javaPath => 'java';
|
String get javaPath => 'java';
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import 'package:flutter_tools/src/base/process.dart';
|
|||||||
import 'package:flutter_tools/src/base/user_messages.dart';
|
import 'package:flutter_tools/src/base/user_messages.dart';
|
||||||
import 'package:flutter_tools/src/build_info.dart';
|
import 'package:flutter_tools/src/build_info.dart';
|
||||||
import 'package:flutter_tools/src/cache.dart';
|
import 'package:flutter_tools/src/cache.dart';
|
||||||
|
import 'package:flutter_tools/src/features.dart';
|
||||||
import 'package:flutter_tools/src/project.dart';
|
import 'package:flutter_tools/src/project.dart';
|
||||||
import 'package:test/fake.dart';
|
import 'package:test/fake.dart';
|
||||||
import 'package:unified_analytics/unified_analytics.dart';
|
import 'package:unified_analytics/unified_analytics.dart';
|
||||||
@ -41,6 +42,11 @@ const String minimalV2EmbeddingManifest = r'''
|
|||||||
''';
|
''';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
// TODO(matanlurey): Remove after `explicit-package-dependencies` is enabled by default.
|
||||||
|
FeatureFlags enableExplicitPackageDependencies() {
|
||||||
|
return TestFeatureFlags(isExplicitPackageDependenciesEnabled: true);
|
||||||
|
}
|
||||||
|
|
||||||
group('gradle build', () {
|
group('gradle build', () {
|
||||||
late BufferLogger logger;
|
late BufferLogger logger;
|
||||||
late FakeAnalytics fakeAnalytics;
|
late FakeAnalytics fakeAnalytics;
|
||||||
@ -1566,6 +1572,141 @@ Gradle Crashed
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Regression test for https://github.com/flutter/flutter/issues/162649.
|
||||||
|
testUsingContext(
|
||||||
|
'buildAar generates tooling for each sub-build for AARs',
|
||||||
|
() async {
|
||||||
|
addTearDown(() {
|
||||||
|
printOnFailure(logger.statusText);
|
||||||
|
printOnFailure(logger.errorText);
|
||||||
|
});
|
||||||
|
final AndroidGradleBuilder builder = AndroidGradleBuilder(
|
||||||
|
java: FakeJava(),
|
||||||
|
logger: logger,
|
||||||
|
processManager: processManager,
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
artifacts: Artifacts.test(),
|
||||||
|
analytics: fakeAnalytics,
|
||||||
|
gradleUtils: FakeGradleUtils(),
|
||||||
|
platform: FakePlatform(),
|
||||||
|
androidStudio: FakeAndroidStudio(),
|
||||||
|
);
|
||||||
|
processManager.addCommands(const <FakeCommand>[
|
||||||
|
FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'gradlew',
|
||||||
|
'-I=/packages/flutter_tools/gradle/aar_init_script.gradle',
|
||||||
|
'-Pflutter-root=/',
|
||||||
|
'-Poutput-dir=/build/host',
|
||||||
|
'-Pis-plugin=false',
|
||||||
|
'-PbuildNumber=1.0',
|
||||||
|
'-q',
|
||||||
|
'-Pdart-obfuscation=false',
|
||||||
|
'-Ptrack-widget-creation=false',
|
||||||
|
'-Ptree-shake-icons=false',
|
||||||
|
'-Ptarget-platform=android-arm,android-arm64,android-x64',
|
||||||
|
'assembleAarDebug',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'gradlew',
|
||||||
|
'-I=/packages/flutter_tools/gradle/aar_init_script.gradle',
|
||||||
|
'-Pflutter-root=/',
|
||||||
|
'-Poutput-dir=/build/host',
|
||||||
|
'-Pis-plugin=false',
|
||||||
|
'-PbuildNumber=1.0',
|
||||||
|
'-q',
|
||||||
|
'-Pdart-obfuscation=false',
|
||||||
|
'-Ptrack-widget-creation=false',
|
||||||
|
'-Ptree-shake-icons=false',
|
||||||
|
'-Ptarget-platform=android-arm,android-arm64,android-x64',
|
||||||
|
'assembleAarProfile',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
FakeCommand(
|
||||||
|
command: <String>[
|
||||||
|
'gradlew',
|
||||||
|
'-I=/packages/flutter_tools/gradle/aar_init_script.gradle',
|
||||||
|
'-Pflutter-root=/',
|
||||||
|
'-Poutput-dir=/build/host',
|
||||||
|
'-Pis-plugin=false',
|
||||||
|
'-PbuildNumber=1.0',
|
||||||
|
'-q',
|
||||||
|
'-Pdart-obfuscation=false',
|
||||||
|
'-Ptrack-widget-creation=false',
|
||||||
|
'-Ptree-shake-icons=false',
|
||||||
|
'-Ptarget-platform=android-arm,android-arm64,android-x64',
|
||||||
|
'assembleAarRelease',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
final File manifestFile = fileSystem.file('pubspec.yaml');
|
||||||
|
manifestFile.createSync(recursive: true);
|
||||||
|
manifestFile.writeAsStringSync('''
|
||||||
|
flutter:
|
||||||
|
module:
|
||||||
|
androidPackage: com.example.test
|
||||||
|
''');
|
||||||
|
|
||||||
|
fileSystem.file('.android/gradlew').createSync(recursive: true);
|
||||||
|
fileSystem.file('.android/gradle.properties').writeAsStringSync('irrelevant');
|
||||||
|
fileSystem.file('.android/build.gradle').createSync(recursive: true);
|
||||||
|
fileSystem.directory('build/host/outputs/repo').createSync(recursive: true);
|
||||||
|
|
||||||
|
final List<(FlutterProject, bool)> generateToolingCalls = <(FlutterProject, bool)>[];
|
||||||
|
await builder.buildAar(
|
||||||
|
project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
|
||||||
|
androidBuildInfo: const <AndroidBuildInfo>{
|
||||||
|
AndroidBuildInfo(
|
||||||
|
BuildInfo(
|
||||||
|
BuildMode.debug,
|
||||||
|
null,
|
||||||
|
treeShakeIcons: false,
|
||||||
|
packageConfigPath: '.dart_tool/package_config.json',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AndroidBuildInfo(
|
||||||
|
BuildInfo(
|
||||||
|
BuildMode.profile,
|
||||||
|
null,
|
||||||
|
treeShakeIcons: false,
|
||||||
|
packageConfigPath: '.dart_tool/package_config.json',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AndroidBuildInfo(
|
||||||
|
BuildInfo(
|
||||||
|
BuildMode.release,
|
||||||
|
null,
|
||||||
|
treeShakeIcons: false,
|
||||||
|
packageConfigPath: '.dart_tool/package_config.json',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
target: '',
|
||||||
|
buildNumber: '1.0',
|
||||||
|
generateTooling: (FlutterProject project, {required bool releaseMode}) async {
|
||||||
|
generateToolingCalls.add((project, releaseMode));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
expect(processManager, hasNoRemainingExpectations);
|
||||||
|
|
||||||
|
// Ideally, this should be checked before each invocation to the process,
|
||||||
|
// but instead we'll assume it was invoked in the same order as the calls
|
||||||
|
// to gradle to keep the scope of this test light.
|
||||||
|
expect(generateToolingCalls, hasLength(3));
|
||||||
|
expect(
|
||||||
|
generateToolingCalls.map(((FlutterProject, bool) call) {
|
||||||
|
return call.$2;
|
||||||
|
}),
|
||||||
|
<bool>[false, false, true],
|
||||||
|
reason: 'generateTooling should omit debug metadata for release builds',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
overrides: <Type, Generator>{FeatureFlags: enableExplicitPackageDependencies},
|
||||||
|
);
|
||||||
|
|
||||||
testUsingContext(
|
testUsingContext(
|
||||||
'Verbose mode for AARs includes Gradle stacktrace and sets debug log level',
|
'Verbose mode for AARs includes Gradle stacktrace and sets debug log level',
|
||||||
() async {
|
() async {
|
||||||
|
@ -20,6 +20,7 @@ class FakeAndroidBuilder implements AndroidBuilder {
|
|||||||
required FlutterProject project,
|
required FlutterProject project,
|
||||||
required Set<AndroidBuildInfo> androidBuildInfo,
|
required Set<AndroidBuildInfo> androidBuildInfo,
|
||||||
required String target,
|
required String target,
|
||||||
|
required Future<void> Function(FlutterProject, {required bool releaseMode}) generateTooling,
|
||||||
String? outputDirectoryPath,
|
String? outputDirectoryPath,
|
||||||
required String buildNumber,
|
required String buildNumber,
|
||||||
}) async {}
|
}) async {}
|
||||||
|
@ -16,10 +16,15 @@ final class FakePubWithPrimedDeps implements Pub {
|
|||||||
/// dev-dependencies ([dependencies]) of any package to a set of any other
|
/// dev-dependencies ([dependencies]) of any package to a set of any other
|
||||||
/// packages. A resulting valid `dart pub deps --json` response is implicitly
|
/// packages. A resulting valid `dart pub deps --json` response is implicitly
|
||||||
/// created.
|
/// created.
|
||||||
|
///
|
||||||
|
/// If [allowGet] is `true`, [Pub.get] can be invoked (all the parameters are
|
||||||
|
/// ignored and it is considered a success); otherwise an error is thrown to
|
||||||
|
/// reject an unexpected call.
|
||||||
factory FakePubWithPrimedDeps({
|
factory FakePubWithPrimedDeps({
|
||||||
String rootPackageName = 'app_name',
|
String rootPackageName = 'app_name',
|
||||||
Set<String> devDependencies = const <String>{},
|
Set<String> devDependencies = const <String>{},
|
||||||
Map<String, Set<String>> dependencies = const <String, Set<String>>{},
|
Map<String, Set<String>> dependencies = const <String, Set<String>>{},
|
||||||
|
bool allowGet = false,
|
||||||
}) {
|
}) {
|
||||||
// Start the packages: [ ... ] list with the root package.
|
// Start the packages: [ ... ] list with the root package.
|
||||||
final List<Object?> packages = <Object?>[
|
final List<Object?> packages = <Object?>[
|
||||||
@ -56,11 +61,34 @@ final class FakePubWithPrimedDeps implements Pub {
|
|||||||
return FakePubWithPrimedDeps._(<String, Object?>{
|
return FakePubWithPrimedDeps._(<String, Object?>{
|
||||||
'root': rootPackageName,
|
'root': rootPackageName,
|
||||||
'packages': packages,
|
'packages': packages,
|
||||||
});
|
}, allowGetToSucceed: allowGet);
|
||||||
}
|
}
|
||||||
|
|
||||||
const FakePubWithPrimedDeps._(this._deps);
|
const FakePubWithPrimedDeps._(this._deps, {required bool allowGetToSucceed})
|
||||||
|
: _allowGetToSucceed = allowGetToSucceed;
|
||||||
final Map<String, Object?> _deps;
|
final Map<String, Object?> _deps;
|
||||||
|
final bool _allowGetToSucceed;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> get({
|
||||||
|
required PubContext context,
|
||||||
|
required FlutterProject project,
|
||||||
|
bool upgrade = false,
|
||||||
|
bool offline = false,
|
||||||
|
String? flutterRootOverride,
|
||||||
|
bool checkUpToDate = false,
|
||||||
|
bool shouldSkipThirdPartyGenerator = true,
|
||||||
|
PubOutputMode outputMode = PubOutputMode.all,
|
||||||
|
}) async {
|
||||||
|
if (_allowGetToSucceed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw UnsupportedError(
|
||||||
|
'Instance did not expect <Pub>.get to be invoked. If this was intentional, '
|
||||||
|
'change the constructor of FakePubWithPrimeDeps to include the parameter '
|
||||||
|
'allowGet: true.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, Object?>> deps(FlutterProject project) async => _deps;
|
Future<Map<String, Object?>> deps(FlutterProject project) async => _deps;
|
||||||
|
Loading…
Reference in New Issue
Block a user