clean.dart 3.82 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';

7 8
import 'package:meta/meta.dart';

9
import '../base/file_system.dart';
10
import '../base/logger.dart';
11
import '../base/platform.dart';
12 13
import '../build_info.dart';
import '../globals.dart';
14 15
import '../ios/xcodeproj.dart';
import '../macos/xcode.dart';
16
import '../project.dart';
17 18 19 20 21 22 23 24 25 26 27
import '../runner/flutter_command.dart';

class CleanCommand extends FlutterCommand {
  CleanCommand() {
    requiresPubspecYaml();
  }

  @override
  final String name = 'clean';

  @override
28
  final String description = 'Delete the build/ and .dart_tool/ directories.';
29

30 31 32
  @override
  Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{};

33
  @override
34
  Future<FlutterCommandResult> runCommand() async {
35 36 37 38 39 40 41 42
    // Clean Xcode to remove intermediate DerivedData artifacts.
    // Do this before removing ephemeral directory, which would delete the xcworkspace.
    final FlutterProject flutterProject = FlutterProject.current();
    if (xcode.isInstalledAndMeetsVersionCheck) {
      await _cleanXcode(flutterProject.ios);
      await _cleanXcode(flutterProject.macos);
    }

43
    final Directory buildDir = fs.directory(getBuildDirectory());
44
    deleteFile(buildDir);
45

46
    deleteFile(flutterProject.dartTool);
47

48
    final Directory androidEphemeralDirectory = flutterProject.android.ephemeralDirectory;
49
    deleteFile(androidEphemeralDirectory);
50 51

    final Directory iosEphemeralDirectory = flutterProject.ios.ephemeralDirectory;
52 53
    deleteFile(iosEphemeralDirectory);

54 55 56
    final Directory linuxEphemeralDirectory = flutterProject.linux.ephemeralDirectory;
    deleteFile(linuxEphemeralDirectory);

57 58
    final Directory macosEphemeralDirectory = flutterProject.macos.ephemeralDirectory;
    deleteFile(macosEphemeralDirectory);
59

60 61 62
    final Directory windowsEphemeralDirectory = flutterProject.windows.ephemeralDirectory;
    deleteFile(windowsEphemeralDirectory);

63 64 65
    return const FlutterCommandResult(ExitStatus.success);
  }

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
  Future<void> _cleanXcode(XcodeBasedProject xcodeProject) async {
    if (!xcodeProject.existsSync()) {
      return;
    }
    final Status xcodeStatus = logger.startProgress('Cleaning Xcode workspace...', timeout: timeoutConfiguration.slowOperation);
    try {
      final Directory xcodeWorkspace = xcodeProject.xcodeWorkspace;
      final XcodeProjectInfo projectInfo = await xcodeProjectInterpreter.getInfo(xcodeWorkspace.parent.path);
      for (String scheme in projectInfo.schemes) {
        xcodeProjectInterpreter.cleanWorkspace(xcodeWorkspace.path, scheme);
      }
    } catch (error) {
      printTrace('Could not clean Xcode workspace: $error');
    } finally {
      xcodeStatus?.stop();
    }
  }

  @visibleForTesting
  void deleteFile(FileSystemEntity file) {
86 87 88 89 90 91 92
    // This will throw a FileSystemException if the directory is missing permissions.
    try {
      if (!file.existsSync()) {
        return;
      }
    } on FileSystemException catch (err) {
      printError('Cannot clean ${file.path}.\n$err');
93 94 95 96 97 98 99 100 101 102
      return;
    }
    final Status deletionStatus = logger.startProgress('Deleting ${file.basename}...', timeout: timeoutConfiguration.fastOperation);
    try {
      file.deleteSync(recursive: true);
    } on FileSystemException catch (error) {
      final String path = file.path;
      if (platform.isWindows) {
        printError(
          'Failed to remove $path. '
103 104 105
            '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');
106 107
      } else {
        printError('Failed to remove $path: $error');
108
      }
109 110
    } finally {
      deletionStatus.stop();
111
    }
112
  }
113
}