Skip to content

Commit 93d8db1

Browse files
stuartmorgan-gjmagman
authored andcommitted
Disable SwiftPM for xcode-analyze
Until flutter/flutter#172427 is resolved, `xcode-analyze` doesn't work as desired with SwiftPM enabled (it analyzes only the test code, not the plugin code). To avoid losing analysis coverage in the meantime, this disabled SwiftPM temporarily while running analysis. This PR also updates `build-examples` to use the newer pubspec-based config option to set the SwiftPM flag state instead of setting global state, to avoid future issues where we are unintentionally bleeding flag changes across different tests, and to make local runs not impact developer machine state. To unit test this functionality, this adds a new feature to the existing process mock system that allows running an arbitrary test callback at the ponit where a process is being run, which in this case allows reading the temporarily-modified pubspec contents at the right point in the command execution. Fixes flutter/flutter#171442
1 parent d909bfc commit 93d8db1

File tree

6 files changed

+207
-230
lines changed

6 files changed

+207
-230
lines changed

script/tool/lib/src/build_examples_command.dart

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -118,20 +118,14 @@ class BuildExamplesCommand extends PackageLoopingCommand {
118118
'arguments.';
119119

120120
/// Returns whether the Swift Package Manager feature should be enabled,
121-
/// disabled, or left to the release channel's default value.
121+
/// disabled, or left to the default value.
122122
bool? get _swiftPackageManagerFeatureConfig {
123123
final List<String> platformFlags = _platforms.keys.toList();
124124
if (!platformFlags.contains(platformIOS) &&
125125
!platformFlags.contains(platformMacOS)) {
126126
return null;
127127
}
128128

129-
// TODO(loic-sharma): Allow enabling on stable once Swift Package Manager
130-
// feature is available on stable.
131-
if (platform.environment['CHANNEL'] != 'master') {
132-
return null;
133-
}
134-
135129
return getNullableBoolArg(_swiftPackageManagerFlag);
136130
}
137131

@@ -150,23 +144,6 @@ class BuildExamplesCommand extends PackageLoopingCommand {
150144
'were specified. At least one platform must be provided.');
151145
throw ToolExit(_exitNoPlatformFlags);
152146
}
153-
154-
switch (_swiftPackageManagerFeatureConfig) {
155-
case true:
156-
await processRunner.runAndStream(
157-
flutterCommand,
158-
<String>['config', '--enable-swift-package-manager'],
159-
exitOnError: true,
160-
);
161-
case false:
162-
await processRunner.runAndStream(
163-
flutterCommand,
164-
<String>['config', '--no-enable-swift-package-manager'],
165-
exitOnError: true,
166-
);
167-
case null:
168-
break;
169-
}
170147
}
171148

172149
@override
@@ -212,8 +189,20 @@ class BuildExamplesCommand extends PackageLoopingCommand {
212189
}
213190
print('');
214191

192+
final bool? swiftPackageManagerOverride =
193+
isPlugin ? _swiftPackageManagerFeatureConfig : null;
194+
215195
bool builtSomething = false;
216196
for (final RepositoryPackage example in package.getExamples()) {
197+
// Rather than changing global config state, enable SwiftPM via a
198+
// temporary package-level override.
199+
if (swiftPackageManagerOverride != null) {
200+
print('Overriding enable-swift-package-manager to '
201+
'$swiftPackageManagerOverride');
202+
setSwiftPackageManagerState(example,
203+
enabled: swiftPackageManagerOverride);
204+
}
205+
217206
final String packageName =
218207
getRelativePosixPath(example.directory, from: packagesDir);
219208

@@ -240,6 +229,12 @@ class BuildExamplesCommand extends PackageLoopingCommand {
240229
errors.add('$packageName (${platform.label})');
241230
}
242231
}
232+
233+
// If an override was added, remove it.
234+
if (swiftPackageManagerOverride != null) {
235+
print('Removing enable-swift-package-manager override');
236+
setSwiftPackageManagerState(example, enabled: null);
237+
}
243238
}
244239

