// 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 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); }