Commit 03d163ce authored by Todd Volkert's avatar Todd Volkert Committed by GitHub

Update tools to use package:process (#7590)

parent 24f1b2ee
......@@ -5,6 +5,7 @@
import 'dart:async';
import 'package:args/args.dart';
import 'package:process/process.dart';
import '../lib/src/base/common.dart';
import '../lib/src/base/config.dart';
......@@ -13,7 +14,6 @@ import '../lib/src/base/file_system.dart';
import '../lib/src/base/io.dart';
import '../lib/src/base/logger.dart';
import '../lib/src/base/os.dart';
import '../lib/src/base/process_manager.dart';
import '../lib/src/cache.dart';
import '../lib/src/flx.dart';
import '../lib/src/globals.dart';
......@@ -39,7 +39,7 @@ Future<Null> main(List<String> args) async {
executableContext.runInZone(() {
// Initialize the context with some defaults.
context.putIfAbsent(FileSystem, () => new LocalFileSystem());
context.putIfAbsent(ProcessManager, () => new ProcessManager());
context.putIfAbsent(ProcessManager, () => new LocalProcessManager());
context.putIfAbsent(Logger, () => new StdoutLogger());
context.putIfAbsent(Cache, () => new Cache());
context.putIfAbsent(Config, () => new Config());
......
......@@ -5,6 +5,7 @@
import 'dart:async';
import 'package:args/command_runner.dart';
import 'package:process/process.dart';
import 'package:stack_trace/stack_trace.dart';
import 'src/base/common.dart';
......@@ -15,7 +16,6 @@ import 'src/base/io.dart';
import 'src/base/logger.dart';
import 'src/base/os.dart';
import 'src/base/process.dart';
import 'src/base/process_manager.dart';
import 'src/base/utils.dart';
import 'src/cache.dart';
import 'src/commands/analyze.dart';
......@@ -103,7 +103,7 @@ Future<Null> main(List<String> args) async {
// Seed these context entries first since others depend on them
context.putIfAbsent(FileSystem, () => new LocalFileSystem());
context.putIfAbsent(ProcessManager, () => new ProcessManager());
context.putIfAbsent(ProcessManager, () => new LocalProcessManager());
context.putIfAbsent(Logger, () => new StdoutLogger());
// Order-independent context entries
......
......@@ -100,16 +100,15 @@ class FlutterCommandRunner extends CommandRunner<Null> {
hide: !verboseHelp,
help:
'Enables recording of process invocations (including stdout and stderr of all such invocations),\n'
'and serializes that recording to the specified location. If the location is a directory, a ZIP\n'
'file named `recording.zip` will be created in that directory. Otherwise, a ZIP file will be\n'
'created with the path specified in this flag.');
'and serializes that recording to a directory with the path specified in this flag. If the\n'
'directory does not already exist, it will be created.');
argParser.addOption('replay-from',
hide: !verboseHelp,
help:
'Enables mocking of process invocations by replaying their stdout, stderr, and exit code from\n'
'the specified recording (obtained via --record-to). If the location is a file, it is assumed to\n'
'be a ZIP file structured according to the output of --record-to. If the location is a directory,\n'
'it is assumed to be an unzipped version of such a ZIP file.');
'the specified recording (obtained via --record-to). The path specified in this flag must refer\n'
'to a directory that holds serialized process invocations structured according to the output of\n'
'--record-to.');
}
@override
......@@ -164,23 +163,11 @@ class FlutterCommandRunner extends CommandRunner<Null> {
throwToolExit('--record-to and --replay-from cannot be used together.');
if (globalResults['record-to'] != null) {
// Turn on recording.
String recordTo = globalResults['record-to'].trim();
if (recordTo.isEmpty)
recordTo = null;
context.setVariable(ProcessManager,
new RecordingProcessManager(recordTo));
enableRecordingProcessManager(globalResults['record-to'].trim());
}
if (globalResults['replay-from'] != null) {
// Turn on replay-based mocking.
try {
context.setVariable(ProcessManager, await ReplayProcessManager.create(
globalResults['replay-from'].trim(),
));
} on ArgumentError {
throwToolExit('--replay-from must specify a valid file or directory.');
}
await enableReplayProcessManager(globalResults['replay-from'].trim());
}
logger.quiet = globalResults['quiet'];
......
......@@ -22,6 +22,7 @@ dependencies:
mustache: ^0.2.5
package_config: '>=0.1.5 <2.0.0'
path: ^1.4.0
process: ^1.0.0
pub_semver: ^1.0.0
stack_trace: ^1.4.0
usage: ^2.2.1
......
......@@ -37,7 +37,6 @@ import 'install_test.dart' as install_test;
import 'logs_test.dart' as logs_test;
import 'os_utils_test.dart' as os_utils_test;
import 'packages_test.dart' as packages_test;
import 'process_manager_test.dart' as process_manager_test;
import 'protocol_discovery_test.dart' as protocol_discovery_test;
import 'run_test.dart' as run_test;
import 'stop_test.dart' as stop_test;
......@@ -77,7 +76,6 @@ void main() {
logs_test.main();
os_utils_test.main();
packages_test.main();
process_manager_test.main();
protocol_discovery_test.main();
run_test.main();
stop_test.main();
......
[
{
"pid": 100,
"basename": "001.sing.100",
"executable": "sing",
"arguments": [
"ppap"
],
"mode": "ProcessStartMode.NORMAL",
"exitCode": 0
},
{
"pid": 101,
"basename": "002.dance.101",
"executable": "dance",
"arguments": [
"gangnam-style"
],
"stdoutEncoding": "system",
"stderrEncoding": "system",
"exitCode": 2
}
]
// 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';
import 'dart:convert';
import 'package:archive/archive.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/base/process_manager.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
typedef bool Predicate<T>(T item);
/// Decodes a UTF8-encoded byte array into a list of Strings, where each list
/// entry represents a line of text.
List<String> _decode(List<int> data) =>
const LineSplitter().convert(UTF8.decode(data));
/// Consumes and returns an entire stream of bytes.
Future<List<int>> _consume(Stream<List<int>> stream) =>
stream.expand((List<int> data) => data).toList();
void main() {
group('RecordingProcessManager', () {
Directory tmp;
ProcessManager manager;
setUp(() {
tmp = fs.systemTempDirectory.createTempSync('flutter_tools_');
manager = new RecordingProcessManager(tmp.path);
});
tearDown(() {
tmp.deleteSync(recursive: true);
});
test('start', () async {
Process process = await manager.start('echo', <String>['foo']);
int pid = process.pid;
int exitCode = await process.exitCode;
List<int> stdout = await _consume(process.stdout);
List<int> stderr = await _consume(process.stderr);
expect(exitCode, 0);
expect(_decode(stdout), <String>['foo']);
expect(stderr, isEmpty);
// Force the recording to be written to disk.
await runShutdownHooks();
_Recording recording = _Recording.readFrom(tmp);
expect(recording.manifest, hasLength(1));
Map<String, dynamic> entry = recording.manifest.first;
expect(entry['pid'], pid);
expect(entry['exitCode'], exitCode);
expect(recording.stdoutForEntryAt(0), stdout);
expect(recording.stderrForEntryAt(0), stderr);
});
test('run', () async {
ProcessResult result = await manager.run('echo', <String>['bar']);
int pid = result.pid;
int exitCode = result.exitCode;
String stdout = result.stdout;
String stderr = result.stderr;
expect(exitCode, 0);
expect(stdout, 'bar\n');
expect(stderr, isEmpty);
// Force the recording to be written to disk.
await runShutdownHooks();
_Recording recording = _Recording.readFrom(tmp);
expect(recording.manifest, hasLength(1));
Map<String, dynamic> entry = recording.manifest.first;
expect(entry['pid'], pid);
expect(entry['exitCode'], exitCode);
expect(recording.stdoutForEntryAt(0), stdout);
expect(recording.stderrForEntryAt(0), stderr);
});
test('runSync', () async {
ProcessResult result = manager.runSync('echo', <String>['baz']);
int pid = result.pid;
int exitCode = result.exitCode;
String stdout = result.stdout;
String stderr = result.stderr;
expect(exitCode, 0);
expect(stdout, 'baz\n');
expect(stderr, isEmpty);
// Force the recording to be written to disk.
await runShutdownHooks();
_Recording recording = _Recording.readFrom(tmp);
expect(recording.manifest, hasLength(1));
Map<String, dynamic> entry = recording.manifest.first;
expect(entry['pid'], pid);
expect(entry['exitCode'], exitCode);
expect(recording.stdoutForEntryAt(0), stdout);
expect(recording.stderrForEntryAt(0), stderr);
});
});
group('ReplayProcessManager', () {
ProcessManager manager;
setUp(() async {
await runInMinimalContext(() async {
Directory dir = fs.directory('test/data/process_manager/replay');
manager = await ReplayProcessManager.create(dir.path);
});
});
tearDown(() async {
// Allow the replay manager to clean up
await runShutdownHooks();
});
test('start', () async {
Process process = await manager.start('sing', <String>['ppap']);
int exitCode = await process.exitCode;
List<int> stdout = await _consume(process.stdout);
List<int> stderr = await _consume(process.stderr);
expect(process.pid, 100);
expect(exitCode, 0);
expect(_decode(stdout), <String>['I have a pen', 'I have a pineapple']);
expect(_decode(stderr), <String>['Uh, pineapple pen']);
});
test('run', () async {
ProcessResult result = await manager.run('dance', <String>['gangnam-style']);
expect(result.pid, 101);
expect(result.exitCode, 2);
expect(result.stdout, '');
expect(result.stderr, 'No one can dance like Psy\n');
});
test('runSync', () {
ProcessResult result = manager.runSync('dance', <String>['gangnam-style']);
expect(result.pid, 101);
expect(result.exitCode, 2);
expect(result.stdout, '');
expect(result.stderr, 'No one can dance like Psy\n');
});
});
}
Future<Null> runInMinimalContext(Future<dynamic> method()) async {
AppContext context = new AppContext();
context.putIfAbsent(FileSystem, () => new LocalFileSystem());
context.putIfAbsent(ProcessManager, () => new ProcessManager());
context.putIfAbsent(Logger, () => new BufferLogger());
context.putIfAbsent(OperatingSystemUtils, () => new OperatingSystemUtils());
await context.runInZone(method);
}
/// A testing utility class that encapsulates a recording.
class _Recording {
final File file;
final Archive _archive;
_Recording(this.file, this._archive);
static _Recording readFrom(Directory dir) {
File file = fs.file(path.join(
dir.path, RecordingProcessManager.kDefaultRecordTo));
Archive archive = new ZipDecoder().decodeBytes(file.readAsBytesSync());
return new _Recording(file, archive);
}
List<Map<String, dynamic>> get manifest {
return JSON.decoder.convert(_getFileContent('MANIFEST.txt', UTF8));
}
dynamic stdoutForEntryAt(int index) =>
_getStdioContent(manifest[index], 'stdout');
dynamic stderrForEntryAt(int index) =>
_getStdioContent(manifest[index], 'stderr');
dynamic _getFileContent(String name, Encoding encoding) {
List<int> bytes = _fileNamed(name).content;
return encoding == null ? bytes : encoding.decode(bytes);
}
dynamic _getStdioContent(Map<String, dynamic> entry, String type) {
String basename = entry['basename'];
String encodingName = entry['${type}Encoding'];
Encoding encoding;
if (encodingName != null)
encoding = encodingName == 'system'
? SYSTEM_ENCODING
: Encoding.getByName(encodingName);
return _getFileContent('$basename.$type', encoding);
}
ArchiveFile _fileNamed(String name) => _archive.firstWhere(_hasName(name));
Predicate<ArchiveFile> _hasName(String name) =>
(ArchiveFile file) => file.name == name;
}
......@@ -3,9 +3,9 @@
// found in the LICENSE file.
import 'package:args/command_runner.dart';
import 'package:process/process.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/process_manager.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:flutter_tools/src/runner/flutter_command_runner.dart';
......
......@@ -10,7 +10,6 @@ import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/process_manager.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/devfs.dart';
......@@ -23,6 +22,7 @@ import 'package:flutter_tools/src/usage.dart';
import 'package:mockito/mockito.dart';
import 'package:path/path.dart' as path;
import 'package:process/process.dart';
import 'package:test/test.dart';
/// Return the test logger. This assumes that the current Logger is a BufferLogger.
......@@ -43,7 +43,7 @@ void testUsingContext(String description, dynamic testMethod(), {
// Initialize the test context with some default mocks.
// Seed these context entries first since others depend on them
testContext.putIfAbsent(FileSystem, () => new LocalFileSystem());
testContext.putIfAbsent(ProcessManager, () => new ProcessManager());
testContext.putIfAbsent(ProcessManager, () => new LocalProcessManager());
testContext.putIfAbsent(Logger, () => new BufferLogger());
// Order-independent context entries
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment