1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Copyright 2017 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.
/// This file serves as the single point of entry into the `dart:io` APIs
/// within Flutter tools.
///
/// In order to make Flutter tools more testable, we use the `FileSystem` APIs
/// in `package:file` rather than using the `dart:io` file APIs directly (see
/// `file_system.dart`). Doing so allows us to swap out local file system
/// access with mockable (or in-memory) file systems, making our tests hermetic
/// vis-a-vis file system access.
///
/// We also use `package:platform` to provide an abstraction away from the
/// static methods in the `dart:io` `Platform` class (see `platform.dart`). As
/// such, do not export Platform from this file!
///
/// To ensure that all file system and platform API access within Flutter tools
/// goes through the proper APIs, we forbid direct imports of `dart:io` (via a
/// test), forcing all callers to instead import this file, which exports the
/// blessed subset of `dart:io` that is legal to use in Flutter tools.
///
/// Because of the nature of this file, it is important that **platform and file
/// APIs not be exported from `dart:io` in this file**! Moreover, be careful
/// about any additional exports that you add to this file, as doing so will
/// increase the API surface that we have to test in Flutter tools, and the APIs
/// in `dart:io` can sometimes be hard to use in tests.
import 'dart:async';
import 'dart:io' as io show exit, IOSink, ProcessSignal, stderr, stdin, Stdout, stdout;
import 'package:meta/meta.dart';
import 'context.dart';
import 'platform.dart';
import 'process.dart';
export 'dart:io'
show
BytesBuilder,
CompressionOptions,
// Directory NO! Use `file_system.dart`
exitCode,
// File NO! Use `file_system.dart`
// FileSystemEntity NO! Use `file_system.dart`
gzip,
HandshakeException,
HttpClient,
HttpClientRequest,
HttpClientResponse,
HttpClientResponseCompressionState,
HttpHeaders,
HttpRequest,
HttpServer,
HttpStatus,
InternetAddress,
InternetAddressType,
IOException,
IOSink,
// Link NO! Use `file_system.dart`
pid,
// Platform NO! use `platform.dart`
Process,
ProcessException,
ProcessResult,
// ProcessSignal NO! Use [ProcessSignal] below.
ProcessStartMode,
// RandomAccessFile NO! Use `file_system.dart`
ServerSocket,
// stderr, NO! Use `io.dart`
// stdin, NO! Use `io.dart`
Stdin,
StdinException,
// stdout, NO! Use `io.dart`
Stdout,
Socket,
SocketException,
systemEncoding,
WebSocket,
WebSocketException,
WebSocketTransformer;
/// Exits the process with the given [exitCode].
typedef ExitFunction = void Function(int exitCode);
const ExitFunction _defaultExitFunction = io.exit;
ExitFunction _exitFunction = _defaultExitFunction;
/// Exits the process.
///
/// This is analogous to the `exit` function in `dart:io`, except that this
/// function may be set to a testing-friendly value by calling
/// [setExitFunctionForTests] (and then restored to its default implementation
/// with [restoreExitFunction]). The default implementation delegates to
/// `dart:io`.
ExitFunction get exit => _exitFunction;
/// Sets the [exit] function to a function that throws an exception rather
/// than exiting the process; this is intended for testing purposes.
@visibleForTesting
void setExitFunctionForTests([ ExitFunction exitFunction ]) {
_exitFunction = exitFunction ?? (int exitCode) {
throw ProcessExit(exitCode, immediate: true);
};
}
/// Restores the [exit] function to the `dart:io` implementation.
@visibleForTesting
void restoreExitFunction() {
_exitFunction = _defaultExitFunction;
}
/// A portable version of [io.ProcessSignal].
///
/// Listening on signals that don't exist on the current platform is just a
/// no-op. This is in contrast to [io.ProcessSignal], where listening to
/// non-existent signals throws an exception.
class ProcessSignal implements io.ProcessSignal {
@visibleForTesting
const ProcessSignal(this._delegate);
static const ProcessSignal SIGWINCH = _PosixProcessSignal._(io.ProcessSignal.sigwinch);
static const ProcessSignal SIGTERM = _PosixProcessSignal._(io.ProcessSignal.sigterm);
static const ProcessSignal SIGUSR1 = _PosixProcessSignal._(io.ProcessSignal.sigusr1);
static const ProcessSignal SIGUSR2 = _PosixProcessSignal._(io.ProcessSignal.sigusr2);
static const ProcessSignal SIGINT = ProcessSignal(io.ProcessSignal.sigint);
static const ProcessSignal SIGKILL = ProcessSignal(io.ProcessSignal.sigkill);
final io.ProcessSignal _delegate;
@override
Stream<ProcessSignal> watch() {
return _delegate.watch().map<ProcessSignal>((io.ProcessSignal signal) => this);
}
@override
String toString() => _delegate.toString();
}
/// A [ProcessSignal] that is only available on Posix platforms.
///
/// Listening to a [_PosixProcessSignal] is a no-op on Windows.
class _PosixProcessSignal extends ProcessSignal {
const _PosixProcessSignal._(io.ProcessSignal wrappedSignal) : super(wrappedSignal);
@override
Stream<ProcessSignal> watch() {
if (platform.isWindows)
return const Stream<ProcessSignal>.empty();
return super.watch();
}
}
class Stdio {
const Stdio();
Stream<List<int>> get stdin => io.stdin;
io.Stdout get stdout => io.stdout;
io.IOSink get stderr => io.stderr;
bool get hasTerminal => io.stdout.hasTerminal;
int get terminalColumns => hasTerminal ? io.stdout.terminalColumns : null;
int get terminalLines => hasTerminal ? io.stdout.terminalLines : null;
bool get supportsAnsiEscapes => hasTerminal ? io.stdout.supportsAnsiEscapes : false;
}
Stdio get stdio => context.get<Stdio>() ?? const Stdio();
io.Stdout get stdout => stdio.stdout;
Stream<List<int>> get stdin => stdio.stdin;
io.IOSink get stderr => stdio.stderr;