Enable Hot Reload on Windows (backed by gen_snapshot) (#8512)
* Enable Hot Reload on Windows (backed by gen_snapshot)
\o/
Two caveats:
* Hot Reload on Windows is slower than on other platforms because gen_snapshot is slower then sky_snapshot
* We currently cannot hot reload projects with spaces in the path
* enable tests
diff --git a/packages/flutter_tools/lib/src/application_package.dart b/packages/flutter_tools/lib/src/application_package.dart
index c361d4b..8f837a0 100644
--- a/packages/flutter_tools/lib/src/application_package.dart
+++ b/packages/flutter_tools/lib/src/application_package.dart
@@ -258,6 +258,7 @@
: new IOSApp.fromIpa(applicationBinary);
case TargetPlatform.darwin_x64:
case TargetPlatform.linux_x64:
+ case TargetPlatform.windows_x64:
return null;
}
assert(platform != null);
@@ -282,6 +283,7 @@
return iOS;
case TargetPlatform.darwin_x64:
case TargetPlatform.linux_x64:
+ case TargetPlatform.windows_x64:
return null;
}
return null;
diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart
index 0aa9ddc..2655019 100644
--- a/packages/flutter_tools/lib/src/artifacts.dart
+++ b/packages/flutter_tools/lib/src/artifacts.dart
@@ -21,6 +21,8 @@
skySnapshot,
snapshotDart,
flutterFramework,
+ vmSnapshotData,
+ isolateSnapshotData
}
String _artifactToFileName(Artifact artifact) {
@@ -49,6 +51,10 @@
return 'snapshot.dart';
case Artifact.flutterFramework:
return 'Flutter.framework';
+ case Artifact.vmSnapshotData:
+ return 'vm_isolate_snapshot.bin';
+ case Artifact.isolateSnapshotData:
+ return 'isolate_snapshot.bin';
}
assert(false, 'Invalid artifact $artifact.');
return null;
@@ -85,6 +91,7 @@
return _getIosArtifactPath(artifact, platform, mode);
case TargetPlatform.darwin_x64:
case TargetPlatform.linux_x64:
+ case TargetPlatform.windows_x64:
assert(mode == null, 'Platform $platform does not support different build modes.');
return _getHostArtifactPath(artifact, platform);
}
@@ -139,6 +146,16 @@
switch (artifact) {
case Artifact.skyShell:
case Artifact.skySnapshot:
+ if (platform == TargetPlatform.windows_x64)
+ throw new UnimplementedError('Artifact $artifact not available on platfrom $platform.');
+ continue returnResourcePath;
+ case Artifact.genSnapshot:
+ case Artifact.vmSnapshotData:
+ case Artifact.isolateSnapshotData:
+ if (platform != TargetPlatform.windows_x64)
+ throw new UnimplementedError('Artifact $artifact not available on platfrom $platform.');
+ continue returnResourcePath;
+ returnResourcePath:
case Artifact.icudtlDat:
String engineArtifactsPath = cache.getArtifactDirectory('engine').path;
String platformDirName = getNameForTargetPlatform(platform);
@@ -147,6 +164,8 @@
assert(false, 'Artifact $artifact not available for platform $platform.');
return null;
}
+ assert(false, 'Artifact $artifact not available for platform $platform.');
+ return null;
}
String _getEngineArtifactsPath(TargetPlatform platform, [BuildMode mode]) {
@@ -155,6 +174,7 @@
switch (platform) {
case TargetPlatform.linux_x64:
case TargetPlatform.darwin_x64:
+ case TargetPlatform.windows_x64:
assert(mode == null, 'Platform $platform does not support different build modes.');
return fs.path.join(engineDir, platformName);
case TargetPlatform.ios:
@@ -174,6 +194,8 @@
return TargetPlatform.darwin_x64;
if (platform.isLinux)
return TargetPlatform.linux_x64;
+ if (platform.isWindows)
+ return TargetPlatform.windows_x64;
throw new UnimplementedError('Host OS not supported.');
}
}
@@ -193,15 +215,12 @@
case Artifact.dartIoEntriesTxt:
return fs.path.join(_engineSrcPath, 'dart', 'runtime', 'bin', _artifactToFileName(artifact));
case Artifact.dartVmEntryPointsTxt:
- return fs.path.join(_engineSrcPath, 'flutter', 'runtime', _artifactToFileName(artifact));
case Artifact.dartVmEntryPointsAndroidTxt:
return fs.path.join(_engineSrcPath, 'flutter', 'runtime', _artifactToFileName(artifact));
case Artifact.snapshotDart:
return fs.path.join(_engineSrcPath, 'flutter', 'lib', 'snapshot', _artifactToFileName(artifact));
case Artifact.classesDexJar:
return fs.path.join(engineOutPath, 'gen', 'flutter', 'shell', 'platform', 'android', 'android', _artifactToFileName(artifact));
- case Artifact.icudtlDat:
- return fs.path.join(engineOutPath, _artifactToFileName(artifact));
case Artifact.libskyShellSo:
String abi = _getAbiDirectory(platform);
return fs.path.join(engineOutPath, 'gen', 'flutter', 'shell', 'platform', 'android', 'android', fs.path.join('android', 'libs', abi, _artifactToFileName(artifact)));
@@ -211,6 +230,10 @@
return _skyShellPath(platform);
case Artifact.skySnapshot:
return _skySnapshotPath();
+ case Artifact.isolateSnapshotData:
+ case Artifact.vmSnapshotData:
+ return fs.path.join(engineOutPath, 'gen', 'flutter', 'lib', 'snapshot', _artifactToFileName(artifact));
+ case Artifact.icudtlDat:
case Artifact.flutterFramework:
return fs.path.join(engineOutPath, _artifactToFileName(artifact));
}
diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart
index 2b3e697..5facec6 100644
--- a/packages/flutter_tools/lib/src/build_info.dart
+++ b/packages/flutter_tools/lib/src/build_info.dart
@@ -66,7 +66,8 @@
android_x86,
ios,
darwin_x64,
- linux_x64
+ linux_x64,
+ windows_x64
}
String getNameForTargetPlatform(TargetPlatform platform) {
@@ -83,6 +84,8 @@
return 'darwin-x64';
case TargetPlatform.linux_x64:
return 'linux-x64';
+ case TargetPlatform.windows_x64:
+ return 'windows-x64';
}
assert(false);
return null;
diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart
index e4c751b..bbcafa7 100644
--- a/packages/flutter_tools/lib/src/cache.dart
+++ b/packages/flutter_tools/lib/src/cache.dart
@@ -289,6 +289,7 @@
];
List<List<String>> get _windowsBinaryDirs => <List<String>>[
+ <String>['windows-x64', 'windows-x64/artifacts.zip'],
<String>['android-arm-profile/windows-x64', 'android-arm-profile/windows-x64.zip'],
<String>['android-arm-release/windows-x64', 'android-arm-release/windows-x64.zip'],
];
diff --git a/packages/flutter_tools/lib/src/commands/build_aot.dart b/packages/flutter_tools/lib/src/commands/build_aot.dart
index 27529c2..4a7337b 100644
--- a/packages/flutter_tools/lib/src/commands/build_aot.dart
+++ b/packages/flutter_tools/lib/src/commands/build_aot.dart
@@ -173,6 +173,7 @@
break;
case TargetPlatform.darwin_x64:
case TargetPlatform.linux_x64:
+ case TargetPlatform.windows_x64:
assert(false);
}
@@ -228,6 +229,7 @@
break;
case TargetPlatform.darwin_x64:
case TargetPlatform.linux_x64:
+ case TargetPlatform.windows_x64:
assert(false);
}
diff --git a/packages/flutter_tools/lib/src/dart/dependencies.dart b/packages/flutter_tools/lib/src/dart/dependencies.dart
index 3c0f10d..d390577 100644
--- a/packages/flutter_tools/lib/src/dart/dependencies.dart
+++ b/packages/flutter_tools/lib/src/dart/dependencies.dart
@@ -5,12 +5,20 @@
import 'dart:convert';
import '../artifacts.dart';
+import '../base/file_system.dart';
+import '../base/platform.dart';
import '../base/process.dart';
class DartDependencySetBuilder {
- DartDependencySetBuilder(this.mainScriptPath,
- this.projectRootPath,
- this.packagesFilePath);
+
+ factory DartDependencySetBuilder(
+ String mainScriptPath, String projectRootPath, String packagesFilePath) {
+ if (platform.isWindows)
+ return new _GenSnapshotDartDependencySetBuilder(mainScriptPath, projectRootPath, packagesFilePath);
+ return new DartDependencySetBuilder._(mainScriptPath, projectRootPath, packagesFilePath);
+ }
+
+ DartDependencySetBuilder._(this.mainScriptPath, this.projectRootPath, this.packagesFilePath);
final String mainScriptPath;
final String projectRootPath;
@@ -32,3 +40,58 @@
return new Set<String>.from(LineSplitter.split(output));
}
}
+
+/// A [DartDependencySetBuilder] that is backed by gen_snapshot.
+class _GenSnapshotDartDependencySetBuilder implements DartDependencySetBuilder {
+ _GenSnapshotDartDependencySetBuilder(this.mainScriptPath,
+ this.projectRootPath,
+ this.packagesFilePath);
+
+ @override
+ final String mainScriptPath;
+ @override
+ final String projectRootPath;
+ @override
+ final String packagesFilePath;
+
+ @override
+ Set<String> build() {
+ final String snapshotterPath =
+ Artifacts.instance.getArtifactPath(Artifact.genSnapshot);
+ final String vmSnapshotData =
+ Artifacts.instance.getArtifactPath(Artifact.vmSnapshotData);
+ final String isolateSnapshotData =
+ Artifacts.instance.getArtifactPath(Artifact.isolateSnapshotData);
+ assert(fs.path.isAbsolute(this.projectRootPath));
+
+ // TODO(goderbauer): Implement --print-deps in gen_snapshot so we don't have to parse the Makefile
+ Directory tempDir = fs.systemTempDirectory.createTempSync('dart_dependency_set_builder_');
+ String depfilePath = fs.path.join(tempDir.path, 'snapshot_blob.bin.d');
+
+ final List<String> args = <String>[
+ snapshotterPath,
+ '--snapshot_kind=script',
+ '--dependencies-only',
+ '--vm_snapshot_data=$vmSnapshotData',
+ '--isolate_snapshot_data=$isolateSnapshotData',
+ '--packages=$packagesFilePath',
+ '--dependencies=$depfilePath',
+ '--script_snapshot=snapshot_blob.bin',
+ mainScriptPath
+ ];
+
+ runSyncAndThrowStdErrOnError(args);
+ String output = fs.file(depfilePath).readAsStringSync();
+ tempDir.deleteSync(recursive: true);
+
+ int splitIndex = output.indexOf(':');
+ if (splitIndex == -1)
+ throw new Exception('Unexpected output $output');
+
+ output = output.substring(splitIndex + 1);
+ // Note: next line means we cannot process anything with spaces in the path
+ // because Makefiles don't support spaces in paths :(
+ List<String> depsList = output.trim().split(' ');
+ return new Set<String>.from(depsList);
+ }
+}
diff --git a/packages/flutter_tools/lib/src/flx.dart b/packages/flutter_tools/lib/src/flx.dart
index b35ccbf..bd0078f 100644
--- a/packages/flutter_tools/lib/src/flx.dart
+++ b/packages/flutter_tools/lib/src/flx.dart
@@ -8,6 +8,7 @@
import 'asset.dart';
import 'base/common.dart';
import 'base/file_system.dart';
+import 'base/platform.dart';
import 'base/process.dart';
import 'build_info.dart';
import 'dart/package_map.dart';
@@ -28,16 +29,37 @@
const String _kSnapshotKey = 'snapshot_blob.bin';
Future<int> createSnapshot({
- String snapshotterPath,
String mainPath,
String snapshotPath,
String depfilePath,
String packages
}) {
- assert(snapshotterPath != null);
+ if (platform.isWindows) {
+ return _creteScriptSnapshotWithGenSnapshot(
+ mainPath: mainPath,
+ snapshotPath: snapshotPath,
+ depfilePath: depfilePath,
+ packages: packages
+ );
+ }
+ return _createScriptSnapshotWithSkySnapshot(
+ mainPath: mainPath,
+ snapshotPath: snapshotPath,
+ depfilePath: depfilePath,
+ packages: packages
+ );
+}
+
+Future<int> _createScriptSnapshotWithSkySnapshot({
+ String mainPath,
+ String snapshotPath,
+ String depfilePath,
+ String packages
+}) {
assert(mainPath != null);
assert(snapshotPath != null);
assert(packages != null);
+ String snapshotterPath = artifacts.getArtifactPath(Artifact.skySnapshot);
final List<String> args = <String>[
snapshotterPath,
@@ -52,6 +74,34 @@
return runCommandAndStreamOutput(args);
}
+Future<int> _creteScriptSnapshotWithGenSnapshot({
+ String mainPath,
+ String snapshotPath,
+ String depfilePath,
+ String packages
+}) {
+ assert(mainPath != null);
+ assert(snapshotPath != null);
+ assert(packages != null);
+ String snapshotterPath = artifacts.getArtifactPath(Artifact.genSnapshot);
+ String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData);
+ String isolateSnapshotData = artifacts.getArtifactPath(Artifact.isolateSnapshotData);
+
+ final List<String> args = <String>[
+ snapshotterPath,
+ '--snapshot_kind=script',
+ '--vm_snapshot_data=$vmSnapshotData',
+ '--isolate_snapshot_data=$isolateSnapshotData',
+ '--packages=$packages',
+ '--script_snapshot=$snapshotPath'
+ ];
+ if (depfilePath != null) {
+ args.add('--dependencies=$depfilePath');
+ }
+ args.add(mainPath);
+ return runCommandAndStreamOutput(args);
+}
+
/// Build the flx in the build directory and return `localBundlePath` on success.
///
/// Return `null` on failure.
@@ -73,7 +123,6 @@
}
Future<Null> build({
- String snapshotterPath,
String mainPath: defaultMainPath,
String manifestPath: defaultManifestPath,
String outputPath,
@@ -110,7 +159,6 @@
// In a precompiled snapshot, the instruction buffer contains script
// content equivalents
int result = await createSnapshot(
- snapshotterPath: snapshotterPath ?? artifacts.getArtifactPath(Artifact.skySnapshot),
mainPath: mainPath,
snapshotPath: snapshotPath,
depfilePath: depfilePath,
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart
index b09fdf4..87baf60 100644
--- a/packages/flutter_tools/lib/src/resident_runner.dart
+++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -161,8 +161,10 @@
ProcessSignal.SIGTERM.watch().listen(_cleanUpAndExit);
if (!supportsServiceProtocol || !supportsRestart)
return;
- ProcessSignal.SIGUSR1.watch().listen(_handleSignal);
- ProcessSignal.SIGUSR2.watch().listen(_handleSignal);
+ if (!platform.isWindows) {
+ ProcessSignal.SIGUSR1.watch().listen(_handleSignal);
+ ProcessSignal.SIGUSR2.watch().listen(_handleSignal);
+ }
}
Future<Null> _cleanUpAndExit(ProcessSignal signal) async {
diff --git a/packages/flutter_tools/test/dart_dependencies_test.dart b/packages/flutter_tools/test/dart_dependencies_test.dart
index 0bb6d1f..9784d67 100644
--- a/packages/flutter_tools/test/dart_dependencies_test.dart
+++ b/packages/flutter_tools/test/dart_dependencies_test.dart
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'dart:io' as io;
-
import 'package:flutter_tools/src/dart/dependencies.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/platform.dart';
@@ -12,7 +10,7 @@
void main() {
group('DartDependencySetBuilder', () {
- final String basePath = fs.path.dirname(platform.script.path);
+ final String basePath = fs.path.dirname(fs.path.fromUri(platform.script));
final String dataPath = fs.path.join(basePath, 'data', 'dart_dependencies_test');
testUsingContext('good', () {
final String testPath = fs.path.join(dataPath, 'good');
@@ -38,5 +36,5 @@
expect(e.contains('unexpected token \'bad\''), isTrue);
}
});
- }, skip: io.Platform.isWindows); // TODO(goderbauer): enable when sky_snapshot is available
+ });
}
diff --git a/packages/flutter_tools/test/dependency_checker_test.dart b/packages/flutter_tools/test/dependency_checker_test.dart
index 8fb4ee4..30ea979 100644
--- a/packages/flutter_tools/test/dependency_checker_test.dart
+++ b/packages/flutter_tools/test/dependency_checker_test.dart
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'dart:io' as io;
-
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/platform.dart';
@@ -56,7 +54,7 @@
// Set 'package:self/bar.dart' file modification time to be in the future.
updateFileModificationTime(barPath, baseTime, 10);
expect(dependencyChecker.check(baseTime), isTrue);
- }, skip: io.Platform.isWindows); // TODO(goderbauer): enable when sky_snapshot is ready on Windows
+ });
testUsingContext('syntax error', () {
final String testPath = fs.path.join(dataPath, 'syntax_error');