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

Commit

Permalink
when getting xcworkspace, exclude hidden files (#114099)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
vashworth authored Nov 7, 2022
1 parent 77c06c2 commit 378387b
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 34 deletions.
4 changes: 2 additions & 2 deletions packages/flutter_tools/lib/src/commands/clean.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,15 @@ class CleanCommand extends FlutterCommand {
}

Future<void> _cleanXcode(XcodeBasedProject xcodeProject) async {
if (!xcodeProject.existsSync()) {
final Directory? xcodeWorkspace = xcodeProject.xcodeWorkspace;
if (xcodeWorkspace == null) {
return;
}
final Status xcodeStatus = globals.logger.startProgress(
'Cleaning Xcode workspace...',
);
try {
final XcodeProjectInterpreter xcodeProjectInterpreter = globals.xcodeProjectInterpreter!;
final Directory xcodeWorkspace = xcodeProject.xcodeWorkspace;
final XcodeProjectInfo projectInfo = (await xcodeProjectInterpreter.getInfo(xcodeWorkspace.parent.path))!;
for (final String scheme in projectInfo.schemes) {
await xcodeProjectInterpreter.cleanWorkspace(xcodeWorkspace.path, scheme, verbose: _verbose);
Expand Down
19 changes: 8 additions & 11 deletions packages/flutter_tools/lib/src/ios/mac.dart
Original file line number Diff line number Diff line change
Expand Up @@ -250,17 +250,14 @@ Future<XcodeBuildResult> buildXcodeProject({
buildCommands.add('-allowProvisioningDeviceRegistration');
}

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

// Check if the project contains a watchOS companion app.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ class XcodeBuildSystemMigration extends ProjectMigrator {
super.logger,
) : _xcodeWorkspaceSharedSettings = project.xcodeWorkspaceSharedSettings;

final File _xcodeWorkspaceSharedSettings;
final File? _xcodeWorkspaceSharedSettings;

@override
void migrate() {
if (!_xcodeWorkspaceSharedSettings.existsSync()) {
final File? xcodeWorkspaceSharedSettings = _xcodeWorkspaceSharedSettings;
if (xcodeWorkspaceSharedSettings == null || !xcodeWorkspaceSharedSettings.existsSync()) {
logger.printTrace('Xcode workspace settings not found, skipping build system migration');
return;
}

final String contents = _xcodeWorkspaceSharedSettings.readAsStringSync();
final String contents = xcodeWorkspaceSharedSettings.readAsStringSync();

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

// contains instead of equals to ignore newline file ending variance.
if (contents.contains(legacyBuildSettingsWorkspace)) {
logger.printStatus('Legacy build system detected, removing ${_xcodeWorkspaceSharedSettings.path}');
_xcodeWorkspaceSharedSettings.deleteSync();
logger.printStatus('Legacy build system detected, removing ${xcodeWorkspaceSharedSettings.path}');
xcodeWorkspaceSharedSettings.deleteSync();
}
}
}
5 changes: 3 additions & 2 deletions packages/flutter_tools/lib/src/macos/build_macos.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ Future<void> buildMacOS({
required bool verboseLogging,
SizeAnalyzer? sizeAnalyzer,
}) async {
if (!flutterProject.macos.xcodeWorkspace.existsSync()) {
final Directory? xcodeWorkspace = flutterProject.macos.xcodeWorkspace;
if (xcodeWorkspace == null) {
throwToolExit('No macOS desktop project configured. '
'See https://docs.flutter.dev/desktop#add-desktop-support-to-an-existing-flutter-app '
'to learn about adding macOS support to a project.');
Expand Down Expand Up @@ -106,7 +107,7 @@ Future<void> buildMacOS({
'/usr/bin/env',
'xcrun',
'xcodebuild',
'-workspace', flutterProject.macos.xcodeWorkspace.path,
'-workspace', xcodeWorkspace.path,
'-configuration', configuration,
'-scheme', 'Runner',
'-derivedDataPath', flutterBuildDir.absolute.path,
Expand Down
19 changes: 16 additions & 3 deletions packages/flutter_tools/lib/src/xcode_project.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,26 @@ abstract class XcodeBasedProject extends FlutterProjectPlatform {
.childFile('contents.xcworkspacedata');

/// The Xcode workspace (.xcworkspace directory) of the host app.
Directory get xcodeWorkspace => hostAppRoot.childDirectory('$_hostAppProjectName.xcworkspace');
Directory? get xcodeWorkspace {
if (!hostAppRoot.existsSync()) {
return null;
}
final List<FileSystemEntity> contents = hostAppRoot.listSync();
for (final FileSystemEntity entity in contents) {
// On certain volume types, there is sometimes a stray `._Runner.xcworkspace` file.
// Find the first non-hidden xcworkspace and return the directory.
if (globals.fs.path.extension(entity.path) == '.xcworkspace' && !globals.fs.path.basename(entity.path).startsWith('.')) {
return hostAppRoot.childDirectory(entity.basename);
}
}
return null;
}

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

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

/// Contains definitions for FLUTTER_ROOT, LOCAL_ENGINE, and more flags for
/// the Xcode build.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ void main() {
'/usr/bin/env',
'xcrun',
'xcodebuild',
'-workspace', flutterProject.macos.xcodeWorkspace.path,
'-workspace', flutterProject.macos.xcodeWorkspace!.path,
'-configuration', configuration,
'-scheme', 'Runner',
'-derivedDataPath', flutterBuildDir.absolute.path,
Expand Down Expand Up @@ -337,14 +337,15 @@ STDERR STUFF

final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory);
final Directory flutterBuildDir = fileSystem.directory(getMacOSBuildDirectory());
createMinimalMockProjectFiles();

fakeProcessManager.addCommands(<FakeCommand>[
FakeCommand(
command: <String>[
'/usr/bin/env',
'xcrun',
'xcodebuild',
'-workspace', flutterProject.macos.xcodeWorkspace.path,
'-workspace', flutterProject.macos.xcodeWorkspace!.path,
'-configuration', 'Debug',
'-scheme', 'Runner',
'-derivedDataPath', flutterBuildDir.absolute.path,
Expand All @@ -359,7 +360,6 @@ STDERR STUFF
]);

final BuildCommand command = BuildCommand();
createMinimalMockProjectFiles();

await createTestCommandRunner(command).run(
const <String>['build', 'macos', '--debug', '--no-pub']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ void main() {
});

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

expect(xcodeProjectInterpreter.workspaces, const <CleanWorkspaceCall>[
expect(xcodeProjectInterpreter.workspaces, const <CleanWorkspaceCall>[
CleanWorkspaceCall('/ios/Runner.xcworkspace', 'Runner', false),
CleanWorkspaceCall('/macos/Runner.xcworkspace', 'Runner', false),
]);
Expand All @@ -81,8 +81,23 @@ void main() {
XcodeProjectInterpreter: () => xcodeProjectInterpreter,
});

testUsingContext('$CleanCommand does not run when there is no xcworkspace', () async {
setupProjectUnderTest(fs.currentDirectory, false);
// Xcode is installed and version satisfactory.
xcodeProjectInterpreter.isInstalled = true;
xcodeProjectInterpreter.version = Version(1000, 0, 0);
await CleanCommand().runCommand();

expect(xcodeProjectInterpreter.workspaces, const <CleanWorkspaceCall>[]);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
Xcode: () => xcode,
XcodeProjectInterpreter: () => xcodeProjectInterpreter,
});

testUsingContext('$CleanCommand cleans Xcode verbosely for iOS and macOS', () async {
setupProjectUnderTest(fs.currentDirectory);
setupProjectUnderTest(fs.currentDirectory, true);
// Xcode is installed and version satisfactory.
xcodeProjectInterpreter.isInstalled = true;
xcodeProjectInterpreter.version = Version(1000, 0, 0);
Expand Down Expand Up @@ -154,12 +169,13 @@ void main() {
});
}

FlutterProject setupProjectUnderTest(Directory currentDirectory) {
FlutterProject setupProjectUnderTest(Directory currentDirectory, bool setupXcodeWorkspace) {
// This needs to be run within testWithoutContext and not setUp since FlutterProject uses context.
final FlutterProject projectUnderTest = FlutterProject.fromDirectory(currentDirectory);
projectUnderTest.ios.xcodeWorkspace.createSync(recursive: true);
projectUnderTest.macos.xcodeWorkspace.createSync(recursive: true);

if (setupXcodeWorkspace == true) {
projectUnderTest.ios.hostAppRoot.childDirectory('Runner.xcworkspace').createSync(recursive: true);
projectUnderTest.macos.hostAppRoot.childDirectory('Runner.xcworkspace').createSync(recursive: true);
}
projectUnderTest.dartTool.createSync(recursive: true);
projectUnderTest.packagesFile.createSync(recursive: true);
projectUnderTest.android.ephemeralDirectory.createSync(recursive: true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,20 @@ keep this 2
expect(testLogger.statusText, isEmpty);
});

testWithoutContext('skipped if _xcodeWorkspaceSharedSettings is null', () {
final XcodeBuildSystemMigration iosProjectMigration = XcodeBuildSystemMigration(
project,
testLogger,
);
project.xcodeWorkspaceSharedSettings = null;

iosProjectMigration.migrate();
expect(xcodeWorkspaceSharedSettings.existsSync(), isFalse);

expect(testLogger.traceText, contains('Xcode workspace settings not found, skipping build system migration'));
expect(testLogger.statusText, isEmpty);
});

testWithoutContext('skipped if nothing to upgrade', () {
const String contents = '''
<?xml version="1.0" encoding="UTF-8"?>
Expand Down Expand Up @@ -995,7 +1009,7 @@ class FakeIosProject extends Fake implements IosProject {
File xcodeProjectWorkspaceData = MemoryFileSystem.test().file('xcodeProjectWorkspaceData');

@override
File xcodeWorkspaceSharedSettings = MemoryFileSystem.test().file('xcodeWorkspaceSharedSettings');
File? xcodeWorkspaceSharedSettings = MemoryFileSystem.test().file('xcodeWorkspaceSharedSettings');

@override
File xcodeProjectInfoFile = MemoryFileSystem.test().file('xcodeProjectInfoFile');
Expand Down
13 changes: 13 additions & 0 deletions packages/flutter_tools/test/general.shard/project_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,19 @@ void main() {
expect(versionInfo['build_number'],'3');
expect(versionInfo['package_name'],'test');
});
_testInMemory('gets xcworkspace directory', () async {
final FlutterProject project = await someProject();
project.ios.xcodeProject.createSync();
project.ios.hostAppRoot.childFile('._Runner.xcworkspace').createSync(recursive: true);
project.ios.hostAppRoot.childFile('Runner.xcworkspace').createSync(recursive: true);

expect(project.ios.xcodeWorkspace?.basename, 'Runner.xcworkspace');
});
_testInMemory('no xcworkspace directory found', () async {
final FlutterProject project = await someProject();
project.ios.xcodeProject.createSync();
expect(project.ios.xcodeWorkspace?.basename, null);
});
});

group('module status', () {
Expand Down

0 comments on commit 378387b

Please sign in to comment.