|  | // Copyright 2020 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | // @dart = 2.8 | 
|  |  | 
|  | /// Library for injecting and mocking I/O functionalities. | 
|  | library io; | 
|  |  | 
|  | import 'dart:async'; | 
|  | import 'dart:io' as dart_io; | 
|  | import 'dart:mirrors'; | 
|  |  | 
|  | import 'package:fxutils/fxutils.dart' as fxutils; | 
|  | import 'package:file/file.dart'; | 
|  | import 'package:file/local.dart'; | 
|  | import 'package:process/process.dart'; | 
|  |  | 
|  | /// Abstract interface for doing I/O (console output, process creation, etc.). | 
|  | /// See `Standard` for the production implemention used to run `fx codesize`. | 
|  | /// When running unit tests, we would provide mock implementations which | 
|  | /// record I/O activities instead. | 
|  | abstract class Io { | 
|  | static Io get() => | 
|  | Zone.current[#io] ?? (throw Exception('Missing dependency #io')); | 
|  |  | 
|  | /// The standard program output stream. | 
|  | StringSink get out; | 
|  |  | 
|  | /// The error output stream. | 
|  | StringSink get err; | 
|  |  | 
|  | /// Prints the object to the standard output stream. | 
|  | void print(Object object); | 
|  |  | 
|  | ProcessManager get processManager; | 
|  |  | 
|  | fxutils.FxEnv get fxEnv; | 
|  |  | 
|  | fxutils.Fx get fx; | 
|  |  | 
|  | /// Sets the exit code of the program. | 
|  | set exitCode(int code); | 
|  |  | 
|  | /// Returns the current working directory path. | 
|  | String get cwd; | 
|  |  | 
|  | /// Returns the environment variables; | 
|  | Map<String, String> get environment; | 
|  |  | 
|  | File createTempFile(String name); | 
|  | } | 
|  |  | 
|  | class Standard implements Io { | 
|  | static Map<Object, Object> inject() => {#io: Standard()}; | 
|  |  | 
|  | final FileSystem _fs = LocalFileSystem(); | 
|  |  | 
|  | @override | 
|  | StringSink get out => dart_io.stdout; | 
|  |  | 
|  | @override | 
|  | StringSink get err => dart_io.stderr; | 
|  |  | 
|  | @override | 
|  | void print(Object object) { | 
|  | dart_io.stdout.writeln(object); | 
|  | } | 
|  |  | 
|  | @override | 
|  | ProcessManager get processManager => LocalProcessManager(); | 
|  |  | 
|  | fxutils.FxEnv _fxEnv; | 
|  |  | 
|  | @override | 
|  | fxutils.FxEnv get fxEnv { | 
|  | if (_fxEnv != null) { | 
|  | return _fxEnv; | 
|  | } | 
|  |  | 
|  | final envReader = fxutils.EnvReader(cwd: cwd, environment: environment); | 
|  | return _fxEnv = fxutils.FxEnv(envReader: envReader); | 
|  | } | 
|  |  | 
|  | fxutils.Fx _fx; | 
|  |  | 
|  | @override | 
|  | fxutils.Fx get fx { | 
|  | if (_fx != null) { | 
|  | return _fx; | 
|  | } | 
|  |  | 
|  | return _fx = fxutils.Fx(fxEnv: fxEnv); | 
|  | } | 
|  |  | 
|  | @override | 
|  | set exitCode(int code) => dart_io.exitCode = code; | 
|  |  | 
|  | @override | 
|  | String get cwd => dart_io.Directory.current.path; | 
|  |  | 
|  | @override | 
|  | Map<String, String> get environment => dart_io.Platform.environment; | 
|  |  | 
|  | @override | 
|  | File createTempFile(String name) => | 
|  | _fs.systemTempDirectory.createTempSync().childFile(name); | 
|  | } | 
|  |  | 
|  | Future<R> runWithIo<IoType extends Io, R>(Future<R> Function() f) { | 
|  | // ignore: avoid_as | 
|  | final IoType io = (reflectType(IoType) as ClassMirror) | 
|  | .newInstance(Symbol(''), []).reflectee; | 
|  | return runZoned(f, | 
|  | zoneSpecification: ZoneSpecification( | 
|  | print: (Zone self, ZoneDelegate parent, Zone zone, String line) => | 
|  | io.out.writeln(line)), | 
|  | zoneValues: {#io: io}); | 
|  | } |