blob: 935b646b0c71e9a1d694195e81b032b8a7e0e002 [file] [log] [blame]
// 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.
/// 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});
}