Unverified Commit 447e3d3f authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] remove globals from compilers (#59184)

Refactors KernelCompiler and ResidentCompiler to no longer use globals (except as a fallback for g3 migration). Improves the compilation error when running flutter test on a package without a flutter_test dependency.

Updates machine mode to output trace text to stderr
parent e1f4cfb4
<<skip until matching line>>
<<stderr>>
<<skip until matching line>>
Failed to load test harness\. +Are you missing a dependency on flutter_test\?
\ No newline at end of file
Error: cannot run without a dependency on "package:flutter_test". Ensure the following lines are present in your pubspec.yaml:
dev_dependencies:
flutter_test:
sdk: flutter
......@@ -128,7 +128,15 @@ Future<void> main(List<String> args) async {
// The mustache dependency is different in google3
TemplateRenderer: () => const MustacheTemplateRenderer(),
if (daemon)
Logger: () => NotifyingLogger(verbose: verbose)
Logger: () => NotifyingLogger(
verbose: verbose,
parent: VerboseLogger(StdoutLogger(
timeoutConfiguration: timeoutConfiguration,
stdio: globals.stdio,
terminal: globals.terminal,
outputPreferences: globals.outputPreferences,
),
))
else if (verbose && !muteCommandLogging)
Logger: () => VerboseLogger(StdoutLogger(
timeoutConfiguration: timeoutConfiguration,
......
......@@ -159,6 +159,11 @@ class EngineBuildPaths {
// Manages the engine artifacts of Flutter.
abstract class Artifacts {
/// A test-specific implementation of artifacts that returns stable paths for
/// all artifacts.
@visibleForTesting
factory Artifacts.test() = _TestArtifacts;
static LocalEngineArtifacts getLocalEngine(EngineBuildPaths engineBuildPaths) {
return LocalEngineArtifacts(
engineBuildPaths.targetEngine,
......@@ -183,7 +188,7 @@ abstract class Artifacts {
/// Manages the engine artifacts downloaded to the local cache.
class CachedArtifacts extends Artifacts {
class CachedArtifacts implements Artifacts {
CachedArtifacts({
@required FileSystem fileSystem,
@required Platform platform,
......@@ -449,7 +454,7 @@ HostPlatform _currentHostPlatformAsHost(Platform platform) {
}
/// Manages the artifacts of a locally built engine.
class LocalEngineArtifacts extends Artifacts {
class LocalEngineArtifacts implements Artifacts {
LocalEngineArtifacts(
this.engineOutPath,
this._hostEngineOutPath, {
......@@ -648,3 +653,26 @@ class OverrideArtifacts implements Artifacts {
String _dartSdkPath(FileSystem fileSystem) {
return fileSystem.path.join(Cache.flutterRoot, 'bin', 'cache', 'dart-sdk');
}
class _TestArtifacts implements Artifacts {
@override
String getArtifactPath(Artifact artifact, {TargetPlatform platform, BuildMode mode}) {
final StringBuffer buffer = StringBuffer();
buffer.write(artifact);
if (platform != null) {
buffer.write('.$platform');
}
if (mode != null) {
buffer.write('.$mode');
}
return buffer.toString();
}
@override
String getEngineType(TargetPlatform platform, [ BuildMode mode ]) {
return 'test-engine';
}
@override
bool get isLocalEngine => false;
}
......@@ -4,8 +4,12 @@
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'package:process/process.dart';
import 'artifacts.dart';
import 'base/context.dart';
import 'base/file_system.dart';
import 'base/logger.dart';
import 'build_info.dart';
import 'compile.dart';
import 'globals.dart' as globals;
......@@ -63,10 +67,19 @@ abstract class CodegenDaemon {
/// supported here. Using the build pipeline implies a fixed multi-root
/// filesystem and requires a pubspec.
class CodeGeneratingKernelCompiler implements KernelCompiler {
const CodeGeneratingKernelCompiler();
static const KernelCompiler _delegate = KernelCompiler();
CodeGeneratingKernelCompiler({
@required FileSystem fileSystem,
@required Artifacts artifacts,
@required ProcessManager processManager,
@required Logger logger,
}) : _delegate = KernelCompiler(
logger: logger,
artifacts: artifacts,
processManager: processManager,
fileSystem: fileSystem,
);
final KernelCompiler _delegate;
@override
Future<CompilerOutput> compile({
String mainPath,
......
......@@ -209,7 +209,7 @@ class AttachCommand extends FlutterCommand {
stdoutCommandResponse,
notifyingLogger: (globals.logger is NotifyingLogger)
? globals.logger as NotifyingLogger
: NotifyingLogger(verbose: globals.logger.isVerbose),
: NotifyingLogger(verbose: globals.logger.isVerbose, parent: globals.logger),
logToStdout: true,
)
: null;
......
......@@ -918,13 +918,14 @@ dynamic _toJsonable(dynamic obj) {
}
class NotifyingLogger extends Logger {
NotifyingLogger({ @required this.verbose }) {
NotifyingLogger({ @required this.verbose, @required this.parent }) {
_messageController = StreamController<LogMessage>.broadcast(
onListen: _onListen,
);
}
final bool verbose;
final Logger parent;
final List<LogMessage> messageBuffer = <LogMessage>[];
StreamController<LogMessage> _messageController;
......@@ -968,7 +969,7 @@ class NotifyingLogger extends Logger {
if (!verbose) {
return;
}
_sendMessage(LogMessage('trace', message));
parent.printError(message);
}
@override
......
......@@ -417,7 +417,7 @@ class RunCommand extends RunCommandBase {
stdoutCommandResponse,
notifyingLogger: (globals.logger is NotifyingLogger)
? globals.logger as NotifyingLogger
: NotifyingLogger(verbose: globals.logger.isVerbose),
: NotifyingLogger(verbose: globals.logger.isVerbose, parent: globals.logger),
logToStdout: true,
);
AppInstance app;
......
......@@ -6,13 +6,15 @@ import 'dart:async';
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'package:process/process.dart';
import 'package:usage/uuid/uuid.dart';
import 'artifacts.dart';
import 'base/common.dart';
import 'base/context.dart';
import 'base/file_system.dart';
import 'base/io.dart';
import 'base/terminal.dart';
import 'base/logger.dart';
import 'build_info.dart';
import 'codegen.dart';
import 'convert.dart';
......@@ -22,18 +24,39 @@ import 'project.dart';
KernelCompilerFactory get kernelCompilerFactory => context.get<KernelCompilerFactory>();
class KernelCompilerFactory {
const KernelCompilerFactory();
const KernelCompilerFactory({
@required FileSystem fileSystem,
@required Artifacts artifacts,
@required ProcessManager processManager,
@required Logger logger,
}) : _fileSystem = fileSystem,
_artifacts = artifacts,
_processManager = processManager,
_logger = logger;
final Logger _logger;
final Artifacts _artifacts;
final ProcessManager _processManager;
final FileSystem _fileSystem;
Future<KernelCompiler> create(FlutterProject flutterProject) async {
if (flutterProject == null || !flutterProject.hasBuilders) {
return const KernelCompiler();
return KernelCompiler(
logger: _logger,
artifacts: _artifacts,
fileSystem: _fileSystem,
processManager: _processManager,
);
}
return const CodeGeneratingKernelCompiler();
return CodeGeneratingKernelCompiler(
logger: _logger,
artifacts: _artifacts,
fileSystem: _fileSystem,
processManager: _processManager,
);
}
}
typedef CompilerMessageConsumer = void Function(String message, { bool emphasis, TerminalColor color });
/// The target model describes the set of core libraries that are available within
/// the SDK.
class TargetModel {
......@@ -88,11 +111,14 @@ enum StdoutState { CollectDiagnostic, CollectDependencies }
/// Handles stdin/stdout communication with the frontend server.
class StdoutHandler {
StdoutHandler({this.consumer = globals.printError}) {
StdoutHandler({
@required Logger logger
}) : _logger = logger {
reset();
}
final CompilerMessageConsumer consumer;
final Logger _logger;
String boundaryKey;
StdoutState state = StdoutState.CollectDiagnostic;
Completer<CompilerOutput> compilerOutput;
......@@ -128,7 +154,9 @@ class StdoutHandler {
}
if (state == StdoutState.CollectDiagnostic) {
if (!_suppressCompilerMessages) {
consumer(message);
_logger.printError(message);
} else {
_logger.printTrace(message);
}
} else {
assert(state == StdoutState.CollectDependencies);
......@@ -140,7 +168,7 @@ class StdoutHandler {
sources.remove(Uri.parse(message.substring(1)));
break;
default:
globals.printTrace('Unexpected prefix for $message uri - ignoring');
_logger.printTrace('Unexpected prefix for $message uri - ignoring');
}
}
}
......@@ -182,8 +210,22 @@ List<String> buildModeOptions(BuildMode mode) {
throw Exception('Unknown BuildMode: $mode');
}
/// A compiler interface for producing single (non-incremental) kernel files.
class KernelCompiler {
const KernelCompiler();
KernelCompiler({
FileSystem fileSystem, // TODO(jonahwilliams): migrate to @required after google3
Logger logger, // TODO(jonahwilliams): migrate to @required after google3
ProcessManager processManager, // TODO(jonahwilliams): migrate to @required after google3
Artifacts artifacts, // TODO(jonahwilliams): migrate to @required after google3
}) : _logger = logger ?? globals.logger,
_fileSystem = fileSystem ?? globals.fs,
_artifacts = artifacts ?? globals.artifacts,
_processManager = processManager ?? globals.processManager;
final FileSystem _fileSystem;
final Artifacts _artifacts;
final ProcessManager _processManager;
final Logger _logger;
Future<CompilerOutput> compile({
String sdkRoot,
......@@ -204,25 +246,23 @@ class KernelCompiler {
@required List<String> dartDefines,
@required PackageConfig packageConfig,
}) async {
final String frontendServer = globals.artifacts.getArtifactPath(
final String frontendServer = _artifacts.getArtifactPath(
Artifact.frontendServerSnapshotForEngineDartSdk
);
// This is a URI, not a file path, so the forward slash is correct even on Windows.
if (!sdkRoot.endsWith('/')) {
sdkRoot = '$sdkRoot/';
}
final String engineDartPath = globals.artifacts.getArtifactPath(Artifact.engineDartBinary);
if (!globals.processManager.canRun(engineDartPath)) {
final String engineDartPath = _artifacts.getArtifactPath(Artifact.engineDartBinary);
if (!_processManager.canRun(engineDartPath)) {
throwToolExit('Unable to find Dart binary at $engineDartPath');
}
Uri mainUri;
if (packagesPath != null) {
mainUri = packageConfig.toPackageUri(globals.fs.file(mainPath).uri);
mainUri = packageConfig.toPackageUri(_fileSystem.file(mainPath).uri);
}
// TODO(jonahwilliams): The output file must already exist, but this seems
// unnecessary.
if (outputFilePath != null && !globals.fs.isFileSync(outputFilePath)) {
globals.fs.file(outputFilePath).createSync(recursive: true);
if (outputFilePath != null && !_fileSystem.isFileSync(outputFilePath)) {
_fileSystem.file(outputFilePath).createSync(recursive: true);
}
final List<String> command = <String>[
engineDartPath,
......@@ -281,13 +321,13 @@ class KernelCompiler {
mainUri?.toString() ?? mainPath,
];
globals.printTrace(command.join(' '));
final Process server = await globals.processManager.start(command);
_logger.printTrace(command.join(' '));
final Process server = await _processManager.start(command);
final StdoutHandler _stdoutHandler = StdoutHandler();
final StdoutHandler _stdoutHandler = StdoutHandler(logger: _logger);
server.stderr
.transform<String>(utf8.decoder)
.listen(globals.printError);
.listen(_logger.printError);
server.stdout
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
......@@ -398,11 +438,13 @@ class _RejectRequest extends _CompilationRequest {
abstract class ResidentCompiler {
factory ResidentCompiler(String sdkRoot, {
@required BuildMode buildMode,
Logger logger, // TODO(jonahwilliams): migrate to @required after google3
ProcessManager processManager, // TODO(jonahwilliams): migrate to @required after google3
Artifacts artifacts, // TODO(jonahwilliams): migrate to @required after google3
bool trackWidgetCreation,
String packagesPath,
List<String> fileSystemRoots,
String fileSystemScheme,
CompilerMessageConsumer compilerMessageConsumer,
String initializeFromDill,
TargetModel targetModel,
bool unsafePackageSerialization,
......@@ -496,11 +538,13 @@ class DefaultResidentCompiler implements ResidentCompiler {
DefaultResidentCompiler(
String sdkRoot, {
@required this.buildMode,
Logger logger, // TODO(jonahwilliams): migrate to @required after google3
ProcessManager processManager, // TODO(jonahwilliams): migrate to @required after google3
Artifacts artifacts, // TODO(jonahwilliams): migrate to @required after google3
this.trackWidgetCreation = true,
this.packagesPath,
this.fileSystemRoots,
this.fileSystemScheme,
CompilerMessageConsumer compilerMessageConsumer = globals.printError,
this.initializeFromDill,
this.targetModel = TargetModel.flutter,
this.unsafePackageSerialization,
......@@ -511,11 +555,18 @@ class DefaultResidentCompiler implements ResidentCompiler {
// Deprecated
List<String> experimentalFlags, // ignore: avoid_unused_constructor_parameters
}) : assert(sdkRoot != null),
_stdoutHandler = StdoutHandler(consumer: compilerMessageConsumer),
_logger = logger ?? globals.logger,
_processManager = processManager ?? globals.processManager,
_artifacts = artifacts ?? globals.artifacts,
_stdoutHandler = StdoutHandler(logger: logger),
dartDefines = dartDefines ?? const <String>[],
// This is a URI, not a file path, so the forward slash is correct even on Windows.
sdkRoot = sdkRoot.endsWith('/') ? sdkRoot : '$sdkRoot/';
final Logger _logger;
final ProcessManager _processManager;
final Artifacts _artifacts;
final BuildMode buildMode;
final bool trackWidgetCreation;
final String packagesPath;
......@@ -584,7 +635,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
final String mainUri = request.packageConfig.toPackageUri(request.mainUri)?.toString()
?? request.mainUri.toString();
_server.stdin.writeln('recompile $mainUri $inputKey');
globals.printTrace('<- recompile $mainUri $inputKey');
_logger.printTrace('<- recompile $mainUri $inputKey');
for (final Uri fileUri in request.invalidatedFiles) {
String message;
if (fileUri.scheme == 'package') {
......@@ -594,10 +645,10 @@ class DefaultResidentCompiler implements ResidentCompiler {
?? fileUri.toString();
}
_server.stdin.writeln(message);
globals.printTrace(message);
_logger.printTrace(message);
}
_server.stdin.writeln(inputKey);
globals.printTrace('<- $inputKey');
_logger.printTrace('<- $inputKey');
return _stdoutHandler.compilerOutput.future;
}
......@@ -623,11 +674,11 @@ class DefaultResidentCompiler implements ResidentCompiler {
String scriptUri,
String outputPath,
) async {
final String frontendServer = globals.artifacts.getArtifactPath(
final String frontendServer = _artifacts.getArtifactPath(
Artifact.frontendServerSnapshotForEngineDartSdk
);
final List<String> command = <String>[
globals.artifacts.getArtifactPath(Artifact.engineDartBinary),
_artifacts.getArtifactPath(Artifact.engineDartBinary),
'--disable-dart-dev',
frontendServer,
'--sdk-root',
......@@ -682,8 +733,8 @@ class DefaultResidentCompiler implements ResidentCompiler {
else
arg,
];
globals.printTrace(command.join(' '));
_server = await globals.processManager.start(command);
_logger.printTrace(command.join(' '));
_server = await _processManager.start(command);
_server.stdout
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
......@@ -701,7 +752,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
_server.stderr
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
.listen(globals.printError);
.listen(_logger.printError);
unawaited(_server.exitCode.then((int code) {
if (code != 0) {
......@@ -710,7 +761,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
}));
_server.stdin.writeln('compile $scriptUri');
globals.printTrace('<- compile $scriptUri');
_logger.printTrace('<- compile $scriptUri');
return _stdoutHandler.compilerOutput.future;
}
......@@ -746,15 +797,17 @@ class DefaultResidentCompiler implements ResidentCompiler {
}
final String inputKey = Uuid().generateV4();
_server.stdin.writeln('compile-expression $inputKey');
_server.stdin.writeln(request.expression);
_server.stdin
..writeln('compile-expression $inputKey')
..writeln(request.expression);
request.definitions?.forEach(_server.stdin.writeln);
_server.stdin.writeln(inputKey);
request.typeDefinitions?.forEach(_server.stdin.writeln);
_server.stdin.writeln(inputKey);
_server.stdin.writeln(request.libraryUri ?? '');
_server.stdin.writeln(request.klass ?? '');
_server.stdin.writeln(request.isStatic ?? false);
_server.stdin
..writeln(inputKey)
..writeln(request.libraryUri ?? '')
..writeln(request.klass ?? '')
..writeln(request.isStatic ?? false);
return _stdoutHandler.compilerOutput.future;
}
......@@ -782,7 +835,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
}
Future<CompilerOutput> _compileExpressionToJs(_CompileExpressionToJsRequest request) async {
_stdoutHandler.reset(suppressCompilerMessages: false, expectSources: false);
_stdoutHandler.reset(suppressCompilerMessages: true, expectSources: false);
// 'compile-expression-to-js' should be invoked after compiler has been started,
// program was compiled.
......@@ -791,16 +844,18 @@ class DefaultResidentCompiler implements ResidentCompiler {
}
final String inputKey = Uuid().generateV4();
_server.stdin.writeln('compile-expression-to-js $inputKey');
_server.stdin.writeln(request.libraryUri ?? '');
_server.stdin.writeln(request.line);
_server.stdin.writeln(request.column);
_server.stdin
..writeln('compile-expression-to-js $inputKey')
..writeln(request.libraryUri ?? '')
..writeln(request.line)
..writeln(request.column);
request.jsModules?.forEach((String k, String v) { _server.stdin.writeln('$k:$v'); });
_server.stdin.writeln(inputKey);
request.jsFrameValues?.forEach((String k, String v) { _server.stdin.writeln('$k:$v'); });
_server.stdin.writeln(inputKey);
_server.stdin.writeln(request.moduleName ?? '');
_server.stdin.writeln(request.expression ?? '');
_server.stdin
..writeln(inputKey)
..writeln(request.moduleName ?? '')
..writeln(request.expression ?? '');
return _stdoutHandler.compilerOutput.future;
}
......@@ -809,7 +864,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
void accept() {
if (_compileRequestNeedsConfirmation) {
_server.stdin.writeln('accept');
globals.printTrace('<- accept');
_logger.printTrace('<- accept');
}
_compileRequestNeedsConfirmation = false;
}
......@@ -831,7 +886,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
}
_stdoutHandler.reset(expectSources: false);
_server.stdin.writeln('reject');
globals.printTrace('<- reject');
_logger.printTrace('<- reject');
_compileRequestNeedsConfirmation = false;
return _stdoutHandler.compilerOutput.future;
}
......@@ -839,7 +894,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
@override
void reset() {
_server?.stdin?.writeln('reset');
globals.printTrace('<- reset');
_logger.printTrace('<- reset');
}
@override
......@@ -848,7 +903,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
if (_server == null) {
return 0;
}
globals.printTrace('killing pid ${_server.pid}');
_logger.printTrace('killing pid ${_server.pid}');
_server.kill();
return _server.exitCode;
}
......
......@@ -148,7 +148,12 @@ Future<T> runInContext<T>(
xcode: globals.xcode,
),
IOSWorkflow: () => const IOSWorkflow(),
KernelCompilerFactory: () => const KernelCompilerFactory(),
KernelCompilerFactory: () => KernelCompilerFactory(
logger: globals.logger,
processManager: globals.processManager,
artifacts: globals.artifacts,
fileSystem: globals.fs,
),
Logger: () => globals.platform.isWindows
? WindowsStdoutLogger(
terminal: globals.terminal,
......
......@@ -18,7 +18,6 @@ import 'base/file_system.dart';
import 'base/io.dart' as io;
import 'base/logger.dart';
import 'base/signals.dart';
import 'base/terminal.dart';
import 'base/utils.dart';
import 'build_info.dart';
import 'build_system/build_system.dart';
......@@ -63,6 +62,9 @@ class FlutterDevice {
dartDefines: buildInfo.dartDefines,
packagesPath: globalPackagesPath,
extraFrontEndOptions: buildInfo.extraFrontEndOptions,
artifacts: globals.artifacts,
processManager: globals.processManager,
logger: globals.logger,
);
/// Create a [FlutterDevice] with optional code generation enabled.
......@@ -99,9 +101,6 @@ class FlutterDevice {
// Override the filesystem scheme so that the frontend_server can find
// the generated entrypoint code.
fileSystemScheme: 'org-dartlang-app',
compilerMessageConsumer:
(String message, {bool emphasis, TerminalColor color, }) =>
globals.printTrace(message),
initializeFromDill: getDefaultCachedKernelPath(
trackWidgetCreation: buildInfo.trackWidgetCreation,
dartDefines: buildInfo.dartDefines,
......@@ -115,6 +114,9 @@ class FlutterDevice {
librariesSpec: globals.fs.file(globals.artifacts
.getArtifactPath(Artifact.flutterWebLibrariesJson)).uri.toString(),
packagesPath: globalPackagesPath,
artifacts: globals.artifacts,
processManager: globals.processManager,
logger: globals.logger,
);
} else {
generator = ResidentCompiler(
......@@ -135,6 +137,9 @@ class FlutterDevice {
dartDefines: buildInfo.dartDefines,
),
packagesPath: globalPackagesPath,
artifacts: globals.artifacts,
processManager: globals.processManager,
logger: globals.logger,
);
}
......
......@@ -9,7 +9,6 @@ import 'package:package_config/package_config.dart';
import '../artifacts.dart';
import '../base/file_system.dart';
import '../base/terminal.dart';
import '../build_info.dart';
import '../bundle.dart';
import '../codegen.dart';
......@@ -71,11 +70,12 @@ class TestCompiler {
ResidentCompiler compiler;
File outputDill;
// Whether to report compiler messages.
bool _suppressOutput = false;
Future<String> compile(Uri mainDart) {
final Completer<String> completer = Completer<String>();
if (compilerController.isClosed) {
return null;
}
compilerController.add(_CompilationRequest(mainDart, completer));
return completer.future;
}
......@@ -99,9 +99,11 @@ class TestCompiler {
Future<ResidentCompiler> createCompiler() async {
final ResidentCompiler residentCompiler = ResidentCompiler(
globals.artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
artifacts: globals.artifacts,
logger: globals.logger,
processManager: globals.processManager,
buildMode: buildMode,
trackWidgetCreation: trackWidgetCreation,
compilerMessageConsumer: _reportCompilerMessage,
initializeFromDill: testFilePath,
unsafePackageSerialization: false,
dartDefines: const <String>[],
......@@ -129,10 +131,28 @@ class TestCompiler {
if (!isEmpty) {
return;
}
_packageConfig ??= await loadPackageConfigWithLogging(
globals.fs.file(globalPackagesPath),
logger: globals.logger,
);
if (_packageConfig == null) {
_packageConfig ??= await loadPackageConfigWithLogging(
globals.fs.file(globalPackagesPath),
logger: globals.logger,
);
// Compilation will fail if there is no flutter_test dependency, since
// this library is imported by the generated entrypoint script.
if (_packageConfig['flutter_test'] == null) {
globals.printError(
'\n'
'Error: cannot run without a dependency on "package:flutter_test". '
'Ensure the following lines are present in your pubspec.yaml:'
'\n\n'
'dev_dependencies:\n'
' flutter_test:\n'
' sdk: flutter\n',
);
request.result.complete(null);
await compilerController.close();
return;
}
}
while (compilationQueue.isNotEmpty) {
final _CompilationRequest request = compilationQueue.first;
globals.printTrace('Compiling ${request.mainUri}');
......@@ -142,7 +162,6 @@ class TestCompiler {
compiler = await createCompiler();
firstCompile = true;
}
_suppressOutput = false;
final CompilerOutput compilerOutput = await compiler.recompile(
request.mainUri,
<Uri>[request.mainUri],
......@@ -179,20 +198,4 @@ class TestCompiler {
compilationQueue.removeAt(0);
}
}
void _reportCompilerMessage(String message, {bool emphasis, TerminalColor color}) {
if (_suppressOutput) {
return;
}
if (message.startsWith("Error: Could not resolve the package 'flutter_test'")) {
globals.printTrace(message);
globals.printError('\n\nFailed to load test harness. Are you missing a dependency on flutter_test?\n',
emphasis: emphasis,
color: color,
);
_suppressOutput = true;
return;
}
globals.printError(message);
}
}
......@@ -21,10 +21,12 @@ import '../../src/mocks.dart';
void main() {
Daemon daemon;
NotifyingLogger notifyingLogger;
BufferLogger bufferLogger;
group('daemon', () {
setUp(() {
notifyingLogger = NotifyingLogger(verbose: false);
bufferLogger = BufferLogger.test();
notifyingLogger = NotifyingLogger(verbose: false, parent: bufferLogger);
});
tearDown(() {
......@@ -299,19 +301,15 @@ void main() {
});
testUsingContext('notifyingLogger outputs trace messages in verbose mode', () async {
final NotifyingLogger logger = NotifyingLogger(verbose: true);
final NotifyingLogger logger = NotifyingLogger(verbose: true, parent: bufferLogger);
final Future<LogMessage> messageResult = logger.onMessage.first;
logger.printTrace('test');
final LogMessage message = await messageResult;
expect(message.level, 'trace');
expect(message.message, 'test');
expect(bufferLogger.errorText, contains('test'));
});
testUsingContext('notifyingLogger ignores trace messages in non-verbose mode', () async {
final NotifyingLogger logger = NotifyingLogger(verbose: false);
final NotifyingLogger logger = NotifyingLogger(verbose: false, parent: bufferLogger);
final Future<LogMessage> messageResult = logger.onMessage.first;
logger.printTrace('test');
......@@ -321,10 +319,11 @@ void main() {
expect(message.level, 'status');
expect(message.message, 'hello');
expect(bufferLogger.errorText, contains('test'));
});
testUsingContext('notifyingLogger buffers messages sent before a subscription', () async {
final NotifyingLogger logger = NotifyingLogger(verbose: false);
final NotifyingLogger logger = NotifyingLogger(verbose: false, parent: bufferLogger);
logger.printStatus('hello');
......
......@@ -4,14 +4,13 @@
import 'dart:async';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:mockito/mockito.dart';
import 'package:package_config/package_config.dart';
import 'package:process/process.dart';
......@@ -27,13 +26,21 @@ void main() {
MockStdIn mockFrontendServerStdIn;
MockStream mockFrontendServerStdErr;
StreamController<String> stdErrStreamController;
BufferLogger testLogger;
setUp(() {
generator = ResidentCompiler('sdkroot', buildMode: BuildMode.debug);
testLogger = BufferLogger.test();
mockProcessManager = MockProcessManager();
mockFrontendServer = MockProcess();
mockFrontendServerStdIn = MockStdIn();
mockFrontendServerStdErr = MockStream();
generator = ResidentCompiler(
'sdkroot',
buildMode: BuildMode.debug,
artifacts: Artifacts.test(),
processManager: mockProcessManager,
logger: testLogger,
);
when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
when(mockFrontendServer.stderr)
......@@ -52,13 +59,14 @@ void main() {
);
});
testUsingContext('compile expression fails if not previously compiled', () async {
testWithoutContext('compile expression fails if not previously compiled', () async {
final CompilerOutput result = await generator.compileExpression(
'2+2', null, null, null, null, false);
expect(result, isNull);
});
testUsingContext('compile expression can compile single expression', () async {
testWithoutContext('compile expression can compile single expression', () async {
final Completer<List<int>> compileResponseCompleter =
Completer<List<int>>();
final Completer<List<int>> compileExpressionResponseCompleter =
......@@ -76,7 +84,7 @@ void main() {
)));
await generator.recompile(
globals.fs.file('/path/to/main.dart').uri,
Uri.file('/path/to/main.dart'),
null, /* invalidatedFiles */
outputPath: '/build/',
packageConfig: PackageConfig.empty,
......@@ -101,14 +109,9 @@ void main() {
}
);
});
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
testUsingContext('compile expressions without awaiting', () async {
testWithoutContext('compile expressions without awaiting', () async {
final Completer<List<int>> compileResponseCompleter = Completer<List<int>>();
final Completer<List<int>> compileExpressionResponseCompleter1 = Completer<List<int>>();
final Completer<List<int>> compileExpressionResponseCompleter2 = Completer<List<int>>();
......@@ -174,10 +177,6 @@ void main() {
)));
expect(await lastExpressionCompleted.future, isTrue);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
}
......
......@@ -4,10 +4,10 @@
import 'dart:async';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/async_guard.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/convert.dart';
......@@ -26,13 +26,21 @@ void main() {
MockStdIn mockFrontendServerStdIn;
MockStream mockFrontendServerStdErr;
StreamController<String> stdErrStreamController;
BufferLogger testLogger;
setUp(() {
generator = ResidentCompiler('sdkroot', buildMode: BuildMode.debug);
testLogger = BufferLogger.test();
mockProcessManager = MockProcessManager();
mockFrontendServer = MockProcess();
mockFrontendServerStdIn = MockStdIn();
mockFrontendServerStdErr = MockStream();
generator = ResidentCompiler(
'sdkroot',
buildMode: BuildMode.debug,
logger: testLogger,
processManager: mockProcessManager,
artifacts: Artifacts.test(),
);
when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
when(mockFrontendServer.stderr)
......@@ -50,7 +58,7 @@ void main() {
);
});
testUsingContext('incremental compile single dart compile', () async {
testWithoutContext('incremental compile single dart compile', () async {
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture(
Future<List<int>>.value(utf8.encode(
......@@ -68,13 +76,9 @@ void main() {
verifyNoMoreInteractions(mockFrontendServerStdIn);
expect(testLogger.errorText, equals('line1\nline2\n'));
expect(output.outputFilename, equals('/path/to/main.dart.dill'));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
testUsingContext('incremental compile single dart compile abnormally terminates', () async {
testWithoutContext('incremental compile single dart compile abnormally terminates', () async {
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => const Stream<List<int>>.empty()
);
......@@ -85,13 +89,9 @@ void main() {
outputPath: '/build/',
packageConfig: PackageConfig.empty,
)), throwsToolExit());
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
testUsingContext('incremental compile single dart compile abnormally terminates via exitCode', () async {
testWithoutContext('incremental compile single dart compile abnormally terminates via exitCode', () async {
when(mockFrontendServer.exitCode)
.thenAnswer((Invocation invocation) async => 1);
when(mockFrontendServer.stdout)
......@@ -104,13 +104,9 @@ void main() {
outputPath: '/build/',
packageConfig: PackageConfig.empty,
)), throwsToolExit());
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
testUsingContext('incremental compile and recompile', () async {
testWithoutContext('incremental compile and recompile', () async {
final StreamController<List<int>> streamController = StreamController<List<int>>();
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => streamController.stream);
......@@ -145,13 +141,9 @@ void main() {
'line1\nline2\n'
'line1\nline2\n'
));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
testUsingContext('incremental compile can suppress errors', () async {
testWithoutContext('incremental compile can suppress errors', () async {
final StreamController<List<int>> stdoutController = StreamController<List<int>>();
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => stdoutController.stream);
......@@ -179,17 +171,14 @@ void main() {
// Compiler message is not printed with suppressErrors: true above.
expect(testLogger.errorText, isNot(equals(
'line0\nline1\n'
'line1\nline2\n'
'line1\nline2\n'
)));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
expect(testLogger.traceText, contains(
'line1\nline2\n'
));
});
testUsingContext('incremental compile and recompile twice', () async {
testWithoutContext('incremental compile and recompile twice', () async {
final StreamController<List<int>> streamController = StreamController<List<int>>();
when(mockFrontendServer.stdout)
.thenAnswer((Invocation invocation) => streamController.stream);
......@@ -216,10 +205,6 @@ void main() {
'line1\nline2\n'
'line2\nline3\n'
));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: kNoColorTerminalPlatform,
});
}
......
......@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/compile.dart';
import '../src/common.dart';
import '../src/context.dart';
void main() {
testUsingContext('StdOutHandler test', () async {
final StdoutHandler stdoutHandler = StdoutHandler();
testWithoutContext('StdoutHandler can produce output message', () async {
final StdoutHandler stdoutHandler = StdoutHandler(logger: BufferLogger.test());
stdoutHandler.handler('result 12345');
expect(stdoutHandler.boundaryKey, '12345');
stdoutHandler.handler('12345');
......@@ -19,7 +19,7 @@ void main() {
expect(output.outputFilename, 'message');
});
test('TargetModel values', () {
testWithoutContext('TargetModel values', () {
expect(TargetModel('vm'), TargetModel.vm);
expect(TargetModel.vm.toString(), 'vm');
......
......@@ -12,6 +12,7 @@ import 'package:flutter_tools/src/test/test_compiler.dart';
import 'package:mockito/mockito.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/testbed.dart';
final Platform linuxPlatform = FakePlatform(
......@@ -32,7 +33,7 @@ void main() {
},
setup: () async {
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
globals.fs.file('.packages').writeAsStringSync('flutter_test:flutter_test/');
globals.fs.file('test/foo.dart').createSync(recursive: true);
residentCompiler = MockResidentCompiler();
testCompiler = FakeTestCompiler(
......@@ -86,6 +87,19 @@ void main() {
expect(testCompiler.compilerController.isClosed, true);
verify(residentCompiler.shutdown()).called(1);
}));
test('Reports an error when there is no dependency on flutter_test', () => testbed.run(() async {
globals.fs.file('.packages').writeAsStringSync('\n');
expect(await testCompiler.compile(Uri.parse('test/foo.dart')), null);
expect(testLogger.errorText, contains('Error: cannot run without a dependency on "package:flutter_test"'));
verifyNever(residentCompiler.recompile(
any,
<Uri>[Uri.parse('test/foo.dart')],
outputPath: testCompiler.outputDill.path,
packageConfig: anyNamed('packageConfig'),
));
}));
});
}
......
......@@ -244,11 +244,11 @@ class FakeProcess implements Process {
FakeProcess({
this.pid = 1,
Future<int> exitCode,
Stream<List<int>> stdin,
IOSink stdin,
this.stdout = const Stream<List<int>>.empty(),
this.stderr = const Stream<List<int>>.empty(),
}) : exitCode = exitCode ?? Future<int>.value(0),
stdin = stdin as IOSink ?? MemoryIOSink();
stdin = stdin ?? MemoryIOSink();
@override
final int pid;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment