Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[tool] Update tool to set macOS deployment target to 10.15. #6605

Merged
merged 11 commits into from
Oct 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 85 additions & 2 deletions script/tool/lib/src/create_all_plugins_app_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,30 @@ import 'dart:io' as io;

import 'package:file/file.dart';
import 'package:path/path.dart' as p;
import 'package:platform/platform.dart';
import 'package:pub_semver/pub_semver.dart';
import 'package:pubspec_parse/pubspec_parse.dart';

import 'common/core.dart';
import 'common/package_command.dart';
import 'common/process_runner.dart';
import 'common/repository_package.dart';

const String _outputDirectoryFlag = 'output-dir';

const int _exitUpdateMacosPodfileFailed = 3;
const int _exitUpdateMacosPbxprojFailed = 4;
const int _exitGenNativeBuildFilesFailed = 5;

/// A command to create an application that builds all in a single application.
class CreateAllPluginsAppCommand extends PackageCommand {
/// Creates an instance of the builder command.
CreateAllPluginsAppCommand(
Directory packagesDir, {
ProcessRunner processRunner = const ProcessRunner(),
Directory? pluginsRoot,
}) : super(packagesDir) {
Platform platform = const LocalPlatform(),
}) : super(packagesDir, processRunner: processRunner, platform: platform) {
final Directory defaultDir =
pluginsRoot ?? packagesDir.fileSystem.currentDirectory;
argParser.addOption(_outputDirectoryFlag,
Expand Down Expand Up @@ -61,10 +69,28 @@ class CreateAllPluginsAppCommand extends PackageCommand {
print('');
}

await _genPubspecWithAllPlugins();

// Run `flutter pub get` to generate all native build files.
// TODO(stuartmorgan): This hangs on Windows for some reason. Since it's
// currently not needed on Windows, skip it there, but we should investigate
// further and/or implement https://github.com/flutter/flutter/issues/93407,
// and remove the need for this conditional.
if (!platform.isWindows) {
if (!await _genNativeBuildFiles()) {
printError(
"Failed to generate native build files via 'flutter pub get'");
throw ToolExit(_exitGenNativeBuildFilesFailed);
}
}

await Future.wait(<Future<void>>[
_genPubspecWithAllPlugins(),
_updateAppGradle(),
_updateManifest(),
_updateMacosPbxproj(),
// This step requires the native file generation triggered by
// flutter pub get above, so can't currently be run on Windows.
if (!platform.isWindows) _updateMacosPodfile(),
]);
}

Expand Down Expand Up @@ -259,4 +285,61 @@ dev_dependencies:${_pubspecMapString(pubspec.devDependencies)}

return buffer.toString();
}

Future<bool> _genNativeBuildFiles() async {
final int exitCode = await processRunner.runAndStream(
flutterCommand,
<String>['pub', 'get'],
workingDir: _appDirectory,
);
return exitCode == 0;
}

Future<void> _updateMacosPodfile() async {
/// Only change the macOS deployment target if the host platform is macOS.
/// The Podfile is not generated on other platforms.
if (!platform.isMacOS) {
return;
}

final File podfileFile =
app.platformDirectory(FlutterPlatform.macos).childFile('Podfile');
if (!podfileFile.existsSync()) {
printError("Can't find Podfile for macOS");
throw ToolExit(_exitUpdateMacosPodfileFailed);
}

final StringBuffer newPodfile = StringBuffer();
for (final String line in podfileFile.readAsLinesSync()) {
if (line.contains('platform :osx')) {
// macOS 10.15 is required by in_app_purchase.
newPodfile.writeln("platform :osx, '10.15'");
} else {
newPodfile.writeln(line);
}
}
podfileFile.writeAsStringSync(newPodfile.toString());
}

