85 lines
3.3 KiB
Dart
85 lines
3.3 KiB
Dart
// 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 'package:process/process.dart';
|
|
import 'package:process/record_replay.dart';
|
|
|
|
import 'common.dart';
|
|
import 'context.dart';
|
|
import 'file_system.dart';
|
|
import 'process.dart';
|
|
|
|
/// The active process manager.
|
|
ProcessManager get processManager => context[ProcessManager];
|
|
|
|
/// Enables recording of process invocation activity to the specified location.
|
|
///
|
|
/// This sets the [active process manager](processManager) to one that records
|
|
/// all process activity before delegating to a [LocalProcessManager].
|
|
///
|
|
/// [location] must either represent a valid, empty directory or a non-existent
|
|
/// file system entity, in which case a directory will be created at that path.
|
|
/// Process invocation activity will be serialized to opaque files in that
|
|
/// directory. The resulting (populated) directory will be suitable for use
|
|
/// with [enableReplayProcessManager].
|
|
void enableRecordingProcessManager(String location) {
|
|
if (location.isEmpty)
|
|
throwToolExit('record-to location not specified');
|
|
switch (fs.typeSync(location, followLinks: false)) {
|
|
case FileSystemEntityType.FILE:
|
|
case FileSystemEntityType.LINK:
|
|
throwToolExit('record-to location must reference a directory');
|
|
break;
|
|
case FileSystemEntityType.DIRECTORY:
|
|
if (fs.directory(location).listSync(followLinks: false).isNotEmpty)
|
|
throwToolExit('record-to directory must be empty');
|
|
break;
|
|
case FileSystemEntityType.NOT_FOUND:
|
|
fs.directory(location).createSync(recursive: true);
|
|
}
|
|
Directory dir = fs.directory(location);
|
|
|
|
ProcessManager delegate = new LocalProcessManager();
|
|
RecordingProcessManager manager = new RecordingProcessManager(delegate, dir);
|
|
addShutdownHook(() async {
|
|
await manager.flush(finishRunningProcesses: true);
|
|
});
|
|
|
|
context.setVariable(ProcessManager, manager);
|
|
}
|
|
|
|
/// Enables process invocation replay mode.
|
|
///
|
|
/// This sets the [active process manager](processManager) to one that replays
|
|
/// process activity from a previously recorded set of invocations.
|
|
///
|
|
/// [location] must represent a directory to which process activity has been
|
|
/// recorded (i.e. the result of having been previously passed to
|
|
/// [enableRecordingProcessManager]).
|
|
Future<Null> enableReplayProcessManager(String location) async {
|
|
if (location.isEmpty)
|
|
throwToolExit('replay-from location not specified');
|
|
Directory dir = fs.directory(location);
|
|
if (!dir.existsSync())
|
|
throwToolExit('replay-from location must reference a directory');
|
|
|
|
ProcessManager manager;
|
|
try {
|
|
manager = await ReplayProcessManager.create(dir,
|
|
// TODO(tvolkert): Once https://github.com/flutter/flutter/issues/7166 is
|
|
// resolved, we can use the default `streamDelay`. In the
|
|
// meantime, native file I/O operations cause our `tail` process
|
|
// streams to flush before our protocol discovery is listening on
|
|
// them, causing us to timeout waiting for the observatory port.
|
|
streamDelay: const Duration(milliseconds: 50),
|
|
);
|
|
} on ArgumentError catch (error) {
|
|
throwToolExit('Invalid replay-from: $error');
|
|
}
|
|
|
|
context.setVariable(ProcessManager, manager);
|
|
}
|