Skip to content

Commit da342e3

Browse files
authored
More implementation of ReplayFileSystem (#32)
Part of flutter#11
1 parent 24f17eb commit da342e3

File tree

10 files changed

+406
-92
lines changed

10 files changed

+406
-92
lines changed

lib/src/backends/record_replay/codecs.dart

Lines changed: 201 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'dart:async';
66
import 'dart:convert';
7+
import 'dart:io' show SYSTEM_ENCODING;
78

89
import 'package:file/file.dart';
910
import 'package:path/path.dart' as path;
@@ -14,15 +15,20 @@ import 'replay_directory.dart';
1415
import 'replay_file.dart';
1516
import 'replay_file_stat.dart';
1617
import 'replay_file_system.dart';
18+
import 'replay_io_sink.dart';
1719
import 'replay_link.dart';
20+
import 'replay_random_access_file.dart';
1821
import 'result_reference.dart';
1922

2023
/// Converter that leaves object untouched.
2124
const Converter<dynamic, dynamic> kPassthrough = const _PassthroughConverter();
2225

2326
/// Converter that will turn an object into a [Future] of that object.
2427
const Converter<dynamic, dynamic> kFutureReviver =
25-
const _FutureDecoder<dynamic>();
28+
const _FutureReviver<dynamic>();
29+
30+
/// Converter that will convert an [Iterable] into a [Stream].
31+
Converter<dynamic, dynamic> kStreamReviver = const _StreamReviver();
2632

2733
/// Converter that will deserialize a [DateTime].
2834
const Converter<dynamic, dynamic> kDateTimeReviver = _DateTimeCodec.kDecoder;
@@ -38,17 +44,50 @@ const Converter<dynamic, dynamic> kEntityTypeReviver =
3844
const Converter<dynamic, dynamic> kPathContextReviver =
3945
_PathContextCodec.kDecoder;
4046

47+
/// Converter that will deserialize a [Uri].
48+
const Converter<dynamic, dynamic> kUriReviver = _UriCodec.kDecoder;
49+
50+
/// Converter that will deserialize a [Encoding].
51+
const Converter<dynamic, dynamic> kEncodingReviver = _EncodingCodec.kDecoder;
52+
53+
/// Converter that will deserialize a [FileSystemEvent].
54+
const Converter<dynamic, dynamic> kFileSystemEventReviver =
55+
_FileSystemEventCodec.kDecoder;
56+
57+
/// Converter that will deserialize each element of a [List] by delegating to
58+
/// the specified [elementReviver].
59+
Converter<dynamic, dynamic> listReviver(
60+
Converter<dynamic, dynamic> elementReviver) =>
61+
new _ListReviver(elementReviver);
62+
63+
/// Converter that will deserialize a blob file reference into the file's bytes.
64+
Converter<dynamic, dynamic> blobReviver(ReplayFileSystemImpl fileSystem) =>
65+
new _BlobReviver(fileSystem);
66+
4167
/// Converter that will deserialize a [ReplayDirectory].
4268
Converter<dynamic, dynamic> directoryReviver(ReplayFileSystemImpl fileSystem) =>
43-
new _DirectoryDecoder(fileSystem);
69+
new _DirectoryReviver(fileSystem);
4470

4571
/// Converter that will deserialize a [ReplayFile].
4672
Converter<dynamic, dynamic> fileReviver(ReplayFileSystemImpl fileSystem) =>
47-
new _FileDecoder(fileSystem);
73+
new _FileReviver(fileSystem);
4874

4975
/// Converter that will deserialize a [ReplayLink].
5076
Converter<dynamic, dynamic> linkReviver(ReplayFileSystemImpl fileSystem) =>
51-
new _LinkDecoder(fileSystem);
77+
new _LinkReviver(fileSystem);
78+
79+
/// Converter that will deserialize an arbitrary [FileSystemEntity].
80+
Converter<dynamic, dynamic> entityReviver(ReplayFileSystemImpl fileSystem) =>
81+
new _FileSystemEntityReviver(fileSystem);
82+
83+
/// Converter that will deserialize a [ReplayRandomAccessFile].
84+
Converter<dynamic, dynamic> randomAccessFileReviver(
85+
ReplayFileSystemImpl fileSystem) =>
86+
new _RandomAccessFileReviver(fileSystem);
87+
88+
/// Converter that will deserialize a [ReplayRandomAccessFile].
89+
Converter<dynamic, dynamic> ioSinkReviver(ReplayFileSystemImpl fileSystem) =>
90+
new _IOSinkReviver(fileSystem);
5291

5392
/// Encodes an arbitrary [object] into a JSON-ready representation (a number,
5493
/// boolean, string, null, list, or map).
@@ -87,16 +126,16 @@ class _GenericEncoder extends Converter<dynamic, dynamic> {
87126
const TypeMatcher<Map<dynamic, dynamic>>(): const _MapEncoder(),
88127
const TypeMatcher<Symbol>(): const _SymbolEncoder(),
89128
const TypeMatcher<DateTime>(): _DateTimeCodec.kEncoder,
90-
const TypeMatcher<Uri>(): const _ToStringEncoder(),
129+
const TypeMatcher<Uri>(): _UriCodec.kEncoder,
91130
const TypeMatcher<path.Context>(): _PathContextCodec.kEncoder,
92131
const TypeMatcher<ResultReference<dynamic>>(): const _ResultEncoder(),
93132
const TypeMatcher<LiveInvocationEvent<dynamic>>(): const _EventEncoder(),
94133
const TypeMatcher<ReplayAware>(): const _ReplayAwareEncoder(),
95-
const TypeMatcher<Encoding>(): const _EncodingEncoder(),
134+
const TypeMatcher<Encoding>(): _EncodingCodec.kEncoder,
96135
const TypeMatcher<FileMode>(): const _FileModeEncoder(),
97136
const TypeMatcher<FileStat>(): _FileStatCodec.kEncoder,
98137
const TypeMatcher<FileSystemEntityType>(): _EntityTypeCodec.kEncoder,
99-
const TypeMatcher<FileSystemEvent>(): const _FileSystemEventEncoder(),
138+
const TypeMatcher<FileSystemEvent>(): _FileSystemEventCodec.kEncoder,
100139
};
101140

102141
/// Default encoder (used for types not covered in [_encoders]).
@@ -163,10 +202,13 @@ class _SymbolEncoder extends Converter<Symbol, String> {
163202
class _DateTimeCodec extends Codec<DateTime, int> {
164203
const _DateTimeCodec();
165204

166-
static int _encode(DateTime input) => input.millisecondsSinceEpoch;
205+
static int _encode(DateTime input) => input?.millisecondsSinceEpoch;
167206

168-
static DateTime _decode(int input) =>
169-
new DateTime.fromMillisecondsSinceEpoch(input);
207+
static DateTime _decode(int input) {
208+
return input == null
209+
? null
210+
: new DateTime.fromMillisecondsSinceEpoch(input);
211+
}
170212

171213
static const Converter<DateTime, int> kEncoder =
172214
const _ForwardingConverter<DateTime, int>(_encode);
@@ -181,11 +223,24 @@ class _DateTimeCodec extends Codec<DateTime, int> {
181223
Converter<int, DateTime> get decoder => kDecoder;
182224
}
183225

184-
class _ToStringEncoder extends Converter<Object, String> {
185-
const _ToStringEncoder();
226+
class _UriCodec extends Codec<Uri, String> {
227+
const _UriCodec();
228+
229+
static String _encode(Uri input) => input.toString();
230+
231+
static Uri _decode(String input) => Uri.parse(input);
232+
233+
static const Converter<Uri, String> kEncoder =
234+
const _ForwardingConverter<Uri, String>(_encode);
235+
236+
static const Converter<String, Uri> kDecoder =
237+
const _ForwardingConverter<String, Uri>(_decode);
186238

187239
@override
188-
String convert(Object input) => input.toString();
240+
Converter<Uri, String> get encoder => kEncoder;
241+
242+
@override
243+
Converter<String, Uri> get decoder => kDecoder;
189244
}
190245

191246
class _PathContextCodec extends Codec<path.Context, Map<String, String>> {
@@ -246,11 +301,31 @@ class _ReplayAwareEncoder extends Converter<ReplayAware, String> {
246301
String convert(ReplayAware input) => input.identifier;
247302
}
248303

249-
class _EncodingEncoder extends Converter<Encoding, String> {
250-
const _EncodingEncoder();
304+
class _EncodingCodec extends Codec<Encoding, String> {
305+
const _EncodingCodec();
306+
307+
static String _encode(Encoding input) => input.name;
308+
309+
static Encoding _decode(String input) {
310+
if (input == 'system') {
311+
return SYSTEM_ENCODING;
312+
} else if (input != null) {
313+
return Encoding.getByName(input);
314+
}
315+
return null;
316+
}
317+
318+
static const Converter<Encoding, String> kEncoder =
319+
const _ForwardingConverter<Encoding, String>(_encode);
320+
321+
static const Converter<String, Encoding> kDecoder =
322+
const _ForwardingConverter<String, Encoding>(_decode);
323+
324+
@override
325+
Converter<Encoding, String> get encoder => kEncoder;
251326

252327
@override
253-
String convert(Encoding input) => input.name;
328+
Converter<String, Encoding> get decoder => kDecoder;
254329
}
255330

256331
class _FileModeEncoder extends Converter<FileMode, String> {
@@ -332,46 +407,143 @@ class _EntityTypeCodec extends Codec<FileSystemEntityType, String> {
332407
Converter<String, FileSystemEntityType> get decoder => kDecoder;
333408
}
334409

335-
class _FileSystemEventEncoder
336-
extends Converter<FileSystemEvent, Map<String, Object>> {
337-
const _FileSystemEventEncoder();
410+
class _FileSystemEventCodec
411+
extends Codec<FileSystemEvent, Map<String, Object>> {
412+
const _FileSystemEventCodec();
338413

339-
@override
340-
Map<String, Object> convert(FileSystemEvent input) {
414+
static Map<String, Object> _encode(FileSystemEvent input) {
341415
return <String, Object>{
342416
'type': input.type,
343417
'path': input.path,
418+
'isDirectory': input.isDirectory,
344419
};
345420
}
421+
422+
static FileSystemEvent _decode(Map<String, Object> input) =>
423+
new _FileSystemEvent(input);
424+
425+
static const Converter<FileSystemEvent, Map<String, Object>> kEncoder =
426+
const _ForwardingConverter<FileSystemEvent, Map<String, Object>>(_encode);
427+
428+
static const Converter<Map<String, Object>, FileSystemEvent> kDecoder =
429+
const _ForwardingConverter<Map<String, Object>, FileSystemEvent>(_decode);
430+
431+
@override
432+
Converter<FileSystemEvent, Map<String, Object>> get encoder => kEncoder;
433+
434+
@override
435+
Converter<Map<String, Object>, FileSystemEvent> get decoder => kDecoder;
436+
}
437+
438+
class _FileSystemEvent implements FileSystemEvent {
439+
final Map<String, Object> _data;
440+
441+
const _FileSystemEvent(this._data);
442+
443+
@override
444+
int get type => _data['type'];
445+
446+
@override
447+
String get path => _data['path'];
448+
449+
@override
450+
bool get isDirectory => _data['isDirectory'];
346451
}
347452

348-
class _FutureDecoder<T> extends Converter<T, Future<T>> {
349-
const _FutureDecoder();
453+
class _FutureReviver<T> extends Converter<T, Future<T>> {
454+
const _FutureReviver();
350455

351456
@override
352457
Future<T> convert(T input) async => input;
353458
}
354459

355-
class _DirectoryDecoder extends Converter<String, Directory> {
460+
class _DirectoryReviver extends Converter<String, Directory> {
356461
final ReplayFileSystemImpl fileSystem;
357-
const _DirectoryDecoder(this.fileSystem);
462+
const _DirectoryReviver(this.fileSystem);
358463

359464
@override
360465
Directory convert(String input) => new ReplayDirectory(fileSystem, input);
361466
}
362467

363-
class _FileDecoder extends Converter<String, File> {
468+
class _FileReviver extends Converter<String, File> {
364469
final ReplayFileSystemImpl fileSystem;
365-
const _FileDecoder(this.fileSystem);
470+
const _FileReviver(this.fileSystem);
366471

367472
@override
368473
File convert(String input) => new ReplayFile(fileSystem, input);
369474
}
370475

371-
class _LinkDecoder extends Converter<String, Link> {
476+
class _LinkReviver extends Converter<String, Link> {
372477
final ReplayFileSystemImpl fileSystem;
373-
const _LinkDecoder(this.fileSystem);
478+
const _LinkReviver(this.fileSystem);
374479

375480
@override
376481
Link convert(String input) => new ReplayLink(fileSystem, input);
377482
}
483+
484+
class _FileSystemEntityReviver extends Converter<String, FileSystemEntity> {
485+
final ReplayFileSystemImpl fileSystem;
486+
const _FileSystemEntityReviver(this.fileSystem);
487+
488+
@override
489+
FileSystemEntity convert(String input) {
490+
if (input.contains('Directory')) {
491+
return new ReplayDirectory(fileSystem, input);
492+
} else if (input.contains('File')) {
493+
return new ReplayFile(fileSystem, input);
494+
} else {
495+
return new ReplayLink(fileSystem, input);
496+
}
497+
}
498+
}
499+
500+
class _RandomAccessFileReviver extends Converter<String, RandomAccessFile> {
501+
final ReplayFileSystemImpl fileSystem;
502+
const _RandomAccessFileReviver(this.fileSystem);
503+
504+
@override
505+
RandomAccessFile convert(String input) =>
506+
new ReplayRandomAccessFile(fileSystem, input);
507+
}
508+
509+
class _IOSinkReviver extends Converter<String, IOSink> {
510+
final ReplayFileSystemImpl fileSystem;
511+
const _IOSinkReviver(this.fileSystem);
512+
513+
@override
514+
IOSink convert(String input) => new ReplayIOSink(fileSystem, input);
515+
}
516+
517+
class _ListReviver extends Converter<Iterable<dynamic>, List<dynamic>> {
518+
final Converter<dynamic, dynamic> elementReviver;
519+
520+
const _ListReviver(this.elementReviver);
521+
522+
@override
523+
List<dynamic> convert(Iterable<dynamic> input) =>
524+
input.map(elementReviver.convert).toList();
525+
}
526+
527+
class _StreamReviver extends Converter<List<dynamic>, Stream<dynamic>> {
528+
const _StreamReviver();
529+
530+
@override
531+
Stream<dynamic> convert(List<dynamic> input) {
532+
return new Stream<dynamic>.fromIterable(input);
533+
}
534+
}
535+
536+
class _BlobReviver extends Converter<String, List<int>> {
537+
final ReplayFileSystemImpl fileSystem;
538+
const _BlobReviver(this.fileSystem);
539+
540+
@override
541+
List<int> convert(String input) {
542+
assert(input.startsWith('!'));
543+
String basename = input.substring(1);
544+
String dirname = fileSystem.recording.path;
545+
String path = fileSystem.recording.fileSystem.path.join(dirname, basename);
546+
File file = fileSystem.recording.fileSystem.file(path);
547+
return file.readAsBytesSync();
548+
}
549+
}

lib/src/backends/record_replay/proxy.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class MethodProxy extends Object implements Function {
4343
}
4444
}
4545

46+
// TODO(tvolkert): remove (https://github.com/dart-lang/sdk/issues/28706)
4647
class _MethodInvocationProxy extends Invocation {
4748
_MethodInvocationProxy(
4849
this.memberName,

lib/src/backends/record_replay/replay_directory.dart

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'dart:convert';
66

77
import 'package:file/file.dart';
88

9+
import 'codecs.dart';
910
import 'replay_file_system.dart';
1011
import 'replay_file_system_entity.dart';
1112

@@ -15,14 +16,24 @@ class ReplayDirectory extends ReplayFileSystemEntity implements Directory {
1516
/// Creates a new `ReplayDirectory`.
1617
ReplayDirectory(ReplayFileSystemImpl fileSystem, String identifier)
1718
: super(fileSystem, identifier) {
18-
// TODO(tvolkert): fill in resurrectors
19+
Converter<dynamic, dynamic> convertThis = directoryReviver(fileSystem);
20+
Converter<dynamic, dynamic> convertFutureThis =
21+
convertThis.fuse(kFutureReviver);
22+
1923
methods.addAll(<Symbol, Converter<dynamic, dynamic>>{
20-
#create: null,
21-
#createSync: null,
22-
#createTemp: null,
23-
#createTempSync: null,
24-
#list: null,
25-
#listSync: null,
24+
#rename: convertFutureThis,
25+
#renameSync: convertThis,
26+
#delete: convertFutureThis,
27+
#create: convertFutureThis,
28+
#createSync: kPassthrough,
29+
#createTemp: convertFutureThis,
30+
#createTempSync: convertThis,
31+
#list: listReviver(entityReviver(fileSystem)).fuse(kStreamReviver),
32+
#listSync: listReviver(entityReviver(fileSystem)),
33+
});
34+
35+
properties.addAll(<Symbol, Converter<dynamic, dynamic>>{
36+
#absolute: convertThis,
2637
});
2738
}
2839
}

0 commit comments

Comments
 (0)