Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Unified Diff: pkg/front_end/lib/src/incremental/file_state.dart

Issue 2865253003: (Reland) Start using FileState/FileSystemState to provide consistent view. (Closed)
Patch Set: New changes. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/front_end/lib/src/incremental/file_state.dart
diff --git a/pkg/front_end/lib/src/incremental/file_state.dart b/pkg/front_end/lib/src/incremental/file_state.dart
new file mode 100644
index 0000000000000000000000000000000000000000..fec7c17940977ef7b681a9df3f08231f8a15ab41
--- /dev/null
+++ b/pkg/front_end/lib/src/incremental/file_state.dart
@@ -0,0 +1,225 @@
+// 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:async';
+import 'dart:convert';
+import 'dart:typed_data';
+
+import 'package:front_end/file_system.dart';
+import 'package:front_end/src/fasta/parser/top_level_parser.dart';
+import 'package:front_end/src/fasta/scanner.dart';
+import 'package:front_end/src/fasta/source/directive_listener.dart';
+import 'package:front_end/src/fasta/translate_uri.dart';
+
+/// Information about a file being compiled, explicitly or implicitly.
+///
+/// It provides a consistent view on its properties.
+///
+/// The properties are not guaranteed to represent the most recent state
+/// of the file system. To update the file to the most recent state, [refresh]
+/// should be called.
+class FileState {
+ final FileSystemState _fsState;
+
+ /// The resolved URI of the file in the file system.
+ final Uri fileUri;
+
+ bool _exists;
+ List<int> _contentBytes;
+ String _content;
+
+ List<FileState> _importedFiles;
+ List<FileState> _exportedFiles;
+ List<FileState> _partFiles;
+
+ Set<FileState> _directReferencedFiles = new Set<FileState>();
+
+ FileState._(this._fsState, this.fileUri);
+
+ /// The content of the file.
+ String get content => _content;
+
+ /// The content bytes of the file.
+ List<int> get contentBytes => _contentBytes;
+
+ /// Whether the file exists.
+ bool get exists => _exists;
+
+ @override
+ int get hashCode => fileUri.hashCode;
+
+ /// Return the set of transitive files - the file itself and all of the
+ /// directly or indirectly referenced files.
+ Set<FileState> get transitiveFiles {
+ // TODO(scheglov) add caching.
+ var transitiveFiles = new Set<FileState>();
+
+ void appendReferenced(FileState file) {
+ if (transitiveFiles.add(file)) {
+ file._directReferencedFiles.forEach(appendReferenced);
+ }
+ }
+
+ appendReferenced(this);
+ return transitiveFiles;
+ }
+
+ @override
+ bool operator ==(Object other) {
+ return other is FileState && other.fileUri == fileUri;
+ }
+
+ /// Read the file content and ensure that all of the file properties are
+ /// consistent with the read content, including all its dependencies.
+ Future<Null> refresh() async {
+ // Read the content.
+ try {
+ FileSystemEntity entry = _fsState.fileSystem.entityForUri(fileUri);
+ _contentBytes = await entry.readAsBytes();
+ _content = UTF8.decode(_contentBytes);
+ _exists = true;
+ } catch (_) {
+ _contentBytes = new Uint8List(0);
+ _content = '';
+ _exists = false;
+ }
+
+ // Parse directives.
+ ScannerResult scannerResults = scanString(_content);
+ var listener = new DirectiveListener();
+ new TopLevelParser(listener).parseUnit(scannerResults.tokens);
+
+ // Build the graph.
+ _importedFiles = <FileState>[];
+ _exportedFiles = <FileState>[];
+ _partFiles = <FileState>[];
+ await _addFileForRelativeUri(_importedFiles, 'dart:core');
+ for (String uri in listener.imports) {
+ await _addFileForRelativeUri(_importedFiles, uri);
+ }
+ for (String uri in listener.exports) {
+ await _addFileForRelativeUri(_exportedFiles, uri);
+ }
+ for (String uri in listener.parts) {
+ await _addFileForRelativeUri(_partFiles, uri);
+ }
+
+ // Compute referenced files.
+ _directReferencedFiles = new Set<FileState>()
+ ..addAll(_importedFiles)
+ ..addAll(_exportedFiles)
+ ..addAll(_partFiles);
+ }
+
+ /// Add the [FileState] for the given [relativeUri] to the [files].
+ /// Do nothing if the URI cannot be parsed, cannot correspond any file, etc.
+ Future<Null> _addFileForRelativeUri(
+ List<FileState> files, String relativeUri) async {
+ if (relativeUri.isEmpty) return;
+
+ // Resolve the relative URI into absolute.
+ // The result is either:
+ // 1) The absolute file URI.
+ // 2) The absolute non-file URI, e.g. `package:foo/foo.dart`.
+ Uri absoluteUri;
+ try {
+ absoluteUri = fileUri.resolve(relativeUri);
+ } on FormatException {
+ return;
+ }
+
+ // Resolve the absolute URI into the absolute file URI.
+ Uri resolvedUri = _fsState.uriTranslator.translate(absoluteUri);
+ if (resolvedUri == null) return;
+
+ FileState file = await _fsState.getFile(resolvedUri);
+ files.add(file);
+ }
+}
+
+/// Information about known file system state.
+class FileSystemState {
+ final FileSystem fileSystem;
+ final TranslateUri uriTranslator;
+
+ _FileSystemView _fileSystemView;
+
+ /// Mapping from file URIs to corresponding [FileState]s.
+ final Map<Uri, FileState> _fileUriToFile = {};
+
+ FileSystemState(this.fileSystem, this.uriTranslator);
+
+ /// Return the [FileSystem] that is backed by this [FileSystemState]. The
+ /// files in this [FileSystem] always have the same content as the
+ /// corresponding [FileState]s, thus avoiding race conditions when a file
+ /// is updated on the actual file system.
+ FileSystem get fileSystemView {
+ return _fileSystemView ??= new _FileSystemView(this);
+ }
+
+ /// Return the [FileState] for the given resolved file [fileUri].
+ /// The returned file has the last known state since it was last refreshed.
+ Future<FileState> getFile(Uri fileUri) async {
+ FileState file = _fileUriToFile[fileUri];
+ if (file == null) {
+ file = new FileState._(this, fileUri);
+ _fileUriToFile[fileUri] = file;
+
+ // Build the sub-graph of the file.
+ await file.refresh();
+ }
+ return file;
+ }
+}
+
+/// [FileSystemState] based implementation of [FileSystem].
+/// It provides a consistent view on the known file system state.
+class _FileSystemView implements FileSystem {
+ final FileSystemState fsState;
+
+ _FileSystemView(this.fsState);
+
+ @override
+ FileSystemEntity entityForUri(Uri uri) {
+ FileState file = fsState._fileUriToFile[uri];
+ return new _FileSystemViewEntry(uri, file);
+ }
+}
+
+/// [FileSystemState] based implementation of [FileSystemEntity].
+class _FileSystemViewEntry implements FileSystemEntity {
+ @override
+ final Uri uri;
+
+ final FileState file;
+
+ _FileSystemViewEntry(this.uri, this.file);
+
+ @override
+ Future<bool> exists() async => file?.exists ?? false;
+
+ @override
+ Future<DateTime> lastModified() async {
+ throw new StateError(
+ 'FileSystemViewEntry modification stamp should not be queried');
+ }
+
+ @override
+ Future<List<int>> readAsBytes() async {
+ _throwIfDoesNotExist();
+ return file.contentBytes;
+ }
+
+ @override
+ Future<String> readAsString() async {
+ _throwIfDoesNotExist();
+ return file.content;
+ }
+
+ void _throwIfDoesNotExist() {
+ if (file == null) {
+ throw new FileSystemException(uri, 'File $uri does not exist.');
+ }
+ }
+}
« no previous file with comments | « pkg/front_end/lib/incremental_kernel_generator.dart ('k') | pkg/front_end/lib/src/incremental_kernel_generator_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698