blob: b6e284618dba8dadc5cf2922699a62c05d89393e [file] [log] [blame]
/*
* 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.server.generated.types.RequestError;
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.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;
}
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")) {
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;
}
}