Skip to content

Commit d579d58

Browse files
authored
Enable Hot Reload on Windows (backed by gen_snapshot) (flutter#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
1 parent 55e10a6 commit d579d58

11 files changed

+161
-21
lines changed

bin/internal/engine.version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
74de13c0bde4eeb967391bd2a7ba973c525113b1
1+
342a31136e2c333bfc8a69edb12efd6231fbd5ea

packages/flutter_tools/lib/src/application_package.dart

+2
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ ApplicationPackage getApplicationPackageForPlatform(TargetPlatform platform, {
258258
: new IOSApp.fromIpa(applicationBinary);
259259
case TargetPlatform.darwin_x64:
260260
case TargetPlatform.linux_x64:
261+
case TargetPlatform.windows_x64:
261262
return null;
262263
}
263264
assert(platform != null);
@@ -282,6 +283,7 @@ class ApplicationPackageStore {
282283
return iOS;
283284
case TargetPlatform.darwin_x64:
284285
case TargetPlatform.linux_x64:
286+
case TargetPlatform.windows_x64:
285287
return null;
286288
}
287289
return null;

packages/flutter_tools/lib/src/artifacts.dart

+26-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ enum Artifact {
2121
skySnapshot,
2222
snapshotDart,
2323
flutterFramework,
24+
vmSnapshotData,
25+
isolateSnapshotData
2426
}
2527

2628
String _artifactToFileName(Artifact artifact) {
@@ -49,6 +51,10 @@ String _artifactToFileName(Artifact artifact) {
4951
return 'snapshot.dart';
5052
case Artifact.flutterFramework:
5153
return 'Flutter.framework';
54+
case Artifact.vmSnapshotData:
55+
return 'vm_isolate_snapshot.bin';
56+
case Artifact.isolateSnapshotData:
57+
return 'isolate_snapshot.bin';
5258
}
5359
assert(false, 'Invalid artifact $artifact.');
5460
return null;
@@ -85,6 +91,7 @@ class CachedArtifacts extends Artifacts {
8591
return _getIosArtifactPath(artifact, platform, mode);
8692
case TargetPlatform.darwin_x64:
8793
case TargetPlatform.linux_x64:
94+
case TargetPlatform.windows_x64:
8895
assert(mode == null, 'Platform $platform does not support different build modes.');
8996
return _getHostArtifactPath(artifact, platform);
9097
}
@@ -139,6 +146,16 @@ class CachedArtifacts extends Artifacts {
139146
switch (artifact) {
140147
case Artifact.skyShell:
141148
case Artifact.skySnapshot:
149+
if (platform == TargetPlatform.windows_x64)
150+
throw new UnimplementedError('Artifact $artifact not available on platfrom $platform.');
151+
continue returnResourcePath;
152+
case Artifact.genSnapshot:
153+
case Artifact.vmSnapshotData:
154+
case Artifact.isolateSnapshotData:
155+
if (platform != TargetPlatform.windows_x64)
156+
throw new UnimplementedError('Artifact $artifact not available on platfrom $platform.');
157+
continue returnResourcePath;
158+
returnResourcePath:
142159
case Artifact.icudtlDat:
143160
String engineArtifactsPath = cache.getArtifactDirectory('engine').path;
144161
String platformDirName = getNameForTargetPlatform(platform);
@@ -147,6 +164,8 @@ class CachedArtifacts extends Artifacts {
147164
assert(false, 'Artifact $artifact not available for platform $platform.');
148165
return null;
149166
}
167+
assert(false, 'Artifact $artifact not available for platform $platform.');
168+
return null;
150169
}
151170

152171
String _getEngineArtifactsPath(TargetPlatform platform, [BuildMode mode]) {
@@ -155,6 +174,7 @@ class CachedArtifacts extends Artifacts {
155174
switch (platform) {
156175
case TargetPlatform.linux_x64:
157176
case TargetPlatform.darwin_x64:
177+
case TargetPlatform.windows_x64:
158178
assert(mode == null, 'Platform $platform does not support different build modes.');
159179
return fs.path.join(engineDir, platformName);
160180
case TargetPlatform.ios:
@@ -174,6 +194,8 @@ class CachedArtifacts extends Artifacts {
174194
return TargetPlatform.darwin_x64;
175195
if (platform.isLinux)
176196
return TargetPlatform.linux_x64;
197+
if (platform.isWindows)
198+
return TargetPlatform.windows_x64;
177199
throw new UnimplementedError('Host OS not supported.');
178200
}
179201
}
@@ -193,15 +215,12 @@ class LocalEngineArtifacts extends Artifacts {
193215
case Artifact.dartIoEntriesTxt:
194216
return fs.path.join(_engineSrcPath, 'dart', 'runtime', 'bin', _artifactToFileName(artifact));
195217
case Artifact.dartVmEntryPointsTxt:
196-
return fs.path.join(_engineSrcPath, 'flutter', 'runtime', _artifactToFileName(artifact));
197218
case Artifact.dartVmEntryPointsAndroidTxt:
198219
return fs.path.join(_engineSrcPath, 'flutter', 'runtime', _artifactToFileName(artifact));
199220
case Artifact.snapshotDart:
200221
return fs.path.join(_engineSrcPath, 'flutter', 'lib', 'snapshot', _artifactToFileName(artifact));
201222
case Artifact.classesDexJar:
202223
return fs.path.join(engineOutPath, 'gen', 'flutter', 'shell', 'platform', 'android', 'android', _artifactToFileName(artifact));
203-
case Artifact.icudtlDat:
204-
return fs.path.join(engineOutPath, _artifactToFileName(artifact));
205224
case Artifact.libskyShellSo:
206225
String abi = _getAbiDirectory(platform);
207226
return fs.path.join(engineOutPath, 'gen', 'flutter', 'shell', 'platform', 'android', 'android', fs.path.join('android', 'libs', abi, _artifactToFileName(artifact)));
@@ -211,6 +230,10 @@ class LocalEngineArtifacts extends Artifacts {
211230
return _skyShellPath(platform);
212231
case Artifact.skySnapshot:
213232
return _skySnapshotPath();
233+
case Artifact.isolateSnapshotData:
234+
case Artifact.vmSnapshotData:
235+
return fs.path.join(engineOutPath, 'gen', 'flutter', 'lib', 'snapshot', _artifactToFileName(artifact));
236+
case Artifact.icudtlDat:
214237
case Artifact.flutterFramework:
215238
return fs.path.join(engineOutPath, _artifactToFileName(artifact));
216239
}

packages/flutter_tools/lib/src/build_info.dart

+4-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ enum TargetPlatform {
6666
android_x86,
6767
ios,
6868
darwin_x64,
69-
linux_x64
69+
linux_x64,
70+
windows_x64
7071
}
7172

7273
String getNameForTargetPlatform(TargetPlatform platform) {
@@ -83,6 +84,8 @@ String getNameForTargetPlatform(TargetPlatform platform) {
8384
return 'darwin-x64';
8485
case TargetPlatform.linux_x64:
8586
return 'linux-x64';
87+
case TargetPlatform.windows_x64:
88+
return 'windows-x64';
8689
}
8790
assert(false);
8891
return null;

packages/flutter_tools/lib/src/cache.dart

+1
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ class FlutterEngine {
289289
];
290290

291291
List<List<String>> get _windowsBinaryDirs => <List<String>>[
292+
<String>['windows-x64', 'windows-x64/artifacts.zip'],
292293
<String>['android-arm-profile/windows-x64', 'android-arm-profile/windows-x64.zip'],
293294
<String>['android-arm-release/windows-x64', 'android-arm-release/windows-x64.zip'],
294295
];

packages/flutter_tools/lib/src/commands/build_aot.dart

+2
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ Future<String> _buildAotSnapshot(
173173
break;
174174
case TargetPlatform.darwin_x64:
175175
case TargetPlatform.linux_x64:
176+
case TargetPlatform.windows_x64:
176177
assert(false);
177178
}
178179

@@ -228,6 +229,7 @@ Future<String> _buildAotSnapshot(
228229
break;
229230
case TargetPlatform.darwin_x64:
230231
case TargetPlatform.linux_x64:
232+
case TargetPlatform.windows_x64:
231233
assert(false);
232234
}
233235

packages/flutter_tools/lib/src/dart/dependencies.dart

+66-3
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@
55
import 'dart:convert';
66

77
import '../artifacts.dart';
8+
import '../base/file_system.dart';
9+
import '../base/platform.dart';
810
import '../base/process.dart';
911

1012
class DartDependencySetBuilder {
11-
DartDependencySetBuilder(this.mainScriptPath,
12-
this.projectRootPath,
13-
this.packagesFilePath);
13+
14+
factory DartDependencySetBuilder(
15+
String mainScriptPath, String projectRootPath, String packagesFilePath) {
16+
if (platform.isWindows)
17+
return new _GenSnapshotDartDependencySetBuilder(mainScriptPath, projectRootPath, packagesFilePath);
18+
return new DartDependencySetBuilder._(mainScriptPath, projectRootPath, packagesFilePath);
19+
}
20+
21+
DartDependencySetBuilder._(this.mainScriptPath, this.projectRootPath, this.packagesFilePath);
1422

1523
final String mainScriptPath;
1624
final String projectRootPath;
@@ -32,3 +40,58 @@ class DartDependencySetBuilder {
3240
return new Set<String>.from(LineSplitter.split(output));
3341
}
3442
}
43+
44+
/// A [DartDependencySetBuilder] that is backed by gen_snapshot.
45+
class _GenSnapshotDartDependencySetBuilder implements DartDependencySetBuilder {
46+
_GenSnapshotDartDependencySetBuilder(this.mainScriptPath,
47+
this.projectRootPath,
48+
this.packagesFilePath);
49+
50+
@override
51+
final String mainScriptPath;
52+
@override
53+
final String projectRootPath;
54+
@override
55+
final String packagesFilePath;
56+
57+
@override
58+
Set<String> build() {
59+
final String snapshotterPath =
60+
Artifacts.instance.getArtifactPath(Artifact.genSnapshot);
61+
final String vmSnapshotData =
62+
Artifacts.instance.getArtifactPath(Artifact.vmSnapshotData);
63+
final String isolateSnapshotData =
64+
Artifacts.instance.getArtifactPath(Artifact.isolateSnapshotData);
65+
assert(fs.path.isAbsolute(this.projectRootPath));
66+
67+
// TODO(goderbauer): Implement --print-deps in gen_snapshot so we don't have to parse the Makefile
68+
Directory tempDir = fs.systemTempDirectory.createTempSync('dart_dependency_set_builder_');
69+
String depfilePath = fs.path.join(tempDir.path, 'snapshot_blob.bin.d');
70+
71+
final List<String> args = <String>[
72+
snapshotterPath,
73+
'--snapshot_kind=script',
74+
'--dependencies-only',
75+
'--vm_snapshot_data=$vmSnapshotData',
76+
'--isolate_snapshot_data=$isolateSnapshotData',
77+
'--packages=$packagesFilePath',
78+
'--dependencies=$depfilePath',
79+
'--script_snapshot=snapshot_blob.bin',
80+
mainScriptPath
81+
];
82+
83+
runSyncAndThrowStdErrOnError(args);
84+
String output = fs.file(depfilePath).readAsStringSync();
85+
tempDir.deleteSync(recursive: true);
86+
87+
int splitIndex = output.indexOf(':');
88+
if (splitIndex == -1)
89+
throw new Exception('Unexpected output $output');
90+
91+
output = output.substring(splitIndex + 1);
92+
// Note: next line means we cannot process anything with spaces in the path
93+
// because Makefiles don't support spaces in paths :(
94+
List<String> depsList = output.trim().split(' ');
95+
return new Set<String>.from(depsList);
96+
}
97+
}

packages/flutter_tools/lib/src/flx.dart

+52-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'artifacts.dart';
88
import 'asset.dart';
99
import 'base/common.dart';
1010
import 'base/file_system.dart';
11+
import 'base/platform.dart';
1112
import 'base/process.dart';
1213
import 'build_info.dart';
1314
import 'dart/package_map.dart';
@@ -28,16 +29,37 @@ const String _kKernelKey = 'kernel_blob.bin';
2829
const String _kSnapshotKey = 'snapshot_blob.bin';
2930

3031
Future<int> createSnapshot({
31-
String snapshotterPath,
3232
String mainPath,
3333
String snapshotPath,
3434
String depfilePath,
3535
String packages
3636
}) {
37-
assert(snapshotterPath != null);
37+
if (platform.isWindows) {
38+
return _creteScriptSnapshotWithGenSnapshot(
39+
mainPath: mainPath,
40+
snapshotPath: snapshotPath,
41+
depfilePath: depfilePath,
42+
packages: packages
43+
);
44+
}
45+
return _createScriptSnapshotWithSkySnapshot(
46+
mainPath: mainPath,
47+
snapshotPath: snapshotPath,
48+
depfilePath: depfilePath,
49+
packages: packages
50+
);
51+
}
52+
53+
Future<int> _createScriptSnapshotWithSkySnapshot({
54+
String mainPath,
55+
String snapshotPath,
56+
String depfilePath,
57+
String packages
58+
}) {
3859
assert(mainPath != null);
3960
assert(snapshotPath != null);
4061
assert(packages != null);
62+
String snapshotterPath = artifacts.getArtifactPath(Artifact.skySnapshot);
4163

4264
final List<String> args = <String>[
4365
snapshotterPath,
@@ -52,6 +74,34 @@ Future<int> createSnapshot({
5274
return runCommandAndStreamOutput(args);
5375
}
5476

77+
Future<int> _creteScriptSnapshotWithGenSnapshot({
78+
String mainPath,
79+
String snapshotPath,
80+
String depfilePath,
81+
String packages
82+
}) {
83+
assert(mainPath != null);
84+
assert(snapshotPath != null);
85+
assert(packages != null);
86+
String snapshotterPath = artifacts.getArtifactPath(Artifact.genSnapshot);
87+
String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData);
88+
String isolateSnapshotData = artifacts.getArtifactPath(Artifact.isolateSnapshotData);
89+
90+
final List<String> args = <String>[
91+
snapshotterPath,
92+
'--snapshot_kind=script',
93+
'--vm_snapshot_data=$vmSnapshotData',
94+
'--isolate_snapshot_data=$isolateSnapshotData',
95+
'--packages=$packages',
96+
'--script_snapshot=$snapshotPath'
97+
];
98+
if (depfilePath != null) {
99+
args.add('--dependencies=$depfilePath');
100+
}
101+
args.add(mainPath);
102+
return runCommandAndStreamOutput(args);
103+
}
104+
55105
/// Build the flx in the build directory and return `localBundlePath` on success.
56106
///
57107
/// Return `null` on failure.
@@ -73,7 +123,6 @@ Future<String> buildFlx({
73123
}
74124

75125
Future<Null> build({
76-
String snapshotterPath,
77126
String mainPath: defaultMainPath,
78127
String manifestPath: defaultManifestPath,
79128
String outputPath,
@@ -110,7 +159,6 @@ Future<Null> build({
110159
// In a precompiled snapshot, the instruction buffer contains script
111160
// content equivalents
112161
int result = await createSnapshot(
113-
snapshotterPath: snapshotterPath ?? artifacts.getArtifactPath(Artifact.skySnapshot),
114162
mainPath: mainPath,
115163
snapshotPath: snapshotPath,
116164
depfilePath: depfilePath,

packages/flutter_tools/lib/src/resident_runner.dart

+4-2
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,10 @@ abstract class ResidentRunner {
161161
ProcessSignal.SIGTERM.watch().listen(_cleanUpAndExit);
162162
if (!supportsServiceProtocol || !supportsRestart)
163163
return;
164-
ProcessSignal.SIGUSR1.watch().listen(_handleSignal);
165-
ProcessSignal.SIGUSR2.watch().listen(_handleSignal);
164+
if (!platform.isWindows) {
165+
ProcessSignal.SIGUSR1.watch().listen(_handleSignal);
166+
ProcessSignal.SIGUSR2.watch().listen(_handleSignal);
167+
}
166168
}
167169

168170
Future<Null> _cleanUpAndExit(ProcessSignal signal) async {

packages/flutter_tools/test/dart_dependencies_test.dart

+2-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:io' as io;
6-
75
import 'package:flutter_tools/src/dart/dependencies.dart';
86
import 'package:flutter_tools/src/base/file_system.dart';
97
import 'package:flutter_tools/src/base/platform.dart';
@@ -12,7 +10,7 @@ import 'src/context.dart';
1210

1311
void main() {
1412
group('DartDependencySetBuilder', () {
15-
final String basePath = fs.path.dirname(platform.script.path);
13+
final String basePath = fs.path.dirname(fs.path.fromUri(platform.script));
1614
final String dataPath = fs.path.join(basePath, 'data', 'dart_dependencies_test');
1715
testUsingContext('good', () {
1816
final String testPath = fs.path.join(dataPath, 'good');
@@ -38,5 +36,5 @@ void main() {
3836
expect(e.contains('unexpected token \'bad\''), isTrue);
3937
}
4038
});
41-
}, skip: io.Platform.isWindows); // TODO(goderbauer): enable when sky_snapshot is available
39+
});
4240
}

packages/flutter_tools/test/dependency_checker_test.dart

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:io' as io;
6-
75
import 'package:file/memory.dart';
86
import 'package:flutter_tools/src/base/file_system.dart';
97
import 'package:flutter_tools/src/base/platform.dart';
@@ -56,7 +54,7 @@ void main() {
5654
// Set 'package:self/bar.dart' file modification time to be in the future.
5755
updateFileModificationTime(barPath, baseTime, 10);
5856
expect(dependencyChecker.check(baseTime), isTrue);
59-
}, skip: io.Platform.isWindows); // TODO(goderbauer): enable when sky_snapshot is ready on Windows
57+
});
6058

6159
testUsingContext('syntax error', () {
6260
final String testPath = fs.path.join(dataPath, 'syntax_error');

0 commit comments

Comments
 (0)