[flutter_tools] io cleanups to simplify null safety migration (#77955)
This commit is contained in:
parent
85b22ff594
commit
9f420ffb3e
@ -48,11 +48,10 @@ import 'dart:io' as io
|
|||||||
stdout;
|
stdout;
|
||||||
|
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
import 'package:file/file.dart';
|
||||||
|
|
||||||
import '../globals.dart' as globals;
|
|
||||||
import 'async_guard.dart';
|
import 'async_guard.dart';
|
||||||
import 'context.dart';
|
import 'platform.dart';
|
||||||
import 'file_system.dart';
|
|
||||||
import 'process.dart';
|
import 'process.dart';
|
||||||
|
|
||||||
export 'dart:io'
|
export 'dart:io'
|
||||||
@ -165,16 +164,18 @@ void restoreExitFunction() {
|
|||||||
/// [ProcessSignal] instances are available on this class (e.g. "send").
|
/// [ProcessSignal] instances are available on this class (e.g. "send").
|
||||||
class ProcessSignal {
|
class ProcessSignal {
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
const ProcessSignal(this._delegate);
|
const ProcessSignal(this._delegate, {@visibleForTesting Platform platform = const LocalPlatform()})
|
||||||
|
: _platform = platform;
|
||||||
|
|
||||||
static const ProcessSignal SIGWINCH = _PosixProcessSignal._(io.ProcessSignal.sigwinch);
|
static const ProcessSignal sigwinch = PosixProcessSignal(io.ProcessSignal.sigwinch);
|
||||||
static const ProcessSignal SIGTERM = _PosixProcessSignal._(io.ProcessSignal.sigterm);
|
static const ProcessSignal sigterm = PosixProcessSignal(io.ProcessSignal.sigterm);
|
||||||
static const ProcessSignal SIGUSR1 = _PosixProcessSignal._(io.ProcessSignal.sigusr1);
|
static const ProcessSignal sigusr1 = PosixProcessSignal(io.ProcessSignal.sigusr1);
|
||||||
static const ProcessSignal SIGUSR2 = _PosixProcessSignal._(io.ProcessSignal.sigusr2);
|
static const ProcessSignal sigusr2 = PosixProcessSignal(io.ProcessSignal.sigusr2);
|
||||||
static const ProcessSignal SIGINT = ProcessSignal(io.ProcessSignal.sigint);
|
static const ProcessSignal sigint = ProcessSignal(io.ProcessSignal.sigint);
|
||||||
static const ProcessSignal SIGKILL = ProcessSignal(io.ProcessSignal.sigkill);
|
static const ProcessSignal sigkill = ProcessSignal(io.ProcessSignal.sigkill);
|
||||||
|
|
||||||
final io.ProcessSignal _delegate;
|
final io.ProcessSignal _delegate;
|
||||||
|
final Platform _platform;
|
||||||
|
|
||||||
Stream<ProcessSignal> watch() {
|
Stream<ProcessSignal> watch() {
|
||||||
return _delegate.watch().map<ProcessSignal>((io.ProcessSignal signal) => this);
|
return _delegate.watch().map<ProcessSignal>((io.ProcessSignal signal) => this);
|
||||||
@ -184,12 +185,12 @@ class ProcessSignal {
|
|||||||
///
|
///
|
||||||
/// Returns true if the signal was delivered, false otherwise.
|
/// Returns true if the signal was delivered, false otherwise.
|
||||||
///
|
///
|
||||||
/// On Windows, this can only be used with [ProcessSignal.SIGTERM], which
|
/// On Windows, this can only be used with [ProcessSignal.sigterm], which
|
||||||
/// terminates the process.
|
/// terminates the process.
|
||||||
///
|
///
|
||||||
/// This is implemented by sending the signal using [Process.killPid].
|
/// This is implemented by sending the signal using [Process.killPid].
|
||||||
bool send(int pid) {
|
bool send(int pid) {
|
||||||
assert(!globals.platform.isWindows || this == ProcessSignal.SIGTERM);
|
assert(!_platform.isWindows || this == ProcessSignal.sigterm);
|
||||||
return io.Process.killPid(pid, _delegate);
|
return io.Process.killPid(pid, _delegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,13 +201,16 @@ class ProcessSignal {
|
|||||||
/// A [ProcessSignal] that is only available on Posix platforms.
|
/// A [ProcessSignal] that is only available on Posix platforms.
|
||||||
///
|
///
|
||||||
/// Listening to a [_PosixProcessSignal] is a no-op on Windows.
|
/// Listening to a [_PosixProcessSignal] is a no-op on Windows.
|
||||||
class _PosixProcessSignal extends ProcessSignal {
|
@visibleForTesting
|
||||||
|
class PosixProcessSignal extends ProcessSignal {
|
||||||
|
|
||||||
const _PosixProcessSignal._(io.ProcessSignal wrappedSignal) : super(wrappedSignal);
|
const PosixProcessSignal(io.ProcessSignal wrappedSignal, {@visibleForTesting Platform platform = const LocalPlatform()})
|
||||||
|
: super(wrappedSignal, platform: platform);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<ProcessSignal> watch() {
|
Stream<ProcessSignal> watch() {
|
||||||
if (globals.platform.isWindows) {
|
// This uses the real platform since it invokes dart:io functionality directly.
|
||||||
|
if (_platform.isWindows) {
|
||||||
return const Stream<ProcessSignal>.empty();
|
return const Stream<ProcessSignal>.empty();
|
||||||
}
|
}
|
||||||
return super.watch();
|
return super.watch();
|
||||||
@ -367,10 +371,9 @@ class Stdio {
|
|||||||
|
|
||||||
/// An overridable version of io.ProcessInfo.
|
/// An overridable version of io.ProcessInfo.
|
||||||
abstract class ProcessInfo {
|
abstract class ProcessInfo {
|
||||||
factory ProcessInfo() => _DefaultProcessInfo(globals.fs);
|
factory ProcessInfo(FileSystem fs) => _DefaultProcessInfo(fs);
|
||||||
factory ProcessInfo.test(FileSystem fs) => _TestProcessInfo(fs);
|
|
||||||
|
|
||||||
static ProcessInfo get instance => context.get<ProcessInfo>();
|
factory ProcessInfo.test(FileSystem fs) => _TestProcessInfo(fs);
|
||||||
|
|
||||||
int get currentRss;
|
int get currentRss;
|
||||||
|
|
||||||
@ -379,8 +382,6 @@ abstract class ProcessInfo {
|
|||||||
File writePidFile(String pidFile);
|
File writePidFile(String pidFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessInfo get processInfo => ProcessInfo.instance;
|
|
||||||
|
|
||||||
/// The default implementation of [ProcessInfo], which uses [io.ProcessInfo].
|
/// The default implementation of [ProcessInfo], which uses [io.ProcessInfo].
|
||||||
class _DefaultProcessInfo implements ProcessInfo {
|
class _DefaultProcessInfo implements ProcessInfo {
|
||||||
_DefaultProcessInfo(this._fileSystem);
|
_DefaultProcessInfo(this._fileSystem);
|
||||||
|
@ -24,8 +24,8 @@ abstract class Signals {
|
|||||||
|
|
||||||
// The default list of signals that should cause the process to exit.
|
// The default list of signals that should cause the process to exit.
|
||||||
static const List<ProcessSignal> defaultExitSignals = <ProcessSignal>[
|
static const List<ProcessSignal> defaultExitSignals = <ProcessSignal>[
|
||||||
ProcessSignal.SIGTERM,
|
ProcessSignal.sigterm,
|
||||||
ProcessSignal.SIGINT,
|
ProcessSignal.sigint,
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Adds a signal handler to run on receipt of signal.
|
/// Adds a signal handler to run on receipt of signal.
|
||||||
|
@ -368,7 +368,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
|
|||||||
logger: globals.logger,
|
logger: globals.logger,
|
||||||
terminal: globals.terminal,
|
terminal: globals.terminal,
|
||||||
signals: globals.signals,
|
signals: globals.signals,
|
||||||
processInfo: processInfo,
|
processInfo: globals.processInfo,
|
||||||
reportReady: boolArg('report-ready'),
|
reportReady: boolArg('report-ready'),
|
||||||
pidFile: stringArg('pid-file'),
|
pidFile: stringArg('pid-file'),
|
||||||
)
|
)
|
||||||
|
@ -67,12 +67,12 @@ class LogsCommand extends FlutterCommand {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// When terminating, close down the log reader.
|
// When terminating, close down the log reader.
|
||||||
ProcessSignal.SIGINT.watch().listen((ProcessSignal signal) {
|
ProcessSignal.sigint.watch().listen((ProcessSignal signal) {
|
||||||
subscription.cancel();
|
subscription.cancel();
|
||||||
globals.printStatus('');
|
globals.printStatus('');
|
||||||
exitCompleter.complete(0);
|
exitCompleter.complete(0);
|
||||||
});
|
});
|
||||||
ProcessSignal.SIGTERM.watch().listen((ProcessSignal signal) {
|
ProcessSignal.sigterm.watch().listen((ProcessSignal signal) {
|
||||||
subscription.cancel();
|
subscription.cancel();
|
||||||
exitCompleter.complete(0);
|
exitCompleter.complete(0);
|
||||||
});
|
});
|
||||||
|
@ -12,7 +12,6 @@ import 'package:vm_service/vm_service.dart';
|
|||||||
import '../android/android_device.dart';
|
import '../android/android_device.dart';
|
||||||
import '../base/common.dart';
|
import '../base/common.dart';
|
||||||
import '../base/file_system.dart';
|
import '../base/file_system.dart';
|
||||||
import '../base/io.dart';
|
|
||||||
import '../base/utils.dart';
|
import '../base/utils.dart';
|
||||||
import '../build_info.dart';
|
import '../build_info.dart';
|
||||||
import '../device.dart';
|
import '../device.dart';
|
||||||
@ -639,7 +638,7 @@ class RunCommand extends RunCommandBase {
|
|||||||
logger: globals.logger,
|
logger: globals.logger,
|
||||||
terminal: globals.terminal,
|
terminal: globals.terminal,
|
||||||
signals: globals.signals,
|
signals: globals.signals,
|
||||||
processInfo: processInfo,
|
processInfo: globals.processInfo,
|
||||||
reportReady: boolArg('report-ready'),
|
reportReady: boolArg('report-ready'),
|
||||||
pidFile: stringArg('pid-file'),
|
pidFile: stringArg('pid-file'),
|
||||||
)
|
)
|
||||||
|
@ -286,7 +286,7 @@ Future<T> runInContext<T>(
|
|||||||
logger: globals.logger,
|
logger: globals.logger,
|
||||||
platform: globals.platform,
|
platform: globals.platform,
|
||||||
),
|
),
|
||||||
ProcessInfo: () => ProcessInfo(),
|
ProcessInfo: () => ProcessInfo(globals.fs),
|
||||||
ProcessManager: () => ErrorHandlingProcessManager(
|
ProcessManager: () => ErrorHandlingProcessManager(
|
||||||
delegate: const LocalProcessManager(),
|
delegate: const LocalProcessManager(),
|
||||||
platform: globals.platform,
|
platform: globals.platform,
|
||||||
|
@ -126,6 +126,8 @@ Future<bool> get isRunningOnBot => botDetector.isRunningOnBot;
|
|||||||
/// The current system clock instance.
|
/// The current system clock instance.
|
||||||
SystemClock get systemClock => context.get<SystemClock>();
|
SystemClock get systemClock => context.get<SystemClock>();
|
||||||
|
|
||||||
|
ProcessInfo get processInfo => context.get<ProcessInfo>();
|
||||||
|
|
||||||
/// Display an error level message to the user. Commands should use this if they
|
/// Display an error level message to the user. Commands should use this if they
|
||||||
/// fail in some way.
|
/// fail in some way.
|
||||||
///
|
///
|
||||||
|
@ -209,7 +209,7 @@ class CommandResultEvent extends UsageEvent {
|
|||||||
// so that we can get the command result even if trying to grab maxRss
|
// so that we can get the command result even if trying to grab maxRss
|
||||||
// throws an exception.
|
// throws an exception.
|
||||||
try {
|
try {
|
||||||
final int maxRss = processInfo.maxRss;
|
final int maxRss = globals.processInfo.maxRss;
|
||||||
flutterUsage.sendEvent(
|
flutterUsage.sendEvent(
|
||||||
'tool-command-max-rss',
|
'tool-command-max-rss',
|
||||||
category,
|
category,
|
||||||
|
@ -1501,11 +1501,11 @@ class TerminalHandler {
|
|||||||
|
|
||||||
void registerSignalHandlers() {
|
void registerSignalHandlers() {
|
||||||
assert(residentRunner.stayResident);
|
assert(residentRunner.stayResident);
|
||||||
_addSignalHandler(io.ProcessSignal.SIGINT, _cleanUp);
|
_addSignalHandler(io.ProcessSignal.sigint, _cleanUp);
|
||||||
_addSignalHandler(io.ProcessSignal.SIGTERM, _cleanUp);
|
_addSignalHandler(io.ProcessSignal.sigterm, _cleanUp);
|
||||||
if (residentRunner.supportsServiceProtocol && residentRunner.supportsRestart) {
|
if (residentRunner.supportsServiceProtocol && residentRunner.supportsRestart) {
|
||||||
_addSignalHandler(io.ProcessSignal.SIGUSR1, _handleSignal);
|
_addSignalHandler(io.ProcessSignal.sigusr1, _handleSignal);
|
||||||
_addSignalHandler(io.ProcessSignal.SIGUSR2, _handleSignal);
|
_addSignalHandler(io.ProcessSignal.sigusr2, _handleSignal);
|
||||||
if (_pidFile != null) {
|
if (_pidFile != null) {
|
||||||
_logger.printTrace('Writing pid to: $_pidFile');
|
_logger.printTrace('Writing pid to: $_pidFile');
|
||||||
_actualPidFile = _processInfo.writePidFile(_pidFile);
|
_actualPidFile = _processInfo.writePidFile(_pidFile);
|
||||||
@ -1663,7 +1663,7 @@ class TerminalHandler {
|
|||||||
}
|
}
|
||||||
_processingUserRequest = true;
|
_processingUserRequest = true;
|
||||||
|
|
||||||
final bool fullRestart = signal == io.ProcessSignal.SIGUSR2;
|
final bool fullRestart = signal == io.ProcessSignal.sigusr2;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await residentRunner.restart(fullRestart: fullRestart);
|
await residentRunner.restart(fullRestart: fullRestart);
|
||||||
|
@ -1075,8 +1075,8 @@ abstract class FlutterCommand extends Command<void> {
|
|||||||
globals.systemClock.now(),
|
globals.systemClock.now(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
globals.signals.addHandler(io.ProcessSignal.SIGTERM, handler);
|
globals.signals.addHandler(io.ProcessSignal.sigterm, handler);
|
||||||
globals.signals.addHandler(io.ProcessSignal.SIGINT, handler);
|
globals.signals.addHandler(io.ProcessSignal.sigint, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Logs data about this command.
|
/// Logs data about this command.
|
||||||
|
@ -9,6 +9,7 @@ import 'dart:io' as io;
|
|||||||
|
|
||||||
import 'package:file/memory.dart';
|
import 'package:file/memory.dart';
|
||||||
import 'package:flutter_tools/src/base/io.dart';
|
import 'package:flutter_tools/src/base/io.dart';
|
||||||
|
import 'package:flutter_tools/src/base/platform.dart';
|
||||||
import 'package:test/fake.dart';
|
import 'package:test/fake.dart';
|
||||||
|
|
||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
@ -66,7 +67,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('ProcessSignal toString() works', () async {
|
testUsingContext('ProcessSignal toString() works', () async {
|
||||||
expect(io.ProcessSignal.sigint.toString(), ProcessSignal.SIGINT.toString());
|
expect(io.ProcessSignal.sigint.toString(), ProcessSignal.sigint.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('exit throws a StateError if called without being overriden', () {
|
test('exit throws a StateError if called without being overriden', () {
|
||||||
@ -100,6 +101,18 @@ void main() {
|
|||||||
|
|
||||||
resetNetworkInterfaceLister();
|
resetNetworkInterfaceLister();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext('Does not listen to Posix process signals on windows', () async {
|
||||||
|
final FakePlatform windows = FakePlatform(operatingSystem: 'windows');
|
||||||
|
final FakePlatform linux = FakePlatform(operatingSystem: 'linux');
|
||||||
|
final FakeProcessSignal fakeSignalA = FakeProcessSignal();
|
||||||
|
final FakeProcessSignal fakeSignalB = FakeProcessSignal();
|
||||||
|
fakeSignalA.controller.add(fakeSignalA);
|
||||||
|
fakeSignalB.controller.add(fakeSignalB);
|
||||||
|
|
||||||
|
expect(await PosixProcessSignal(fakeSignalA, platform: windows).watch().isEmpty, true);
|
||||||
|
expect(await PosixProcessSignal(fakeSignalB, platform: linux).watch().first, isNotNull);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class FakeProcessSignal extends Fake implements io.ProcessSignal {
|
class FakeProcessSignal extends Fake implements io.ProcessSignal {
|
||||||
|
@ -637,7 +637,7 @@ class FakeSignals implements Signals {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Object addHandler(ProcessSignal signal, SignalHandler handler) {
|
Object addHandler(ProcessSignal signal, SignalHandler handler) {
|
||||||
if (signal == ProcessSignal.SIGTERM) {
|
if (signal == ProcessSignal.sigterm) {
|
||||||
return delegate.addHandler(subForSigTerm, handler);
|
return delegate.addHandler(subForSigTerm, handler);
|
||||||
}
|
}
|
||||||
return delegate.addHandler(signal, handler);
|
return delegate.addHandler(signal, handler);
|
||||||
|
@ -204,7 +204,7 @@ abstract class FlutterTestDriver {
|
|||||||
|
|
||||||
Future<int> _killForcefully() {
|
Future<int> _killForcefully() {
|
||||||
_debugPrint('Sending SIGKILL to $_processPid..');
|
_debugPrint('Sending SIGKILL to $_processPid..');
|
||||||
ProcessSignal.SIGKILL.send(_processPid);
|
ProcessSignal.sigkill.send(_processPid);
|
||||||
return _process.exitCode;
|
return _process.exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user