Skip to content

Commit bd1f6a6

Browse files
committed
Wait a second before making edits to files on Windows
dart:io does not have millisecond-level precision on file stats and instead, the modified time is rounded to the nearest second. If edits and recompiles are done within the same second as the previous compile, frontend_server_common can't tell that the files have changed. Instead, wait a second before editing. In order to support this, edits are staged at once. Without this, we'd be waiting multiple seconds for several edits.
1 parent b947357 commit bd1f6a6

7 files changed

+120
-97
lines changed

dwds/test/common/hot_restart_common.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,13 @@ void runTests({
4747
}
4848

4949
Future<void> makeEditAndRecompile() async {
50-
context.makeEditToDartEntryFile(
51-
toReplace: originalString,
52-
replaceWith: newString,
53-
);
50+
await context.makeEdits([
51+
(
52+
file: context.project.dartEntryFileName,
53+
originalString: originalString,
54+
newString: newString,
55+
),
56+
]);
5457
await recompile(hasEdits: true);
5558
}
5659

dwds/test/common/hot_restart_correctness_common.dart

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ void runTests({
3838
final context = TestContext(testHotRestart2, provider);
3939

4040
Future<void> makeEditAndRecompile() async {
41-
context.makeEditToDartLibFile(
42-
libFileName: 'library2.dart',
43-
toReplace: originalString,
44-
replaceWith: newString,
45-
);
41+
await context.makeEdits([
42+
(
43+
file: 'library2.dart',
44+
originalString: originalString,
45+
newString: newString,
46+
),
47+
]);
4648
if (compilationMode == CompilationMode.frontendServer) {
4749
await context.recompile(fullRestart: true);
4850
} else {

dwds/test/devtools_test.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,13 @@ void main() {
112112
// https://github.com/dart-lang/webdev/pull/901#issuecomment-586438132
113113
final client = context.debugConnection.vmService;
114114
await client.streamListen('Isolate');
115-
context.makeEditToDartEntryFile(
116-
toReplace: 'Hello World!',
117-
replaceWith: 'Bonjour le monde!',
118-
);
115+
await context.makeEdits([
116+
(
117+
file: context.project.dartEntryFileName,
118+
originalString: 'Hello World!',
119+
newString: 'Bonjour le monde!',
120+
),
121+
]);
119122
await context.waitForSuccessfulBuild(propagateToBrowser: true);
120123

121124
final eventsDone = expectLater(

dwds/test/fixtures/context.dart

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -565,23 +565,32 @@ class TestContext {
565565
_outputDir = null;
566566
}
567567

568-
void makeEditToDartEntryFile({
569-
required String toReplace,
570-
required String replaceWith,
571-
}) {
572-
final file = File(project.dartEntryFilePath);
573-
final fileContents = file.readAsStringSync();
574-
file.writeAsStringSync(fileContents.replaceAll(toReplace, replaceWith));
575-
}
576-
577-
void makeEditToDartLibFile({
578-
required String libFileName,
579-
required String toReplace,
580-
required String replaceWith,
581-
}) {
582-
final file = File(project.dartLibFilePath(libFileName));
583-
final fileContents = file.readAsStringSync();
584-
file.writeAsStringSync(fileContents.replaceAll(toReplace, replaceWith));
568+
/// Given a list of edits, use file IO to write them to the file system.
569+
///
570+
/// If `file` has the same name as the project's entry file name, that file
571+
/// will be edited. Otherwise, it's assumed to be a library file.
572+
// TODO(srujzs): It's possible we may want a library file with the same name
573+
// as the entry file, but this function doesn't allow that. Potentially
574+
// support that.
575+
Future<void> makeEdits(
576+
List<({String file, String originalString, String newString})> edits,
577+
) async {
578+
// `dart:io`'s `stat` on Windows does not have millisecond precision so we
579+
// need to make sure we wait long enough that modifications result in a
580+
// timestamp that is guaranteed to be after the previous compile.
581+
// TODO(https://github.com/dart-lang/sdk/issues/51937): Remove once this bug
582+
// is fixed.
583+
if (Platform.isWindows) await Future.delayed(Duration(seconds: 1));
584+
for (var (:file, :originalString, :newString) in edits) {
585+
if (file == project.dartEntryFileName) {
586+
file = project.dartEntryFilePath;
587+
} else {
588+
file = project.dartLibFilePath(file);
589+
}
590+
final f = File(project.dartLibFilePath(file));
591+
final fileContents = f.readAsStringSync();
592+
f.writeAsStringSync(fileContents.replaceAll(originalString, newString));
593+
}
585594
}
586595

587596
void addLibraryFile({required String libFileName, required String contents}) {

dwds/test/hot_reload_breakpoints_test.dart

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -35,28 +35,11 @@ void main() {
3535

3636
tearDownAll(provider.dispose);
3737

38-
void makeEdit(String file, String originalString, String newString) {
39-
if (file == project.dartEntryFileName) {
40-
context.makeEditToDartEntryFile(
41-
toReplace: originalString,
42-
replaceWith: newString,
43-
);
44-
} else {
45-
context.makeEditToDartLibFile(
46-
libFileName: file,
47-
toReplace: originalString,
48-
replaceWith: newString,
49-
);
50-
}
51-
}
52-
53-
Future<void> makeEditAndRecompile(
54-
String file,
55-
String originalString,
56-
String newString,
38+
Future<void> makeEditsAndRecompile(
39+
List<({String file, String originalString, String newString})> edits,
5740
) async {
58-
makeEdit(file, originalString, newString);
59-
await context.recompile(fullRestart: false);
41+
await context.makeEdits(edits);
42+
await context.recompile(fullRestart: true);
6043
}
6144

6245
group('when pause_isolates_on_start is true', () {
@@ -255,7 +238,9 @@ void main() {
255238
await resumeAndExpectLog(oldString);
256239

257240
// Modify the string that gets printed.
258-
await makeEditAndRecompile(mainFile, oldString, newString);
241+
await makeEditsAndRecompile([
242+
(file: mainFile, originalString: oldString, newString: newString),
243+
]);
259244

260245
await hotReloadAndHandlePausePost([
261246
(file: mainFile, breakpointMarker: callLogMarker, bp: bp),
@@ -291,7 +276,9 @@ void main() {
291276
final extraLog = 'hot reload';
292277
final oldString = "log('";
293278
final newString = "log('$extraLog');\n$oldString";
294-
await makeEditAndRecompile(mainFile, oldString, newString);
279+
await makeEditsAndRecompile([
280+
(file: mainFile, originalString: oldString, newString: newString),
281+
]);
295282

296283
bp =
297284
(await hotReloadAndHandlePausePost([
@@ -307,7 +294,9 @@ void main() {
307294
await resumeAndExpectLog(genLog);
308295

309296
// Remove the line we just added.
310-
await makeEditAndRecompile(mainFile, newString, oldString);
297+
await makeEditsAndRecompile([
298+
(file: mainFile, originalString: newString, newString: oldString),
299+
]);
311300

312301
await hotReloadAndHandlePausePost([
313302
(file: mainFile, breakpointMarker: callLogMarker, bp: bp),
@@ -363,10 +352,13 @@ void main() {
363352
final newImports =
364353
'$oldImports\n'
365354
"import 'package:_test_hot_reload_breakpoints/library.dart';";
366-
makeEdit(mainFile, oldImports, newImports);
355+
final edits = [
356+
(file: mainFile, originalString: oldImports, newString: newImports),
357+
];
367358
final oldLog = "log('\$mainValue');";
368359
final newLog = "log('\$libraryValue');";
369-
await makeEditAndRecompile(mainFile, oldLog, newLog);
360+
edits.add((file: mainFile, originalString: oldLog, newString: newLog));
361+
await makeEditsAndRecompile(edits);
370362

371363
await hotReloadAndHandlePausePost([
372364
(file: mainFile, breakpointMarker: callLogMarker, bp: bp),
@@ -410,6 +402,8 @@ void main() {
410402

411403
// Add library files, import them, but only refer to the last one in main.
412404
final numFiles = 50;
405+
final edits =
406+
<({String file, String originalString, String newString})>[];
413407
for (var i = 1; i <= numFiles; i++) {
414408
final libFile = 'library$i.dart';
415409
context.addLibraryFile(
@@ -422,11 +416,16 @@ void main() {
422416
final newImports =
423417
'$oldImports\n'
424418
"import 'package:_test_hot_reload_breakpoints/$libFile';";
425-
makeEdit(mainFile, oldImports, newImports);
419+
edits.add((
420+
file: mainFile,
421+
originalString: oldImports,
422+
newString: newImports,
423+
));
426424
}
427425
final oldLog = "log('\$mainValue');";
428426
final newLog = "log('\$libraryValue$numFiles');";
429-
await makeEditAndRecompile(mainFile, oldLog, newLog);
427+
edits.add((file: mainFile, originalString: oldLog, newString: newLog));
428+
await makeEditsAndRecompile(edits);
430429

431430
await hotReloadAndHandlePausePost([
432431
(file: mainFile, breakpointMarker: callLogMarker, bp: bp),
@@ -460,7 +459,9 @@ void main() {
460459

461460
final oldLog = "log('\$mainValue');";
462461
final newLog = "log('\${closure()}');";
463-
await makeEditAndRecompile(mainFile, oldLog, newLog);
462+
await makeEditsAndRecompile([
463+
(file: mainFile, originalString: oldLog, newString: newLog),
464+
]);
464465

465466
bp =
466467
(await hotReloadAndHandlePausePost([
@@ -478,11 +479,13 @@ void main() {
478479
await resumeAndExpectLog(oldCapturedString);
479480

480481
final newCapturedString = 'captured closure gen1';
481-
await makeEditAndRecompile(
482-
mainFile,
483-
oldCapturedString,
484-
newCapturedString,
485-
);
482+
await makeEditsAndRecompile([
483+
(
484+
file: mainFile,
485+
originalString: oldCapturedString,
486+
newString: newCapturedString,
487+
),
488+
]);
486489

487490
await hotReloadAndHandlePausePost([
488491
(file: mainFile, breakpointMarker: capturedStringMarker, bp: bp),
@@ -539,7 +542,9 @@ void main() {
539542
await callEvaluateAndExpectLog(oldString);
540543

541544
// Modify the string that gets printed and hot reload.
542-
await makeEditAndRecompile(mainFile, oldString, newString);
545+
await makeEditsAndRecompile([
546+
(file: mainFile, originalString: oldString, newString: newString),
547+
]);
543548
final vm = await client.getVM();
544549
final isolate = await client.getIsolate(vm.isolates!.first.id!);
545550
final report = await client.reloadSources(isolate.id!);

dwds/test/hot_reload_test.dart

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@ void main() {
4040
}
4141

4242
Future<void> makeEditAndRecompile() async {
43-
context.makeEditToDartLibFile(
44-
libFileName: 'library1.dart',
45-
toReplace: originalString,
46-
replaceWith: newString,
47-
);
43+
await context.makeEdits([
44+
(
45+
file: 'library1.dart',
46+
originalString: originalString,
47+
newString: newString,
48+
),
49+
]);
4850
await recompile();
4951
}
5052

dwds/test/hot_restart_breakpoints_test.dart

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,10 @@ void main() {
3636

3737
tearDownAll(provider.dispose);
3838

39-
void makeEdit(String file, String originalString, String newString) {
40-
if (file == project.dartEntryFileName) {
41-
context.makeEditToDartEntryFile(
42-
toReplace: originalString,
43-
replaceWith: newString,
44-
);
45-
} else {
46-
context.makeEditToDartLibFile(
47-
libFileName: file,
48-
toReplace: originalString,
49-
replaceWith: newString,
50-
);
51-
}
52-
}
53-
54-
Future<void> makeEditAndRecompile(
55-
String file,
56-
String originalString,
57-
String newString,
39+
Future<void> makeEditsAndRecompile(
40+
List<({String file, String originalString, String newString})> edits,
5841
) async {
59-
makeEdit(file, originalString, newString);
42+
await context.makeEdits(edits);
6043
await context.recompile(fullRestart: true);
6144
}
6245

@@ -215,7 +198,9 @@ void main() {
215198

216199
await addBreakpoint(file: mainFile, breakpointMarker: callLogMarker);
217200

218-
await makeEditAndRecompile(mainFile, oldLog, newLog);
201+
await makeEditsAndRecompile([
202+
(file: mainFile, originalString: oldLog, newString: newLog),
203+
]);
219204

220205
final breakpointFuture = waitForBreakpoint();
221206

@@ -239,7 +224,9 @@ void main() {
239224
final extraLog = 'hot reload';
240225
final oldString = "log('";
241226
final newString = "log('$extraLog');\n$oldString";
242-
await makeEditAndRecompile(mainFile, oldString, newString);
227+
await makeEditsAndRecompile([
228+
(file: mainFile, originalString: oldString, newString: newString),
229+
]);
243230

244231
var breakpointFuture = waitForBreakpoint();
245232

@@ -256,7 +243,9 @@ void main() {
256243
consoleLogs.clear();
257244

258245
// Remove the line we just added.
259-
await makeEditAndRecompile(mainFile, newString, oldString);
246+
await makeEditsAndRecompile([
247+
(file: mainFile, originalString: newString, newString: oldString),
248+
]);
260249

261250
breakpointFuture = waitForBreakpoint();
262251

@@ -293,10 +282,13 @@ void main() {
293282
final newImports =
294283
'$oldImports\n'
295284
"import 'package:_test_hot_restart_breakpoints/library.dart';";
296-
makeEdit(mainFile, oldImports, newImports);
285+
final edits = [
286+
(file: mainFile, originalString: oldImports, newString: newImports),
287+
];
297288
final oldLog = "log('$genLog');";
298289
final newLog = "log('\$libraryValue');";
299-
await makeEditAndRecompile(mainFile, oldLog, newLog);
290+
edits.add((file: mainFile, originalString: oldLog, newString: newLog));
291+
await makeEditsAndRecompile(edits);
300292

301293
var breakpointFuture = waitForBreakpoint();
302294

@@ -329,6 +321,8 @@ void main() {
329321

330322
// Add library files, import them, but only refer to the last one in main.
331323
final numFiles = 50;
324+
final edits =
325+
<({String file, String originalString, String newString})>[];
332326
for (var i = 1; i <= numFiles; i++) {
333327
final libFile = 'library$i.dart';
334328
context.addLibraryFile(
@@ -341,11 +335,16 @@ void main() {
341335
final newImports =
342336
'$oldImports\n'
343337
"import 'package:_test_hot_restart_breakpoints/$libFile';";
344-
makeEdit(mainFile, oldImports, newImports);
338+
edits.add((
339+
file: mainFile,
340+
originalString: oldImports,
341+
newString: newImports,
342+
));
345343
}
346344
final oldLog = "log('$genLog');";
347345
final newLog = "log('\$libraryValue$numFiles');";
348-
await makeEditAndRecompile(mainFile, oldLog, newLog);
346+
edits.add((file: mainFile, originalString: oldLog, newString: newLog));
347+
await makeEditsAndRecompile(edits);
349348

350349
var breakpointFuture = waitForBreakpoint();
351350

0 commit comments

Comments
 (0)