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

Commit 378387b

Browse files
authored
when getting xcworkspace, exclude hidden files (#114099)
* exclude xcworkspace that begins with a period * fix if spacing, add comment * add unit test for when no xcworkspace found * update to use xcodeWorkspace, make it nullable and refactor * check if hostAppRoot exists before trying to get xcworkspace * use local variables to take advantage of type promotion * only check if not null, don't need to check if exists * readd exist check for migrate * readd missing line at end of file
1 parent 77c06c2 commit 378387b

File tree

9 files changed

+89
-34
lines changed

9 files changed

+89
-34
lines changed

packages/flutter_tools/lib/src/commands/clean.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,15 @@ class CleanCommand extends FlutterCommand {
7171
}
7272

7373
Future<void> _cleanXcode(XcodeBasedProject xcodeProject) async {
74-
if (!xcodeProject.existsSync()) {
74+
final Directory? xcodeWorkspace = xcodeProject.xcodeWorkspace;
75+
if (xcodeWorkspace == null) {
7576
return;
7677
}
7778
final Status xcodeStatus = globals.logger.startProgress(
7879
'Cleaning Xcode workspace...',
7980
);
8081
try {
8182
final XcodeProjectInterpreter xcodeProjectInterpreter = globals.xcodeProjectInterpreter!;
82-
final Directory xcodeWorkspace = xcodeProject.xcodeWorkspace;
8383
final XcodeProjectInfo projectInfo = (await xcodeProjectInterpreter.getInfo(xcodeWorkspace.parent.path))!;
8484
for (final String scheme in projectInfo.schemes) {
8585
await xcodeProjectInterpreter.cleanWorkspace(xcodeWorkspace.path, scheme, verbose: _verbose);

packages/flutter_tools/lib/src/ios/mac.dart

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -250,17 +250,14 @@ Future<XcodeBuildResult> buildXcodeProject({
250250
buildCommands.add('-allowProvisioningDeviceRegistration');
251251
}
252252

253-
final List<FileSystemEntity> contents = app.project.hostAppRoot.listSync();
254-
for (final FileSystemEntity entity in contents) {
255-
if (globals.fs.path.extension(entity.path) == '.xcworkspace') {
256-
buildCommands.addAll(<String>[
257-
'-workspace', globals.fs.path.basename(entity.path),
258-
'-scheme', scheme,
259-
if (buildAction != XcodeBuildAction.archive) // dSYM files aren't copied to the archive if BUILD_DIR is set.
260-
'BUILD_DIR=${globals.fs.path.absolute(getIosBuildDirectory())}',
261-
]);
262-
break;
263-
}
253+
final Directory? workspacePath = app.project.xcodeWorkspace;
254+
if (workspacePath != null) {
255+
buildCommands.addAll(<String>[
256+
'-workspace', workspacePath.basename,
257+
'-scheme', scheme,
258+
if (buildAction != XcodeBuildAction.archive) // dSYM files aren't copied to the archive if BUILD_DIR is set.
259+
'BUILD_DIR=${globals.fs.path.absolute(getIosBuildDirectory())}',
260+
]);
264261
}
265262

266263
// Check if the project contains a watchOS companion app.

packages/flutter_tools/lib/src/ios/migrations/xcode_build_system_migration.dart

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,17 @@ class XcodeBuildSystemMigration extends ProjectMigrator {
1515
super.logger,
1616
) : _xcodeWorkspaceSharedSettings = project.xcodeWorkspaceSharedSettings;
1717

18-
final File _xcodeWorkspaceSharedSettings;
18+
final File? _xcodeWorkspaceSharedSettings;
1919

2020
@override
2121
void migrate() {
22-
if (!_xcodeWorkspaceSharedSettings.existsSync()) {
22+
final File? xcodeWorkspaceSharedSettings = _xcodeWorkspaceSharedSettings;
23+
if (xcodeWorkspaceSharedSettings == null || !xcodeWorkspaceSharedSettings.existsSync()) {
2324
logger.printTrace('Xcode workspace settings not found, skipping build system migration');
2425
return;
2526
}
2627

27-
final String contents = _xcodeWorkspaceSharedSettings.readAsStringSync();
28+
final String contents = xcodeWorkspaceSharedSettings.readAsStringSync();
2829

2930
// Only delete this file when it is pointing to the legacy build system.
3031
const String legacyBuildSettingsWorkspace = '''
@@ -33,8 +34,8 @@ class XcodeBuildSystemMigration extends ProjectMigrator {
3334

3435
// contains instead of equals to ignore newline file ending variance.
3536
if (contents.contains(legacyBuildSettingsWorkspace)) {
36-
logger.printStatus('Legacy build system detected, removing ${_xcodeWorkspaceSharedSettings.path}');
37-
_xcodeWorkspaceSharedSettings.deleteSync();
37+
logger.printStatus('Legacy build system detected, removing ${xcodeWorkspaceSharedSettings.path}');
38+
xcodeWorkspaceSharedSettings.deleteSync();
3839
}
3940
}
4041
}

packages/flutter_tools/lib/src/macos/build_macos.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ Future<void> buildMacOS({
3636
required bool verboseLogging,
3737
SizeAnalyzer? sizeAnalyzer,
3838
}) async {
39-
if (!flutterProject.macos.xcodeWorkspace.existsSync()) {
39+
final Directory? xcodeWorkspace = flutterProject.macos.xcodeWorkspace;
40+
if (xcodeWorkspace == null) {
4041
throwToolExit('No macOS desktop project configured. '
4142
'See https://docs.flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app '
4243
'to learn about adding macOS support to a project.');
@@ -106,7 +107,7 @@ Future<void> buildMacOS({
106107
'/usr/bin/env',
107108
'xcrun',
108109
'xcodebuild',
109-
'-workspace', flutterProject.macos.xcodeWorkspace.path,
110+
'-workspace', xcodeWorkspace.path,
110111
'-configuration', configuration,
111112
'-scheme', 'Runner',
112113
'-derivedDataPath', flutterBuildDir.absolute.path,

packages/flutter_tools/lib/src/xcode_project.dart

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,26 @@ abstract class XcodeBasedProject extends FlutterProjectPlatform {
4747
.childFile('contents.xcworkspacedata');
4848

4949
/// The Xcode workspace (.xcworkspace directory) of the host app.
50-
Directory get xcodeWorkspace => hostAppRoot.childDirectory('$_hostAppProjectName.xcworkspace');
50+
Directory? get xcodeWorkspace {
51+
if (!hostAppRoot.existsSync()) {
52+
return null;
53+
}
54+
final List<FileSystemEntity> contents = hostAppRoot.listSync();
55+
for (final FileSystemEntity entity in contents) {
56+
// On certain volume types, there is sometimes a stray `._Runner.xcworkspace` file.
57+
// Find the first non-hidden xcworkspace and return the directory.
58+
if (globals.fs.path.extension(entity.path) == '.xcworkspace' && !globals.fs.path.basename(entity.path).startsWith('.')) {
59+
return hostAppRoot.childDirectory(entity.basename);
60+
}
61+
}
62+
return null;
63+
}
5164

5265
/// Xcode workspace shared data directory for the host app.
53-
Directory get xcodeWorkspaceSharedData => xcodeWorkspace.childDirectory('xcshareddata');
66+
Directory? get xcodeWorkspaceSharedData => xcodeWorkspace?.childDirectory('xcshareddata');
5467

5568
/// Xcode workspace shared workspace settings file for the host app.
56-
File get xcodeWorkspaceSharedSettings => xcodeWorkspaceSharedData.childFile('WorkspaceSettings.xcsettings');
69+
File? get xcodeWorkspaceSharedSettings => xcodeWorkspaceSharedData?.childFile('WorkspaceSettings.xcsettings');
5770

5871
/// Contains definitions for FLUTTER_ROOT, LOCAL_ENGINE, and more flags for
5972
/// the Xcode build.

packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ void main() {
9999
'/usr/bin/env',
100100
'xcrun',
101101
'xcodebuild',
102-
'-workspace', flutterProject.macos.xcodeWorkspace.path,
102+
'-workspace', flutterProject.macos.xcodeWorkspace!.path,
103103
'-configuration', configuration,
104104
'-scheme', 'Runner',
105105
'-derivedDataPath', flutterBuildDir.absolute.path,
@@ -337,14 +337,15 @@ STDERR STUFF
337337

338338
final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory);
339339
final Directory flutterBuildDir = fileSystem.directory(getMacOSBuildDirectory());
340+
createMinimalMockProjectFiles();
340341

341342
fakeProcessManager.addCommands(<FakeCommand>[
342343
FakeCommand(
343344
command: <String>[
344345
'/usr/bin/env',
345346
'xcrun',
346347
'xcodebuild',
347-
'-workspace', flutterProject.macos.xcodeWorkspace.path,
348+
'-workspace', flutterProject.macos.xcodeWorkspace!.path,
348349
'-configuration', 'Debug',
349350
'-scheme', 'Runner',
350351
'-derivedDataPath', flutterBuildDir.absolute.path,
@@ -359,7 +360,6 @@ STDERR STUFF
359360
]);
360361

361362
final BuildCommand command = BuildCommand();
362-
createMinimalMockProjectFiles();
363363

364364
await createTestCommandRunner(command).run(
365365
const <String>['build', 'macos', '--debug', '--no-pub']

packages/flutter_tools/test/commands.shard/hermetic/clean_test.dart

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void main() {
4444
});
4545

4646
testUsingContext('$CleanCommand removes build and .dart_tool and ephemeral directories, cleans Xcode for iOS and macOS', () async {
47-
final FlutterProject projectUnderTest = setupProjectUnderTest(fs.currentDirectory);
47+
final FlutterProject projectUnderTest = setupProjectUnderTest(fs.currentDirectory, true);
4848
// Xcode is installed and version satisfactory.
4949
xcodeProjectInterpreter.isInstalled = true;
5050
xcodeProjectInterpreter.version = Version(1000, 0, 0);
@@ -70,7 +70,7 @@ void main() {
7070
expect(projectUnderTest.flutterPluginsDependenciesFile, isNot(exists));
7171
expect(projectUnderTest.packagesFile, isNot(exists));
7272

73-
expect(xcodeProjectInterpreter.workspaces, const <CleanWorkspaceCall>[
73+
expect(xcodeProjectInterpreter.workspaces, const <CleanWorkspaceCall>[
7474
CleanWorkspaceCall('/ios/Runner.xcworkspace', 'Runner', false),
7575
CleanWorkspaceCall('/macos/Runner.xcworkspace', 'Runner', false),
7676
]);
@@ -81,8 +81,23 @@ void main() {
8181
XcodeProjectInterpreter: () => xcodeProjectInterpreter,
8282
});
8383

84+
testUsingContext('$CleanCommand does not run when there is no xcworkspace', () async {
85+
setupProjectUnderTest(fs.currentDirectory, false);
86+
// Xcode is installed and version satisfactory.
87+
xcodeProjectInterpreter.isInstalled = true;
88+
xcodeProjectInterpreter.version = Version(1000, 0, 0);
89+
await CleanCommand().runCommand();
90+
91+
expect(xcodeProjectInterpreter.workspaces, const <CleanWorkspaceCall>[]);
92+
}, overrides: <Type, Generator>{
93+
FileSystem: () => fs,
94+
ProcessManager: () => FakeProcessManager.any(),
95+
Xcode: () => xcode,
96+
XcodeProjectInterpreter: () => xcodeProjectInterpreter,
97+
});
98+
8499
testUsingContext('$CleanCommand cleans Xcode verbosely for iOS and macOS', () async {
85-
setupProjectUnderTest(fs.currentDirectory);
100+
setupProjectUnderTest(fs.currentDirectory, true);
86101
// Xcode is installed and version satisfactory.
87102
xcodeProjectInterpreter.isInstalled = true;
88103
xcodeProjectInterpreter.version = Version(1000, 0, 0);
@@ -154,12 +169,13 @@ void main() {
154169
});
155170
}
156171

157-
FlutterProject setupProjectUnderTest(Directory currentDirectory) {
172+
FlutterProject setupProjectUnderTest(Directory currentDirectory, bool setupXcodeWorkspace) {
158173
// This needs to be run within testWithoutContext and not setUp since FlutterProject uses context.
159174
final FlutterProject projectUnderTest = FlutterProject.fromDirectory(currentDirectory);
160-
projectUnderTest.ios.xcodeWorkspace.createSync(recursive: true);
161-
projectUnderTest.macos.xcodeWorkspace.createSync(recursive: true);
162-
175+
if (setupXcodeWorkspace == true) {
176+
projectUnderTest.ios.hostAppRoot.childDirectory('Runner.xcworkspace').createSync(recursive: true);
177+
projectUnderTest.macos.hostAppRoot.childDirectory('Runner.xcworkspace').createSync(recursive: true);
178+
}
163179
projectUnderTest.dartTool.createSync(recursive: true);
164180
projectUnderTest.packagesFile.createSync(recursive: true);
165181
projectUnderTest.android.ephemeralDirectory.createSync(recursive: true);

packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,20 @@ keep this 2
208208
expect(testLogger.statusText, isEmpty);
209209
});
210210

211+
testWithoutContext('skipped if _xcodeWorkspaceSharedSettings is null', () {
212+
final XcodeBuildSystemMigration iosProjectMigration = XcodeBuildSystemMigration(
213+
project,
214+
testLogger,
215+
);
216+
project.xcodeWorkspaceSharedSettings = null;
217+
218+
iosProjectMigration.migrate();
219+
expect(xcodeWorkspaceSharedSettings.existsSync(), isFalse);
220+
221+
expect(testLogger.traceText, contains('Xcode workspace settings not found, skipping build system migration'));
222+
expect(testLogger.statusText, isEmpty);
223+
});
224+
211225
testWithoutContext('skipped if nothing to upgrade', () {
212226
const String contents = '''
213227
<?xml version="1.0" encoding="UTF-8"?>
@@ -995,7 +1009,7 @@ class FakeIosProject extends Fake implements IosProject {
9951009
File xcodeProjectWorkspaceData = MemoryFileSystem.test().file('xcodeProjectWorkspaceData');
9961010

9971011
@override
998-
File xcodeWorkspaceSharedSettings = MemoryFileSystem.test().file('xcodeWorkspaceSharedSettings');
1012+
File? xcodeWorkspaceSharedSettings = MemoryFileSystem.test().file('xcodeWorkspaceSharedSettings');
9991013

10001014
@override
10011015
File xcodeProjectInfoFile = MemoryFileSystem.test().file('xcodeProjectInfoFile');

packages/flutter_tools/test/general.shard/project_test.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,19 @@ void main() {
350350
expect(versionInfo['build_number'],'3');
351351
expect(versionInfo['package_name'],'test');
352352
});
353+
_testInMemory('gets xcworkspace directory', () async {
354+
final FlutterProject project = await someProject();
355+
project.ios.xcodeProject.createSync();
356+
project.ios.hostAppRoot.childFile('._Runner.xcworkspace').createSync(recursive: true);
357+
project.ios.hostAppRoot.childFile('Runner.xcworkspace').createSync(recursive: true);
358+
359+
expect(project.ios.xcodeWorkspace?.basename, 'Runner.xcworkspace');
360+
});
361+
_testInMemory('no xcworkspace directory found', () async {
362+
final FlutterProject project = await someProject();
363+
project.ios.xcodeProject.createSync();
364+
expect(project.ios.xcodeWorkspace?.basename, null);
365+
});
353366
});
354367

355368
group('module status', () {

0 commit comments

Comments
 (0)