Future<void> _updateMacosPbxproj() async {
final File pbxprojFile = app
.platformDirectory(FlutterPlatform.macos)
.childDirectory('Runner.xcodeproj')
.childFile('project.pbxproj');
if (!pbxprojFile.existsSync()) {
printError("Can't find project.pbxproj for macOS");
throw ToolExit(_exitUpdateMacosPbxprojFailed);
}

final StringBuffer newPbxproj = StringBuffer();
for (final String line in pbxprojFile.readAsLinesSync()) {
if (line.contains('MACOSX_DEPLOYMENT_TARGET')) {
// macOS 10.15 is required by in_app_purchase.
newPbxproj.writeln(' MACOSX_DEPLOYMENT_TARGET = 10.15;');
} else {
newPbxproj.writeln(line);
}
}
pbxprojFile.writeAsStringSync(newPbxproj.toString());
}
}
90 changes: 90 additions & 0 deletions script/tool/test/create_all_plugins_app_command_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import 'dart:io' as io;
import 'package:args/command_runner.dart';
import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:flutter_plugin_tools/src/common/core.dart';
import 'package:flutter_plugin_tools/src/create_all_plugins_app_command.dart';
import 'package:platform/platform.dart';
import 'package:test/test.dart';

import 'mocks.dart';
import 'util.dart';

void main() {
Expand All @@ -20,6 +22,7 @@ void main() {
late FileSystem fileSystem;
late Directory testRoot;
late Directory packagesDir;
late RecordingProcessRunner processRunner;

setUp(() {
// Since the core of this command is a call to 'flutter create', the test
Expand All @@ -28,9 +31,11 @@ void main() {
fileSystem = const LocalFileSystem();
testRoot = fileSystem.systemTempDirectory.createTempSync();
packagesDir = testRoot.childDirectory('packages');
processRunner = RecordingProcessRunner();

command = CreateAllPluginsAppCommand(
packagesDir,
processRunner: processRunner,
pluginsRoot: testRoot,
);
runner = CommandRunner<void>(
Expand Down Expand Up @@ -103,6 +108,91 @@ void main() {
baselinePubspec.environment?[dartSdkKey]);
});

test('macOS deployment target is modified in Podfile', () async {
createFakePlugin('plugina', packagesDir);

final File podfileFile = command.packagesDir.parent
.childDirectory('all_plugins')
.childDirectory('macos')
.childFile('Podfile');
podfileFile.createSync(recursive: true);
podfileFile.writeAsStringSync("""
platform :osx, '10.11'
# some other line
""");

await runCapturingPrint(runner, <String>['all-plugins-app']);
final List<String> podfile = command.app
.platformDirectory(FlutterPlatform.macos)
.childFile('Podfile')
.readAsLinesSync();

expect(
podfile,
everyElement((String line) =>
!line.contains('platform :osx') || line.contains("'10.15'")));
},
// Podfile is only generated (and thus only edited) on macOS.
skip: !io.Platform.isMacOS);

test('macOS deployment target is modified in pbxproj', () async {
createFakePlugin('plugina', packagesDir);

await runCapturingPrint(runner, <String>['all-plugins-app']);
final List<String> pbxproj = command.app
.platformDirectory(FlutterPlatform.macos)
.childDirectory('Runner.xcodeproj')
.childFile('project.pbxproj')
.readAsLinesSync();

expect(
pbxproj,
everyElement((String line) =>
!line.contains('MACOSX_DEPLOYMENT_TARGET') ||
line.contains('10.15')));
});

test('calls flutter pub get', () async {
createFakePlugin('plugina', packagesDir);

await runCapturingPrint(runner, <String>['all-plugins-app']);

expect(
processRunner.recordedCalls,
orderedEquals(<ProcessCall>[
ProcessCall(
getFlutterCommand(const LocalPlatform()),
const <String>['pub', 'get'],
testRoot.childDirectory('all_plugins').path),
]));
},
// See comment about Windows in create_all_plugins_app_command.dart
skip: io.Platform.isWindows);

test('fails if flutter pub get fails', () async {
createFakePlugin('plugina', packagesDir);

processRunner.mockProcessesForExecutable[
getFlutterCommand(const LocalPlatform())] = <io.Process>[
MockProcess(exitCode: 1)
];
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['all-plugins-app'], errorHandler: (Error e) {
commandError = e;
});

expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(<Matcher>[
contains(
"Failed to generate native build files via 'flutter pub get'"),
]));
},
// See comment about Windows in create_all_plugins_app_command.dart
skip: io.Platform.isWindows);

test('handles --output-dir', () async {
createFakePlugin('plugina', packagesDir);

Expand Down