| // Copyright 2013 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/file.dart'; |
| import 'package:platform/platform.dart'; |
| |
| import 'common/core.dart'; |
| import 'common/package_looping_command.dart'; |
| import 'common/plugin_utils.dart'; |
| import 'common/process_runner.dart'; |
| import 'common/repository_package.dart'; |
| import 'common/xcode.dart'; |
| |
| /// The command to run Xcode's static analyzer on plugins. |
| class XcodeAnalyzeCommand extends PackageLoopingCommand { |
| /// Creates an instance of the test command. |
| XcodeAnalyzeCommand( |
| Directory packagesDir, { |
| ProcessRunner processRunner = const ProcessRunner(), |
| Platform platform = const LocalPlatform(), |
| }) : _xcode = Xcode(processRunner: processRunner, log: true), |
| super(packagesDir, processRunner: processRunner, platform: platform) { |
| argParser.addFlag(platformIOS, help: 'Analyze iOS'); |
| argParser.addFlag(platformMacOS, help: 'Analyze macOS'); |
| argParser.addOption(_minIOSVersionArg, |
| help: 'Sets the minimum iOS deployment version to use when compiling, ' |
| 'overriding the default minimum version. This can be used to find ' |
| 'deprecation warnings that will affect the plugin in the future.'); |
| argParser.addOption(_minMacOSVersionArg, |
| help: |
| 'Sets the minimum macOS deployment version to use when compiling, ' |
| 'overriding the default minimum version. This can be used to find ' |
| 'deprecation warnings that will affect the plugin in the future.'); |
| } |
| |
| static const String _minIOSVersionArg = 'ios-min-version'; |
| static const String _minMacOSVersionArg = 'macos-min-version'; |
| |
| final Xcode _xcode; |
| |
| @override |
| final String name = 'xcode-analyze'; |
| |
| @override |
| final String description = |
| 'Runs Xcode analysis on the iOS and/or macOS example apps.'; |
| |
| @override |
| Future<void> initializeRun() async { |
| if (!(getBoolArg(platformIOS) || getBoolArg(platformMacOS))) { |
| printError('At least one platform flag must be provided.'); |
| throw ToolExit(exitInvalidArguments); |
| } |
| } |
| |
| @override |
| Future<PackageResult> runForPackage(RepositoryPackage package) async { |
| final bool testIOS = getBoolArg(platformIOS) && |
| pluginSupportsPlatform(platformIOS, package, |
| requiredMode: PlatformSupport.inline); |
| final bool testMacOS = getBoolArg(platformMacOS) && |
| pluginSupportsPlatform(platformMacOS, package, |
| requiredMode: PlatformSupport.inline); |
| |
| final bool multiplePlatformsRequested = |
| getBoolArg(platformIOS) && getBoolArg(platformMacOS); |
| if (!(testIOS || testMacOS)) { |
| return PackageResult.skip('Not implemented for target platform(s).'); |
| } |
| |
| final String minIOSVersion = getStringArg(_minIOSVersionArg); |
| final String minMacOSVersion = getStringArg(_minMacOSVersionArg); |
| |
| final List<String> failures = <String>[]; |
| if (testIOS && |
| !await _analyzePlugin(package, 'iOS', extraFlags: <String>[ |
| '-destination', |
| 'generic/platform=iOS Simulator', |
| if (minIOSVersion.isNotEmpty) |
| 'IPHONEOS_DEPLOYMENT_TARGET=$minIOSVersion', |
| ])) { |
| failures.add('iOS'); |
| } |
| if (testMacOS && |
| !await _analyzePlugin(package, 'macOS', extraFlags: <String>[ |
| if (minMacOSVersion.isNotEmpty) |
| 'MACOSX_DEPLOYMENT_TARGET=$minMacOSVersion', |
| ])) { |
| failures.add('macOS'); |
| } |
| |
| // Only provide the failing platform in the failure details if testing |
| // multiple platforms, otherwise it's just noise. |
| return failures.isEmpty |
| ? PackageResult.success() |
| : PackageResult.fail( |
| multiplePlatformsRequested ? failures : <String>[]); |
| } |
| |
| /// Analyzes [plugin] for [platform], returning true if it passed analysis. |
| Future<bool> _analyzePlugin( |
| RepositoryPackage plugin, |
| String platform, { |
| List<String> extraFlags = const <String>[], |
| }) async { |
| bool passing = true; |
| for (final RepositoryPackage example in plugin.getExamples()) { |
| // Running tests and static analyzer. |
| final String examplePath = getRelativePosixPath(example.directory, |
| from: plugin.directory.parent); |
| print('Running $platform tests and analyzer for $examplePath...'); |
| final int exitCode = await _xcode.runXcodeBuild( |
| example.directory, |
| actions: <String>['analyze'], |
| workspace: '${platform.toLowerCase()}/Runner.xcworkspace', |
| scheme: 'Runner', |
| configuration: 'Debug', |
| extraFlags: <String>[ |
| ...extraFlags, |
| 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', |
| ], |
| ); |
| if (exitCode == 0) { |
| printSuccess('$examplePath ($platform) passed analysis.'); |
| } else { |
| printError('$examplePath ($platform) failed analysis.'); |
| passing = false; |
| } |
| } |
| return passing; |
| } |
| } |