blob: 1dc52e35465f772e3e87ed4b4de975678797b419 [file] [log] [blame]
// 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 'dart:convert';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import '../src/common.dart';
import 'test_utils.dart';
class SwiftPackageManagerUtils {
static Future<void> enableSwiftPackageManager(
String flutterBin,
String workingDirectory,
) async {
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'config',
'--enable-swift-package-manager',
'-v',
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to enable Swift Package Manager: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
verbose: true,
);
}
static Future<void> disableSwiftPackageManager(
String flutterBin,
String workingDirectory,
) async {
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'config',
'--no-enable-swift-package-manager',
'-v',
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to disable Swift Package Manager: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
verbose: true,
);
}
static Future<String> createApp(
String flutterBin,
String workingDirectory, {
required String platform,
required String iosLanguage,
required List<String> options,
bool usesSwiftPackageManager = false,
}) async {
final String appTemplateType = usesSwiftPackageManager ? 'spm' : 'default';
final String appName = '${platform}_${iosLanguage}_${appTemplateType}_app';
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'create',
'--org',
'io.flutter.devicelab',
'-i',
iosLanguage,
...options,
appName,
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to create app: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
return fileSystem.path.join(
workingDirectory,
appName,
);
}
static Future<void> buildApp(
String flutterBin,
String workingDirectory, {
required List<String> options,
List<Pattern>? expectedLines,
List<String>? unexpectedLines,
}) async {
final List<Pattern> remainingExpectedLines = expectedLines ?? <Pattern>[];
final List<String> unexpectedLinesFound = <String>[];
final List<String> command = <String>[
flutterBin,
...getLocalEngineArguments(),
'build',
...options,
];
final ProcessResult result = await processManager.run(
command,
workingDirectory: workingDirectory,
);
final List<String> stdout = LineSplitter.split(result.stdout.toString()).toList();
final List<String> stderr = LineSplitter.split(result.stderr.toString()).toList();
final List<String> output = stdout + stderr;
for (final String line in output) {
// Remove "[ +3 ms] " prefix
String trimmedLine = line.trim();
if (trimmedLine.startsWith('[')) {
final int prefixEndIndex = trimmedLine.indexOf(']');
if (prefixEndIndex > 0) {
trimmedLine = trimmedLine
.substring(prefixEndIndex + 1, trimmedLine.length)
.trim();
}
}
remainingExpectedLines.remove(trimmedLine);
remainingExpectedLines.removeWhere((Pattern expectedLine) => trimmedLine.contains(expectedLine));
if (unexpectedLines != null) {
if (unexpectedLines.where((String unexpectedLine) => trimmedLine.contains(unexpectedLine)).firstOrNull != null) {
unexpectedLinesFound.add(trimmedLine);
}
}
}
expect(
result.exitCode,
0,
reason: 'Failed to build app for "${command.join(' ')}":\n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
expect(
remainingExpectedLines,
isEmpty,
reason: 'Did not find expected lines for "${command.join(' ')}":\n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
expect(
unexpectedLinesFound,
isEmpty,
reason: 'Found unexpected lines for "${command.join(' ')}":\n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
}
static Future<void> cleanApp(String flutterBin, String workingDirectory) async {
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'clean',
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to clean app: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
}
static Future<SwiftPackageManagerPlugin> createPlugin(
String flutterBin,
String workingDirectory, {
required String platform,
required String iosLanguage,
bool usesSwiftPackageManager = false,
}) async {
final String dependencyManager = usesSwiftPackageManager ? 'spm' : 'cocoapods';
// Create plugin
final String pluginName = '${platform}_${iosLanguage}_${dependencyManager}_plugin';
final ProcessResult result = await processManager.run(
<String>[
flutterBin,
...getLocalEngineArguments(),
'create',
'--org',
'io.flutter.devicelab',
'--template=plugin',
'--platforms=$platform',
'-i',
iosLanguage,
pluginName,
],
workingDirectory: workingDirectory,
);
expect(
result.exitCode,
0,
reason: 'Failed to create plugin: \n'
'stdout: \n${result.stdout}\n'
'stderr: \n${result.stderr}\n',
);
final Directory pluginDirectory = fileSystem.directory(
fileSystem.path.join(workingDirectory, pluginName),
);
return SwiftPackageManagerPlugin(
pluginName: pluginName,
pluginPath: pluginDirectory.path,
platform: platform,
);
}
static void addDependency({
required SwiftPackageManagerPlugin plugin,
required String appDirectoryPath,
}) {
final File pubspec = fileSystem.file(
fileSystem.path.join(appDirectoryPath, 'pubspec.yaml'),
);
final String pubspecContent = pubspec.readAsStringSync();
pubspec.writeAsStringSync(
pubspecContent.replaceFirst(
'\ndependencies:\n',
'\ndependencies:\n ${plugin.pluginName}:\n path: ${plugin.pluginPath}\n',
),
);
}
static void disableSwiftPackageManagerByPubspec({
required String appDirectoryPath,
}) {
final File pubspec = fileSystem.file(
fileSystem.path.join(appDirectoryPath, 'pubspec.yaml'),
);
final String pubspecContent = pubspec.readAsStringSync();
pubspec.writeAsStringSync(
pubspecContent.replaceFirst(
'\n# The following section is specific to Flutter packages.\nflutter:\n',
'\n# The following section is specific to Flutter packages.\nflutter:\n disable-swift-package-manager: true',
),
);
}
static SwiftPackageManagerPlugin integrationTestPlugin(String platform) {
final String flutterRoot = getFlutterRoot();
return SwiftPackageManagerPlugin(
platform: platform,
pluginName:
(platform == 'ios') ? 'integration_test' : 'integration_test_macos',
pluginPath: (platform == 'ios')
? fileSystem.path.join(flutterRoot, 'packages', 'integration_test')
: fileSystem.path.join(flutterRoot, 'packages', 'integration_test', 'integration_test_macos'),
);
}
static List<Pattern> expectedLines({
required String platform,
required String appDirectoryPath,
SwiftPackageManagerPlugin? cocoaPodsPlugin,
SwiftPackageManagerPlugin? swiftPackagePlugin,
bool swiftPackageMangerEnabled = false,
bool migrated = false,
}) {
final String frameworkName = platform == 'ios' ? 'Flutter' : 'FlutterMacOS';
final String appPlatformDirectoryPath = fileSystem.path.join(
appDirectoryPath,
platform,
);
final List<Pattern> expectedLines = <Pattern>[];
if (swiftPackageMangerEnabled) {
expectedLines.addAll(<String>[
'FlutterGeneratedPluginSwiftPackage: $appPlatformDirectoryPath/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage',
"➜ Explicit dependency on target 'FlutterGeneratedPluginSwiftPackage' in project 'FlutterGeneratedPluginSwiftPackage'",
]);
}
if (swiftPackagePlugin != null) {
// If using a Swift Package plugin, but Swift Package Manager is not enabled, it falls back to being used as a CocoaPods plugin.
if (swiftPackageMangerEnabled) {
expectedLines.addAll(<Pattern>[
RegExp('${swiftPackagePlugin.pluginName}: [/private]*${swiftPackagePlugin.pluginPath}/$platform/${swiftPackagePlugin.pluginName} @ local'),
"➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project '${swiftPackagePlugin.pluginName}'",
]);
} else {
expectedLines.addAll(<String>[
'-> Installing ${swiftPackagePlugin.pluginName} (0.0.1)',
"➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project 'Pods'",
]);
}
}
if (cocoaPodsPlugin != null) {
expectedLines.addAll(<String>[
'Running pod install...',
'-> Installing $frameworkName (1.0.0)',
'-> Installing ${cocoaPodsPlugin.pluginName} (0.0.1)',
"Target 'Pods-Runner' in project 'Pods'",
"➜ Explicit dependency on target '$frameworkName' in project 'Pods'",
"➜ Explicit dependency on target '${cocoaPodsPlugin.pluginName}' in project 'Pods'",
]);
}
if (migrated) {
expectedLines.addAll(<String>[
'Adding Swift Package Manager integration...',
'Running pod install...',
"Target 'Pods-Runner' in project 'Pods'",
]);
}
return expectedLines;
}
static List<String> unexpectedLines({
required String platform,
required String appDirectoryPath,
SwiftPackageManagerPlugin? cocoaPodsPlugin,
SwiftPackageManagerPlugin? swiftPackagePlugin,
bool swiftPackageMangerEnabled = false,
bool migrated = false,
}) {
final String frameworkName = platform == 'ios' ? 'Flutter' : 'FlutterMacOS';
final List<String> unexpectedLines = <String>[];
if (cocoaPodsPlugin == null && !migrated) {
unexpectedLines.addAll(<String>[
'Running pod install...',
'-> Installing $frameworkName (1.0.0)',
"Target 'Pods-Runner' in project 'Pods'",
]);
}
if (swiftPackagePlugin != null) {
if (swiftPackageMangerEnabled) {
unexpectedLines.addAll(<String>[
'-> Installing ${swiftPackagePlugin.pluginName} (0.0.1)',
"➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project 'Pods'",
]);
} else {
unexpectedLines.addAll(<String>[
'${swiftPackagePlugin.pluginName}: ${swiftPackagePlugin.pluginPath}/$platform/${swiftPackagePlugin.pluginName} @ local',
"➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project '${swiftPackagePlugin.pluginName}'",
]);
}
}
if (!migrated) {
unexpectedLines.addAll(<String>[
'Adding Swift Package Manager integration...',
]);
}
return unexpectedLines;
}
}
class SwiftPackageManagerPlugin {
SwiftPackageManagerPlugin({
required this.pluginName,
required this.pluginPath,
required this.platform,
});
final String pluginName;
final String pluginPath;
final String platform;
String get exampleAppPath => fileSystem.path.join(pluginPath, 'example');
String get exampleAppPlatformPath => fileSystem.path.join(exampleAppPath, platform);
}