forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement RecordingFileSystem. (flutter#16)
To be followed by ReplayFileSystem in an upcoming commit. First part of flutter#11
- Loading branch information
Showing
21 changed files
with
2,049 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,68 @@ | ||
analyzer: | ||
strong-mode: true | ||
language: | ||
enableSuperMixins: true | ||
enableStrictCallChecks: true | ||
enableSuperMixins: true | ||
errors: | ||
# Allow having TODOs in the code | ||
todo: ignore | ||
|
||
linter: | ||
rules: | ||
# Errors | ||
# these rules are documented on and in the same order as | ||
# the Dart Lint rules page to make maintenance easier | ||
# http://dart-lang.github.io/linter/lints/ | ||
|
||
# === error rules === | ||
- avoid_empty_else | ||
# TODO - comment_references | ||
- cancel_subscriptions | ||
# TODO - close_sinks | ||
- control_flow_in_finally | ||
- empty_statements | ||
- hash_and_equals | ||
- invariant_booleans | ||
- iterable_contains_unrelated_type | ||
- list_remove_unrelated_type | ||
- literal_only_boolean_expressions | ||
- test_types_in_equals | ||
- throw_in_finally | ||
- unrelated_type_equality_checks | ||
- valid_regexps | ||
|
||
# Style | ||
# TODO: - annotate_overrides | ||
# === style rules === | ||
- always_declare_return_types | ||
# TODO - always_specify_types | ||
# TODO - annotate_overrides | ||
# TODO - avoid_as | ||
- avoid_init_to_null | ||
- avoid_return_types_on_setters | ||
- await_only_futures | ||
- camel_case_types | ||
# TODO: - comment_references | ||
# TODO - camel_case_types | ||
# TODO - constant_identifier_names | ||
- control_flow_in_finally | ||
- empty_catches | ||
- empty_constructor_bodies | ||
- hash_and_equals | ||
- implementation_imports | ||
- library_names | ||
- library_prefixes | ||
- non_constant_identifier_names | ||
- one_member_abstracts | ||
- only_throw_errors | ||
- overridden_fields | ||
- package_api_docs | ||
- package_prefixed_library_names | ||
- prefer_is_not_empty | ||
# TODO - public_member_api_docs | ||
- slash_for_doc_comments | ||
- sort_constructors_first | ||
# TODO - sort_unnamed_constructors_first | ||
- super_goes_last | ||
# TODO - type_annotate_public_apis | ||
- type_init_formals | ||
- unrelated_type_equality_checks | ||
# TODO - unawaited_futures | ||
- unnecessary_brace_in_string_interp | ||
- unnecessary_getters_setters | ||
|
||
# === pub rules === | ||
- package_names |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
export 'src/backends/record_replay/events.dart' | ||
show InvocationEvent, PropertyGetEvent, PropertySetEvent, MethodEvent; | ||
export 'src/backends/record_replay/recording.dart'; | ||
export 'src/backends/record_replay/recording_file_system.dart' | ||
show RecordingFileSystem; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
/// Encoded value of the file system in a recording. | ||
const String kFileSystemEncodedValue = '__fs__'; | ||
|
||
/// The name of the recording manifest file. | ||
const String kManifestName = 'MANIFEST.txt'; | ||
|
||
/// Gets an id guaranteed to be unique on this isolate for objects within this | ||
/// library. | ||
int newUid() => _nextUid++; | ||
int _nextUid = 1; | ||
|
||
/// Gets the name of the specified [symbol]. | ||
// TODO(tvolkert): Symbol.name (https://github.com/dart-lang/sdk/issues/28372) | ||
String getSymbolName(Symbol symbol) { | ||
// Format of `str` is `Symbol("<name>")` | ||
String str = symbol.toString(); | ||
int offset = str.indexOf('"') + 1; | ||
return str.substring(offset, str.indexOf('"', offset)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | ||
// for details. 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:convert'; | ||
|
||
import 'package:file/file.dart'; | ||
import 'package:path/path.dart' as p; | ||
|
||
import 'common.dart'; | ||
import 'events.dart'; | ||
import 'recording_directory.dart'; | ||
import 'recording_file.dart'; | ||
import 'recording_file_system_entity.dart'; | ||
import 'recording_io_sink.dart'; | ||
import 'recording_link.dart'; | ||
import 'recording_random_access_file.dart'; | ||
|
||
/// Encodes an object into a JSON-ready representation. | ||
typedef dynamic _Encoder(dynamic object); | ||
|
||
/// This class is a work-around for the "is" operator not accepting a variable | ||
/// value as its right operand (https://github.com/dart-lang/sdk/issues/27680). | ||
class _TypeMatcher<T> { | ||
/// Creates a type matcher for the given type parameter. | ||
const _TypeMatcher(); | ||
|
||
/// Returns `true` if the given object is of type `T`. | ||
bool check(dynamic object) => object is T; | ||
} | ||
|
||
/// Known encoders. Types not covered here will be encoded using | ||
/// [_encodeDefault]. | ||
/// | ||
/// When encoding an object, we will walk this map in iteration order looking | ||
/// for a matching encoder. Thus, when there are two encoders that match an | ||
// object, the first one will win. | ||
const Map<_TypeMatcher, _Encoder> _kEncoders = const <_TypeMatcher, _Encoder>{ | ||
const _TypeMatcher<num>(): _encodeRaw, | ||
const _TypeMatcher<bool>(): _encodeRaw, | ||
const _TypeMatcher<String>(): _encodeRaw, | ||
const _TypeMatcher<Null>(): _encodeRaw, | ||
const _TypeMatcher<List>(): _encodeRaw, | ||
const _TypeMatcher<Map>(): _encodeMap, | ||
const _TypeMatcher<Iterable>(): _encodeIterable, | ||
const _TypeMatcher<Symbol>(): getSymbolName, | ||
const _TypeMatcher<DateTime>(): _encodeDateTime, | ||
const _TypeMatcher<Uri>(): _encodeUri, | ||
const _TypeMatcher<p.Context>(): _encodePathContext, | ||
const _TypeMatcher<EventImpl>(): _encodeEvent, | ||
const _TypeMatcher<FileSystem>(): _encodeFileSystem, | ||
const _TypeMatcher<RecordingDirectory>(): _encodeFileSystemEntity, | ||
const _TypeMatcher<RecordingFile>(): _encodeFileSystemEntity, | ||
const _TypeMatcher<RecordingLink>(): _encodeFileSystemEntity, | ||
const _TypeMatcher<RecordingIOSink>(): _encodeIOSink, | ||
const _TypeMatcher<RecordingRandomAccessFile>(): _encodeRandomAccessFile, | ||
const _TypeMatcher<Encoding>(): _encodeEncoding, | ||
const _TypeMatcher<FileMode>(): _encodeFileMode, | ||
const _TypeMatcher<FileStat>(): _encodeFileStat, | ||
const _TypeMatcher<FileSystemEntityType>(): _encodeFileSystemEntityType, | ||
const _TypeMatcher<FileSystemEvent>(): _encodeFileSystemEvent, | ||
}; | ||
|
||
/// Encodes [object] into a JSON-ready representation. | ||
/// | ||
/// This function is intended to be used as the `toEncodable` argument to the | ||
/// `JsonEncoder` constructors. | ||
/// | ||
/// See also: | ||
/// - [JsonEncoder.withIndent] | ||
dynamic encode(dynamic object) { | ||
_Encoder encoder = _encodeDefault; | ||
for (_TypeMatcher matcher in _kEncoders.keys) { | ||
if (matcher.check(object)) { | ||
encoder = _kEncoders[matcher]; | ||
break; | ||
} | ||
} | ||
return encoder(object); | ||
} | ||
|
||
/// Default encoder (used for types not covered in [_kEncoders]). | ||
String _encodeDefault(dynamic object) => object.runtimeType.toString(); | ||
|
||
/// Pass-through encoder. | ||
dynamic _encodeRaw(dynamic object) => object; | ||
|
||
List<T> _encodeIterable<T>(Iterable<T> iterable) => iterable.toList(); | ||
|
||
/// Encodes the map keys, and passes the values through. | ||
/// | ||
/// As [JsonEncoder] encodes an object graph, it will repeatedly call | ||
/// `toEncodable` to encode unknown types, so any values in a map that need | ||
/// special encoding will already be handled by `JsonEncoder`. However, the | ||
/// encoder won't try to encode map *keys* by default, which is why we encode | ||
/// them here. | ||
Map<String, T> _encodeMap<T>(Map<dynamic, T> map) { | ||
Map<String, T> encoded = <String, T>{}; | ||
for (dynamic key in map.keys) { | ||
String encodedKey = encode(key); | ||
encoded[encodedKey] = map[key]; | ||
} | ||
return encoded; | ||
} | ||
|
||
int _encodeDateTime(DateTime dateTime) => dateTime.millisecondsSinceEpoch; | ||
|
||
String _encodeUri(Uri uri) => uri.toString(); | ||
|
||
Map<String, String> _encodePathContext(p.Context context) => <String, String>{ | ||
'style': context.style.name, | ||
'cwd': context.current, | ||
}; | ||
|
||
Map<String, dynamic> _encodeEvent(EventImpl event) => event.encode(); | ||
|
||
String _encodeFileSystem(FileSystem fs) => kFileSystemEncodedValue; | ||
|
||
/// Encodes a file system entity by using its `uid` as a reference identifier. | ||
/// During replay, this allows us to tie the return value of of one event to | ||
/// the object of another. | ||
String _encodeFileSystemEntity(RecordingFileSystemEntity entity) { | ||
return '${entity.runtimeType}@${entity.uid}'; | ||
} | ||
|
||
String _encodeIOSink(RecordingIOSink sink) { | ||
return '${sink.runtimeType}@${sink.uid}'; | ||
} | ||
|
||
String _encodeRandomAccessFile(RecordingRandomAccessFile raf) { | ||
return '${raf.runtimeType}@${raf.uid}'; | ||
} | ||
|
||
String _encodeEncoding(Encoding encoding) => encoding.name; | ||
|
||
String _encodeFileMode(FileMode fileMode) { | ||
switch (fileMode) { | ||
case FileMode.READ: | ||
return 'READ'; | ||
case FileMode.WRITE: | ||
return 'WRITE'; | ||
case FileMode.APPEND: | ||
return 'APPEND'; | ||
case FileMode.WRITE_ONLY: | ||
return 'WRITE_ONLY'; | ||
case FileMode.WRITE_ONLY_APPEND: | ||
return 'WRITE_ONLY_APPEND'; | ||
} | ||
throw new ArgumentError('Invalid value: $fileMode'); | ||
} | ||
|
||
Map<String, dynamic> _encodeFileStat(FileStat stat) => <String, dynamic>{ | ||
'changed': stat.changed, | ||
'modified': stat.modified, | ||
'accessed': stat.accessed, | ||
'type': stat.type, | ||
'mode': stat.mode, | ||
'size': stat.size, | ||
'modeString': stat.modeString(), | ||
}; | ||
|
||
String _encodeFileSystemEntityType(FileSystemEntityType type) => | ||
type.toString(); | ||
|
||
Map<String, dynamic> _encodeFileSystemEvent(FileSystemEvent event) => | ||
<String, dynamic>{ | ||
'type': event.type, | ||
'path': event.path, | ||
}; |
Oops, something went wrong.