blob: 311eef33e2207e9a7d90c47262ae110dfbd771d3 [file] [log] [blame]
Ian Hickson449f4a62019-11-27 15:04:02 -08001// Copyright 2014 The Flutter Authors. All rights reserved.
Michael Goderbauer1eed6df2017-10-19 11:23:42 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Jenn Magder892d62f2019-08-21 18:42:56 -07005import 'package:meta/meta.dart';
6
Michael Goderbauer1eed6df2017-10-19 11:23:42 -07007import '../base/file_system.dart';
Jenn Magder892d62f2019-08-21 18:42:56 -07008import '../base/logger.dart';
Michael Goderbauer1eed6df2017-10-19 11:23:42 -07009import '../build_info.dart';
Jonah Williamsee7a37f2020-01-06 11:04:20 -080010import '../globals.dart' as globals;
Jenn Magder892d62f2019-08-21 18:42:56 -070011import '../ios/xcodeproj.dart';
Jonah Williamsfa5f3da2019-01-25 09:30:11 -080012import '../project.dart';
Michael Goderbauer1eed6df2017-10-19 11:23:42 -070013import '../runner/flutter_command.dart';
14
15class CleanCommand extends FlutterCommand {
Jenn Magdera61bff22020-03-19 09:51:01 -070016 CleanCommand({
17 bool verbose = false,
18 }) : _verbose = verbose {
Michael Goderbauer1eed6df2017-10-19 11:23:42 -070019 requiresPubspecYaml();
20 }
21
Jenn Magdera61bff22020-03-19 09:51:01 -070022 final bool _verbose;
23
Michael Goderbauer1eed6df2017-10-19 11:23:42 -070024 @override
25 final String name = 'clean';
26
27 @override
Jonah Williamsfa5f3da2019-01-25 09:30:11 -080028 final String description = 'Delete the build/ and .dart_tool/ directories.';
Michael Goderbauer1eed6df2017-10-19 11:23:42 -070029
30 @override
Jonah Williams9baffb92019-04-08 13:49:09 -070031 Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{};
32
33 @override
Alexandre Ardhuin2d3ff102018-10-05 07:54:56 +020034 Future<FlutterCommandResult> runCommand() async {
Jenn Magder892d62f2019-08-21 18:42:56 -070035 // Clean Xcode to remove intermediate DerivedData artifacts.
36 // Do this before removing ephemeral directory, which would delete the xcworkspace.
jmagman0a586102019-08-09 17:26:51 -070037 final FlutterProject flutterProject = FlutterProject.current();
Jenn Magder91f79022020-01-25 11:18:02 -080038 if (globals.xcode.isInstalledAndMeetsVersionCheck) {
Jenn Magder892d62f2019-08-21 18:42:56 -070039 await _cleanXcode(flutterProject.ios);
40 await _cleanXcode(flutterProject.macos);
41 }
42
Jonah Williamsee7a37f2020-01-06 11:04:20 -080043 final Directory buildDir = globals.fs.directory(getBuildDirectory());
Jenn Magder892d62f2019-08-21 18:42:56 -070044 deleteFile(buildDir);
45
46 deleteFile(flutterProject.dartTool);
Alexandre Ardhuin2d3ff102018-10-05 07:54:56 +020047
Jenn Magder4fb9ce82020-02-27 12:18:06 -080048 deleteFile(flutterProject.android.ephemeralDirectory);
jmagman0a586102019-08-09 17:26:51 -070049
Jenn Magder4fb9ce82020-02-27 12:18:06 -080050 deleteFile(flutterProject.ios.ephemeralDirectory);
51 deleteFile(flutterProject.ios.generatedXcodePropertiesFile);
52 deleteFile(flutterProject.ios.generatedEnvironmentVariableExportScript);
53 deleteFile(flutterProject.ios.compiledDartFramework);
Jenn Magder892d62f2019-08-21 18:42:56 -070054
Jenn Magder4fb9ce82020-02-27 12:18:06 -080055 deleteFile(flutterProject.linux.ephemeralDirectory);
56 deleteFile(flutterProject.macos.ephemeralDirectory);
57 deleteFile(flutterProject.windows.ephemeralDirectory);
Jonah Williams3a976fe2020-07-22 18:39:33 -070058 deleteFile(flutterProject.flutterPluginsDependenciesFile);
59 deleteFile(flutterProject.flutterPluginsFile);
stuartmorgand03aeca2019-09-16 16:04:55 -070060
Jonah Williamsfa5f3da2019-01-25 09:30:11 -080061 return const FlutterCommandResult(ExitStatus.success);
Michael Goderbauer1eed6df2017-10-19 11:23:42 -070062 }
Zachary Anderson6fe45fb2019-07-24 10:56:06 -070063
Jenn Magder892d62f2019-08-21 18:42:56 -070064 Future<void> _cleanXcode(XcodeBasedProject xcodeProject) async {
65 if (!xcodeProject.existsSync()) {
66 return;
67 }
Jonah Williamsee7a37f2020-01-06 11:04:20 -080068 final Status xcodeStatus = globals.logger.startProgress(
69 'Cleaning Xcode workspace...',
70 timeout: timeoutConfiguration.slowOperation,
71 );
Jenn Magder892d62f2019-08-21 18:42:56 -070072 try {
73 final Directory xcodeWorkspace = xcodeProject.xcodeWorkspace;
Jenn Magderee845252020-03-18 15:55:09 -070074 final XcodeProjectInfo projectInfo = await globals.xcodeProjectInterpreter.getInfo(xcodeWorkspace.parent.path);
Alexandre Ardhuin4f9b6cf2020-01-07 16:32:04 +010075 for (final String scheme in projectInfo.schemes) {
Jenn Magdera61bff22020-03-19 09:51:01 -070076 await globals.xcodeProjectInterpreter.cleanWorkspace(xcodeWorkspace.path, scheme, verbose: _verbose);
Jenn Magder892d62f2019-08-21 18:42:56 -070077 }
Zachary Anderson6c408a02020-03-06 10:22:12 -080078 } on Exception catch (error) {
Jonah Williamsee7a37f2020-01-06 11:04:20 -080079 globals.printTrace('Could not clean Xcode workspace: $error');
Jenn Magder892d62f2019-08-21 18:42:56 -070080 } finally {
81 xcodeStatus?.stop();
82 }
83 }
84
85 @visibleForTesting
86 void deleteFile(FileSystemEntity file) {
Jonah Williamsae207b52019-10-25 15:02:38 -070087 // This will throw a FileSystemException if the directory is missing permissions.
88 try {
89 if (!file.existsSync()) {
90 return;
91 }
92 } on FileSystemException catch (err) {
Jonah Williamsee7a37f2020-01-06 11:04:20 -080093 globals.printError('Cannot clean ${file.path}.\n$err');
Jenn Magder892d62f2019-08-21 18:42:56 -070094 return;
95 }
Jonah Williamsee7a37f2020-01-06 11:04:20 -080096 final Status deletionStatus = globals.logger.startProgress(
97 'Deleting ${file.basename}...',
98 timeout: timeoutConfiguration.fastOperation,
99 );
Jenn Magder892d62f2019-08-21 18:42:56 -0700100 try {
101 file.deleteSync(recursive: true);
102 } on FileSystemException catch (error) {
103 final String path = file.path;
Jonah Williamsee7a37f2020-01-06 11:04:20 -0800104 if (globals.platform.isWindows) {
105 globals.printError(
Jenn Magder892d62f2019-08-21 18:42:56 -0700106 'Failed to remove $path. '
jmagman0a586102019-08-09 17:26:51 -0700107 'A program may still be using a file in the directory or the directory itself. '
108 'To find and stop such a program, see: '
109 'https://superuser.com/questions/1333118/cant-delete-empty-folder-because-it-is-used');
Jenn Magder892d62f2019-08-21 18:42:56 -0700110 } else {
Jonah Williamsee7a37f2020-01-06 11:04:20 -0800111 globals.printError('Failed to remove $path: $error');
jmagman0a586102019-08-09 17:26:51 -0700112 }
Jenn Magder892d62f2019-08-21 18:42:56 -0700113 } finally {
114 deletionStatus.stop();
jmagman0a586102019-08-09 17:26:51 -0700115 }
Zachary Anderson6fe45fb2019-07-24 10:56:06 -0700116 }
Michael Goderbauer1eed6df2017-10-19 11:23:42 -0700117}