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