Unverified Commit 6259b690 authored by Enguerrand ARMINJON's avatar Enguerrand ARMINJON Committed by GitHub

feature/clean-a-specific-scheme: Add this-scheme new flag for clean command (#116733)

Co-authored-by: 's avatarEnguerrand_ARMINJON_MAC_2 <earminjon@sqli.com>
parent 902d86e0
......@@ -5,6 +5,7 @@
import 'package:meta/meta.dart';
import '../../src/macos/xcode.dart';
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/logger.dart';
import '../build_info.dart';
......@@ -18,6 +19,10 @@ class CleanCommand extends FlutterCommand {
bool verbose = false,
}) : _verbose = verbose {
requiresPubspecYaml();
argParser.addOption(
'scheme',
help: 'When cleaning Xcode schemes, clean only the specified scheme.',
);
}
final bool _verbose;
......@@ -81,11 +86,27 @@ class CleanCommand extends FlutterCommand {
try {
final XcodeProjectInterpreter xcodeProjectInterpreter = globals.xcodeProjectInterpreter!;
final XcodeProjectInfo projectInfo = (await xcodeProjectInterpreter.getInfo(xcodeWorkspace.parent.path))!;
for (final String scheme in projectInfo.schemes) {
if (argResults?.wasParsed('scheme') ?? false) {
final String scheme = argResults!['scheme'] as String;
if (scheme.isEmpty) {
throwToolExit('No scheme was specified for --scheme');
}
if (!projectInfo.schemes.contains(scheme)) {
throwToolExit('Scheme "$scheme" not found in ${projectInfo.schemes}');
}
await xcodeProjectInterpreter.cleanWorkspace(xcodeWorkspace.path, scheme, verbose: _verbose);
} else {
for (final String scheme in projectInfo.schemes) {
await xcodeProjectInterpreter.cleanWorkspace(xcodeWorkspace.path, scheme, verbose: _verbose);
}
}
} on Exception catch (error) {
globals.printTrace('Could not clean Xcode workspace: $error');
final String message = 'Could not clean Xcode workspace: $error';
if (argResults?.wasParsed('scheme') ?? false) {
throwToolExit(message);
} else {
globals.printTrace(message);
}
} finally {
xcodeStatus.stop();
}
......@@ -110,8 +131,7 @@ class CleanCommand extends FlutterCommand {
} on FileSystemException catch (error) {
final String path = file.path;
if (globals.platform.isWindows) {
globals.printError(
'Failed to remove $path. '
globals.printError('Failed to remove $path. '
'A program may still be using a file in the directory or the directory itself. '
'To find and stop such a program, see: '
'https://superuser.com/questions/1333118/cant-delete-empty-folder-because-it-is-used');
......
......@@ -2,12 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/version.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/clean.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/macos/xcode.dart';
......@@ -17,6 +19,7 @@ import 'package:test/fake.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/test_flutter_command_runner.dart';
void main() {
group('clean command', () {
......@@ -24,6 +27,7 @@ void main() {
late FakeXcodeProjectInterpreter xcodeProjectInterpreter;
setUp(() {
Cache.disableLocking();
xcodeProjectInterpreter = FakeXcodeProjectInterpreter();
xcode = Xcode.test(
processManager: FakeProcessManager.any(),
......@@ -37,6 +41,7 @@ void main() {
setUp(() {
fs = MemoryFileSystem.test();
fs.file('pubspec.yaml').createSync(recursive: true);
final Directory currentDirectory = fs.currentDirectory;
buildDirectory = currentDirectory.childDirectory('build');
......@@ -72,7 +77,30 @@ void main() {
expect(xcodeProjectInterpreter.workspaces, const <CleanWorkspaceCall>[
CleanWorkspaceCall('/ios/Runner.xcworkspace', 'Runner', false),
CleanWorkspaceCall('/ios/Runner.xcworkspace', 'custom-scheme', false),
CleanWorkspaceCall('/macos/Runner.xcworkspace', 'Runner', false),
CleanWorkspaceCall('/macos/Runner.xcworkspace', 'custom-scheme', false),
]);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
Xcode: () => xcode,
XcodeProjectInterpreter: () => xcodeProjectInterpreter,
});
testUsingContext('$CleanCommand removes a specific xcode scheme --scheme', () async {
setupProjectUnderTest(fs.currentDirectory, true);
// Xcode is installed and version satisfactory.
xcodeProjectInterpreter.isInstalled = true;
xcodeProjectInterpreter.version = Version(1000, 0, 0);
final CleanCommand command = CleanCommand();
final CommandRunner<void> runner = createTestCommandRunner(command);
await runner.run(<String>['clean', '--scheme=custom-scheme']);
expect(xcodeProjectInterpreter.workspaces, <CleanWorkspaceCall>[
const CleanWorkspaceCall('/ios/Runner.xcworkspace', 'custom-scheme', false),
const CleanWorkspaceCall('/macos/Runner.xcworkspace', 'custom-scheme', false),
]);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
......@@ -96,6 +124,28 @@ void main() {
XcodeProjectInterpreter: () => xcodeProjectInterpreter,
});
testUsingContext('$CleanCommand throws when given an invalid value for --scheme', () async {
setupProjectUnderTest(fs.currentDirectory, true);
// Xcode is installed and version satisfactory.
xcodeProjectInterpreter.isInstalled = true;
xcodeProjectInterpreter.version = Version(1000, 0, 0);
final CleanCommand command = CleanCommand();
expect(
() => createTestCommandRunner(command).run(<String>['clean', '--scheme']),
throwsUsageException(),
);
expect(
() => createTestCommandRunner(command).run(<String>['clean', '--scheme=unknown']),
throwsToolExit(),
);
}, 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, true);
// Xcode is installed and version satisfactory.
......@@ -106,7 +156,9 @@ void main() {
expect(xcodeProjectInterpreter.workspaces, const <CleanWorkspaceCall>[
CleanWorkspaceCall('/ios/Runner.xcworkspace', 'Runner', true),
CleanWorkspaceCall('/ios/Runner.xcworkspace', 'custom-scheme', true),
CleanWorkspaceCall('/macos/Runner.xcworkspace', 'Runner', true),
CleanWorkspaceCall('/macos/Runner.xcworkspace', 'custom-scheme', true),
]);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
......@@ -209,7 +261,7 @@ class FakeXcodeProjectInterpreter extends Fake implements XcodeProjectInterprete
return XcodeProjectInfo(
const <String>[],
const <String>[],
<String>['Runner'],
<String>['Runner', 'custom-scheme'],
BufferLogger.test(),
);
}
......
......@@ -4,6 +4,7 @@
import 'dart:async';
import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/context.dart';
......@@ -103,6 +104,18 @@ Matcher throwsToolExit({ int? exitCode, Pattern? message }) {
/// Matcher for [ToolExit]s.
final TypeMatcher<ToolExit> _isToolExit = isA<ToolExit>();
/// Matcher for functions that throw [UsageException].
Matcher throwsUsageException({Pattern? message }) {
Matcher matcher = _isUsageException;
if (message != null) {
matcher = allOf(matcher, (UsageException e) => e.message.contains(message));
}
return throwsA(matcher);
}
/// Matcher for [UsageException]s.
final TypeMatcher<UsageException> _isUsageException = isA<UsageException>();
/// Matcher for functions that throw [ProcessException].
Matcher throwsProcessException({ Pattern? message }) {
Matcher matcher = _isProcessException;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment