packages.dart 7.1 KB
Newer Older
1 2 3 4 5 6
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';

7
import '../base/common.dart';
8 9
import '../base/os.dart';
import '../dart/pub.dart';
10
import '../project.dart';
11
import '../reporting/usage.dart';
12 13 14 15
import '../runner/flutter_command.dart';

class PackagesCommand extends FlutterCommand {
  PackagesCommand() {
16 17 18
    addSubcommand(PackagesGetCommand('get', false));
    addSubcommand(PackagesGetCommand('upgrade', true));
    addSubcommand(PackagesTestCommand());
19
    addSubcommand(PackagesForwardCommand('downgrade', 'Downgrade packages in a Flutter project', requiresPubspec: true));
20
    addSubcommand(PackagesForwardCommand('publish', 'Publish the current package to pub.dev', requiresPubspec: true));
21 22 23 24
    addSubcommand(PackagesForwardCommand('deps', 'Print package dependencies', requiresPubspec: true));
    addSubcommand(PackagesForwardCommand('run', 'Run an executable from a package', requiresPubspec: true));
    addSubcommand(PackagesForwardCommand('cache', 'Work with the Pub system cache'));
    addSubcommand(PackagesForwardCommand('version', 'Print Pub version'));
25
    addSubcommand(PackagesForwardCommand('uploader', 'Manage uploaders for a package on pub.dev'));
26
    addSubcommand(PackagesForwardCommand('global', 'Work with Pub global packages'));
27
    addSubcommand(PackagesPassthroughCommand());
28 29 30
  }

  @override
31
  final String name = 'pub';
32 33

  @override
34
  List<String> get aliases => const <String>['packages'];
35 36 37 38

  @override
  final String description = 'Commands for managing Flutter packages.';

39 40 41 42 43
  @override
  Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
    DevelopmentArtifact.universal,
  };

44
  @override
45
  Future<FlutterCommandResult> runCommand() async => null;
46 47 48
}

class PackagesGetCommand extends FlutterCommand {
49
  PackagesGetCommand(this.name, this.upgrade) {
50
    requiresPubspecYaml();
51 52
    argParser.addFlag('offline',
      negatable: false,
53
      help: 'Use cached packages instead of accessing the network.',
54 55
    );
  }
56

57 58 59 60 61
  @override
  final String name;

  final bool upgrade;

62
  @override
63 64 65
  String get description {
    return '${ upgrade ? "Upgrade" : "Get" } packages in a Flutter project.';
  }
66 67

  @override
68
  String get invocation {
69
    return '${runner.executableName} pub $name [<target directory>]';
70
  }
71

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
  @override
  Future<Map<String, String>> get usageValues async {
    final Map<String, String> usageValues = <String, String>{};
    final String workingDirectory = argResults.rest.length == 1 ? argResults.rest[0] : null;
    final String target = findProjectRoot(workingDirectory);
    if (target == null) {
      return usageValues;
    }
    final FlutterProject rootProject = FlutterProject.fromPath(target);
    final bool hasPlugins = await rootProject.flutterPluginsFile.exists();
    if (hasPlugins) {
      final int numberOfPlugins = (await rootProject.flutterPluginsFile.readAsLines()).length;
      usageValues[kCommandPackagesNumberPlugins] = '$numberOfPlugins';
    } else {
      usageValues[kCommandPackagesNumberPlugins] = '0';
    }
    usageValues[kCommandPackagesProjectModule] = '${rootProject.isModule}';
    return usageValues;
  }

