/* * Copyright (c) 2014, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.debug.core.source; import com.google.common.collect.Maps; import com.google.common.util.concurrent.Uninterruptibles; import com.google.dart.server.CreateContextConsumer; import com.google.dart.server.MapUriConsumer; import com.google.dart.tools.core.DartCore; import com.google.dart.tools.core.DartCoreDebug; import com.google.dart.tools.core.analysis.model.IFileInfo; import com.google.dart.tools.core.analysis.model.ProjectManager; import com.google.dart.tools.core.internal.util.ResourceUtil; import com.google.dart.tools.debug.core.DartLaunchConfigWrapper; import org.dartlang.analysis.server.protocol.RequestError; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import java.io.File; import java.net.URI; import java.net.URISyntaxException; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * A helper for converting URIs to files paths and vice versa. */ public class UriToFileResolver { private IContainer container; private final Map<String, String> urlToFileCache = Maps.newHashMap(); private final Map<String, String> fileToUriCache = Maps.newHashMap(); private String executionContextId; public UriToFileResolver(ILaunch launch) { ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration(); DartLaunchConfigWrapper wrapper = new DartLaunchConfigWrapper(launchConfiguration); container = wrapper.getSourceDirectory(); if (container == null) { IResource resource = wrapper.getApplicationResource(); if (resource instanceof IContainer) { container = resource.getParent(); } else if (resource != null) { container = resource.getParent(); } } String resourcePath = container != null ? container.getLocation().toOSString() : null; // create an execution context if (DartCoreDebug.ENABLE_ANALYSIS_SERVER && resourcePath != null) { DartCore.getAnalysisServer().execution_createContext( resourcePath, new CreateContextConsumer() { @Override public void computedExecutionContext(String contextId) { executionContextId = contextId; } @Override public void onError(RequestError requestError) { } }); } } public void dispose() { // delete the execution context if (DartCoreDebug.ENABLE_ANALYSIS_SERVER && executionContextId != null) { DartCore.getAnalysisServer().execution_deleteContext(executionContextId); executionContextId = null; } } public String getFileForUri(String url) { if (container == null) { return null; } String file = urlToFileCache.get(url); if (file == null) { file = getFileForUri0(url); urlToFileCache.put(url, file); } return file; } public String getUriForPath(String file) { if (container == null) { return null; } String uri = fileToUriCache.get(file); if (uri == null) { uri = getUriForPath0(file); fileToUriCache.put(file, uri); } return uri; } private String getFileForUri0(String url) { final String chromeExt = "chrome-extension://"; try { String filePath; // /Users/foo/dart/serverapp/serverapp.dart // file:///Users/foo/dart/webapp2/webapp2.dart // http://0.0.0.0:3030/webapp/webapp.dart // package:abc/abc.dart // chrome-extension://kcjgcakhgelcejampmijgkjkadfcncjl/spark.dart // resolve package: urls to file: urls if (DartCore.isPackageSpec(url)) { url = resolvePackageUri(url); } if (url == null) { return null; } // Special case Chrome extension paths. if (url.startsWith(chromeExt)) { url = url.substring(chromeExt.length()); if (url.indexOf('/') != -1) { url = url.substring(url.indexOf('/') + 1); } } if (url.startsWith("/")) { return url; } // for windows filepaths // C:\Users\dgluxjs_light2\dgluxjs_light2\lib\designer\dg_designer_mediators.dart if (DartCore.isWindows() && url.matches("(?i)[A-Z]:.*")) { return url; } URI uri = new URI(url); String uriScheme = uri.getScheme(); // handle dart:lib/lib.dart in DartSdkSourceContainer, // exclude "_patch.dart" files, they don't exist as files in sdk/lib folder if (uri != null && "dart".equals(uriScheme)) { if (!url.endsWith("_patch.dart") && !(url.contains("-patch"))) { return url; } } // Handle both fully absolute path names and http: urls. if (uriScheme == null) { // handle relative file path filePath = resolveRelativePath(url); } else { filePath = uri.getPath(); } if (filePath == null) { return null; } else { return returnAbsoluteOrRelative(filePath); } } catch (URISyntaxException e) { return null; } } /** * It seems that {@link ProjectManager#resolvePathToPackage} works only in limited cases. So, here * is a copy of another implementation. */ private String getUriForPath_fromServerBreakpointManager(String filePath) { File javaFile = new File(filePath); IFile resourceFile = ResourceUtil.getFile(javaFile); if (resourceFile == null) { return null; } String locationUrl = resourceFile.getLocation().toFile().toURI().toString(); int index = locationUrl.indexOf(DartCore.PACKAGES_DIRECTORY_URL); if (index != -1) { locationUrl = DartCore.PACKAGE_SCHEME_SPEC + locationUrl.substring(index + DartCore.PACKAGES_DIRECTORY_URL.length()); return locationUrl; } index = locationUrl.lastIndexOf(DartCore.LIB_URL_PATH); if (index != -1) { String path = resourceFile.getLocation().toString(); path = path.substring(0, path.lastIndexOf(DartCore.LIB_URL_PATH)); File packagesDir = new File(path, DartCore.PACKAGES_DIRECTORY_NAME); if (packagesDir.exists()) { String packageName = DartCore.getSelfLinkedPackageName(resourceFile); if (packageName != null) { locationUrl = DartCore.PACKAGE_SCHEME_SPEC + packageName + "/" + locationUrl.substring(index + DartCore.LIB_URL_PATH.length()); return locationUrl; } } } return null; } private String getUriForPath0(String file) { if (DartCoreDebug.ENABLE_ANALYSIS_SERVER) { if (executionContextId != null) { final String[] uriPtr = {null}; final CountDownLatch latch = new CountDownLatch(1); DartCore.getAnalysisServer().execution_mapUri( executionContextId, file, null, new MapUriConsumer() { @Override public void computedFileOrUri(String file, String uri) { uriPtr[0] = uri; latch.countDown(); } @Override public void onError(RequestError requestError) { latch.countDown(); } }); Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.SECONDS); return uriPtr[0]; } } else { { String uri = getUriForPath_fromServerBreakpointManager(file); if (uri != null) { return uri; } } return DartCore.getProjectManager().resolvePathToPackage(container, file); } return null; } private String resolvePackageUri(String url) { if (DartCoreDebug.ENABLE_ANALYSIS_SERVER) { if (executionContextId != null) { final String[] filePtr = {null}; final CountDownLatch latch = new CountDownLatch(1); DartCore.getAnalysisServer().execution_mapUri( executionContextId, null, url, new MapUriConsumer() { @Override public void computedFileOrUri(String file, String uri) { filePtr[0] = file; latch.countDown(); } @Override public void onError(RequestError requestError) { latch.countDown(); } }); Uninterruptibles.awaitUninterruptibly(latch, 1, TimeUnit.SECONDS); return filePtr[0]; } } else { ProjectManager projectManager = DartCore.getProjectManager(); IFileInfo fileInfo = projectManager.resolveUriToFileInfo(container, url); if (fileInfo != null) { // Return the workspace relative file, if there is one. if (fileInfo.getResource() != null) { return fileInfo.getResource().getLocationURI().toString(); } else { File file = fileInfo.getFile(); File absoluteFile = file.getAbsoluteFile(); return absoluteFile.toURI().toString(); } } } return null; } private String resolveRelativePath(String url) { if (container != null) { IResource file = container.findMember(url); if (file == null) { file = container.getProject().findMember(url); } if (file != null) { return file.getLocation().toOSString(); } } return null; } private String returnAbsoluteOrRelative(String path) { // If path exists, return that. File file = new File(path); if (file.exists()) { return path; } // Try and return a path relative to the resource. if (container != null) { int index = path.indexOf('/'); while (index != -1) { String subPath = path.substring(index + 1); IResource resource = container.findMember(subPath); if (resource != null) { return resource.getLocation().toFile().getAbsolutePath(); } index = path.indexOf('/', index + 1); } } // Else, return the original path. return path; } }