New package:build workspace before we support it at the language level
Change-Id: I3252a55d520e7f67666684369467af8ec88aea29
Reviewed-on: https://dart-review.googlesource.com/56285
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Mike Fairhurst <mfairhurst@google.com>
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index 7be888a..e967809 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -23,6 +23,7 @@
import 'package:analyzer/src/generated/bazel.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/gn.dart';
+import 'package:analyzer/src/generated/package_build.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/workspace.dart';
@@ -281,11 +282,13 @@
Workspace createWorkspace(String rootPath) {
if (_hasPackageFileInPath(rootPath)) {
// Bazel workspaces that include package files are treated like normal
- // (non-Bazel) directories.
- return _BasicWorkspace.find(resourceProvider, rootPath, this);
+ // (non-Bazel) directories. But may still use package:build.
+ return PackageBuildWorkspace.find(resourceProvider, rootPath, this) ??
+ _BasicWorkspace.find(resourceProvider, rootPath, this);
}
Workspace workspace = BazelWorkspace.find(resourceProvider, rootPath);
workspace ??= GnWorkspace.find(resourceProvider, rootPath);
+ workspace ??= PackageBuildWorkspace.find(resourceProvider, rootPath, this);
return workspace ?? _BasicWorkspace.find(resourceProvider, rootPath, this);
}
diff --git a/pkg/analyzer/lib/src/generated/package_build.dart b/pkg/analyzer/lib/src/generated/package_build.dart
new file mode 100644
index 0000000..96e2dcf
--- /dev/null
+++ b/pkg/analyzer/lib/src/generated/package_build.dart
@@ -0,0 +1,300 @@
+// Copyright (c) 2018, 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:collection';
+import 'dart:core';
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/file_system/file_system.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/generated/workspace.dart';
+import 'package:analyzer/src/source/package_map_resolver.dart';
+import 'package:package_config/packages.dart';
+import 'package:path/path.dart';
+import 'package:yaml/yaml.dart';
+
+/**
+ * Instances of the class `PackageBuildFileUriResolver` resolve `file` URI's by
+ * first resolving file uri's in the expected way, and then by looking in the
+ * corresponding generated directories.
+ */
+class PackageBuildFileUriResolver extends ResourceUriResolver {
+ final PackageBuildWorkspace workspace;
+
+ PackageBuildFileUriResolver(PackageBuildWorkspace 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] that can resolve `package` URIs in [PackageBuildWorkspace].
+ */
+class PackageBuildPackageUriResolver extends UriResolver {
+ final PackageBuildWorkspace _workspace;
+ final UriResolver _normalUriResolver;
+ final Context _context;
+
+ /**
+ * The cache of absolute [Uri]s to [Source]s mappings.
+ */
+ final Map<Uri, Source> _sourceCache = new HashMap<Uri, Source>();
+
+ PackageBuildPackageUriResolver(
+ PackageBuildWorkspace workspace, this._normalUriResolver)
+ : _workspace = workspace,
+ _context = workspace.provider.pathContext;
+
+ @override
+ Source resolveAbsolute(Uri _ignore, [Uri uri]) {
+ uri ??= _ignore;
+ return _sourceCache.putIfAbsent(uri, () {
+ if (uri.scheme != 'package') {
+ return null;
+ }
+
+ Source basicResolverSource = _normalUriResolver.resolveAbsolute(uri);
+ if (basicResolverSource != null && basicResolverSource.exists()) {
+ return basicResolverSource;
+ }
+
+ 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('/', _context.separator);
+
+ File file = _workspace.builtFile(
+ _workspace.builtPackageSourcePath(filePath), packageName);
+ if (file != null && file.exists) {
+ return file.createSource(uri);
+ }
+ return basicResolverSource;
+ });
+ }
+
+ @override
+ Uri restoreAbsolute(Source source) {
+ Context context = _workspace.provider.pathContext;
+ String path = source.fullName;
+
+ if (context.isWithin(_workspace.root, path)) {
+ String relative = context.relative(path, from: _workspace.root);
+ List<String> components = context.split(relative);
+ if (components.length > 4 &&
+ components[0] == 'build' &&
+ components[1] == 'generated' &&
+ components[3] == 'lib') {
+ String packageName = components[2];
+ String pathInLib = components.skip(4).join('/');
+ return Uri.parse('package:$packageName/$pathInLib');
+ }
+ }
+ return source.uri;
+ }
+}
+
+/**
+ * Information about a package:build workspace.
+ */
+class PackageBuildWorkspace extends Workspace {
+ /**
+ * The name of the directory that identifies the root of the workspace. Note,
+ * the presence of this file does not show package:build is used. For that,
+ * the subdirectory [_dartToolBuildName] must exist. A `pub` subdirectory
+ * will usually exist in non-package:build projects too.
+ */
+ static const String _dartToolRootName = '.dart_tool';
+
+ /**
+ * The name of the subdirectory in [_dartToolName] that distinguishes projects
+ * built with package:build.
+ */
+ static const String _dartToolBuildName = 'build';
+
+ /**
+ * We use pubspec.yaml to get the package name to be consistent with how
+ * package:build does it.
+ */
+ static const String _pubspecName = 'pubspec.yaml';
+
+ /**
+ * The resource provider used to access the file system.
+ */
+ final ResourceProvider provider;
+
+ /**
+ * The absolute workspace root path (the directory containing the `.dart_tool`
+ * directory).
+ */
+ final String root;
+
+ /**
+ * The name of the package under development as defined in pubspec.yaml. This
+ * matches the behavior of package:build.
+ */
+ final String projectPackageName;
+
+ final ContextBuilder _builder;
+
+ /**
+ * The map of package locations indexed by package name.
+ *
+ * This is a cached field.
+ */
+ Map<String, List<Folder>> _packageMap;
+
+ /**
+ * The package location strategy.
+ *
+ * This is a cached field.
+ */
+ Packages _packages;
+
+ PackageBuildWorkspace._(
+ this.provider, this.root, this.projectPackageName, this._builder);
+
+ @override
+ Map<String, List<Folder>> get packageMap {
+ _packageMap ??= _builder.convertPackagesToMap(packages);
+ return _packageMap;
+ }
+
+ Packages get packages {
+ _packages ??= _builder.createPackageMap(root);
+ return _packages;
+ }
+
+ @override
+ UriResolver get packageUriResolver => new PackageBuildPackageUriResolver(
+ this, new PackageMapUriResolver(provider, packageMap));
+
+ /**
+ * For some package file, which may or may not be a package source (it could
+ * be in `bin/`, `web/`, etc), find where its built counterpart will exist if
+ * its a generated source.
+ *
+ * To get a [builtPath] for a package source file to use in this method,
+ * use [builtPackageSourcePath]. For `bin/`, `web/`, etc, it must be relative
+ * to the project root.
+ */
+ File builtFile(String builtPath, String packageName) {
+ if (!packageMap.containsKey(packageName)) {
+ return null;
+ }
+ String path = context.join(
+ root, _dartToolRootName, 'build', 'generated', packageName, builtPath);
+ return provider.getFile(path);
+ }
+
+ /**
+ * Unlike the way that sources are resolved against `.packages` (if foo points
+ * to folder bar, then `foo:baz.dart` is found at `bar/baz.dart`), the built
+ * sources for a package require the `lib/` prefix first. This is because
+ * `bin/`, `web/`, and `test/` etc can all be built as well. This method
+ * exists to give a name to that prefix processing step.
+ */
+ String builtPackageSourcePath(String path) {
+ assert(context.isRelative(path));
+ return context.join('lib', path);
+ }
+
+ @override
+ SourceFactory createSourceFactory(DartSdk sdk) {
+ List<UriResolver> resolvers = <UriResolver>[];
+ if (sdk != null) {
+ resolvers.add(new DartUriResolver(sdk));
+ }
+ resolvers.add(packageUriResolver);
+ resolvers.add(new PackageBuildFileUriResolver(this));
+ return new SourceFactory(resolvers, packages, provider);
+ }
+
+ /**
+ * Return the file with the given [path], looking first into directories for
+ * source files, and then in the generated directory
+ * `.dart_tool/build/generated/$projectPackageName/$FILE`. The file in the
+ * workspace root is returned even if it does not exist. Return `null` if the
+ * given [path] is not in the workspace [root].
+ */
+ File findFile(String path) {
+ assert(context.isAbsolute(path));
+ try {
+ final String builtPath = context.relative(path, from: root);
+ final File file = builtFile(builtPath, projectPackageName);
+
+ if (file.exists) {
+ return file;
+ }
+
+ return provider.getFile(path);
+ } catch (_) {
+ return null;
+ }
+ }
+
+ /**
+ * Find the package:build workspace that contains the given [path].
+ *
+ * Return `null` if the path is not in a package:build workspace.
+ */
+ static PackageBuildWorkspace find(
+ ResourceProvider provider, String path, ContextBuilder builder) {
+ Context context = provider.pathContext;
+
+ // Ensure that the path is absolute and normalized.
+ if (!context.isAbsolute(path)) {
+ throw new ArgumentError('Not an absolute path: $path');
+ }
+ path = context.normalize(path);
+
+ Folder folder = provider.getFolder(path);
+ while (true) {
+ Folder parent = folder.parent;
+ if (parent == null) {
+ return null;
+ }
+
+ final File pubspec = folder.getChildAssumingFile(_pubspecName);
+ final Folder dartToolDir =
+ folder.getChildAssumingFolder(_dartToolRootName);
+ final Folder dartToolBuildDir =
+ dartToolDir.getChildAssumingFolder(_dartToolBuildName);
+
+ // Found the .dart_tool file, that's our project root. We also require a
+ // pubspec, to know the package name that package:build will assume.
+ if (dartToolBuildDir.exists && pubspec.exists) {
+ try {
+ final yaml = loadYaml(pubspec.readAsStringSync());
+ return new PackageBuildWorkspace._(
+ provider, folder.path, yaml['name'], builder);
+ } on Exception {}
+ }
+
+ // Go up the folder.
+ folder = parent;
+ }
+ }
+}
diff --git a/pkg/analyzer/test/generated/package_build_test.dart b/pkg/analyzer/test/generated/package_build_test.dart
new file mode 100644
index 0000000..1b2dedd
--- /dev/null
+++ b/pkg/analyzer/test/generated/package_build_test.dart
@@ -0,0 +1,479 @@
+// Copyright (c) 2018, 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 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/generated/package_build.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:mockito/mockito.dart';
+import 'package:package_config/packages.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(PackageBuildFileUriResolverTest);
+ defineReflectiveTests(PackageBuildPackageUriResolverTest);
+ defineReflectiveTests(PackageBuildWorkspaceTest);
+ });
+}
+
+class MockContextBuilder extends Mock implements ContextBuilder {}
+
+class MockPackages extends Mock implements Packages {}
+
+class MockUriResolver extends Mock implements UriResolver {}
+
+@reflectiveTest
+class PackageBuildFileUriResolverTest extends _BaseTest {
+ PackageBuildWorkspace workspace;
+ PackageBuildFileUriResolver resolver;
+
+ void setUp() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ final ContextBuilder contextBuilder = new MockContextBuilder();
+ final Packages packages = new MockPackages();
+ when(contextBuilder.createPackageMap(_p('/workspace')))
+ .thenReturn(packages);
+ when(contextBuilder.convertPackagesToMap(packages))
+ .thenReturn({'project': []});
+ workspace =
+ PackageBuildWorkspace.find(provider, _p('/workspace'), contextBuilder);
+ resolver = new PackageBuildFileUriResolver(workspace);
+ provider.newFile(_p('/workspace/test.dart'), '');
+ provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/project/gen.dart'), '');
+ }
+
+ void test_resolveAbsolute_doesNotExist() {
+ Source source = _resolvePath('/workspace/foo.dart');
+ expect(source, isNotNull);
+ expect(source.exists(), isFalse);
+ expect(source.fullName, _p('/workspace/foo.dart'));
+ }
+
+ void test_resolveAbsolute_file() {
+ Source source = _resolvePath('/workspace/test.dart');
+ expect(source, isNotNull);
+ expect(source.exists(), isTrue);
+ expect(source.fullName, _p('/workspace/test.dart'));
+ }
+
+ void test_resolveAbsolute_folder() {
+ Source source = _resolvePath('/workspace');
+ expect(source, isNotNull);
+ expect(source.exists(), isFalse);
+ expect(source.fullName, _p('/workspace'));
+ }
+
+ void test_resolveAbsolute_generated_file_exists_one() {
+ Source source = _resolvePath('/workspace/gen.dart');
+ expect(source, isNotNull);
+ expect(source.exists(), isTrue);
+ expect(source.fullName,
+ _p('/workspace/.dart_tool/build/generated/project/gen.dart'));
+ }
+
+ void test_resolveAbsolute_notFile_dartUri() {
+ Uri uri = new Uri(scheme: 'dart', path: 'core');
+ Source source = resolver.resolveAbsolute(uri);
+ expect(source, isNull);
+ }
+
+ void test_resolveAbsolute_notFile_httpsUri() {
+ Uri uri = new Uri(scheme: 'https', path: '127.0.0.1/test.dart');
+ Source source = resolver.resolveAbsolute(uri);
+ expect(source, isNull);
+ }
+
+ void test_restoreAbsolute() {
+ Uri uri = provider.pathContext.toUri(_p('/workspace/test.dart'));
+ Source source = resolver.resolveAbsolute(uri);
+ expect(source, isNotNull);
+ expect(resolver.restoreAbsolute(source), uri);
+ expect(
+ resolver.restoreAbsolute(
+ new NonExistingSource(source.fullName, null, null)),
+ uri);
+ }
+
+ Source _resolvePath(String absolutePosixPath) {
+ String absolutePath = provider.convertPath(absolutePosixPath);
+ Uri uri = provider.pathContext.toUri(absolutePath);
+ return resolver.resolveAbsolute(uri);
+ }
+}
+
+@reflectiveTest
+class PackageBuildPackageUriResolverTest extends _BaseTest {
+ PackageBuildWorkspace workspace;
+ PackageBuildPackageUriResolver resolver;
+ UriResolver packageUriResolver;
+
+ Uri addPackageSource(String path, String uriStr, {bool create: true}) {
+ Uri uri = Uri.parse(uriStr);
+ final File file =
+ create ? provider.newFile(_p(path), '') : provider.getResource(path);
+ final Source source = file.createSource(uri);
+ when(packageUriResolver.resolveAbsolute(uri)).thenReturn(source);
+ return uri;
+ }
+
+ void setUp() {
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ }
+
+ void test_resolveAbsolute_generated() {
+ _addResources([
+ '/workspace/.dart_tool/build/generated/project/lib/generated_file.dart',
+ ]);
+ final Uri sourceUri = addPackageSource('/workspace/lib/generated_file.dart',
+ 'package:project/generated_file.dart',
+ create: false);
+ _assertResolveUri(sourceUri,
+ '/workspace/.dart_tool/build/generated/project/lib/generated_file.dart',
+ exists: true);
+ }
+
+ void test_resolveAbsolute_null_notPackage() {
+ _addResources([
+ '/workspace/.dart_tool/build/generated',
+ ]);
+ Source source = resolver.resolveAbsolute(Uri.parse('dart:async'));
+ expect(source, isNull);
+ }
+
+ void test_resolveAbsolute_null_startsWithSlash() {
+ _addResources([
+ '/workspace/.dart_tool/build/generated',
+ ]);
+ Source source =
+ resolver.resolveAbsolute(Uri.parse('package:/foo/bar.dart'));
+ expect(source, isNull);
+ }
+
+ void test_resolveAbsolute_source() {
+ _addResources([
+ '/workspace/.dart_tool/build/generated/project/lib/source_file.dart',
+ ]);
+ final Uri sourceUri = addPackageSource(
+ '/workspace/lib/source_file.dart', 'package:project/source_file.dart');
+ _assertResolveUri(sourceUri, '/workspace/lib/source_file.dart',
+ exists: true);
+ }
+
+ void test_resolveAbsolute_workspace_doesNotExist() {
+ _addResources([
+ '/workspace/.dart_tool/build/generated',
+ ]);
+ final Uri sourceUri = addPackageSource(
+ '/workspace/lib/doesNotExist.dart', 'package:project/doesNotExist.dart',
+ create: false);
+ _assertResolveUri(sourceUri, '/workspace/lib/doesNotExist.dart',
+ exists: false);
+ }
+
+ void _addResources(List<String> paths, {String workspacePath: '/workspace'}) {
+ for (String path in paths) {
+ if (path.endsWith('/')) {
+ provider.newFolder(_p(path.substring(0, path.length - 1)));
+ } else {
+ provider.newFile(_p(path), '');
+ }
+ }
+ final contextBuilder = new MockContextBuilder();
+ final packages = new MockPackages();
+ when(contextBuilder.createPackageMap(_p(workspacePath)))
+ .thenReturn(packages);
+ when(contextBuilder.convertPackagesToMap(packages))
+ .thenReturn({'project': []});
+ workspace =
+ PackageBuildWorkspace.find(provider, _p(workspacePath), contextBuilder);
+ packageUriResolver = new MockUriResolver();
+ resolver =
+ new PackageBuildPackageUriResolver(workspace, packageUriResolver);
+ }
+
+ Source _assertResolveUri(Uri uri, String posixPath,
+ {bool exists: true, bool restore: true}) {
+ Source source = resolver.resolveAbsolute(uri);
+ expect(source, isNotNull);
+ expect(source.fullName, _p(posixPath));
+ expect(source.uri, uri);
+ expect(source.exists(), exists);
+ // If enabled, test also "restoreAbsolute".
+ if (restore) {
+ Uri restoredUri = resolver.restoreAbsolute(source);
+ expect(restoredUri.toString(), uri.toString());
+ }
+ return source;
+ }
+}
+
+@reflectiveTest
+class PackageBuildWorkspaceTest extends _BaseTest {
+ void test_builtFile_currentProject() {
+ provider.newFolder(_p('/workspace/.dart_tool/build'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final libFile = provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/project/lib/file.dart'), '');
+ expect(workspace.builtFile('lib/file.dart', 'project'), libFile);
+ }
+
+ void test_builtFile_importedPackage() {
+ provider.newFolder(_p('/workspace/.dart_tool/build'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project', 'foo']);
+
+ final libFile = provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/foo/lib/file.dart'), '');
+ expect(workspace.builtFile('lib/file.dart', 'foo'), libFile);
+ }
+
+ void test_builtFile_notInPackagesGetsHidden() {
+ provider.newFolder(_p('/workspace/.dart_tool/build'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+
+ // Ensure package:bar is not configured.
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project', 'foo']);
+
+ // Create a generated file in package:bar.
+ provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/bar/lib/file.dart'), '');
+
+ // Bar not in packages, file should not be returned.
+ expect(workspace.builtFile('lib/file.dart', 'bar'), isNull);
+ }
+
+ void test_find_fail_notAbsolute() {
+ expect(
+ () => PackageBuildWorkspace.find(
+ provider, _p('not_absolute'), new MockContextBuilder()),
+ throwsArgumentError);
+ }
+
+ void test_find_hasDartToolAndPubspec() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+ provider, _p('/workspace'), new MockContextBuilder());
+ expect(workspace.root, _p('/workspace'));
+ expect(workspace.projectPackageName, 'project');
+ }
+
+ void test_find_hasDartToolAndPubspec_inParentDirectory() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFolder(_p('/workspace/opened/up/a/child/dir/.dart_tool/build'));
+ provider.newFileWithBytes(
+ _p('/workspace/opened/up/a/child/dir/pubspec.yaml'),
+ 'name: subproject'.codeUnits);
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(provider,
+ _p('/workspace/opened/up/a/child/dir'), new MockContextBuilder());
+ expect(workspace.root, _p('/workspace/opened/up/a/child/dir'));
+ expect(workspace.projectPackageName, 'subproject');
+ }
+
+ void
+ test_find_hasDartToolAndPubspec_inParentDirectory_ignoresMalformedPubspec() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFolder(_p('/workspace/opened/up/a/child/dir/.dart_tool/build'));
+ provider.newFileWithBytes(
+ _p('/workspace/opened/up/a/child/dir/pubspec.yaml'),
+ 'not: yaml: here!!! 111'.codeUnits);
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(provider,
+ _p('/workspace/opened/up/a/child/dir'), new MockContextBuilder());
+ expect(workspace.root, _p('/workspace'));
+ expect(workspace.projectPackageName, 'project');
+ }
+
+ void test_find_hasDartToolAndPubspec_inParentDirectory_ignoresSoloDartTool() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFolder(_p('/workspace/opened/up/a/child/dir'));
+ provider.newFolder(_p('/workspace/opened/up/a/child/dir/.dart_tool/build'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(provider,
+ _p('/workspace/opened/up/a/child/dir'), new MockContextBuilder());
+ expect(workspace.root, _p('/workspace'));
+ expect(workspace.projectPackageName, 'project');
+ }
+
+ void test_find_hasDartToolAndPubspec_inParentDirectory_ignoresSoloPubspec() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFolder(_p('/workspace/opened/up/a/child/dir'));
+ provider.newFileWithBytes(
+ _p('/workspace/opened/up/a/child/dir/pubspec.yaml'),
+ 'name: subproject'.codeUnits);
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(provider,
+ _p('/workspace/opened/up/a/child/dir'), new MockContextBuilder());
+ expect(workspace.root, _p('/workspace'));
+ expect(workspace.projectPackageName, 'project');
+ }
+
+ void test_find_hasDartToolNoBuild() {
+ // Edge case: an empty .dart_tool directory. Don't assume package:build.
+ provider.newFolder(_p('/workspace/.dart_tool'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+ provider, _p('/workspace'), new MockContextBuilder());
+ expect(workspace, isNull);
+ }
+
+ void test_find_hasDartToolNoPubspec() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+ provider, _p('/workspace'), new MockContextBuilder());
+ expect(workspace, isNull);
+ }
+
+ void test_find_hasDartToolPubButNotBuild() {
+ // Dart projects will have this directory, that don't use package:build.
+ provider.newFolder(_p('/workspace/.dart_tool/pub'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+ provider, _p('/workspace'), new MockContextBuilder());
+ expect(workspace, isNull);
+ }
+
+ void test_find_hasMalformedPubspec() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'not: yaml: here! 1111'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+ provider, _p('/workspace'), new MockContextBuilder());
+ expect(workspace, isNull);
+ }
+
+ void test_find_hasPubspecNoDartTool() {
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+ provider, _p('/workspace'), new MockContextBuilder());
+ expect(workspace, isNull);
+ }
+
+ void test_findFile_bin() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/bin'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final binFile = provider.newFile(_p('/workspace/bin/file.dart'), '');
+ expect(workspace.findFile('/workspace/bin/file.dart'), binFile);
+ }
+
+ void test_findFile_binGenerated() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/bin'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final binFile = provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/project/bin/file.dart'), '');
+ expect(workspace.findFile('/workspace/bin/file.dart'), binFile);
+ }
+
+ void test_findFile_libGenerated() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final libFile = provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/project/lib/file.dart'), '');
+ expect(workspace.findFile('/workspace/lib/file.dart'), libFile);
+ }
+
+ void test_findFile_test() {
+ provider
+ .newFolder(_p('/workspace/.dart_tool/build/generated/project/test'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final testFile = provider.newFile(_p('/workspace/test/file.dart'), '');
+ expect(workspace.findFile('/workspace/test/file.dart'), testFile);
+ }
+
+ void test_findFile_testGenerated() {
+ provider
+ .newFolder(_p('/workspace/.dart_tool/build/generated/project/test'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final testFile = provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/project/test/file.dart'), '');
+ expect(workspace.findFile('/workspace/test/file.dart'), testFile);
+ }
+
+ void test_findFile_web() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/web'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final webFile = provider.newFile(_p('/workspace/web/file.dart'), '');
+ expect(workspace.findFile('/workspace/web/file.dart'), webFile);
+ }
+
+ void test_findFile_webGenerated() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/web'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final webFile = provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/project/web/file.dart'), '');
+ expect(workspace.findFile('/workspace/web/file.dart'), webFile);
+ }
+
+ PackageBuildWorkspace _createWorkspace(
+ String root, List<String> packageNames) {
+ final contextBuilder = new MockContextBuilder();
+ final packages = new MockPackages();
+ final packageMap = new Map.fromIterable(packageNames, value: ((_) => []));
+ when(contextBuilder.createPackageMap(_p(root))).thenReturn(packages);
+ when(contextBuilder.convertPackagesToMap(packages)).thenReturn(packageMap);
+ when(packages.asMap()).thenReturn(packageMap);
+ return PackageBuildWorkspace.find(provider, _p(root), contextBuilder);
+ }
+}
+
+class _BaseTest {
+ final MemoryResourceProvider provider = new MemoryResourceProvider();
+
+ /**
+ * Return the [provider] specific path for the given Posix [path].
+ */
+ String _p(String path) => provider.convertPath(path);
+}