Unverified Commit b7e30cfc authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] update compilation to use package config (#54467)

parent e5ea6ddb
......@@ -373,7 +373,11 @@ class WebAssetServer implements AssetReader {
/// Write a single file into the in-memory cache.
void writeFile(String filePath, String contents) {
_files[filePath] = Uint8List.fromList(utf8.encode(contents));
writeBytes(filePath, utf8.encode(contents) as Uint8List);
}
void writeBytes(String filePath, Uint8List contents) {
_files[filePath] = contents;
}
/// Update the in-memory asset server with the provided source and manifest files.
......@@ -620,6 +624,9 @@ class WebDevFS implements DevFS {
@override
DateTime lastCompiled;
@override
PackageConfig lastPackageConfig;
// We do not evict assets on the web.
@override
Set<String> get assetPathsToEvict => const <String>{};
......@@ -668,7 +675,7 @@ class WebDevFS implements DevFS {
@override
Future<UpdateFSReport> update({
String mainPath,
Uri mainUri,
String target,
AssetBundle bundle,
DateTime firstBuildTime,
......@@ -681,20 +688,23 @@ class WebDevFS implements DevFS {
String pathToReload,
List<Uri> invalidatedFiles,
bool skipAssets = false,
@required PackageConfig packageConfig,
}) async {
assert(trackWidgetCreation != null);
assert(generator != null);
final String outputDirectoryPath = globals.fs.file(mainPath).parent.path;
lastPackageConfig = packageConfig;
final File mainFile = globals.fs.file(mainUri);
final String outputDirectoryPath = mainFile.parent.path;
if (bundleFirstUpload) {
webAssetServer.entrypointCacheDirectory = globals.fs.directory(outputDirectoryPath);
generator.addFileSystemRoot(outputDirectoryPath);
final String entrypoint = globals.fs.path.basename(mainPath);
webAssetServer.writeFile(entrypoint, globals.fs.file(mainPath).readAsStringSync());
final String entrypoint = globals.fs.path.basename(mainFile.path);
webAssetServer.writeBytes(entrypoint, mainFile.readAsBytesSync());
webAssetServer.writeBytes('require.js', requireJS.readAsBytesSync());
webAssetServer.writeBytes('stack_trace_mapper.js', stackTraceMapper.readAsBytesSync());
webAssetServer.writeFile('manifest.json', '{"info":"manifest not generated in run mode."}');
webAssetServer.writeFile('flutter_service_worker.js', '// Service worker not loaded in run mode.');
webAssetServer.writeFile('require.js', requireJS.readAsStringSync());
webAssetServer.writeFile('stack_trace_mapper.js', stackTraceMapper.readAsStringSync());
webAssetServer.writeFile(
'main.dart.js',
generateBootstrapScript(
......@@ -727,11 +737,14 @@ class WebDevFS implements DevFS {
// mapping the file name, this is done via an additional file root and
// specicial hard-coded scheme.
final CompilerOutput compilerOutput = await generator.recompile(
'org-dartlang-app:///' + globals.fs.path.basename(mainPath),
Uri(
scheme: 'org-dartlang-app',
path: '/' + mainUri.pathSegments.last,
),
invalidatedFiles,
outputPath: dillOutputPath ??
getDefaultApplicationKernelPath(trackWidgetCreation: trackWidgetCreation),
packagesFilePath: packagesFilePath,
packageConfig: packageConfig,
);
if (compilerOutput == null || compilerOutput.errorCount > 0) {
return UpdateFSReport(success: false);
......
......@@ -6,6 +6,7 @@ import 'dart:async';
import 'package:dwds/dwds.dart';
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'package:vm_service/vm_service.dart' as vmservice;
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
hide StackTrace;
......@@ -21,7 +22,6 @@ import '../base/terminal.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../cache.dart';
import '../compile.dart';
import '../convert.dart';
import '../dart/pub.dart';
import '../devfs.dart';
......@@ -558,7 +558,7 @@ class _ResidentWebRunner extends ResidentWebRunner {
// Flutter web projects need to include a generated main entrypoint to call the
// appropriate bootstrap method and inject plugins.
// Keep this in sync with build_system/targets/web.dart.
Future<String> _generateEntrypoint(String main, String packagesPath) async {
Future<Uri> _generateEntrypoint(Uri mainUri, PackageConfig packageConfig) async {
File result = _generatedEntrypointDirectory?.childFile('web_entrypoint.dart');
if (_generatedEntrypointDirectory == null) {
_generatedEntrypointDirectory ??= globals.fs.systemTempDirectory.createTempSync('flutter_tools.')
......@@ -569,18 +569,20 @@ class _ResidentWebRunner extends ResidentWebRunner {
.any((Plugin p) => p.platforms.containsKey(WebPlugin.kConfigKey));
await injectPlugins(flutterProject, checkProjects: true);
final PackageUriMapper packageUriMapper = PackageUriMapper(main, packagesPath, null, null);
final String generatedPath = globals.fs.currentDirectory
final Uri generatedUri = globals.fs.currentDirectory
.childDirectory('lib')
.childFile('generated_plugin_registrant.dart')
.absolute.path;
final Uri generatedImport = packageUriMapper.map(generatedPath);
String importedEntrypoint = packageUriMapper.map(main)?.toString();
.absolute.uri;
final Uri generatedImport = packageConfig.toPackageUri(generatedUri);
Uri importedEntrypoint = packageConfig.toPackageUri(mainUri);
// Special handling for entrypoints that are not under lib, such as test scripts.
if (importedEntrypoint == null) {
final String parent = globals.fs.file(main).parent.path;
final String parent = globals.fs.file(mainUri).parent.path;
flutterDevices.first.generator.addFileSystemRoot(parent);
importedEntrypoint = 'org-dartlang-app:///${globals.fs.path.basename(main)}';
importedEntrypoint = Uri(
scheme: 'org-dartlang-app',
path: '/' + mainUri.pathSegments.last,
);
}
final String entrypoint = <String>[
......@@ -604,7 +606,7 @@ class _ResidentWebRunner extends ResidentWebRunner {
].join('\n');
result.writeAsStringSync(entrypoint);
}
return result.path;
return result.absolute.uri;
}
Future<UpdateFSReport> _updateDevFS({bool fullRestart = false}) async {
......@@ -617,18 +619,21 @@ class _ResidentWebRunner extends ResidentWebRunner {
return UpdateFSReport(success: false);
}
}
final List<Uri> invalidatedFiles =
await projectFileInvalidator.findInvalidated(
final InvalidationResult invalidationResult = await projectFileInvalidator.findInvalidated(
lastCompiled: device.devFS.lastCompiled,
urisToMonitor: device.devFS.sources,
packagesPath: packagesFilePath,
packageConfig: device.devFS.lastPackageConfig,
);
final Status devFSStatus = globals.logger.startProgress(
'Syncing files to device ${device.device.name}...',
timeout: timeoutConfiguration.fastOperation,
);
final UpdateFSReport report = await device.devFS.update(
mainPath: await _generateEntrypoint(mainPath, packagesFilePath),
mainUri: await _generateEntrypoint(
globals.fs.file(mainPath).absolute.uri,
invalidationResult.packageConfig,
),
target: target,
bundle: assetBundle,
firstBuildTime: firstBuildTime,
......@@ -638,7 +643,8 @@ class _ResidentWebRunner extends ResidentWebRunner {
dillOutputPath: dillOutputPath,
projectRootPath: projectRootPath,
pathToReload: getReloadPath(fullRestart: fullRestart),
invalidatedFiles: invalidatedFiles,
invalidatedFiles: invalidationResult.uris,
packageConfig: invalidationResult.packageConfig,
trackWidgetCreation: true,
);
devFSStatus.stop();
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:package_config/package_config.dart';
import '../../artifacts.dart';
import '../../base/build.dart';
import '../../base/file_system.dart';
......@@ -196,7 +198,7 @@ class KernelSnapshot extends Target {
}
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final String targetFile = environment.defines[kTargetFile] ?? globals.fs.path.join('lib', 'main.dart');
final String packagesPath = environment.projectDir.childFile('.packages').path;
final File packagesFile = environment.projectDir.childFile('.packages');
final String targetFileAbsolute = globals.fs.file(targetFile).absolute.path;
// everything besides 'false' is considered to be enabled.
final bool trackWidgetCreation = environment.defines[kTrackWidgetCreation] != 'false';
......@@ -229,6 +231,17 @@ class KernelSnapshot extends Target {
forceLinkPlatform = false;
}
final PackageConfig packageConfig = await loadPackageConfigUri(
packagesFile.absolute.uri,
loader: (Uri uri) {
final File file = globals.fs.file(uri);
if (!file.existsSync()) {
return null;
}
return file.readAsBytes();
}
);
final CompilerOutput output = await compiler.compile(
sdkRoot: globals.artifacts.getArtifactPath(
Artifact.flutterPatchedSdkPath,
......@@ -240,7 +253,7 @@ class KernelSnapshot extends Target {
trackWidgetCreation: trackWidgetCreation && buildMode == BuildMode.debug,
targetModel: targetModel,
outputFilePath: environment.buildDir.childFile('app.dill').path,
packagesPath: packagesPath,
packagesPath: packagesFile.path,
linkPlatformKernelIn: forceLinkPlatform || buildMode.isPrecompiled,
mainPath: targetFileAbsolute,
depFilePath: environment.buildDir.childFile('kernel_snapshot.d').path,
......@@ -248,6 +261,7 @@ class KernelSnapshot extends Target {
fileSystemRoots: fileSystemRoots,
fileSystemScheme: fileSystemScheme,
dartDefines: parseDartDefines(environment),
packageConfig: packageConfig,
);
if (output == null || output.errorCount != 0) {
throw Exception('Errors during snapshot creation: $output');
......
......@@ -3,12 +3,12 @@
// found in the LICENSE file.
import 'package:crypto/crypto.dart';
import 'package:package_config/package_config.dart';
import '../../artifacts.dart';
import '../../base/file_system.dart';
import '../../base/io.dart';
import '../../build_info.dart';
import '../../compile.dart';
import '../../dart/package_map.dart';
import '../../globals.dart' as globals;
import '../build_system.dart';
......@@ -56,35 +56,39 @@ class WebEntrypointTarget extends Target {
final String targetFile = environment.defines[kTargetFile];
final bool shouldInitializePlatform = environment.defines[kInitializePlatform] == 'true';
final bool hasPlugins = environment.defines[kHasWebPlugins] == 'true';
final String importPath = globals.fs.path.absolute(targetFile);
final Uri importUri = environment.fileSystem.file(targetFile).absolute.uri;
final PackageConfig packageConfig = await loadPackageConfigUri(
environment.projectDir.childFile('.packages').absolute.uri,
loader: (Uri uri) {
final File file = environment.fileSystem.file(uri);
if (!file.existsSync()) {
return null;
}
return file.readAsBytes();
}
);
// Use the package uri mapper to find the correct package-scheme import path
// Use the PackageConfig to find the correct package-scheme import path
// for the user application. If the application has a mix of package-scheme
// and relative imports for a library, then importing the entrypoint as a
// file-scheme will cause said library to be recognized as two distinct
// libraries. This can cause surprising behavior as types from that library
// will be considered distinct from each other.
final PackageUriMapper packageUriMapper = PackageUriMapper(
importPath,
PackageMap.globalPackagesPath,
null,
null,
);
// By construction, this will only be null if the .packages file does not
// have an entry for the user's application or if the main file is
// outside of the lib/ directory.
final String mainImport = packageUriMapper.map(importPath)?.toString()
?? globals.fs.file(importPath).absolute.uri.toString();
final String mainImport = packageConfig.toPackageUri(importUri)?.toString()
?? importUri.toString();
String contents;
if (hasPlugins) {
final String generatedPath = environment.projectDir
final Uri generatedUri = environment.projectDir
.childDirectory('lib')
.childFile('generated_plugin_registrant.dart')
.absolute.path;
final String generatedImport = packageUriMapper.map(generatedPath)?.toString()
?? globals.fs.file(generatedPath).absolute.uri.toString();
.absolute
.uri;
final String generatedImport = packageConfig.toPackageUri(generatedUri)?.toString()
?? generatedUri.toString();
contents = '''
import 'dart:ui' as ui;
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'base/context.dart';
import 'build_info.dart';
......@@ -72,7 +73,6 @@ class CodeGeneratingKernelCompiler implements KernelCompiler {
String outputFilePath,
bool linkPlatformKernelIn = false,
bool aot = false,
@required BuildMode buildMode,
bool trackWidgetCreation,
List<String> extraFrontEndOptions,
String sdkRoot,
......@@ -84,6 +84,8 @@ class CodeGeneratingKernelCompiler implements KernelCompiler {
String initializeFromDill,
String platformDill,
List<String> dartDefines,
@required BuildMode buildMode,
@required PackageConfig packageConfig,
}) async {
final FlutterProject flutterProject = FlutterProject.current();
final CodegenDaemon codegenDaemon = await codeGenerator.daemon(flutterProject);
......@@ -113,6 +115,7 @@ class CodeGeneratingKernelCompiler implements KernelCompiler {
targetModel: targetModel,
initializeFromDill: initializeFromDill,
dartDefines: dartDefines,
packageConfig: packageConfig,
);
}
}
......@@ -170,7 +173,12 @@ class CodeGeneratingResidentCompiler implements ResidentCompiler {
}
@override
Future<CompilerOutput> recompile(String mainPath, List<Uri> invalidatedFiles, {String outputPath, String packagesFilePath}) async {
Future<CompilerOutput> recompile(
Uri mainUri,
List<Uri> invalidatedFiles, {
String outputPath,
PackageConfig packageConfig,
}) async {
if (_codegenDaemon.lastStatus != CodegenStatus.Succeeded && _codegenDaemon.lastStatus != CodegenStatus.Failed) {
await _codegenDaemon.buildResults.firstWhere((CodegenStatus status) {
return status == CodegenStatus.Succeeded || status == CodegenStatus.Failed;
......@@ -180,10 +188,10 @@ class CodeGeneratingResidentCompiler implements ResidentCompiler {
globals.printError('Code generation failed, build may have compile errors.');
}
return _residentCompiler.recompile(
mainPath,
mainUri,
invalidatedFiles,
outputPath: outputPath,
packagesFilePath: packagesFilePath,
packageConfig: packageConfig,
);
}
......
......@@ -5,6 +5,7 @@
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'package:usage/uuid/uuid.dart';
import 'artifacts.dart';
......@@ -15,7 +16,6 @@ import 'base/terminal.dart';
import 'build_info.dart';
import 'codegen.dart';
import 'convert.dart';
import 'dart/package_map.dart';
import 'globals.dart' as globals;
import 'project.dart';
......@@ -193,54 +193,6 @@ class StdoutHandler {
}
}
/// Converts filesystem paths to package URIs.
class PackageUriMapper {
PackageUriMapper(String scriptPath, String packagesPath, String fileSystemScheme, List<String> fileSystemRoots) {
final Map<String, Uri> packageMap = PackageMap(globals.fs.path.absolute(packagesPath), fileSystem: globals.fs).map;
final bool isWindowsPath = globals.platform.isWindows && !scriptPath.startsWith('org-dartlang-app');
final String scriptUri = Uri.file(scriptPath, windows: isWindowsPath).toString();
for (final String packageName in packageMap.keys) {
final String prefix = packageMap[packageName].toString();
// Only perform a multi-root mapping if there are multiple roots.
if (fileSystemScheme != null
&& fileSystemRoots != null
&& fileSystemRoots.length > 1
&& prefix.contains(fileSystemScheme)) {
_packageName = packageName;
_uriPrefixes = fileSystemRoots
.map((String name) => Uri.file(name, windows:globals.platform.isWindows).toString())
.toList();
return;
}
if (scriptUri.startsWith(prefix)) {
_packageName = packageName;
_uriPrefixes = <String>[prefix];
return;
}
}
}
String _packageName;
List<String> _uriPrefixes;
Uri map(String scriptPath) {
if (_packageName == null) {
return null;
}
final String scriptUri = Uri.file(scriptPath, windows: globals.platform.isWindows).toString();
for (final String uriPrefix in _uriPrefixes) {
if (scriptUri.startsWith(uriPrefix)) {
return Uri.parse('package:$_packageName/${scriptUri.substring(uriPrefix.length)}');
}
}
return null;
}
static Uri findUri(String scriptPath, String packagesPath, String fileSystemScheme, List<String> fileSystemRoots) {
return PackageUriMapper(scriptPath, packagesPath, fileSystemScheme, fileSystemRoots).map(scriptPath);
}
}
/// List the preconfigured build options for a given build mode.
List<String> buildModeOptions(BuildMode mode) {
switch (mode) {
......@@ -276,17 +228,18 @@ class KernelCompiler {
String outputFilePath,
String depFilePath,
TargetModel targetModel = TargetModel.flutter,
@required BuildMode buildMode,
bool linkPlatformKernelIn = false,
bool aot = false,
@required bool trackWidgetCreation,
List<String> extraFrontEndOptions,
String packagesPath,
List<String> fileSystemRoots,
String fileSystemScheme,
String initializeFromDill,
String platformDill,
@required String packagesPath,
@required BuildMode buildMode,
@required bool trackWidgetCreation,
@required List<String> dartDefines,
@required PackageConfig packageConfig,
}) async {
final String frontendServer = globals.artifacts.getArtifactPath(
Artifact.frontendServerSnapshotForEngineDartSdk
......@@ -301,7 +254,7 @@ class KernelCompiler {
}
Uri mainUri;
if (packagesPath != null) {
mainUri = PackageUriMapper.findUri(mainPath, packagesPath, fileSystemScheme, fileSystemRoots);
mainUri = packageConfig.toPackageUri(globals.fs.file(mainPath).uri);
}
// TODO(jonahwilliams): The output file must already exist, but this seems
// unnecessary.
......@@ -392,16 +345,16 @@ abstract class _CompilationRequest {
class _RecompileRequest extends _CompilationRequest {
_RecompileRequest(
Completer<CompilerOutput> completer,
this.mainPath,
this.mainUri,
this.invalidatedFiles,
this.outputPath,
this.packagesFilePath,
this.packageConfig,
) : super(completer);
String mainPath;
Uri mainUri;
List<Uri> invalidatedFiles;
String outputPath;
String packagesFilePath;
PackageConfig packageConfig;
@override
Future<CompilerOutput> _run(DefaultResidentCompiler compiler) async =>
......@@ -499,10 +452,10 @@ abstract class ResidentCompiler {
/// Binary file name is returned if compilation was successful, otherwise
/// null is returned.
Future<CompilerOutput> recompile(
String mainPath,
Uri mainUri,
List<Uri> invalidatedFiles, {
@required String outputPath,
String packagesFilePath,
@required PackageConfig packageConfig,
});
Future<CompilerOutput> compileExpression(
......@@ -620,56 +573,46 @@ class DefaultResidentCompiler implements ResidentCompiler {
@override
Future<CompilerOutput> recompile(
String mainPath,
Uri mainUri,
List<Uri> invalidatedFiles, {
@required String outputPath,
String packagesFilePath,
@required PackageConfig packageConfig,
}) async {
assert (outputPath != null);
assert(outputPath != null);
if (!_controller.hasListener) {
_controller.stream.listen(_handleCompilationRequest);
}
final Completer<CompilerOutput> completer = Completer<CompilerOutput>();
_controller.add(
_RecompileRequest(completer, mainPath, invalidatedFiles, outputPath, packagesFilePath)
_RecompileRequest(completer, mainUri, invalidatedFiles, outputPath, packageConfig)
);
return completer.future;
}
Future<CompilerOutput> _recompile(_RecompileRequest request) async {
_stdoutHandler.reset();
// First time recompile is called we actually have to compile the app from
// scratch ignoring list of invalidated files.
PackageUriMapper packageUriMapper;
if (request.packagesFilePath != null || packagesPath != null) {
packageUriMapper = PackageUriMapper(
request.mainPath,
request.packagesFilePath ?? packagesPath,
fileSystemScheme,
fileSystemRoots,
);
}
_compileRequestNeedsConfirmation = true;
if (_server == null) {
return _compile(
_mapFilename(request.mainPath, packageUriMapper),
request.packageConfig.toPackageUri(request.mainUri)?.toString() ?? request.mainUri.toString(),
request.outputPath,
_mapFilename(request.packagesFilePath ?? packagesPath, /* packageUriMapper= */ null),
);
}
final String inputKey = Uuid().generateV4();
final String mainUri = request.mainPath != null
? _mapFilename(request.mainPath, packageUriMapper) + ' '
: '';
_server.stdin.writeln('recompile $mainUri$inputKey');
globals.printTrace('<- recompile $mainUri$inputKey');
final String mainUri = request.packageConfig.toPackageUri(request.mainUri)?.toString()
?? request.mainUri.toString();
_server.stdin.writeln('recompile $mainUri $inputKey');
globals.printTrace('<- recompile $mainUri $inputKey');
for (final Uri fileUri in request.invalidatedFiles) {
final String message = _mapFileUri(fileUri.toString(), packageUriMapper);
String message;
if (fileUri.scheme == 'package') {
message = fileUri.toString();
} else {
message = request.packageConfig.toPackageUri(fileUri)?.toString()
?? fileUri.toString();
}
_server.stdin.writeln(message);
globals.printTrace(message);
}
......@@ -699,7 +642,6 @@ class DefaultResidentCompiler implements ResidentCompiler {
Future<CompilerOutput> _compile(
String scriptUri,
String outputPath,
String packagesFilePath,
) async {
final String frontendServer = globals.artifacts.getArtifactPath(
Artifact.frontendServerSnapshotForEngineDartSdk
......@@ -726,10 +668,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
'--libraries-spec',
librariesSpec,
],
if (packagesFilePath != null) ...<String>[
'--packages',
packagesFilePath,
] else if (packagesPath != null) ...<String>[
if (packagesPath != null) ...<String>[
'--packages',
packagesPath,
],
......@@ -916,43 +855,6 @@ class DefaultResidentCompiler implements ResidentCompiler {
globals.printTrace('<- reset');
}
String _mapFilename(String filename, PackageUriMapper packageUriMapper) {
return _doMapFilename(filename, packageUriMapper) ?? filename;
}
String _mapFileUri(String fileUri, PackageUriMapper packageUriMapper) {
String filename;
try {
filename = Uri.parse(fileUri).toFilePath();
} on UnsupportedError catch (_) {
return fileUri;
}
return _doMapFilename(filename, packageUriMapper) ?? fileUri;
}
String _doMapFilename(String filename, PackageUriMapper packageUriMapper) {
if (packageUriMapper != null) {
final Uri packageUri = packageUriMapper.map(filename);
if (packageUri != null) {
return packageUri.toString();
}
}
if (fileSystemRoots != null) {
for (final String root in fileSystemRoots) {
if (filename.startsWith(root)) {
return Uri(
scheme: fileSystemScheme, path: filename.substring(root.length))
.toString();
}
}
}
if (globals.platform.isWindows && fileSystemRoots != null && fileSystemRoots.length > 1) {
return Uri.file(filename, windows: globals.platform.isWindows).toString();
}
return null;
}
@override
Future<dynamic> shutdown() async {
// Server was never successfully created.
......
......@@ -5,6 +5,7 @@
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'package:vm_service/vm_service.dart' as vmservice;
import 'asset.dart';
......@@ -17,7 +18,6 @@ import 'build_info.dart';
import 'bundle.dart';
import 'compile.dart';
import 'convert.dart' show base64, utf8;
import 'dart/package_map.dart';
import 'globals.dart' as globals;
import 'vmservice.dart';
......@@ -395,32 +395,28 @@ class DevFS {
VMService serviceProtocol,
this.fsName,
this.rootDirectory, {
String packagesFilePath,
@required OperatingSystemUtils osUtils,
}) : _operations = ServiceProtocolDevFSOperations(serviceProtocol),
_httpWriter = _DevFSHttpWriter(
fsName,
serviceProtocol,
osUtils: osUtils,
),
_packagesFilePath = packagesFilePath ?? globals.fs.path.join(rootDirectory.path, kPackagesFileName);
);
DevFS.operations(
this._operations,
this.fsName,
this.rootDirectory, {
String packagesFilePath,
}) : _httpWriter = null,
_packagesFilePath = packagesFilePath ?? globals.fs.path.join(rootDirectory.path, kPackagesFileName);
this.rootDirectory,
) : _httpWriter = null;
final DevFSOperations _operations;
final _DevFSHttpWriter _httpWriter;
final String fsName;
final Directory rootDirectory;
final String _packagesFilePath;
final Set<String> assetPathsToEvict = <String>{};
List<Uri> sources = <Uri>[];
DateTime lastCompiled;
PackageConfig lastPackageConfig;
Uri _baseUri;
Uri get baseUri => _baseUri;
......@@ -462,23 +458,25 @@ class DevFS {
///
/// Returns the number of bytes synced.
Future<UpdateFSReport> update({
@required String mainPath,
@required Uri mainUri,
@required ResidentCompiler generator,
@required bool trackWidgetCreation,
@required String pathToReload,
@required List<Uri> invalidatedFiles,
@required PackageConfig packageConfig,
String target,
AssetBundle bundle,
DateTime firstBuildTime,
bool bundleFirstUpload = false,
@required ResidentCompiler generator,
String dillOutputPath,
@required bool trackWidgetCreation,
bool fullRestart = false,
String projectRootPath,
@required String pathToReload,
@required List<Uri> invalidatedFiles,
bool skipAssets = false,
}) async {
assert(trackWidgetCreation != null);
assert(generator != null);
final DateTime candidateCompileTime = DateTime.now();
lastPackageConfig = packageConfig;
// Update modified files
final String assetBuildDirPrefix = _asUriPath(getAssetBuildDirectory());
......@@ -514,10 +512,10 @@ class DevFS {
// dill files that depend on the invalidated files.
globals.printTrace('Compiling dart to kernel with ${invalidatedFiles.length} updated files');
final CompilerOutput compilerOutput = await generator.recompile(
mainPath,
mainUri,
invalidatedFiles,
outputPath: dillOutputPath ?? getDefaultApplicationKernelPath(trackWidgetCreation: trackWidgetCreation),
packagesFilePath : _packagesFilePath,
outputPath: dillOutputPath ?? getDefaultApplicationKernelPath(trackWidgetCreation: trackWidgetCreation),
packageConfig: packageConfig,
);
if (compilerOutput == null || compilerOutput.errorCount > 0) {
return UpdateFSReport(success: false);
......
......@@ -7,6 +7,7 @@ import 'dart:async';
import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:devtools_server/devtools_server.dart' as devtools_server;
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'application_package.dart';
import 'artifacts.dart';
......@@ -58,6 +59,7 @@ class FlutterDevice {
targetModel: targetModel,
experimentalFlags: experimentalFlags,
dartDefines: buildInfo.dartDefines,
packagesPath: PackageMap.globalPackagesPath,
);
/// Create a [FlutterDevice] with optional code generation enabled.
......@@ -104,7 +106,8 @@ class FlutterDevice {
.absolute.uri.toString(),
dartDefines: buildInfo.dartDefines,
librariesSpec: globals.fs.file(globals.artifacts
.getArtifactPath(Artifact.flutterWebLibrariesJson)).uri.toString()
.getArtifactPath(Artifact.flutterWebLibrariesJson)).uri.toString(),
packagesPath: PackageMap.globalPackagesPath,
);
} else {
generator = ResidentCompiler(
......@@ -121,6 +124,7 @@ class FlutterDevice {
experimentalFlags: experimentalFlags,
dartDefines: buildInfo.dartDefines,
initializeFromDill: globals.fs.path.join(getBuildDirectory(), 'cache.dill'),
packagesPath: PackageMap.globalPackagesPath,
);
}
......@@ -285,7 +289,6 @@ class FlutterDevice {
vmService,
fsName,
rootDirectory,
packagesFilePath: packagesFilePath,
osUtils: globals.os,
);
return devFS.create();
......@@ -548,7 +551,7 @@ class FlutterDevice {
}
Future<UpdateFSReport> updateDevFS({
String mainPath,
Uri mainUri,
String target,
AssetBundle bundle,
DateTime firstBuildTime,
......@@ -559,6 +562,7 @@ class FlutterDevice {
String pathToReload,
@required String dillOutputPath,
@required List<Uri> invalidatedFiles,
@required PackageConfig packageConfig,
}) async {
final Status devFSStatus = globals.logger.startProgress(
'Syncing files to device ${device.name}...',
......@@ -567,7 +571,7 @@ class FlutterDevice {
UpdateFSReport report;
try {
report = await devFS.update(
mainPath: mainPath,
mainUri: mainUri,
target: target,
bundle: bundle,
firstBuildTime: firstBuildTime,
......@@ -579,6 +583,7 @@ class FlutterDevice {
projectRootPath: projectRootPath,
pathToReload: pathToReload,
invalidatedFiles: invalidatedFiles,
packageConfig: packageConfig,
);
} on DevFSException {
devFSStatus.cancel();
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:async';
import 'package:package_config/package_config.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:platform/platform.dart';
import 'package:meta/meta.dart';
......@@ -17,6 +18,7 @@ import 'build_info.dart';
import 'bundle.dart';
import 'compile.dart';
import 'convert.dart';
import 'dart/package_map.dart';
import 'devfs.dart';
import 'device.dart';
import 'globals.dart' as globals;
......@@ -151,13 +153,23 @@ class HotRunner extends ResidentRunner {
}
@override
Future<OperationResult> reloadMethod({String libraryId, String classId}) async {
Future<OperationResult> reloadMethod({ String libraryId, String classId }) async {
final Stopwatch stopwatch = Stopwatch()..start();
final UpdateFSReport results = UpdateFSReport(success: true);
final List<Uri> invalidated = <Uri>[Uri.parse(libraryId)];
final PackageConfig packageConfig = await loadPackageConfigUri(
globals.fs.file(PackageMap.globalPackagesPath).absolute.uri,
loader: (Uri uri) {
final File file = globals.fs.file(uri);
if (!file.existsSync()) {
return null;
}
return file.readAsBytes();
}
);
for (final FlutterDevice device in flutterDevices) {
results.incorporateResults(await device.updateDevFS(
mainPath: mainPath,
mainUri: globals.fs.file(mainPath).absolute.uri,
target: target,
bundle: assetBundle,
firstBuildTime: firstBuildTime,
......@@ -167,6 +179,7 @@ class HotRunner extends ResidentRunner {
projectRootPath: projectRootPath,
pathToReload: getReloadPath(fullRestart: false),
invalidatedFiles: invalidated,
packageConfig: packageConfig,
dillOutputPath: dillOutputPath,
));
}
......@@ -345,6 +358,16 @@ class HotRunner extends ResidentRunner {
firstBuildTime = DateTime.now();
final List<Future<bool>> startupTasks = <Future<bool>>[];
final PackageConfig packageConfig = await loadPackageConfigUri(
globals.fs.file(PackageMap.globalPackagesPath).absolute.uri,
loader: (Uri uri) {
final File file = globals.fs.file(uri);
if (!file.existsSync()) {
return null;
}
return file.readAsBytes();
}
);
for (final FlutterDevice device in flutterDevices) {
// Here we initialize the frontend_server concurrently with the platform
// build, reducing overall initialization time. This is safe because the first
......@@ -353,11 +376,11 @@ class HotRunner extends ResidentRunner {
if (device.generator != null) {
startupTasks.add(
device.generator.recompile(
mainPath,
globals.fs.file(mainPath).uri,
<Uri>[],
outputPath: dillOutputPath ??
getDefaultApplicationKernelPath(trackWidgetCreation: debuggingOptions.buildInfo.trackWidgetCreation),
packagesFilePath : packagesFilePath,
packageConfig: packageConfig,
).then((CompilerOutput output) => output?.errorCount == 0)
);
}
......@@ -405,18 +428,17 @@ class HotRunner extends ResidentRunner {
}
}
// Picking up first device's compiler as a source of truth - compilers
// for all devices should be in sync.
final List<Uri> invalidatedFiles = await projectFileInvalidator.findInvalidated(
final InvalidationResult invalidationResult = await projectFileInvalidator.findInvalidated(
lastCompiled: flutterDevices[0].devFS.lastCompiled,
urisToMonitor: flutterDevices[0].devFS.sources,
packagesPath: packagesFilePath,
asyncScanning: hotRunnerConfig.asyncScanning,
packageConfig: flutterDevices[0].devFS.lastPackageConfig,
);
final UpdateFSReport results = UpdateFSReport(success: true);
for (final FlutterDevice device in flutterDevices) {
results.incorporateResults(await device.updateDevFS(
mainPath: mainPath,
mainUri: globals.fs.file(mainPath).absolute.uri,
target: target,
bundle: assetBundle,
firstBuildTime: firstBuildTime,
......@@ -425,7 +447,8 @@ class HotRunner extends ResidentRunner {
fullRestart: fullRestart,
projectRootPath: projectRootPath,
pathToReload: getReloadPath(fullRestart: fullRestart),
invalidatedFiles: invalidatedFiles,
invalidatedFiles: invalidationResult.uris,
packageConfig: invalidationResult.packageConfig,
dillOutputPath: dillOutputPath,
));
}
......@@ -1156,6 +1179,17 @@ class HotRunner extends ResidentRunner {
}
}
/// The result of an invalidation check from [ProjectFileInvalidator].
class InvalidationResult {
const InvalidationResult({
this.uris,
this.packageConfig,
});
final List<Uri> uris;
final PackageConfig packageConfig;
}
/// The [ProjectFileInvalidator] track the dependencies for a running
/// application to determine when they are dirty.
class ProjectFileInvalidator {
......@@ -1182,10 +1216,11 @@ class ProjectFileInvalidator {
// ~2000 files.
static const int _kMaxPendingStats = 8;
Future<List<Uri>> findInvalidated({
Future<InvalidationResult> findInvalidated({
@required DateTime lastCompiled,
@required List<Uri> urisToMonitor,
@required String packagesPath,
@required PackageConfig packageConfig,
bool asyncScanning = false,
}) async {
assert(urisToMonitor != null);
......@@ -1194,7 +1229,10 @@ class ProjectFileInvalidator {
if (lastCompiled == null) {
// Initial load.
assert(urisToMonitor.isEmpty);
return <Uri>[];
return InvalidationResult(
packageConfig: await _createPackageConfig(packagesPath),
uris: <Uri>[]
);
}
final Stopwatch stopwatch = Stopwatch()..start();
......@@ -1202,9 +1240,6 @@ class ProjectFileInvalidator {
// Don't watch pub cache directories to speed things up a little.
for (final Uri uri in urisToMonitor)
if (_isNotInPubCache(uri)) uri,
// We need to check the .packages file too since it is not used in compilation.
_fileSystem.file(packagesPath).uri,
];
final List<Uri> invalidatedFiles = <Uri>[];
......@@ -1233,16 +1268,41 @@ class ProjectFileInvalidator {
}
}
}
// We need to check the .packages file too since it is not used in compilation.
final Uri packageUri = _fileSystem.file(packagesPath).uri;
final DateTime updatedAt = _fileSystem.statSync(
packageUri.toFilePath(windows: _platform.isWindows)).modified;
if (updatedAt != null && updatedAt.isAfter(lastCompiled)) {
invalidatedFiles.add(packageUri);
packageConfig = await _createPackageConfig(packagesPath);
}
_logger.printTrace(
'Scanned through ${urisToScan.length} files in '
'${stopwatch.elapsedMilliseconds}ms'
'${asyncScanning ? " (async)" : ""}',
);
return invalidatedFiles;
return InvalidationResult(
packageConfig: packageConfig,
uris: invalidatedFiles,
);
}
bool _isNotInPubCache(Uri uri) {
return !(_platform.isWindows && uri.path.contains(_pubCachePathWindows))
&& !uri.path.contains(_pubCachePathLinuxAndMac);
}
Future<PackageConfig> _createPackageConfig(String packagesPath) {
return loadPackageConfigUri(
_fileSystem.file(packagesPath).absolute.uri,
loader: (Uri uri) {
final File file = _fileSystem.file(uri);
if (!file.existsSync()) {
return null;
}
return file.readAsBytes();
}
);
}
}
......@@ -448,7 +448,7 @@ class FlutterPlatform extends PlatformPlugin {
if (precompiledDillPath == null && precompiledDillFiles == null) {
// Lazily instantiate compiler so it is built only if it is actually used.
compiler ??= TestCompiler(buildMode, trackWidgetCreation, flutterProject);
mainDart = await compiler.compile(mainDart);
mainDart = await compiler.compile(globals.fs.file(mainDart).uri);
if (mainDart == null) {
controller.sink.addError(_getErrorMessage('Compilation failed', testPath, shellPath));
......
......@@ -869,7 +869,7 @@ class TestGoldenComparator {
// Lazily create the compiler
_compiler = _compiler ?? compilerFactory();
final String output = await _compiler.compile(listenerFile.path);
final String output = await _compiler.compile(listenerFile.uri);
final List<String> command = <String>[
shellPath,
'--disable-observatory',
......
......@@ -5,6 +5,7 @@
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import '../artifacts.dart';
import '../base/file_system.dart';
......@@ -19,8 +20,9 @@ import '../project.dart';
/// A request to the [TestCompiler] for recompilation.
class _CompilationRequest {
_CompilationRequest(this.path, this.result);
String path;
_CompilationRequest(this.mainUri, this.result);
Uri mainUri;
Completer<String> result;
}
......@@ -70,7 +72,7 @@ class TestCompiler {
// Whether to report compiler messages.
bool _suppressOutput = false;
Future<String> compile(String mainDart) {
Future<String> compile(Uri mainDart) {
final Completer<String> completer = Completer<String>();
compilerController.add(_CompilationRequest(mainDart, completer));
return completer.future;
......@@ -95,13 +97,13 @@ class TestCompiler {
Future<ResidentCompiler> createCompiler() async {
final ResidentCompiler residentCompiler = ResidentCompiler(
globals.artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
packagesPath: PackageMap.globalPackagesPath,
buildMode: buildMode,
trackWidgetCreation: trackWidgetCreation,
compilerMessageConsumer: _reportCompilerMessage,
initializeFromDill: testFilePath,
unsafePackageSerialization: false,
dartDefines: const <String>[],
packagesPath: PackageMap.globalPackagesPath,
);
if (flutterProject.hasBuilders) {
return CodeGeneratingResidentCompiler.create(
......@@ -112,6 +114,8 @@ class TestCompiler {
return residentCompiler;
}
PackageConfig _packageConfig;
// Handle a compilation request.
Future<void> _onCompilationRequest(_CompilationRequest request) async {
final bool isEmpty = compilationQueue.isEmpty;
......@@ -122,9 +126,19 @@ class TestCompiler {
if (!isEmpty) {
return;
}
_packageConfig ??= await loadPackageConfigUri(
globals.fs.file(PackageMap.globalPackagesPath).absolute.uri,
loader: (Uri uri) async {
final File file = globals.fs.file(uri);
if (!file.existsSync()) {
return null;
}
return file.readAsBytes();
}
);
while (compilationQueue.isNotEmpty) {
final _CompilationRequest request = compilationQueue.first;
globals.printTrace('Compiling ${request.path}');
globals.printTrace('Compiling ${request.mainUri}');
final Stopwatch compilerTime = Stopwatch()..start();
bool firstCompile = false;
if (compiler == null) {
......@@ -133,9 +147,10 @@ class TestCompiler {
}
_suppressOutput = false;
final CompilerOutput compilerOutput = await compiler.recompile(
request.path,
<Uri>[Uri.parse(request.path)],
request.mainUri,
<Uri>[request.mainUri],
outputPath: outputDill.path,
packageConfig: _packageConfig,
);
final String outputPath = compilerOutput?.outputFilename;
......@@ -143,12 +158,13 @@ class TestCompiler {
// errors, pass [null] upwards to the consumer and shutdown the
// compiler to avoid reusing compiler that might have gotten into
// a weird state.
final String path = request.mainUri.toFilePath(windows: globals.platform.isWindows);
if (outputPath == null || compilerOutput.errorCount > 0) {
request.result.complete(null);
await _shutdown();
} else {
final File outputFile = globals.fs.file(outputPath);
final File kernelReadyToRun = await outputFile.copy('${request.path}.dill');
final File kernelReadyToRun = await outputFile.copy('$path.dill');
final File testCache = globals.fs.file(testFilePath);
if (firstCompile || !testCache.existsSync() || (testCache.lengthSync() < outputFile.lengthSync())) {
// The idea is to keep the cache file up-to-date and include as
......@@ -161,7 +177,7 @@ class TestCompiler {
compiler.accept();
compiler.reset();
}
globals.printTrace('Compiling ${request.path} took ${compilerTime.elapsedMilliseconds}ms');
globals.printTrace('Compiling $path took ${compilerTime.elapsedMilliseconds}ms');
// Only remove now when we finished processing the element
compilationQueue.removeAt(0);
}
......
......@@ -140,7 +140,7 @@ void main() {
// Import.
expect(generated, contains("import 'file:///other/lib/main.dart' as entrypoint;"));
expect(generated, contains("import 'file:///foo/lib/generated_plugin_registrant.dart';"));
expect(generated, contains("import 'package:foo/generated_plugin_registrant.dart';"));
}));
......
......@@ -11,6 +11,7 @@ import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:mockito/mockito.dart';
import 'package:package_config/package_config.dart';
import 'package:process/process.dart';
import 'package:platform/platform.dart';
......@@ -59,6 +60,8 @@ void main() {
buildMode: BuildMode.debug,
trackWidgetCreation: false,
dartDefines: const <String>[],
packageConfig: PackageConfig.empty,
packagesPath: '.packages',
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
......@@ -88,6 +91,8 @@ void main() {
trackWidgetCreation: false,
aot: true,
dartDefines: const <String>[],
packageConfig: PackageConfig.empty,
packagesPath: '.packages',
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
......@@ -121,6 +126,8 @@ void main() {
trackWidgetCreation: false,
aot: true,
dartDefines: const <String>[],
packageConfig: PackageConfig.empty,
packagesPath: '.packages',
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
......@@ -152,6 +159,8 @@ void main() {
buildMode: BuildMode.debug,
trackWidgetCreation: false,
dartDefines: const <String>[],
packageConfig: PackageConfig.empty,
packagesPath: '.packages',
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
......@@ -179,6 +188,8 @@ void main() {
buildMode: BuildMode.debug,
trackWidgetCreation: false,
dartDefines: const <String>[],
packageConfig: PackageConfig.empty,
packagesPath: '.packages',
);
expect(mockFrontendServerStdIn.getAndClear(), isEmpty);
expect(testLogger.errorText, equals('\nCompiler message:\nline1\nline2\n'));
......@@ -201,6 +212,8 @@ void main() {
buildMode: BuildMode.debug,
trackWidgetCreation: false,
dartDefines: const <String>['FOO=bar', 'BAZ=qux'],
packageConfig: PackageConfig.empty,
packagesPath: '.packages',
);
expect(latestCommand, containsAllInOrder(<String>['-DFOO=bar', '-DBAZ=qux']));
......
......@@ -10,7 +10,9 @@ import 'package:flutter_tools/src/base/terminal.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';
import 'package:platform/platform.dart';
......@@ -74,12 +76,13 @@ void main() {
)));
await generator.recompile(
'/path/to/main.dart',
globals.fs.file('/path/to/main.dart').uri,
null, /* invalidatedFiles */
outputPath: '/build/',
packageConfig: PackageConfig.empty,
).then((CompilerOutput output) {
expect(mockFrontendServerStdIn.getAndClear(),
'compile /path/to/main.dart\n');
'compile file:///path/to/main.dart\n');
verifyNoMoreInteractions(mockFrontendServerStdIn);
expect(testLogger.errorText,
equals('\nCompiler message:\nline1\nline2\n'));
......@@ -122,9 +125,10 @@ void main() {
// The test manages timing via completers.
unawaited(
generator.recompile(
'/path/to/main.dart',
Uri.parse('/path/to/main.dart'),
null, /* invalidatedFiles */
outputPath: '/build/',
packageConfig: PackageConfig.empty,
).then((CompilerOutput outputCompile) {
expect(testLogger.errorText,
equals('\nCompiler message:\nline1\nline2\n'));
......
......@@ -11,6 +11,7 @@ import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:mockito/mockito.dart';
import 'package:package_config/package_config.dart';
import 'package:process/process.dart';
import 'package:platform/platform.dart';
......@@ -58,9 +59,10 @@ void main() {
));
final CompilerOutput output = await generator.recompile(
'/path/to/main.dart',
Uri.parse('/path/to/main.dart'),
null /* invalidatedFiles */,
outputPath: '/build/',
packageConfig: PackageConfig.empty,
);
expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
verifyNoMoreInteractions(mockFrontendServerStdIn);
......@@ -78,9 +80,10 @@ void main() {
);
expect(asyncGuard(() => generator.recompile(
'/path/to/main.dart',
Uri.parse('/path/to/main.dart'),
null, /* invalidatedFiles */
outputPath: '/build/',
packageConfig: PackageConfig.empty,
)), throwsToolExit());
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
......@@ -96,9 +99,10 @@ void main() {
);
expect(asyncGuard(() => generator.recompile(
'/path/to/main.dart',
Uri.parse('/path/to/main.dart'),
null, /* invalidatedFiles */
outputPath: '/build/',
packageConfig: PackageConfig.empty,
)), throwsToolExit());
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
......@@ -112,9 +116,10 @@ void main() {
.thenAnswer((Invocation invocation) => streamController.stream);
streamController.add(utf8.encode('result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0\n'));
await generator.recompile(
'/path/to/main.dart',
Uri.parse('/path/to/main.dart'),
null, /* invalidatedFiles */
outputPath: '/build/',
packageConfig: PackageConfig.empty,
);
expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
......@@ -153,7 +158,12 @@ void main() {
streamController.add(utf8.encode(
'result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0\n'
));
await generator.recompile('/path/to/main.dart', null /* invalidatedFiles */, outputPath: '/build/');
await generator.recompile(
Uri.parse('/path/to/main.dart'),
null /* invalidatedFiles */,
outputPath: '/build/',
packageConfig: PackageConfig.empty,
);
expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
await _recompile(streamController, generator, mockFrontendServerStdIn,
......@@ -187,16 +197,18 @@ Future<void> _recompile(
streamController.add(utf8.encode(mockCompilerOutput));
});
final CompilerOutput output = await generator.recompile(
null /* mainPath */,
Uri.parse('/path/to/main.dart'),
<Uri>[Uri.parse('/path/to/main.dart')],
outputPath: '/build/',
packageConfig: PackageConfig.empty,
);
expect(output.outputFilename, equals('/path/to/main.dart.dill'));
final String commands = mockFrontendServerStdIn.getAndClear();
final RegExp re = RegExp(r'^recompile (.*)\n/path/to/main.dart\n(.*)\n$');
expect(commands, matches(re));
final Match match = re.firstMatch(commands);
expect(match[1] == match[2], isTrue);
final RegExp whitespace = RegExp(r'\s+');
final List<String> parts = commands.split(whitespace);
// Test that uuid matches at beginning and end.
expect(parts[2], equals(parts[4]));
mockFrontendServerStdIn.stdInWrites.clear();
}
......
......@@ -16,6 +16,7 @@ import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/devfs.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:mockito/mockito.dart';
import 'package:package_config/package_config.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
import '../src/common.dart';
......@@ -160,11 +161,12 @@ void main() {
final MockResidentCompiler residentCompiler = MockResidentCompiler();
final UpdateFSReport report = await devFS.update(
mainPath: 'lib/foo.txt',
mainUri: Uri.parse('lib/foo.txt'),
generator: residentCompiler,
pathToReload: 'lib/foo.txt.dill',
trackWidgetCreation: false,
invalidatedFiles: <Uri>[],
packageConfig: PackageConfig.empty,
);
expect(report.syncedBytes, 22);
......@@ -221,11 +223,12 @@ void main() {
expect(devFS.assetPathsToEvict, isEmpty);
final UpdateFSReport report = await devFS.update(
mainPath: 'lib/foo.txt',
mainUri: Uri.parse('lib/foo.txt'),
generator: residentCompiler,
pathToReload: 'lib/foo.txt.dill',
trackWidgetCreation: false,
invalidatedFiles: <Uri>[],
packageConfig: PackageConfig.empty,
);
vmService.expectMessages(<String>[
'writeFile test lib/foo.txt.dill',
......@@ -284,17 +287,18 @@ void main() {
any,
any,
outputPath: anyNamed('outputPath'),
packagesFilePath: anyNamed('packagesFilePath'),
packageConfig: anyNamed('packageConfig'),
)).thenAnswer((Invocation invocation) {
return Future<CompilerOutput>.value(const CompilerOutput('example', 2, <Uri>[]));
});
final UpdateFSReport report = await devFS.update(
mainPath: 'lib/foo.txt',
mainUri: Uri.parse('lib/foo.txt'),
generator: residentCompiler,
pathToReload: 'lib/foo.txt.dill',
trackWidgetCreation: false,
invalidatedFiles: <Uri>[],
packageConfig: PackageConfig.empty,
);
expect(report.success, false);
......@@ -316,18 +320,19 @@ void main() {
any,
any,
outputPath: anyNamed('outputPath'),
packagesFilePath: anyNamed('packagesFilePath'),
packageConfig: anyNamed('packageConfig'),
)).thenAnswer((Invocation invocation) {
fs.file('example').createSync();
return Future<CompilerOutput>.value(CompilerOutput('example', 0, <Uri>[sourceFile.uri]));
});
final UpdateFSReport report = await devFS.update(
mainPath: 'lib/main.dart',
mainUri: Uri.parse('lib/main.dart'),
generator: residentCompiler,
pathToReload: 'lib/foo.txt.dill',
trackWidgetCreation: false,
invalidatedFiles: <Uri>[],
packageConfig: PackageConfig.empty,
);
expect(report.success, true);
......
......@@ -103,7 +103,7 @@ void main() {
MockLocalEngineArtifacts mockArtifacts;
when(mockDevFs.update(
mainPath: anyNamed('mainPath'),
mainUri: anyNamed('mainUri'),
target: anyNamed('target'),
bundle: anyNamed('bundle'),
firstBuildTime: anyNamed('firstBuildTime'),
......@@ -115,6 +115,7 @@ void main() {
projectRootPath: anyNamed('projectRootPath'),
pathToReload: anyNamed('pathToReload'),
invalidatedFiles: anyNamed('invalidatedFiles'),
packageConfig: anyNamed('packageConfig'),
)).thenAnswer((Invocation _) => Future<UpdateFSReport>.value(
UpdateFSReport(success: true, syncedBytes: 1000, invalidatedSourcesCount: 1)));
when(mockDevFs.assetPathsToEvict).thenReturn(<String>{});
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:typed_data';
import 'package:flutter_tools/src/base/file_system.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 '../src/common.dart';
import '../src/context.dart';
const String packagesContents = r'''
xml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/xml-3.2.3/lib/
yaml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.15/lib/
example:file:///example/lib/
''';
const String multiRootPackagesContents = r'''
xml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/xml-3.2.3/lib/
yaml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.15/lib/
example:org-dartlang-app:/
''';
void main() {
MockFileSystem mockFileSystem;
MockFile mockFile;
setUp(() {
mockFileSystem = MockFileSystem();
mockFile = MockFile();
when(mockFileSystem.path).thenReturn(globals.fs.path);
when(mockFileSystem.file(any)).thenReturn(mockFile);
when(mockFile.readAsBytesSync()).thenReturn(utf8.encode(packagesContents) as Uint8List);
});
testUsingContext('Can map main.dart to correct package', () async {
final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages', null, null);
expect(packageUriMapper.map('/example/lib/main.dart').toString(),
'package:example/main.dart');
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('single-root maps file from other package to null', () async {
final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages', null, null);
expect(packageUriMapper.map('/xml/lib/xml.dart'), null);
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('single-root maps non-main file from same package', () async {
final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages', null, null);
expect(packageUriMapper.map('/example/lib/src/foo.dart').toString(),
'package:example/src/foo.dart');
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('multi-root maps main file from same package on multiroot scheme', () async {
final MockFileSystem mockFileSystem = MockFileSystem();
final MockFile mockFile = MockFile();
when(mockFileSystem.path).thenReturn(globals.fs.path);
when(mockFileSystem.file(any)).thenReturn(mockFile);
when(mockFile.readAsBytesSync())
.thenReturn(utf8.encode(multiRootPackagesContents) as Uint8List);
final PackageUriMapper packageUriMapper = PackageUriMapper(
'/example/lib/main.dart',
'.packages',
'org-dartlang-app',
<String>['/example/lib/', '/gen/lib/']);
expect(packageUriMapper.map('/example/lib/main.dart').toString(),
'package:example/main.dart');
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
}
class MockFileSystem extends Mock implements FileSystem {}
class MockFile extends Mock implements File {}
......@@ -3,84 +3,123 @@
// found in the LICENSE file.
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/run_hot.dart';
import 'package:package_config/package_config.dart';
import 'package:platform/platform.dart';
import '../src/common.dart';
import '../src/mocks.dart';
// assumption: tests have a timeout less than 100 days
final DateTime inFuture = DateTime.now().add(const Duration(days: 100));
void main() {
BufferLogger bufferLogger;
setUp(() {
bufferLogger = BufferLogger(
terminal: AnsiTerminal(
stdio: MockStdio(),
platform: FakePlatform(),
),
outputPreferences: OutputPreferences.test(),
);
});
for (final bool asyncScanning in <bool>[true, false]) {
testWithoutContext('No last compile, asyncScanning: $asyncScanning', () async {
final FileSystem fileSystem = MemoryFileSystem();
final ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator(
fileSystem: MemoryFileSystem(),
fileSystem: fileSystem,
platform: FakePlatform(),
logger: bufferLogger,
logger: BufferLogger.test(),
);
fileSystem.file('.packages').writeAsStringSync('\n');
expect(
await projectFileInvalidator.findInvalidated(
(await projectFileInvalidator.findInvalidated(
lastCompiled: null,
urisToMonitor: <Uri>[],
packagesPath: '',
packagesPath: '.packages',
asyncScanning: asyncScanning,
),
packageConfig: PackageConfig.empty,
)).uris,
isEmpty,
);
});
testWithoutContext('Empty project, asyncScanning: $asyncScanning', () async {
final FileSystem fileSystem = MemoryFileSystem();
final ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator(
fileSystem: MemoryFileSystem(),
fileSystem: fileSystem,
platform: FakePlatform(),
logger: bufferLogger,
logger: BufferLogger.test(),
);
fileSystem.file('.packages').writeAsStringSync('\n');
expect(
await projectFileInvalidator.findInvalidated(
(await projectFileInvalidator.findInvalidated(
lastCompiled: inFuture,
urisToMonitor: <Uri>[],
packagesPath: '',
packagesPath: '.packages',
asyncScanning: asyncScanning,
),
packageConfig: PackageConfig.empty,
)).uris,
isEmpty,
);
});
testWithoutContext('Non-existent files are ignored, asyncScanning: $asyncScanning', () async {
final FileSystem fileSystem = MemoryFileSystem();
final ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator(
fileSystem: MemoryFileSystem(),
platform: FakePlatform(),
logger: bufferLogger,
logger: BufferLogger.test(),
);
fileSystem.file('.packages').writeAsStringSync('\n');
expect(
await projectFileInvalidator.findInvalidated(
(await projectFileInvalidator.findInvalidated(
lastCompiled: inFuture,
urisToMonitor: <Uri>[Uri.parse('/not-there-anymore'),],
packagesPath: '',
packagesPath: '.packages',
asyncScanning: asyncScanning,
),
packageConfig: PackageConfig.empty,
)).uris,
isEmpty,
);
});
testWithoutContext('Picks up changes to the .packages file and updates PackageConfig'
', asyncScanning: $asyncScanning', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final PackageConfig packageConfig = PackageConfig.empty;
final ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator(
fileSystem: fileSystem,
platform: FakePlatform(),
logger: BufferLogger.test(),
);
fileSystem.file('.packages')
.writeAsStringSync('\n');
final InvalidationResult invalidationResult = await projectFileInvalidator.findInvalidated(
lastCompiled: null,
urisToMonitor: <Uri>[],
packagesPath: '.packages',
asyncScanning: asyncScanning,
packageConfig: packageConfig,
);
expect(invalidationResult.packageConfig, isNot(packageConfig));
fileSystem.file('.packages')
.writeAsStringSync('foo:lib/\n');
final DateTime packagesUpdated = fileSystem.statSync('.packages')
.modified;
final InvalidationResult nextInvalidationResult = await projectFileInvalidator
.findInvalidated(
lastCompiled: packagesUpdated.subtract(const Duration(seconds: 1)),
urisToMonitor: <Uri>[],
packagesPath: '.packages',
asyncScanning: asyncScanning,
packageConfig: PackageConfig.empty,
);
expect(nextInvalidationResult.uris, contains(Uri.parse('.packages')));
// The PackagConfig should have been recreated too
expect(nextInvalidationResult.packageConfig,
isNot(invalidationResult.packageConfig));
});
}
}
......@@ -44,6 +44,7 @@ void main() {
setUp(() {
testbed = Testbed(setup: () {
globals.fs.file('.packages').writeAsStringSync('\n');
globals.fs.file(globals.fs.path.join('build', 'app.dill'))
..createSync(recursive: true)
..writeAsStringSync('ABC');
......@@ -69,9 +70,8 @@ void main() {
when(mockDevFS.assetPathsToEvict).thenReturn(<String>{});
// FlutterDevice Mocks.
when(mockFlutterDevice.updateDevFS(
// Intentionally provide empty list to match above mock.
invalidatedFiles: <Uri>[],
mainPath: anyNamed('mainPath'),
invalidatedFiles: anyNamed('invalidatedFiles'),
mainUri: anyNamed('mainUri'),
target: anyNamed('target'),
bundle: anyNamed('bundle'),
firstBuildTime: anyNamed('firstBuildTime'),
......@@ -81,6 +81,7 @@ void main() {
projectRootPath: anyNamed('projectRootPath'),
pathToReload: anyNamed('pathToReload'),
dillOutputPath: anyNamed('dillOutputPath'),
packageConfig: anyNamed('packageConfig'),
)).thenAnswer((Invocation invocation) async {
return UpdateFSReport(
success: true,
......@@ -225,7 +226,7 @@ void main() {
));
await onAppStart.future;
when(mockFlutterDevice.updateDevFS(
mainPath: anyNamed('mainPath'),
mainUri: anyNamed('mainUri'),
target: anyNamed('target'),
bundle: anyNamed('bundle'),
firstBuildTime: anyNamed('firstBuildTime'),
......@@ -236,6 +237,7 @@ void main() {
pathToReload: anyNamed('pathToReload'),
invalidatedFiles: anyNamed('invalidatedFiles'),
dillOutputPath: anyNamed('dillOutputPath'),
packageConfig: anyNamed('packageConfig'),
)).thenThrow(vm_service.RPCError('something bad happened', 666, ''));
final OperationResult result = await residentRunner.restart(fullRestart: false);
......@@ -330,7 +332,7 @@ void main() {
));
await onAppStart.future;
when(mockFlutterDevice.updateDevFS(
mainPath: anyNamed('mainPath'),
mainUri: anyNamed('mainUri'),
target: anyNamed('target'),
bundle: anyNamed('bundle'),
firstBuildTime: anyNamed('firstBuildTime'),
......@@ -341,6 +343,7 @@ void main() {
pathToReload: anyNamed('pathToReload'),
invalidatedFiles: anyNamed('invalidatedFiles'),
dillOutputPath: anyNamed('dillOutputPath'),
packageConfig: anyNamed('packageConfig'),
)).thenThrow(vm_service.RPCError('something bad happened', 666, ''));
final OperationResult result = await residentRunner.restart(fullRestart: true);
......
......@@ -94,7 +94,7 @@ void main() {
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
globals.fs.file(globals.fs.path.join('web', 'index.html')).createSync(recursive: true);
when(mockWebDevFS.update(
mainPath: anyNamed('mainPath'),
mainUri: anyNamed('mainUri'),
target: anyNamed('target'),
bundle: anyNamed('bundle'),
firstBuildTime: anyNamed('firstBuildTime'),
......@@ -106,6 +106,7 @@ void main() {
pathToReload: anyNamed('pathToReload'),
invalidatedFiles: anyNamed('invalidatedFiles'),
trackWidgetCreation: true,
packageConfig: anyNamed('packageConfig'),
)).thenAnswer((Invocation _) async {
return UpdateFSReport(success: true, syncedBytes: 0)..invalidatedModules = <String>[];
});
......@@ -313,7 +314,7 @@ void main() {
_setupMocks();
launchChromeInstance(mockChrome);
when(mockWebDevFS.update(
mainPath: anyNamed('mainPath'),
mainUri: anyNamed('mainUri'),
target: anyNamed('target'),
bundle: anyNamed('bundle'),
firstBuildTime: anyNamed('firstBuildTime'),
......@@ -325,9 +326,10 @@ void main() {
projectRootPath: anyNamed('projectRootPath'),
pathToReload: anyNamed('pathToReload'),
invalidatedFiles: anyNamed('invalidatedFiles'),
packageConfig: anyNamed('packageConfig'),
)).thenAnswer((Invocation invocation) async {
// Generated entrypoint file in temp dir.
expect(invocation.namedArguments[#mainPath], contains('entrypoint.dart'));
expect(invocation.namedArguments[#mainUri].toString(), contains('entrypoint.dart'));
return UpdateFSReport(success: true)
..invalidatedModules = <String>['example'];
});
......@@ -362,9 +364,9 @@ void main() {
test('Can hot restart after attaching', () => testbed.run(() async {
_setupMocks();
launchChromeInstance(mockChrome);
String entrypointFileName;
Uri entrypointFileUri;
when(mockWebDevFS.update(
mainPath: anyNamed('mainPath'),
mainUri: anyNamed('mainUri'),
target: anyNamed('target'),
bundle: anyNamed('bundle'),
firstBuildTime: anyNamed('firstBuildTime'),
......@@ -376,8 +378,9 @@ void main() {
projectRootPath: anyNamed('projectRootPath'),
pathToReload: anyNamed('pathToReload'),
invalidatedFiles: anyNamed('invalidatedFiles'),
packageConfig: anyNamed('packageConfig'),
)).thenAnswer((Invocation invocation) async {
entrypointFileName = invocation.namedArguments[#mainPath] as String;
entrypointFileUri = invocation.namedArguments[#mainUri] as Uri;
return UpdateFSReport(success: true)
..invalidatedModules = <String>['example'];
});
......@@ -389,8 +392,8 @@ void main() {
final OperationResult result = await residentWebRunner.restart(fullRestart: true);
// Ensure that generated entrypoint is generated correctly.
expect(entrypointFileName, isNotNull);
final String entrypointContents = globals.fs.file(entrypointFileName).readAsStringSync();
expect(entrypointFileUri, isNotNull);
final String entrypointContents = globals.fs.file(entrypointFileUri).readAsStringSync();
expect(entrypointContents, contains('// Flutter web bootstrap script'));
expect(entrypointContents, contains("import 'dart:ui' as ui;"));
expect(entrypointContents, contains('await ui.webOnlyInitializePlatform();'));
......@@ -417,7 +420,7 @@ void main() {
_setupMocks();
when(mockFlutterDevice.device).thenReturn(mockWebServerDevice);
when(mockWebDevFS.update(
mainPath: anyNamed('mainPath'),
mainUri: anyNamed('mainUri'),
target: anyNamed('target'),
bundle: anyNamed('bundle'),
firstBuildTime: anyNamed('firstBuildTime'),
......@@ -429,6 +432,7 @@ void main() {
projectRootPath: anyNamed('projectRootPath'),
pathToReload: anyNamed('pathToReload'),
invalidatedFiles: anyNamed('invalidatedFiles'),
packageConfig: anyNamed('packageConfig'),
)).thenAnswer((Invocation invocation) async {
return UpdateFSReport(success: true)
..invalidatedModules = <String>['example'];
......@@ -469,7 +473,7 @@ void main() {
test('Exits when initial compile fails', () => testbed.run(() async {
_setupMocks();
when(mockWebDevFS.update(
mainPath: anyNamed('mainPath'),
mainUri: anyNamed('mainUri'),
target: anyNamed('target'),
bundle: anyNamed('bundle'),
firstBuildTime: anyNamed('firstBuildTime'),
......@@ -480,6 +484,7 @@ void main() {
projectRootPath: anyNamed('projectRootPath'),
pathToReload: anyNamed('pathToReload'),
invalidatedFiles: anyNamed('invalidatedFiles'),
packageConfig: anyNamed('packageConfig'),
trackWidgetCreation: true,
)).thenAnswer((Invocation _) async {
return UpdateFSReport(success: false, syncedBytes: 0)..invalidatedModules = <String>[];
......@@ -527,7 +532,7 @@ void main() {
));
await connectionInfoCompleter.future;
when(mockWebDevFS.update(
mainPath: anyNamed('mainPath'),
mainUri: anyNamed('mainUri'),
target: anyNamed('target'),
bundle: anyNamed('bundle'),
firstBuildTime: anyNamed('firstBuildTime'),
......@@ -538,6 +543,7 @@ void main() {
projectRootPath: anyNamed('projectRootPath'),
pathToReload: anyNamed('pathToReload'),
invalidatedFiles: anyNamed('invalidatedFiles'),
packageConfig: anyNamed('packageConfig'),
trackWidgetCreation: true,
)).thenAnswer((Invocation _) async {
return UpdateFSReport(success: false, syncedBytes: 0)..invalidatedModules = <String>[];
......
......@@ -2,16 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/test/test_compiler.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import '../src/common.dart';
import '../src/testbed.dart';
final Platform linuxPlatform = FakePlatform(
operatingSystem: 'linux',
environment: <String, String>{},
);
void main() {
group(TestCompiler, () {
Testbed testbed;
......@@ -20,6 +27,9 @@ void main() {
setUp(() {
testbed = Testbed(
overrides: <Type, Generator>{
Platform: () => linuxPlatform,
},
setup: () async {
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
......@@ -37,37 +47,42 @@ void main() {
test('Reports a dill file when compile is successful', () => testbed.run(() async {
when(residentCompiler.recompile(
'test/foo.dart',
any,
<Uri>[Uri.parse('test/foo.dart')],
outputPath: testCompiler.outputDill.path,
packageConfig: anyNamed('packageConfig'),
)).thenAnswer((Invocation invocation) async {
globals.fs.file('abc.dill').createSync();
return const CompilerOutput('abc.dill', 0, <Uri>[]);
});
expect(await testCompiler.compile('test/foo.dart'), 'test/foo.dart.dill');
expect(globals.fs.file('test/foo.dart.dill').existsSync(), true);
expect(await testCompiler.compile(Uri.parse('test/foo.dart')), 'test/foo.dart.dill');
expect(globals.fs.file('test/foo.dart.dill'), exists);
}));
test('Reports null when a compile fails', () => testbed.run(() async {
when(residentCompiler.recompile(
'test/foo.dart',
any,
<Uri>[Uri.parse('test/foo.dart')],
outputPath: testCompiler.outputDill.path,
packageConfig: anyNamed('packageConfig'),
)).thenAnswer((Invocation invocation) async {
globals.fs.file('abc.dill').createSync();
return const CompilerOutput('abc.dill', 1, <Uri>[]);
});
expect(await testCompiler.compile('test/foo.dart'), null);
expect(globals.fs.file('test/foo.dart.dill').existsSync(), false);
expect(await testCompiler.compile(Uri.parse('test/foo.dart')), null);
expect(globals.fs.file('test/foo.dart.dill'), isNot(exists));
verify(residentCompiler.shutdown()).called(1);
}));
test('Disposing test compiler shuts down backing compiler', () => testbed.run(() async {
testCompiler.compiler = residentCompiler;
expect(testCompiler.compilerController.isClosed, false);
await testCompiler.dispose();
expect(testCompiler.compilerController.isClosed, true);
verify(residentCompiler.shutdown()).called(1);
}));
......
......@@ -360,7 +360,7 @@ void main() {
any,
any,
outputPath: anyNamed('outputPath'),
packagesFilePath: anyNamed('packagesFilePath'),
packageConfig: anyNamed('packageConfig'),
)).thenAnswer((Invocation invocation) async {
return const CompilerOutput('a', 0, <Uri>[]);
});
......@@ -402,11 +402,12 @@ void main() {
webDevFS.webAssetServer.dartSdkSourcemap.createSync(recursive: true);
await webDevFS.update(
mainPath: globals.fs.path.join('lib', 'main.dart'),
mainUri: globals.fs.file(globals.fs.path.join('lib', 'main.dart')).uri,
generator: residentCompiler,
trackWidgetCreation: true,
bundleFirstUpload: true,
invalidatedFiles: <Uri>[],
packageConfig: PackageConfig.empty,
);
expect(webDevFS.webAssetServer.getFile('require.js'), isNotNull);
......@@ -452,7 +453,7 @@ void main() {
any,
any,
outputPath: anyNamed('outputPath'),
packagesFilePath: anyNamed('packagesFilePath'),
packageConfig: anyNamed('packageConfig'),
)).thenAnswer((Invocation invocation) async {
return const CompilerOutput('a', 0, <Uri>[]);
});
......
......@@ -6,6 +6,7 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io' as io show IOSink, ProcessSignal, Stdout, StdoutException;
import 'package:package_config/package_config.dart';
import 'package:platform/platform.dart';
import 'package:flutter_tools/src/android/android_device.dart';
......@@ -662,7 +663,7 @@ class MockResidentCompiler extends BasicMock implements ResidentCompiler {
}
@override
Future<CompilerOutput> recompile(String mainPath, List<Uri> invalidatedFiles, { String outputPath, String packagesFilePath }) async {
Future<CompilerOutput> recompile(Uri mainPath, List<Uri> invalidatedFiles, { String outputPath, PackageConfig packageConfig }) async {
globals.fs.file(outputPath).createSync(recursive: true);
globals.fs.file(outputPath).writeAsStringSync('compiled_kernel_output');
return CompilerOutput(outputPath, 0, <Uri>[]);
......
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