Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| // Copyright (c) 2016, 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/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:path/path.dart'; | |
| /** | |
| * Instances of the class `BazelFileUriResolver` resolve `file` URI's by first | |
| * resolving file uri's in the expected way, and then by looking in the | |
| * corresponding generated directories. | |
| */ | |
| class BazelFileUriResolver extends ResourceUriResolver { | |
| final BazelWorkspace workspace; | |
| BazelFileUriResolver(BazelWorkspace 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 [BazelWorkspace]. | |
| */ | |
| class BazelPackageUriResolver extends UriResolver { | |
| final BazelWorkspace _workspace; | |
| final Context _context; | |
| /** | |
| * The cache of absolute [Uri]s to [Source]s mappings. | |
| */ | |
| final Map<Uri, Source> _sourceCache = new HashMap<Uri, Source>(); | |
| BazelPackageUriResolver(BazelWorkspace workspace) | |
| : _workspace = workspace, | |
| _context = workspace.provider.pathContext; | |
| @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('/', _context.separator); | |
| if (packageName.indexOf('.') == -1) { | |
| String path = _context.join(_workspace.root, 'third_party', 'dart', | |
| packageName, 'lib', filePath); | |
| File file = _workspace.findFile(path); | |
| return file?.createSource(uri); | |
| } else { | |
| String packagePath = packageName.replaceAll('.', _context.separator); | |
| String path = | |
| _context.join(_workspace.root, packagePath, 'lib', filePath); | |
| File file = _workspace.findFile(path); | |
| return file?.createSource(uri); | |
| } | |
| }); | |
| } | |
| @override | |
| Uri restoreAbsolute(Source source) { | |
| Context context = _workspace.provider.pathContext; | |
| String path = source.fullName; | |
| Uri restore(String root, String path) { | |
| if (root != null && context.isWithin(root, path)) { | |
| String relative = context.relative(path, from: root); | |
| List<String> components = context.split(relative); | |
| if (components.length > 4 && | |
| components[0] == 'third_party' && | |
| components[1] == 'dart' && | |
| components[3] == 'lib') { | |
| String packageName = components[2]; | |
| String pathInLib = components.skip(4).join('/'); | |
| return Uri.parse('package:$packageName/$pathInLib'); | |
| } else { | |
| for (int i = 2; i < components.length - 1; i++) { | |
| String component = components[i]; | |
| if (component == 'lib') { | |
| String packageName = components.getRange(0, i).join('.'); | |
| String pathInLib = components.skip(i + 1).join('/'); | |
| return Uri.parse('package:$packageName/$pathInLib'); | |
| } | |
| } | |
| } | |
| } | |
| return null; | |
| } | |
| // Search in each root. | |
| for (String root in [ | |
| _workspace.bin, | |
| _workspace.genfiles, | |
| _workspace.readonly, | |
| _workspace.root | |
| ]) { | |
| Uri uri = restore(root, path); | |
| if (uri != null) { | |
| return uri; | |
| } | |
| } | |
| return null; | |
| } | |
| } | |
| /** | |
| * Information about a Bazel workspace. | |
| */ | |
| class BazelWorkspace extends Workspace { | |
| static const String _WORKSPACE = 'WORKSPACE'; | |
| static const String _READONLY = 'READONLY'; | |
| /** | |
| * Default prefix for "-genfiles" and "-bin" that will be assumed if no build | |
| * output symlinks are found. | |
| */ | |
| static const defaultSymlinkPrefix = 'bazel'; | |
| final ResourceProvider provider; | |
| /** | |
| * The absolute workspace root path. | |
| * | |
| * It contains the `WORKSPACE` file or its parent contains the `READONLY` | |
| * folder. | |
| */ | |
| final String root; | |
| /** | |
| * The absolute path to the optional read only workspace root, in the | |
| * `READONLY` folder if a git-based workspace, or `null`. | |
| */ | |
| final String readonly; | |
| /** | |
| * The absolute path to the `bazel-bin` folder. | |
| */ | |
| final String bin; | |
| /** | |
| * The absolute path to the `bazel-genfiles` folder. | |
| */ | |
| final String genfiles; | |
| BazelWorkspace._( | |
| this.provider, this.root, this.readonly, this.bin, this.genfiles); | |
| @override | |
| Map<String, List<Folder>> get packageMap => null; | |
| @override | |
| UriResolver get packageUriResolver => new BazelPackageUriResolver(this); | |
| @override | |
| SourceFactory createSourceFactory(DartSdk sdk) { | |
| List<UriResolver> resolvers = <UriResolver>[]; | |
| if (sdk != null) { | |
| resolvers.add(new DartUriResolver(sdk)); | |
| } | |
| resolvers.add(packageUriResolver); | |
| resolvers.add(new BazelFileUriResolver(this)); | |
| return new SourceFactory(resolvers, null, provider); | |
| } | |
| /** | |
| * Return the file with the given [absolutePath], looking first into | |
| * directories for generated files: `bazel-bin` and `bazel-genfiles`, and | |
| * then into the workspace root. The file in the workspace root is returned | |
| * even if it does not exist. Return `null` if the given [absolutePath] is | |
| * not in the workspace [root]. | |
| */ | |
| File findFile(String absolutePath) { | |
| Context context = provider.pathContext; | |
| try { | |
| String relative = context.relative(absolutePath, from: root); | |
| // genfiles | |
| if (genfiles != null) { | |
| File file = provider.getFile(context.join(genfiles, relative)); | |
| if (file.exists) { | |
| return file; | |
| } | |
| } | |
| // bin | |
| if (bin != null) { | |
| File file = provider.getFile(context.join(bin, relative)); | |
| if (file.exists) { | |
| return file; | |
| } | |
| } | |
| // Writable | |
| File writableFile = provider.getFile(absolutePath); | |
| if (writableFile.exists) { | |
| return writableFile; | |
| } | |
| // READONLY | |
| if (readonly != null) { | |
| File file = provider.getFile(context.join(readonly, relative)); | |
| if (file.exists) { | |
| return file; | |
| } | |
| } | |
| // Not generated, return the default one. | |
| return writableFile; | |
| } catch (_) { | |
| return null; | |
| } | |
| } | |
| /** | |
| * Find the Bazel workspace that contains the given [path]. | |
| * | |
| * Return `null` if a workspace markers, such as the `WORKSPACE` file, or | |
| * the sibling `READONLY` folder cannot be found. | |
| * | |
| * Return `null` if the workspace does not have `bazel-genfiles` or | |
| * `blaze-genfiles` folders, so we don't know where to search generated files. | |
| * | |
| * Return `null` if there is a folder 'foo' with the sibling `READONLY` | |
| * folder, but there is corresponding folder 'foo' in `READONLY`, i.e. the | |
| * corresponding readonly workspace root. | |
| */ | |
| static BazelWorkspace 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 READONLY folder, might be a git-based workspace. | |
| Folder readonlyFolder = parent.getChildAssumingFolder(_READONLY); | |
| if (readonlyFolder.exists) { | |
| String root = folder.path; | |
| String readonlyRoot = | |
| context.join(readonlyFolder.path, folder.shortName); | |
| if (provider.getFolder(readonlyRoot).exists) { | |
| String symlinkPrefix = _findSymlinkPrefix(provider, root); | |
| if (symlinkPrefix != null) { | |
| return new BazelWorkspace._( | |
| provider, | |
| root, | |
| readonlyRoot, | |
| context.join(root, '$symlinkPrefix-bin'), | |
| context.join(root, '$symlinkPrefix-genfiles')); | |
| } | |
| } | |
| } | |
| // Found the WORKSPACE file, must be a non-git workspace. | |
| if (folder.getChildAssumingFile(_WORKSPACE).exists) { | |
| String root = folder.path; | |
| String symlinkPrefix = _findSymlinkPrefix(provider, root); | |
| if (symlinkPrefix == null) { | |
| return null; | |
| } | |
| return new BazelWorkspace._( | |
| provider, | |
| root, | |
| null, | |
| context.join(root, '$symlinkPrefix-bin'), | |
| context.join(root, '$symlinkPrefix-genfiles')); | |
| } | |
| // Go up the folder. | |
| folder = parent; | |
| } | |
| } | |
| /** | |
| * Return the symlink prefix for folders `X-bin` or `X-genfiles` by probing | |
| * the internal `blaze-genfiles` and `bazel-genfiles`. Make a default | |
| * assumption according to defaultSymlinkPrefix if neither of the folders | |
| * exists. | |
| */ | |
| static String _findSymlinkPrefix(ResourceProvider provider, String root) { | |
| Context context = provider.pathContext; | |
| if (provider.getFolder(context.join(root, 'blaze-genfiles')).exists) { | |
| return 'blaze'; | |
| } | |
| if (provider.getFolder(context.join(root, 'bazel-genfiles')).exists) { | |
| return 'bazel'; | |
| } | |
| // Couldn't find it. Make a default assumption. | |
| return defaultSymlinkPrefix; | |
| } | |
| } |