[go: nahoru, domu]

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

Commit

Permalink
[tool] Check for search paths in Swift plugins (#6954)
Browse files Browse the repository at this point in the history
* Rename command, bump version

* Update tests to write actual podspecs

* Add new check

* Analyzer fix

* Unhdo file move
  • Loading branch information
stuartmorgan committed Jan 13, 2023
1 parent d607cd9 commit e2d174c
Show file tree
Hide file tree
Showing 8 changed files with 513 additions and 235 deletions.
1 change: 1 addition & 0 deletions .ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ targets:
# TODO(stuartmorgan): Move this to ARM once google_maps_flutter has ARM
# support. `pod lint` makes a synthetic target that doesn't respect the
# pod's arch exclusions, so fails to build.
# When moving it, rename the task and file to check_podspecs
- name: Mac_x64 lint_podspecs
recipe: plugins/plugins
timeout: 30
Expand Down
4 changes: 2 additions & 2 deletions .ci/targets/mac_lint_podspecs.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
tasks:
- name: prepare tool
script: .ci/scripts/prepare_tool.sh
- name: lint iOS and macOS podspecs
- name: validate iOS and macOS podspecs
script: script/tool_runner.sh
args: ["podspecs"]
args: ["podspec-check"]
6 changes: 6 additions & 0 deletions script/tool/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.13.3

* Renames `podspecs` to `podspec-check`. The old name will continue to work.
* Adds validation of the Swift-in-Obj-C-projects workaround in the podspecs of
iOS plugin implementations that use Swift.

## 0.13.2+1

* Replaces deprecated `flutter format` with `dart format` in `format`
Expand Down
4 changes: 2 additions & 2 deletions script/tool/lib/src/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ import 'fix_command.dart';
import 'format_command.dart';
import 'license_check_command.dart';
import 'lint_android_command.dart';
import 'lint_podspecs_command.dart';
import 'list_command.dart';
import 'make_deps_path_based_command.dart';
import 'native_test_command.dart';
import 'podspec_check_command.dart';
import 'publish_check_command.dart';
import 'publish_command.dart';
import 'pubspec_check_command.dart';
Expand Down Expand Up @@ -66,7 +66,7 @@ void main(List<String> args) {
..addCommand(FormatCommand(packagesDir))
..addCommand(LicenseCheckCommand(packagesDir))
..addCommand(LintAndroidCommand(packagesDir))
..addCommand(LintPodspecsCommand(packagesDir))
..addCommand(PodspecCheckCommand(packagesDir))
..addCommand(ListCommand(packagesDir))
..addCommand(NativeTestCommand(packagesDir))
..addCommand(MakeDepsPathBasedCommand(packagesDir))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import 'dart:convert';
import 'dart:io';

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

import 'common/core.dart';
Expand All @@ -20,23 +19,24 @@ const int _exitPodNotInstalled = 3;
/// Lint the CocoaPod podspecs and run unit tests.
///
/// See https://guides.cocoapods.org/terminal/commands.html#pod_lib_lint.
class LintPodspecsCommand extends PackageLoopingCommand {
class PodspecCheckCommand extends PackageLoopingCommand {
/// Creates an instance of the linter command.
LintPodspecsCommand(
PodspecCheckCommand(
Directory packagesDir, {
ProcessRunner processRunner = const ProcessRunner(),
Platform platform = const LocalPlatform(),
}) : super(packagesDir, processRunner: processRunner, platform: platform);

@override
final String name = 'podspecs';
final String name = 'podspec-check';

@override
List<String> get aliases => <String>['podspec'];
List<String> get aliases => <String>['podspec', 'podspecs'];

@override
final String description =
'Runs "pod lib lint" on all iOS and macOS plugin podspecs.\n\n'
'Runs "pod lib lint" on all iOS and macOS plugin podspecs, as well as '
'making sure the podspecs follow repository standards.\n\n'
'This command requires "pod" and "flutter" to be in your path. Runs on macOS only.';

@override
Expand Down Expand Up @@ -69,9 +69,32 @@ class LintPodspecsCommand extends PackageLoopingCommand {

for (final File podspec in podspecs) {
if (!await _lintPodspec(podspec)) {
errors.add(p.basename(podspec.path));
errors.add(podspec.basename);
}
}

if (await _hasIOSSwiftCode(package)) {
print('iOS Swift code found, checking for search paths settings...');
for (final File podspec in podspecs) {
if (_isPodspecMissingSearchPaths(podspec)) {
const String workaroundBlock = r'''
s.xcconfig = {
'LIBRARY_SEARCH_PATHS' => '$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift',
'LD_RUNPATH_SEARCH_PATHS' => '/usr/lib/swift',
}
''';
final String path =
getRelativePosixPath(podspec, from: package.directory);
printError('$path is missing seach path configuration. Any iOS '
'plugin implementation that contains Swift implementation code '
'needs to contain the following:\n\n'
'$workaroundBlock\n'
'For more details, see https://github.com/flutter/flutter/issues/118418.');
errors.add(podspec.basename);
}
}
}

return errors.isEmpty
? PackageResult.success()
: PackageResult.fail(errors);
Expand All @@ -92,7 +115,7 @@ class LintPodspecsCommand extends PackageLoopingCommand {
// Do not run the static analyzer on plugins with known analyzer issues.
final String podspecPath = podspec.path;

final String podspecBasename = p.basename(podspecPath);
final String podspecBasename = podspec.basename;
print('Linting $podspecBasename');

// Lint plugin as framework (use_frameworks!).
Expand Down Expand Up @@ -126,4 +149,46 @@ class LintPodspecsCommand extends PackageLoopingCommand {
return processRunner.run('pod', arguments,
workingDir: packagesDir, stdoutEncoding: utf8, stderrEncoding: utf8);
}

/// Returns true if there is any iOS plugin implementation code written in
/// Swift.
Future<bool> _hasIOSSwiftCode(RepositoryPackage package) async {
return getFilesForPackage(package).any((File entity) {
final String relativePath =
getRelativePosixPath(entity, from: package.directory);
// Ignore example code.
if (relativePath.startsWith('example/')) {
return false;
}
final String filePath = entity.path;
return path.extension(filePath) == '.swift';
});
}

/// Returns true if [podspec] could apply to iOS, but does not have the
/// workaround for search paths that makes Swift plugins build correctly in
/// Objective-C applications. See
/// https://github.com/flutter/flutter/issues/118418 for context and details.
///
/// This does not check that the plugin has Swift code, and thus whether the
/// workaround is needed, only whether or not it is there.
bool _isPodspecMissingSearchPaths(File podspec) {
final String directory = podspec.parent.basename;
// All macOS Flutter apps are Swift, so macOS-only podspecs don't need the
// workaround. If it's anywhere other than macos/, err or the side of
// assuming it's required.
if (directory == 'macos') {
return false;
}

// This errs on the side of being too strict, to minimize the chance of
// accidental incorrect configuration. If we ever need more flexibility
// due to a false negative we can adjust this as necessary.
final RegExp workaround = RegExp(r'''
\s*s\.(?:ios\.)?xcconfig = {[^}]*
\s*'LIBRARY_SEARCH_PATHS' => '\$\(TOOLCHAIN_DIR\)/usr/lib/swift/\$\(PLATFORM_NAME\)/ \$\(SDKROOT\)/usr/lib/swift',
\s*'LD_RUNPATH_SEARCH_PATHS' => '/usr/lib/swift',[^}]*
\s*}''', dotAll: true);
return !workaround.hasMatch(podspec.readAsStringSync());
}
}
2 changes: 1 addition & 1 deletion script/tool/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: flutter_plugin_tools
description: Productivity utils for flutter/plugins and flutter/packages
repository: https://github.com/flutter/plugins/tree/main/script/tool
version: 0.13.2+1
version: 0.13.3

dependencies:
args: ^2.1.0
Expand Down
Loading

0 comments on commit e2d174c

Please sign in to comment.