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

Unified Diff: pkg/analysis_server/lib/src/context_manager.dart

Issue 1242023008: Server .packages support. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: More merging/nits. Created 5 years, 5 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/analysis_server/lib/src/context_manager.dart
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 51c42d29c85938cbfd68b7131c3ee0b8235bf761..fb1c3b4f5976cff18bd9f68d078ed152c813840c 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -6,6 +6,7 @@ library context.directory.manager;
import 'dart:async';
import 'dart:collection';
+import 'dart:convert';
import 'dart:core' hide Resource;
import 'package:analysis_server/src/analysis_server.dart';
@@ -20,6 +21,9 @@ import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
+import 'package:package_config/packages.dart';
+import 'package:package_config/packages_file.dart' as pkgfile show parse;
+import 'package:package_config/src/packages_impl.dart' show MapPackages;
import 'package:path/path.dart' as pathos;
import 'package:watcher/watcher.dart';
import 'package:yaml/yaml.dart';
@@ -29,6 +33,12 @@ import 'package:yaml/yaml.dart';
* folders that should correspond to analysis contexts.
*/
abstract class AbstractContextManager implements ContextManager {
+
+ /**
+ * Temporary flag to hide WIP .packages support (DEP 5).
+ */
+ static bool ENABLE_PACKAGESPEC_SUPPORT = false;
+
/**
* The name of the `lib` directory.
*/
@@ -45,6 +55,11 @@ abstract class AbstractContextManager implements ContextManager {
static const String PUBSPEC_NAME = 'pubspec.yaml';
/**
+ * File name of package spec files.
+ */
+ static const String PACKAGE_SPEC_NAME = '.packages';
+
+ /**
* [_ContextInfo] object for each included directory in the most
* recent successful call to [setRoots].
*/
@@ -113,7 +128,8 @@ abstract class AbstractContextManager implements ContextManager {
/**
* Create and return a new analysis context.
*/
- AnalysisContext addContext(Folder folder, UriResolver packageUriResolver);
+ AnalysisContext addContext(
+ Folder folder, UriResolver packageUriResolver, Packages packages);
/**
* Called when the set of files associated with a context have changed (or
@@ -170,14 +186,20 @@ abstract class AbstractContextManager implements ContextManager {
// Do nothing.
}
- /// Sets the [ignorePatterns] for the context [folder].
- void setIgnorePatternsForContext(Folder folder, List<String> ignorePatterns) {
- _ContextInfo info = _contexts[folder];
- if (info == null) {
- return;
+ @override
+ bool isInAnalysisRoot(String path) {
+ // check if excluded
+ if (_isExcluded(path)) {
+ return false;
}
- var pathFilter = info.pathFilter;
- pathFilter.setIgnorePatterns(ignorePatterns);
+ // check if in of the roots
+ for (Folder root in _contexts.keys) {
+ if (root.contains(path)) {
+ return true;
+ }
+ }
+ // no
+ return false;
}
/// Process [options] for the context [folder].
@@ -200,22 +222,6 @@ abstract class AbstractContextManager implements ContextManager {
}
@override
- bool isInAnalysisRoot(String path) {
- // check if excluded
- if (_isExcluded(path)) {
- return false;
- }
- // check if in of the roots
- for (Folder root in _contexts.keys) {
- if (root.contains(path)) {
- return true;
- }
- }
- // no
- return false;
- }
-
- @override
void refresh(List<Resource> roots) {
// Destroy old contexts
List<Folder> contextFolders = _contexts.keys.toList();
@@ -240,6 +246,16 @@ abstract class AbstractContextManager implements ContextManager {
*/
void removeContext(Folder folder);
+ /// Sets the [ignorePatterns] for the context [folder].
+ void setIgnorePatternsForContext(Folder folder, List<String> ignorePatterns) {
+ _ContextInfo info = _contexts[folder];
+ if (info == null) {
+ return;
+ }
+ var pathFilter = info.pathFilter;
+ pathFilter.setIgnorePatterns(ignorePatterns);
+ }
+
@override
void setRoots(List<String> includedPaths, List<String> excludedPaths,
Map<String, String> packageRoots) {
@@ -334,7 +350,7 @@ abstract class AbstractContextManager implements ContextManager {
* Called when the package map for a context has changed.
*/
void updateContextPackageUriResolver(
- Folder contextFolder, UriResolver packageUriResolver);
+ Folder contextFolder, UriResolver packageUriResolver, Packages packages);
/**
* Resursively adds all Dart and HTML files to the [changeSet].
@@ -431,6 +447,22 @@ abstract class AbstractContextManager implements ContextManager {
info.dependencySubscriptions.clear();
}
+ void _checkForPackagespecUpdate(
+ String path, _ContextInfo info, Folder folder) {
+ // Check to see if this is the .packages file for this context and if so,
+ // update the context's source factory.
+ if (pathContext.basename(path) == PACKAGE_SPEC_NAME &&
+ info.isPathToPackageDescription(path)) {
+ File packagespec = resourceProvider.getFile(path);
+ if (packagespec.exists) {
+ Packages packages = _readPackagespec(packagespec);
+ if (packages != null) {
+ updateContextPackageUriResolver(folder, null, packages);
+ }
+ }
+ }
+ }
+
/**
* Compute the appropriate package URI resolver for [folder], and store
* dependency information in [info]. Return `null` if no package map can
@@ -511,9 +543,9 @@ abstract class AbstractContextManager implements ContextManager {
* Create a new empty context associated with [folder].
*/
_ContextInfo _createContext(
- Folder folder, File pubspecFile, List<_ContextInfo> children) {
+ Folder folder, File packagespecFile, List<_ContextInfo> children) {
_ContextInfo info = new _ContextInfo(
- folder, pubspecFile, children, normalizedPackageRoots[folder.path]);
+ folder, packagespecFile, children, normalizedPackageRoots[folder.path]);
_contexts[folder] = info;
var options = analysisOptionsProvider.getOptions(folder);
processOptionsForContext(folder, options);
@@ -521,8 +553,22 @@ abstract class AbstractContextManager implements ContextManager {
_handleWatchEvent(folder, info, event);
});
try {
- UriResolver packageUriResolver = _computePackageUriResolver(folder, info);
- info.context = addContext(folder, packageUriResolver);
+ Packages packages;
+ UriResolver packageUriResolver;
+
+ if (ENABLE_PACKAGESPEC_SUPPORT) {
+ // Try .packages first.
+ if (pathos.basename(packagespecFile.path) == PACKAGE_SPEC_NAME) {
+ packages = _readPackagespec(packagespecFile);
+ }
+ }
+
+ // Next resort to a package uri resolver.
+ if (packages == null) {
+ packageUriResolver = _computePackageUriResolver(folder, info);
+ }
+
+ info.context = addContext(folder, packageUriResolver, packages);
info.context.name = folder.path;
} catch (_) {
info.changeSubscription.cancel();
@@ -538,13 +584,13 @@ abstract class AbstractContextManager implements ContextManager {
* created for them and excluded from the context associated with the
* [folder].
*
- * If [withPubspecOnly] is `true`, a context will be created only if there
- * is a 'pubspec.yaml' file in the [folder].
+ * If [withPackageSpecOnly] is `true`, a context will be created only if there
+ * is a 'pubspec.yaml' or '.packages' file in the [folder].
*
- * Returns create pubspec-based contexts.
+ * Returns created contexts.
*/
- List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) {
- // try to find subfolders with pubspec files
+ List<_ContextInfo> _createContexts(Folder folder, bool withPackageSpecOnly) {
+ // Try to find subfolders with pubspecs or .packages files.
List<_ContextInfo> children = <_ContextInfo>[];
try {
for (Resource child in folder.getChildren()) {
@@ -556,20 +602,31 @@ abstract class AbstractContextManager implements ContextManager {
// The directory either doesn't exist or cannot be read. Either way, there
// are no subfolders that need to be added.
}
- // check whether there is a pubspec in the folder
- File pubspecFile = folder.getChild(PUBSPEC_NAME);
- if (pubspecFile.exists) {
+
+ File packageSpec;
+
+ if (ENABLE_PACKAGESPEC_SUPPORT) {
+ // Start by looking for .packages.
+ packageSpec = folder.getChild(PACKAGE_SPEC_NAME);
+ }
+
+ // Fall back to looking for a pubspec.
+ if (packageSpec == null || !packageSpec.exists) {
+ packageSpec = folder.getChild(PUBSPEC_NAME);
+ }
+
+ if (packageSpec.exists) {
return <_ContextInfo>[
- _createContextWithSources(folder, pubspecFile, children)
+ _createContextWithSources(folder, packageSpec, children)
];
}
- // no pubspec, done
- if (withPubspecOnly) {
+ // No packagespec? Done.
+ if (withPackageSpecOnly) {
return children;
}
- // OK, create a context without a pubspec
+ // OK, create a context without a packagespec.
return <_ContextInfo>[
- _createContextWithSources(folder, pubspecFile, children)
+ _createContextWithSources(folder, packageSpec, children)
];
}
@@ -599,11 +656,11 @@ abstract class AbstractContextManager implements ContextManager {
}
/**
- * Extract a new [pubspecFile]-based context from [oldInfo].
+ * Extract a new [packagespecFile]-based context from [oldInfo].
*/
- void _extractContext(_ContextInfo oldInfo, File pubspecFile) {
- Folder newFolder = pubspecFile.parent;
- _ContextInfo newInfo = _createContext(newFolder, pubspecFile, []);
+ void _extractContext(_ContextInfo oldInfo, File packagespecFile) {
+ Folder newFolder = packagespecFile.parent;
+ _ContextInfo newInfo = _createContext(newFolder, packagespecFile, []);
newInfo.parent = oldInfo;
// prepare sources to extract
Map<String, Source> extractedSources = new HashMap<String, Source>();
@@ -657,12 +714,46 @@ abstract class AbstractContextManager implements ContextManager {
if (_isInPackagesDir(path, folder)) {
return;
}
+
Resource resource = resourceProvider.getResource(path);
- // pubspec was added in a sub-folder, extract a new context
- if (_isPubspec(path) && info.isRoot && !info.isPubspec(path)) {
- _extractContext(info, resource);
- return;
+
+ if (ENABLE_PACKAGESPEC_SUPPORT) {
+ String directoryPath = pathContext.dirname(path);
+
+ // Check to see if we need to create a new context.
+ if (info.isRoot) {
+
+ // Only create a new context if this is not the same directory
+ // described by our info object.
+ if (info.folder.path != directoryPath) {
+ if (_isPubspec(path)) {
+ // Check for a sibling .packages file.
+ if (!resourceProvider.getFile(
+ pathos.join(directoryPath, PACKAGE_SPEC_NAME)).exists) {
+ _extractContext(info, resource);
+ return;
+ }
+ }
+ if (_isPackagespec(path)) {
+ // Check for a sibling pubspec.yaml file.
+ if (!resourceProvider
+ .getFile(pathos.join(directoryPath, PUBSPEC_NAME)).exists) {
+ _extractContext(info, resource);
+ return;
+ }
+ }
+ }
+ }
+ } else {
+ // pubspec was added in a sub-folder, extract a new context
+ if (_isPubspec(path) &&
+ info.isRoot &&
+ !info.isPathToPackageDescription(path)) {
+ _extractContext(info, resource);
+ return;
+ }
}
+
// If the file went away and was replaced by a folder before we
// had a chance to process the event, resource might be a Folder. In
// that case don't add it.
@@ -678,11 +769,41 @@ abstract class AbstractContextManager implements ContextManager {
}
break;
case ChangeType.REMOVE:
- // pubspec was removed, merge the context into its parent
- if (info.isPubspec(path) && !info.isRoot) {
- _mergeContext(info);
- return;
+
+ // If package spec info is removed, check to see if we can merge contexts.
+ // Note that it's important to verify that there is NEITHER a .packages nor a
+ // lingering pubspec.yaml before merging.
+ if (!info.isRoot) {
+ if (ENABLE_PACKAGESPEC_SUPPORT) {
+ String directoryPath = pathContext.dirname(path);
+
+ // Only merge if this is the same directory described by our info object.
+ if (info.folder.path == directoryPath) {
+ if (_isPubspec(path)) {
+ // Check for a sibling .packages file.
+ if (!resourceProvider.getFile(
+ pathos.join(directoryPath, PACKAGE_SPEC_NAME)).exists) {
+ _mergeContext(info);
+ return;
+ }
+ }
+ if (_isPackagespec(path)) {
+ // Check for a sibling pubspec.yaml file.
+ if (!resourceProvider
+ .getFile(pathos.join(directoryPath, PUBSPEC_NAME)).exists) {
+ _mergeContext(info);
+ return;
+ }
+ }
+ }
+ } else {
+ if (info.isPathToPackageDescription(path)) {
+ _mergeContext(info);
+ return;
+ }
+ }
}
+
List<Source> sources = info.context.getSourcesWithFullName(path);
if (!sources.isEmpty) {
ChangeSet changeSet = new ChangeSet();
@@ -705,6 +826,9 @@ abstract class AbstractContextManager implements ContextManager {
break;
}
+ //TODO(pquitslund): find the right place for this
+ _checkForPackagespecUpdate(path, info, folder);
+
if (info.packageMapInfo != null &&
info.packageMapInfo.isChangedDependency(path, resourceProvider)) {
_recomputePackageUriResolver(info);
@@ -714,9 +838,7 @@ abstract class AbstractContextManager implements ContextManager {
/**
* Returns `true` if the given [path] is excluded by [excludedPaths].
*/
- bool _isExcluded(String path) {
- return _isExcludedBy(excludedPaths, path);
- }
+ bool _isExcluded(String path) => _isExcludedBy(excludedPaths, path);
/**
* Returns `true` if the given [path] is excluded by [excludedPaths].
@@ -740,12 +862,10 @@ abstract class AbstractContextManager implements ContextManager {
return pathParts.contains(PACKAGES_NAME);
}
- /**
- * Returns `true` if the given absolute [path] is a pubspec file.
- */
- bool _isPubspec(String path) {
- return pathContext.basename(path) == PUBSPEC_NAME;
- }
+ bool _isPackagespec(String path) =>
+ pathContext.basename(path) == PACKAGE_SPEC_NAME;
+
+ bool _isPubspec(String path) => pathContext.basename(path) == PUBSPEC_NAME;
/**
* Merges [info] context into its parent.
@@ -766,6 +886,18 @@ abstract class AbstractContextManager implements ContextManager {
}
}
+ Packages _readPackagespec(File specFile) {
+ try {
+ String contents = specFile.readAsStringSync();
+ Map<String, Uri> map =
+ pkgfile.parse(UTF8.encode(contents), new Uri.file(specFile.path));
+ return new MapPackages(map);
+ } catch (_) {
+ //TODO(pquitslund): consider creating an error for the spec file.
+ return null;
+ }
+ }
+
/**
* Recompute the package URI resolver for the context described by [info],
* and update the client appropriately.
@@ -777,7 +909,7 @@ abstract class AbstractContextManager implements ContextManager {
// "pub list" is in progress is just going to get thrown away anyhow.
UriResolver packageUriResolver =
_computePackageUriResolver(info.folder, info);
- updateContextPackageUriResolver(info.folder, packageUriResolver);
+ updateContextPackageUriResolver(info.folder, packageUriResolver, null);
}
/**
@@ -923,9 +1055,9 @@ class _ContextInfo {
_ContextInfo parent;
/**
- * The `pubspec.yaml` file path for this context.
+ * The package description file path for this context.
*/
- String pubspecPath;
+ String packageDescriptionPath;
/**
* Stream subscription we are using to watch the context's directory for
@@ -958,10 +1090,11 @@ class _ContextInfo {
*/
OptimizingPubPackageMapInfo packageMapInfo;
- _ContextInfo(Folder folder, File pubspecFile, this.children, this.packageRoot)
+ _ContextInfo(
+ Folder folder, File packagespecFile, this.children, this.packageRoot)
: folder = folder,
pathFilter = new PathFilter(folder.path, null) {
- pubspecPath = pubspecFile.path;
+ packageDescriptionPath = packagespecFile.path;
for (_ContextInfo child in children) {
child.parent = this;
}
@@ -981,20 +1114,18 @@ class _ContextInfo {
});
}
- /// Returns `true` if [path] should be ignored.
- bool ignored(String path) => pathFilter.ignored(path);
-
/**
* Returns `true` if [resource] is excluded, as it is in one of the children.
*/
- bool excludesResource(Resource resource) {
- return excludes(resource.path);
- }
+ bool excludesResource(Resource resource) => excludes(resource.path);
+
+ /// Returns `true` if [path] should be ignored.
+ bool ignored(String path) => pathFilter.ignored(path);
/**
- * Returns `true` if [path] is the pubspec file of this context.
+ * Returns `true` if [path] is the package description file for this context
+ * (pubspec.yaml or .packages).
*/
- bool isPubspec(String path) {
- return path == pubspecPath;
- }
+ bool isPathToPackageDescription(String path) =>
+ path == packageDescriptionPath;
}
« no previous file with comments | « pkg/analysis_server/lib/src/analysis_server.dart ('k') | pkg/analysis_server/test/context_manager_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698