Skip to content

Commit 292abf7

Browse files
authored
"flutter packages pub ..." to passthrough to dart pub (flutter#10044)
1 parent 91b1a07 commit 292abf7

File tree

4 files changed

+184
-25
lines changed

4 files changed

+184
-25
lines changed

packages/flutter_tools/lib/src/commands/packages.dart

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class PackagesCommand extends FlutterCommand {
1313
PackagesCommand() {
1414
addSubcommand(new PackagesGetCommand('get', false));
1515
addSubcommand(new PackagesGetCommand('upgrade', true));
16+
addSubcommand(new PackagesTestCommand());
17+
addSubcommand(new PackagesPassthroughCommand());
1618
}
1719

1820
@override
@@ -35,18 +37,18 @@ class PackagesCommand extends FlutterCommand {
3537
}
3638

3739
class PackagesGetCommand extends FlutterCommand {
38-
@override
39-
final String name;
40-
41-
final bool upgrade;
42-
4340
PackagesGetCommand(this.name, this.upgrade) {
4441
argParser.addFlag('offline',
4542
negatable: false,
4643
help: 'Use cached packages instead of accessing the network.'
4744
);
4845
}
4946

47+
@override
48+
final String name;
49+
50+
final bool upgrade;
51+
5052
@override
5153
String get description {
5254
return '${ upgrade ? "Upgrade" : "Get" } packages in a Flutter project.';
@@ -72,9 +74,6 @@ class PackagesGetCommand extends FlutterCommand {
7274
);
7375
}
7476

75-
// TODO(ianh): If the user is using a local build, we should use the
76-
// packages from their build instead of the cache.
77-
7877
await pubGet(
7978
directory: target,
8079
upgrade: upgrade,
@@ -83,3 +82,47 @@ class PackagesGetCommand extends FlutterCommand {
8382
);
8483
}
8584
}
85+
86+
class PackagesTestCommand extends FlutterCommand {
87+
@override
88+
String get name => 'test';
89+
90+
@override
91+
String get description {
92+
return 'Run the "test" package.\n'
93+
'This is similar to "flutter test", but instead of hosting the tests in the\n'
94+
'flutter environment it hosts the tests in a pure Dart environment. The main\n'
95+
'differences are that the "dart:ui" library is not available and that tests\n'
96+
'run faster. This is helpful for testing libraries that do not depend on any\n'
97+
'packages from the Flutter SDK. It is equivalent to "pub run test".';
98+
}
99+
100+
@override
101+
String get invocation {
102+
return '${runner.executableName} packages test [<tests...>]';
103+
}
104+
105+
@override
106+
Future<Null> runCommand() => pub(<String>['run', 'test']..addAll(argResults.rest));
107+
}
108+
109+
class PackagesPassthroughCommand extends FlutterCommand {
110+
PackagesPassthroughCommand();
111+
112+
@override
113+
String get name => 'pub';
114+
115+
@override
116+
String get description {
117+
return 'Pass the remaining arguments to Dart\'s "pub" tool.\n'
118+
'This runs the "pub" tool in a Flutter context.';
119+
}
120+
121+
@override
122+
String get invocation {
123+
return '${runner.executableName} packages pub [<arguments...>]';
124+
}
125+
126+
@override
127+
Future<Null> runCommand() => pub(argResults.rest);
128+
}

packages/flutter_tools/lib/src/dart/pub.dart

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,18 @@ Future<Null> pubGet({
4747

4848
if (!checkLastModified || _shouldRunPubGet(pubSpecYaml: pubSpecYaml, dotPackages: dotPackages)) {
4949
final String command = upgrade ? 'upgrade' : 'get';
50-
final Status status = logger.startProgress("Running 'flutter packages $command' in ${fs.path.basename(directory)}...",
51-
expectSlowOperation: true);
52-
final List<String> args = <String>[sdkBinaryName('pub'), '--verbosity=warning', command, '--no-precompile'];
50+
final Status status = logger.startProgress(
51+
'Running "flutter packages $command" in ${fs.path.basename(directory)}...',
52+
expectSlowOperation: true,
53+
);
54+
final List<String> args = <String>['--verbosity=warning', command, '--no-precompile'];
5355
if (offline)
5456
args.add('--offline');
55-
final int code = await runCommandAndStreamOutput(args,
56-
workingDirectory: directory,
57-
mapFunction: _filterOverrideWarnings,
58-
environment: <String, String>{ 'FLUTTER_ROOT': Cache.flutterRoot, _pubEnvironmentKey: _getPubEnvironmentValue() }
59-
);
60-
status.stop();
61-
if (code != 0)
62-
throwToolExit('pub $command failed ($code)', exitCode: code);
57+
try {
58+
await pub(args, directory: directory, filter: _filterOverrideWarnings, failureMessage: 'pub $command failed');
59+
} finally {
60+
status.stop();
61+
}
6362
}
6463

6564
if (!dotPackages.existsSync())
@@ -69,6 +68,24 @@ Future<Null> pubGet({
6968
throwToolExit('$directory: pub did not update .packages file (pubspec.yaml file has a newer timestamp)');
7069
}
7170

71+
typedef String MessageFilter(String message);
72+
73+
Future<Null> pub(List<String> arguments, {
74+
String directory,
75+
MessageFilter filter,
76+
String failureMessage: 'pub failed'
77+
}) async {
78+
final List<String> command = <String>[ sdkBinaryName('pub') ]..addAll(arguments);
79+
final int code = await runCommandAndStreamOutput(
80+
command,
81+
workingDirectory: directory,
82+
mapFunction: filter,
83+
environment: <String, String>{ 'FLUTTER_ROOT': Cache.flutterRoot, _pubEnvironmentKey: _getPubEnvironmentValue() }
84+
);
85+
if (code != 0)
86+
throwToolExit('$failureMessage ($code)', exitCode: code);
87+
}
88+
7289
final RegExp _analyzerWarning = new RegExp(r'^! \w+ [^ ]+ from path \.\./\.\./bin/cache/dart-sdk/lib/\w+$');
7390

7491
/// The console environment key used by the pub tool.

packages/flutter_tools/test/commands/packages_test.dart

Lines changed: 104 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,20 @@ import 'dart:async';
66

77
import 'package:args/command_runner.dart';
88
import 'package:flutter_tools/src/base/file_system.dart';
9+
import 'package:flutter_tools/src/base/io.dart';
910
import 'package:flutter_tools/src/cache.dart';
1011
import 'package:flutter_tools/src/commands/packages.dart';
12+
import 'package:process/process.dart';
1113
import 'package:test/test.dart';
1214

1315
import '../src/common.dart';
1416
import '../src/context.dart';
1517

1618
void main() {
17-
group('packages', () {
19+
Cache.disableLocking();
20+
group('packages get/upgrade', () {
1821
Directory temp;
1922

20-
setUpAll(() {
21-
Cache.disableLocking();
22-
});
23-
2423
setUp(() {
2524
temp = fs.systemTempDirectory.createTempSync('flutter_tools');
2625
});
@@ -68,4 +67,104 @@ void main() {
6867
expectExists(projectPath, '.packages');
6968
});
7069
});
70+
71+
group('packages test/pub', () {
72+
final List<List<dynamic>> log = <List<dynamic>>[];
73+
testUsingContext('test', () async {
74+
log.clear();
75+
await createTestCommandRunner(new PackagesCommand()).run(<String>['packages', 'test']);
76+
expect(log, hasLength(1));
77+
expect(log[0], hasLength(3));
78+
expect(log[0][0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
79+
expect(log[0][1], 'run');
80+
expect(log[0][2], 'test');
81+
}, overrides: <Type, Generator>{
82+
ProcessManager: () {
83+
return new MockProcessManager((List<dynamic> command) {
84+
log.add(command);
85+
});
86+
},
87+
});
88+
testUsingContext('run', () async {
89+
log.clear();
90+
await createTestCommandRunner(new PackagesCommand()).run(<String>['packages', '--verbose', 'pub', 'run', '--foo', 'bar']);
91+
expect(log, hasLength(1));
92+
expect(log[0], hasLength(4));
93+
expect(log[0][0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
94+
expect(log[0][1], 'run');
95+
expect(log[0][2], '--foo');
96+
expect(log[0][3], 'bar');
97+
}, overrides: <Type, Generator>{
98+
ProcessManager: () {
99+
return new MockProcessManager((List<dynamic> command) {
100+
log.add(command);
101+
});
102+
},
103+
});
104+
});
105+
}
106+
107+
typedef void StartCallback(List<dynamic> command);
108+
109+
class MockProcessManager implements ProcessManager {
110+
MockProcessManager(this.onStart);
111+
112+
final StartCallback onStart;
113+
114+
@override
115+
Future<Process> start(
116+
List<dynamic> command, {
117+
String workingDirectory,
118+
Map<String, String> environment,
119+
bool includeParentEnvironment: true,
120+
bool runInShell: false,
121+
ProcessStartMode mode: ProcessStartMode.NORMAL,
122+
}) {
123+
onStart(command);
124+
return new Future<Process>.value(new MockProcess());
125+
}
126+
127+
@override
128+
dynamic noSuchMethod(Invocation invocation) => null;
129+
}
130+
131+
class MockProcess implements Process {
132+
@override
133+
Stream<List<int>> get stdout => new MockStream<List<int>>();
134+
135+
@override
136+
Stream<List<int>> get stderr => new MockStream<List<int>>();
137+
138+
@override
139+
Future<int> get exitCode => new Future<int>.value(0);
140+
141+
@override
142+
dynamic noSuchMethod(Invocation invocation) => null;
143+
}
144+
145+
class MockStream<T> implements Stream<T> {
146+
@override
147+
Stream<S> transform<S>(StreamTransformer<T, S> streamTransformer) => new MockStream<S>();
148+
149+
@override
150+
Stream<T> where(bool test(T event)) => new MockStream<T>();
151+
152+
@override
153+
StreamSubscription<T> listen(void onData(T event), {Function onError, void onDone(), bool cancelOnError}) {
154+
return new MockStreamSubscription<T>();
155+
}
156+
157+
@override
158+
dynamic noSuchMethod(Invocation invocation) => null;
159+
}
160+
161+
class MockStreamSubscription<T> implements StreamSubscription<T> {
162+
@override
163+
Future<E> asFuture<E>([E futureValue]) => new Future<E>.value();
164+
165+
@override
166+
Future<Null> cancel() => null;
167+
168+
@override
169+
dynamic noSuchMethod(Invocation invocation) => null;
71170
}

packages/flutter_tools/test/src/common.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ String getFlutterRoot() {
5151
}
5252

5353
CommandRunner<Null> createTestCommandRunner([FlutterCommand command]) {
54-
final FlutterCommandRunner runner = new FlutterCommandRunner();
54+
final FlutterCommandRunner runner = new FlutterCommandRunner();
5555
if (command != null)
5656
runner.addCommand(command);
5757
return runner;

0 commit comments

Comments
 (0)