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

Unified Diff: pkg/analyzer/lib/src/generated/gn.dart

Issue 2651613003: Added support for GN workspaces. (Closed)
Patch Set: Tests Created 3 years, 11 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
« no previous file with comments | « pkg/analyzer/lib/src/context/builder.dart ('k') | pkg/analyzer/test/generated/gn_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/generated/gn.dart
diff --git a/pkg/analyzer/lib/src/generated/gn.dart b/pkg/analyzer/lib/src/generated/gn.dart
new file mode 100644
index 0000000000000000000000000000000000000000..ea198335cf12ffe806c4b68a50d3a5885d855d63
--- /dev/null
+++ b/pkg/analyzer/lib/src/generated/gn.dart
@@ -0,0 +1,255 @@
+// 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.
+
+library analyzer.src.generated.gn;
+
+import 'dart:collection';
+import 'dart:core';
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/util/fast_uri.dart';
+import 'package:path/path.dart';
+
+/**
+ * The [UriResolver] used to resolve `file` URIs in a [GnWorkspace].
+ */
+class GnFileUriResolver extends ResourceUriResolver {
+ /**
+ * The workspace associated with this resolver.
+ */
+ final GnWorkspace workspace;
+
+ /**
+ * Initialize a newly created resolver to be associated with the given
+ * [workspace].
+ */
+ GnFileUriResolver(GnWorkspace workspace)
+ : workspace = workspace,
+ super(workspace.provider);
+
+ @override
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+ if (!ResourceUriResolver.isFileUri(uri)) {
+ return null;
+ }
+ String path = provider.pathContext.fromUri(uri);
+ File file = workspace.findFile(path);
+ if (file != null) {
+ return file.createSource(actualUri ?? uri);
+ }
+ return null;
+ }
+}
+
+/**
+ * The [UriResolver] used to resolve `package` URIs in a [GnWorkspace].
+ */
+class GnPackageUriResolver extends UriResolver {
+ /**
+ * The workspace associated with this resolver.
+ */
+ final GnWorkspace workspace;
+
+ /**
+ * The path context that should be used to manipulate file system paths.
+ */
+ final Context pathContext;
+
+ /**
+ * The map of package sources indexed by package name.
+ */
+ final Map<String, String> _packages;
+
+ /**
+ * The cache of absolute [Uri]s to [Source]s mappings.
+ */
+ final Map<Uri, Source> _sourceCache = new HashMap<Uri, Source>();
+
+ /**
+ * Initialize a newly created resolver to be associated with the given
+ * [workspace].
+ */
+ GnPackageUriResolver(GnWorkspace workspace)
+ : workspace = workspace,
+ pathContext = workspace.provider.pathContext,
+ _packages = workspace.packages;
+
+ @override
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+ return _sourceCache.putIfAbsent(uri, () {
+ if (uri.scheme != 'package') {
+ return null;
+ }
+
+ String uriPath = uri.path;
+ int slash = uriPath.indexOf('/');
+
+ // If the path either starts with a slash or has no slash, it is invalid.
+ if (slash < 1) {
+ return null;
+ }
+
+ String packageName = uriPath.substring(0, slash);
+ String fileUriPart = uriPath.substring(slash + 1);
+ String filePath = fileUriPart.replaceAll('/', pathContext.separator);
+
+ if (!_packages.containsKey(packageName)) {
+ return null;
+ }
+ String packageBase = _packages[packageName];
+ String path = pathContext.join(packageBase, filePath);
+ File file = workspace.findFile(path);
+ return file?.createSource(uri);
+ });
+ }
+
+ @override
+ Uri restoreAbsolute(Source source) {
+ Context context = workspace.provider.pathContext;
+ String path = source.fullName;
+
+ if (!context.isWithin(workspace.root, path)) {
+ return null;
+ }
+
+ String package = _packages.keys.firstWhere(
+ (key) => context.isWithin(_packages[key], path),
+ orElse: () => null);
+
+ if (package == null) {
+ return null;
+ }
+
+ String sourcePath = context.relative(path, from: _packages[package]);
+
+ return FastUri.parse('package:$package/$sourcePath');
+ }
+}
+
+/**
+ * Information about a Gn workspace.
+ */
+class GnWorkspace {
+ /**
+ * The name of the directory that identifies the root of the workspace.
+ */
+ static const String _jiriRootName = '.jiri_root';
+
+ /**
+ * The resource provider used to access the file system.
+ */
+ final ResourceProvider provider;
+
+ /**
+ * The absolute workspace root path (the directory containing the `.jiri_root`
+ * directory).
+ */
+ final String root;
+
+ /**
+ * The map of package sources indexed by package name.
+ */
+ final Map<String, String> packages;
+
+ GnWorkspace._(this.provider, this.root, this.packages);
+
+ /**
+ * Return a map of package sources.
+ */
+ Map<String, List<Folder>> get packageMap {
+ Map<String, List<Folder>> result = new HashMap<String, List<Folder>>();
+ packages.forEach((package, sourceDir) {
+ result[package] = [provider.getFolder(sourceDir)];
+ });
+ return result;
+ }
+
+ /**
+ * Return the file with the given [absolutePath].
+ *
+ * Return `null` if the given [absolutePath] is not in the workspace [root].
+ */
+ File findFile(String absolutePath) {
+ try {
+ File writableFile = provider.getFile(absolutePath);
+ return writableFile;
+ } catch (_) {
+ return null;
+ }
+ }
+
+ /**
+ * Locate the output directory.
+ *
+ * Return `null` if it could not be found.
+ */
+ static String _getOutDirectory(ResourceProvider provider, String root) =>
+ provider
+ .getFolder('$root/out')
+ .getChildren()
+ .where((resource) => resource is Folder)
+ .map((resource) => resource as Folder)
+ .firstWhere((Folder folder) {
+ String baseName = basename(folder.path);
+ // TODO(pylaligand): find a better way to locate the proper directory.
+ return baseName.startsWith('debug') || baseName.startsWith('release');
+ }, orElse: () => null)?.path;
+
+ /**
+ * Return a map of package source locations indexed by package name.
+ */
+ static Map<String, String> _getPackages(
+ ResourceProvider provider, String outDirectory) {
+ String packagesDir = '$outDirectory/gen/dart.sources';
+ Map<String, String> result = new HashMap<String, String>();
+ provider
+ .getFolder(packagesDir)
+ .getChildren()
+ .where((resource) => resource is File)
+ .map((resource) => resource as File)
+ .forEach((file) {
+ String packageName = basename(file.path);
+ String source = file.readAsStringSync();
+ result[packageName] = source;
+ });
+ return result;
+ }
+
+ /**
+ * Find the Gn workspace that contains the given [path].
+ *
+ * Return `null` if a workspace markers, such as the `.jiri_root` directory
+ * cannot be found.
+ */
+ static GnWorkspace find(ResourceProvider provider, String path) {
+ Context context = provider.pathContext;
+
+ // Ensure that the path is absolute and normalized.
+ if (!context.isAbsolute(path)) {
+ throw new ArgumentError('not absolute: $path');
+ }
+ path = context.normalize(path);
+
+ Folder folder = provider.getFolder(path);
+ while (true) {
+ Folder parent = folder.parent;
+ if (parent == null) {
+ return null;
+ }
+
+ // Found the .jiri_root file, must be a non-git workspace.
+ if (folder.getChildAssumingFolder(_jiriRootName).exists) {
+ String root = folder.path;
+ String outDirectory = _getOutDirectory(provider, root);
+ Map<String, String> packages = _getPackages(provider, outDirectory);
+ return new GnWorkspace._(provider, root, packages);
+ }
+
+ // Go up the folder.
+ folder = parent;
+ }
+ }
+}
« no previous file with comments | « pkg/analyzer/lib/src/context/builder.dart ('k') | pkg/analyzer/test/generated/gn_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698