245240
if (!builtSomething) {

script/tool/lib/src/common/plugin_utils.dart

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// found in the LICENSE file.
44

55
import 'package:yaml/yaml.dart';
6+
import 'package:yaml_edit/yaml_edit.dart';
67

78
import 'core.dart';
89
import 'repository_package.dart';
@@ -83,6 +84,57 @@ bool pluginHasNativeCodeForPlatform(String platform, RepositoryPackage plugin) {
8384
return pluginClass != null && pluginClass != 'none';
8485
}
8586

87+
/// Adds or removes a package-level Swift Package Manager override to the given
88+
/// package.
89+
///
90+
/// A null enabled state clears the package-local override, defaulting to whatever the
91+
/// global state is.
92+
void setSwiftPackageManagerState(RepositoryPackage package,
93+
{required bool? enabled}) {
94+
const String swiftPMFlag = 'enable-swift-package-manager';
95+
const String flutterKey = 'flutter';
96+
const List<String> flutterPath = <String>[flutterKey];
97+
const List<String> configPath = <String>[flutterKey, 'config'];
98+
99+
final YamlEditor editablePubspec =
100+
YamlEditor(package.pubspecFile.readAsStringSync());
101+
final YamlMap configMap =
102+
editablePubspec.parseAt(configPath, orElse: () => YamlMap()) as YamlMap;
103+
if (enabled == null) {
104+
if (!configMap.containsKey(swiftPMFlag)) {
105+
// Nothing to do.
106+
return;
107+
} else if (configMap.length == 1) {
108+
// The config section only exists for this override, so remove the whole
109+
// section.
110+
editablePubspec.remove(configPath);
111+
// The entire flutter: section may also only have been added for the
112+
// config, in which case it should be removed as well.
113+
final YamlMap flutterMap = editablePubspec.parseAt(flutterPath,
114+
orElse: () => YamlMap()) as YamlMap;
115+
if (flutterMap.isEmpty) {
116+
editablePubspec.remove(flutterPath);
117+
}
118+
} else {
119+
// Remove the specific entry, leaving the rest of the config section.
120+
editablePubspec.remove(<String>[...configPath, swiftPMFlag]);
121+
}
122+
} else {
123+
// Ensure that the section exists.
124+
if (configMap.isEmpty) {
125+
final YamlMap root = editablePubspec.parseAt(<String>[]) as YamlMap;
126+
if (!root.containsKey(flutterKey)) {
127+
editablePubspec.update(flutterPath, YamlMap());
128+
}
129+
editablePubspec.update(configPath, YamlMap());
130+
}
131+
// Then add the flag.
132+
editablePubspec.update(<String>[...configPath, swiftPMFlag], enabled);
133+
}
134+
135+
package.pubspecFile.writeAsStringSync(editablePubspec.toString());
136+
}
137+
86138
/// Returns the
87139
/// flutter:
88140
/// plugin:

script/tool/lib/src/xcode_analyze_command.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,14 @@ class XcodeAnalyzeCommand extends PackageLoopingCommand {
121121
targetPlatform == FlutterPlatform.ios ? 'iOS' : 'macOS';
122122
bool passing = true;
123123
for (final RepositoryPackage example in plugin.getExamples()) {
124+
// See https://github.com/flutter/flutter/issues/172427 for discussion of
125+
// why this is currently necessary.
126+
print('Disabling Swift Package Manager...');
127+
setSwiftPackageManagerState(example, enabled: false);
128+
124129
// Unconditionally re-run build with --debug --config-only, to ensure that
125-
// the project is in a debug state even if it was previously configured.
130+
// the project is in a debug state even if it was previously configured,
131+
// and that SwiftPM is disabled.
126132
print('Running flutter build --config-only...');
127133
final bool buildSuccess = await runConfigOnlyBuild(
128134
example,
@@ -162,6 +168,9 @@ class XcodeAnalyzeCommand extends PackageLoopingCommand {
162168
printError('$examplePath ($platformString) failed analysis.');
163169
passing = false;
164170
}
171+
172+
print('Removing Swift Package Manager override...');
173+
setSwiftPackageManagerState(example, enabled: null);
165174
}
166175
return passing;
167176
}

0 commit comments

Comments
 (0)