  Future<void> _runPubGet(String directory) async {
    final Stopwatch pubGetTimer = Stopwatch()..start();
    try {
      await pubGet(context: PubContext.pubGet,
        directory: directory,
        upgrade: upgrade ,
        offline: argResults['offline'],
        checkLastModified: false,
      );
      pubGetTimer.stop();
      flutterUsage.sendEvent('packages-pub-get', 'success');
      flutterUsage.sendTiming('packages-pub-get', 'success', pubGetTimer.elapsed);
    } catch (_) {
      pubGetTimer.stop();
      flutterUsage.sendEvent('packages-pub-get', 'failure');
      flutterUsage.sendTiming('packages-pub-get', 'failure', pubGetTimer.elapsed);
      rethrow;
    }
110 111
  }

112
  @override
113
  Future<FlutterCommandResult> runCommand() async {
114 115
    if (argResults.rest.length > 1)
      throwToolExit('Too many arguments.\n$usage');
116

117 118
    final String workingDirectory = argResults.rest.length == 1 ? argResults.rest[0] : null;
    final String target = findProjectRoot(workingDirectory);
119
    if (target == null) {
120
      throwToolExit(
121
       'Expected to find project root in '
122
       '${ workingDirectory ?? "current working directory" }.'
123 124
      );
    }
125

126
    await _runPubGet(target);
127
    final FlutterProject rootProject = FlutterProject.fromPath(target);
128
    await rootProject.ensureReadyForPlatformSpecificTooling(checkProjects: true);
129 130 131 132 133

    // Get/upgrade packages in example app as well
    if (rootProject.hasExampleApp) {
      final FlutterProject exampleProject = rootProject.example;
      await _runPubGet(exampleProject.directory.path);
134
      await exampleProject.ensureReadyForPlatformSpecificTooling(checkProjects: true);
135
    }
136 137

    return null;
138 139
  }
}
140 141

class PackagesTestCommand extends FlutterCommand {
142 143 144 145
  PackagesTestCommand() {
    requiresPubspecYaml();
  }

146 147 148 149 150 151
  @override
  String get name => 'test';

  @override
  String get description {
    return 'Run the "test" package.\n'
152 153 154 155
           'This is similar to "flutter test", but instead of hosting the tests in the '
           'flutter environment it hosts the tests in a pure Dart environment. The main '
           'differences are that the "dart:ui" library is not available and that tests '
           'run faster. This is helpful for testing libraries that do not depend on any '
156 157 158 159 160
           'packages from the Flutter SDK. It is equivalent to "pub run test".';
  }

  @override
  String get invocation {
161
    return '${runner.executableName} pub test [<tests...>]';
162 163 164
  }

  @override
165
  Future<FlutterCommandResult> runCommand() async {
166
    await pub(<String>['run', 'test', ...argResults.rest], context: PubContext.runTest, retry: false);
167 168
    return null;
  }
169 170
}

171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
class PackagesForwardCommand extends FlutterCommand {
  PackagesForwardCommand(this._commandName, this._description, {bool requiresPubspec = false}) {
    if (requiresPubspec) {
      requiresPubspecYaml();
    }
  }
  final String _commandName;
  final String _description;

  @override
  String get name => _commandName;

  @override
  String get description {
    return '$_description.\n'
           'This runs the "pub" tool in a Flutter context.';
  }

  @override
  String get invocation {
191
    return '${runner.executableName} pub $_commandName [<arguments...>]';
192 193 194 195
  }

  @override
  Future<FlutterCommandResult> runCommand() async {
196
    await pub(<String>[_commandName, ...argResults.rest], context: PubContext.pubForward, retry: false);
197 198 199 200 201
    return null;
  }

}

202
class PackagesPassthroughCommand extends FlutterCommand {
203 204 205
  PackagesPassthroughCommand() {
    requiresPubspecYaml();
  }
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221

  @override
  String get name => 'pub';

  @override
  String get description {
    return 'Pass the remaining arguments to Dart\'s "pub" tool.\n'
           'This runs the "pub" tool in a Flutter context.';
  }

  @override
  String get invocation {
    return '${runner.executableName} packages pub [<arguments...>]';
  }

  @override
222 223 224 225
  Future<FlutterCommandResult> runCommand() async {
    await pubInteractively(argResults.rest);
    return null;
  }
226
}