Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
Michael Goderbauer | 1eed6df | 2017-10-19 11:23:42 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 5 | import 'package:meta/meta.dart'; |
| 6 | |
Michael Goderbauer | 1eed6df | 2017-10-19 11:23:42 -0700 | [diff] [blame] | 7 | import '../base/file_system.dart'; |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 8 | import '../base/logger.dart'; |
Michael Goderbauer | 1eed6df | 2017-10-19 11:23:42 -0700 | [diff] [blame] | 9 | import '../build_info.dart'; |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 10 | import '../globals.dart' as globals; |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 11 | import '../ios/xcodeproj.dart'; |
Jonah Williams | fa5f3da | 2019-01-25 09:30:11 -0800 | [diff] [blame] | 12 | import '../project.dart'; |
Michael Goderbauer | 1eed6df | 2017-10-19 11:23:42 -0700 | [diff] [blame] | 13 | import '../runner/flutter_command.dart'; |
| 14 | |
| 15 | class CleanCommand extends FlutterCommand { |
Jenn Magder | a61bff2 | 2020-03-19 09:51:01 -0700 | [diff] [blame] | 16 | CleanCommand({ |
| 17 | bool verbose = false, |
| 18 | }) : _verbose = verbose { |
Michael Goderbauer | 1eed6df | 2017-10-19 11:23:42 -0700 | [diff] [blame] | 19 | requiresPubspecYaml(); |
| 20 | } |
| 21 | |
Jenn Magder | a61bff2 | 2020-03-19 09:51:01 -0700 | [diff] [blame] | 22 | final bool _verbose; |
| 23 | |
Michael Goderbauer | 1eed6df | 2017-10-19 11:23:42 -0700 | [diff] [blame] | 24 | @override |
| 25 | final String name = 'clean'; |
| 26 | |
| 27 | @override |
Jonah Williams | fa5f3da | 2019-01-25 09:30:11 -0800 | [diff] [blame] | 28 | final String description = 'Delete the build/ and .dart_tool/ directories.'; |
Michael Goderbauer | 1eed6df | 2017-10-19 11:23:42 -0700 | [diff] [blame] | 29 | |
| 30 | @override |
Jonah Williams | 9baffb9 | 2019-04-08 13:49:09 -0700 | [diff] [blame] | 31 | Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{}; |
| 32 | |
| 33 | @override |
Alexandre Ardhuin | 2d3ff10 | 2018-10-05 07:54:56 +0200 | [diff] [blame] | 34 | Future<FlutterCommandResult> runCommand() async { |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 35 | // Clean Xcode to remove intermediate DerivedData artifacts. |
| 36 | // Do this before removing ephemeral directory, which would delete the xcworkspace. |
jmagman | 0a58610 | 2019-08-09 17:26:51 -0700 | [diff] [blame] | 37 | final FlutterProject flutterProject = FlutterProject.current(); |
Jenn Magder | 91f7902 | 2020-01-25 11:18:02 -0800 | [diff] [blame] | 38 | if (globals.xcode.isInstalledAndMeetsVersionCheck) { |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 39 | await _cleanXcode(flutterProject.ios); |
| 40 | await _cleanXcode(flutterProject.macos); |
| 41 | } |
| 42 | |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 43 | final Directory buildDir = globals.fs.directory(getBuildDirectory()); |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 44 | deleteFile(buildDir); |
| 45 | |
| 46 | deleteFile(flutterProject.dartTool); |
Alexandre Ardhuin | 2d3ff10 | 2018-10-05 07:54:56 +0200 | [diff] [blame] | 47 | |
Jenn Magder | 4fb9ce8 | 2020-02-27 12:18:06 -0800 | [diff] [blame] | 48 | deleteFile(flutterProject.android.ephemeralDirectory); |
jmagman | 0a58610 | 2019-08-09 17:26:51 -0700 | [diff] [blame] | 49 | |
Jenn Magder | 4fb9ce8 | 2020-02-27 12:18:06 -0800 | [diff] [blame] | 50 | deleteFile(flutterProject.ios.ephemeralDirectory); |
| 51 | deleteFile(flutterProject.ios.generatedXcodePropertiesFile); |
| 52 | deleteFile(flutterProject.ios.generatedEnvironmentVariableExportScript); |
| 53 | deleteFile(flutterProject.ios.compiledDartFramework); |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 54 | |
Jenn Magder | 4fb9ce8 | 2020-02-27 12:18:06 -0800 | [diff] [blame] | 55 | deleteFile(flutterProject.linux.ephemeralDirectory); |
| 56 | deleteFile(flutterProject.macos.ephemeralDirectory); |
| 57 | deleteFile(flutterProject.windows.ephemeralDirectory); |
Jonah Williams | 3a976fe | 2020-07-22 18:39:33 -0700 | [diff] [blame] | 58 | deleteFile(flutterProject.flutterPluginsDependenciesFile); |
| 59 | deleteFile(flutterProject.flutterPluginsFile); |
stuartmorgan | d03aeca | 2019-09-16 16:04:55 -0700 | [diff] [blame] | 60 | |
Jonah Williams | fa5f3da | 2019-01-25 09:30:11 -0800 | [diff] [blame] | 61 | return const FlutterCommandResult(ExitStatus.success); |
Michael Goderbauer | 1eed6df | 2017-10-19 11:23:42 -0700 | [diff] [blame] | 62 | } |
Zachary Anderson | 6fe45fb | 2019-07-24 10:56:06 -0700 | [diff] [blame] | 63 | |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 64 | Future<void> _cleanXcode(XcodeBasedProject xcodeProject) async { |
| 65 | if (!xcodeProject.existsSync()) { |
| 66 | return; |
| 67 | } |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 68 | final Status xcodeStatus = globals.logger.startProgress( |
| 69 | 'Cleaning Xcode workspace...', |
| 70 | timeout: timeoutConfiguration.slowOperation, |
| 71 | ); |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 72 | try { |
| 73 | final Directory xcodeWorkspace = xcodeProject.xcodeWorkspace; |
Jenn Magder | ee84525 | 2020-03-18 15:55:09 -0700 | [diff] [blame] | 74 | final XcodeProjectInfo projectInfo = await globals.xcodeProjectInterpreter.getInfo(xcodeWorkspace.parent.path); |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 75 | for (final String scheme in projectInfo.schemes) { |
Jenn Magder | a61bff2 | 2020-03-19 09:51:01 -0700 | [diff] [blame] | 76 | await globals.xcodeProjectInterpreter.cleanWorkspace(xcodeWorkspace.path, scheme, verbose: _verbose); |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 77 | } |
Zachary Anderson | 6c408a0 | 2020-03-06 10:22:12 -0800 | [diff] [blame] | 78 | } on Exception catch (error) { |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 79 | globals.printTrace('Could not clean Xcode workspace: $error'); |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 80 | } finally { |
| 81 | xcodeStatus?.stop(); |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | @visibleForTesting |
| 86 | void deleteFile(FileSystemEntity file) { |
Jonah Williams | ae207b5 | 2019-10-25 15:02:38 -0700 | [diff] [blame] | 87 | // 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 Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 93 | globals.printError('Cannot clean ${file.path}.\n$err'); |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 94 | return; |
| 95 | } |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 96 | final Status deletionStatus = globals.logger.startProgress( |
| 97 | 'Deleting ${file.basename}...', |
| 98 | timeout: timeoutConfiguration.fastOperation, |
| 99 | ); |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 100 | try { |
| 101 | file.deleteSync(recursive: true); |
| 102 | } on FileSystemException catch (error) { |
| 103 | final String path = file.path; |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 104 | if (globals.platform.isWindows) { |
| 105 | globals.printError( |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 106 | 'Failed to remove $path. ' |
jmagman | 0a58610 | 2019-08-09 17:26:51 -0700 | [diff] [blame] | 107 | '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 Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 110 | } else { |
Jonah Williams | ee7a37f | 2020-01-06 11:04:20 -0800 | [diff] [blame] | 111 | globals.printError('Failed to remove $path: $error'); |
jmagman | 0a58610 | 2019-08-09 17:26:51 -0700 | [diff] [blame] | 112 | } |
Jenn Magder | 892d62f | 2019-08-21 18:42:56 -0700 | [diff] [blame] | 113 | } finally { |
| 114 | deletionStatus.stop(); |
jmagman | 0a58610 | 2019-08-09 17:26:51 -0700 | [diff] [blame] | 115 | } |
Zachary Anderson | 6fe45fb | 2019-07-24 10:56:06 -0700 | [diff] [blame] | 116 | } |
Michael Goderbauer | 1eed6df | 2017-10-19 11:23:42 -0700 | [diff] [blame] | 117 | } |