Skip to content

Commit

Permalink
Sources of binary dependencies are available to NetBeans just like wi…
Browse files Browse the repository at this point in the history
…th the Maven plugin.
  • Loading branch information
kelemen committed Aug 14, 2012
1 parent 3c04d21 commit da9ddf1
Show file tree
Hide file tree
Showing 12 changed files with 581 additions and 40 deletions.
2 changes: 0 additions & 2 deletions readme.md
Expand Up @@ -59,5 +59,3 @@ Current Limitations
tasks will be needed to make the project really usable. Also global custom tasks
like with the Maven plugin would be nice as well. Allowing to execute custom tasks
is relatively straightforward to implement.
- Sources for dependencies cannot be downloaded nor attached. This could only
be implemented like in the Maven plugin if the tooling API is updated.
27 changes: 26 additions & 1 deletion src/org/netbeans/gradle/project/GradleBinaryForSourceQuery.java
Expand Up @@ -2,6 +2,7 @@

import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -10,9 +11,11 @@
import java.util.logging.Logger;
import javax.swing.event.ChangeListener;
import org.netbeans.api.java.queries.BinaryForSourceQuery;
import org.netbeans.gradle.project.model.NbDependencyGroup;
import org.netbeans.gradle.project.model.NbGradleModule;
import org.netbeans.gradle.project.model.NbModelUtils;
import org.netbeans.gradle.project.model.NbSourceType;
import org.netbeans.gradle.project.model.NbUriDependency;
import org.netbeans.spi.java.queries.BinaryForSourceQueryImplementation;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
Expand Down Expand Up @@ -77,6 +80,28 @@ private static URL[] getTestBinariesOfModule(NbGradleModule module) {
return NO_ROOTS;
}

private static URL[] getDependencyBinaries(NbGradleModule module, FileObject root) {
for (NbDependencyGroup dependency: module.getDependencies().values()) {
for (NbUriDependency uriDep: dependency.getUriDependencies()) {
URI srcUri = uriDep.getSrcUri();
if (srcUri != null) {
FileObject srcRoot = NbModelUtils.uriToFileObject(srcUri);
if (srcRoot != null && srcRoot.equals(root)) {
try {
return new URL[]{uriDep.getUri().toURL()};
} catch (MalformedURLException ex) {
// This should not happend but we cannot do anything
// in this case.
LOGGER.log(Level.SEVERE, "Cannot convert URI to URL: " + uriDep.getUri(), ex);
return null;
}
}
}
}
}
return null;
}

private static URL[] tryGetRoots(
NbGradleModule module, FileObject root) {
SourceType sourceType = getSourceRootType(module, root);
Expand All @@ -86,7 +111,7 @@ private static URL[] tryGetRoots(
case TEST:
return getTestBinariesOfModule(module);
case UNKNOWN:
return null;
return getDependencyBinaries(module, root);
default:
throw new AssertionError(sourceType.name());

Expand Down
125 changes: 125 additions & 0 deletions src/org/netbeans/gradle/project/GradleCacheBinaryForSourceQuery.java
@@ -0,0 +1,125 @@
package org.netbeans.gradle.project;

import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeListener;
import org.netbeans.api.java.queries.BinaryForSourceQuery.Result;
import org.netbeans.spi.java.queries.BinaryForSourceQueryImplementation;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.ChangeSupport;
import org.openide.util.lookup.ServiceProvider;
import org.openide.util.lookup.ServiceProviders;

@ServiceProviders({@ServiceProvider(service = BinaryForSourceQueryImplementation.class)})
public final class GradleCacheBinaryForSourceQuery implements BinaryForSourceQueryImplementation {
private static final URL[] NO_ROOTS = new URL[0];
private static final ChangeSupport CHANGES = new ChangeSupport(ChangeSupport.class);

// This cache cannot shrink because SourceForBinaryQueryImplementation
// requires that we return the exact same object when the same URL is
// querried. This is a very limiting constraint but I don't want to risk to
// violate the constraint.
private final ConcurrentMap<FileObject, Result> cache;

public GradleCacheBinaryForSourceQuery() {
this.cache = new ConcurrentHashMap<FileObject, Result>();
}

public static void notifyCacheChange() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
CHANGES.fireChange();
}
});
}

@Override
public Result findBinaryRoots(URL sourceRoot) {
if (GradleFileUtils.GRADLE_CACHE_HOME == null) {
return null;
}

File sourceRootFile = FileUtil.archiveOrDirForURL(sourceRoot);
if (sourceRootFile == null) {
return null;
}
final FileObject sourceRootObj = FileUtil.toFileObject(sourceRootFile);
if (sourceRootObj == null) {
return null;
}

Result result = cache.get(sourceRootObj);
if (result != null) {
return result;
}

FileObject cacheHome = FileUtil.toFileObject(GradleFileUtils.GRADLE_CACHE_HOME);
if (cacheHome == null || !FileUtil.isParentOf(cacheHome, sourceRootObj)) {
return null;
}

result = new Result() {
@Override
public URL[] getRoots() {
// The cache directory of Gradle looks like this:
//
// ...... \\source\\HASH_OF_SOURCE\\binary-sources.jar
// ...... \\jar\\HASH_OF_BINARY\\binary.jar
FileObject hashDir = sourceRootObj.getParent();
if (hashDir == null) {
return NO_ROOTS;
}

FileObject srcDir = hashDir.getParent();
if (srcDir == null) {
return NO_ROOTS;
}

if (!GradleFileUtils.SOURCE_DIR_NAME.equals(srcDir.getNameExt())) {
return NO_ROOTS;
}

FileObject artifactRoot = srcDir.getParent();
if (artifactRoot == null) {
return NO_ROOTS;
}

FileObject binDir = artifactRoot.getFileObject(GradleFileUtils.BINARY_DIR_NAME);
if (binDir == null) {
return NO_ROOTS;
}

String binFileName = GradleFileUtils.sourceToBinaryName(sourceRootObj);
if (binFileName == null) {
return NO_ROOTS;
}

FileObject binFile = GradleFileUtils.getFileFromASubDir(binDir, binFileName);
if (binFile != null) {
return new URL[]{binFile.toURL()};
}
else {
return NO_ROOTS;
}
}

@Override
public void addChangeListener(ChangeListener l) {
CHANGES.addChangeListener(l);
}

@Override
public void removeChangeListener(ChangeListener l) {
CHANGES.removeChangeListener(l);
}
};

Result oldResult = cache.putIfAbsent(sourceRootObj, result);
return oldResult != null ? oldResult : result;
}
}
133 changes: 133 additions & 0 deletions src/org/netbeans/gradle/project/GradleCacheSourceForBinaryQuery.java
@@ -0,0 +1,133 @@
package org.netbeans.gradle.project;

import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeListener;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation;
import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.ChangeSupport;
import org.openide.util.lookup.ServiceProvider;
import org.openide.util.lookup.ServiceProviders;

@ServiceProviders({
@ServiceProvider(service = SourceForBinaryQueryImplementation2.class),
@ServiceProvider(service = SourceForBinaryQueryImplementation.class)})
public final class GradleCacheSourceForBinaryQuery implements SourceForBinaryQueryImplementation2 {
private static final FileObject[] NO_ROOTS = new FileObject[0];
private static final ChangeSupport CHANGES = new ChangeSupport(ChangeSupport.class);

// This cache cannot shrink because SourceForBinaryQueryImplementation
// requires that we return the exact same object when the same URL is
// querried. This is a very limiting constraint but I don't want to risk to
// violate the constraint.
private final ConcurrentMap<FileObject, Result> cache;

public GradleCacheSourceForBinaryQuery() {
this.cache = new ConcurrentHashMap<FileObject, Result>();
}

public static void notifyCacheChange() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
CHANGES.fireChange();
}
});
}

@Override
public Result findSourceRoots2(URL binaryRoot) {
if (GradleFileUtils.GRADLE_CACHE_HOME == null) {
return null;
}

File binaryRootFile = FileUtil.archiveOrDirForURL(binaryRoot);
if (binaryRootFile == null) {
return null;
}
final FileObject binaryRootObj = FileUtil.toFileObject(binaryRootFile);
if (binaryRootObj == null) {
return null;
}

Result result = cache.get(binaryRootObj);
if (result != null) {
return result;
}

FileObject cacheHome = FileUtil.toFileObject(GradleFileUtils.GRADLE_CACHE_HOME);
if (cacheHome == null || !FileUtil.isParentOf(cacheHome, binaryRootObj)) {
return null;
}

result = new Result() {
@Override
public boolean preferSources() {
return false;
}

@Override
public FileObject[] getRoots() {
// The cache directory of Gradle looks like this:
//
// ...... \\source\\HASH_OF_SOURCE\\binary-sources.jar
// ...... \\jar\\HASH_OF_BINARY\\binary.jar
FileObject hashDir = binaryRootObj.getParent();
if (hashDir == null) {
return NO_ROOTS;
}

FileObject binDir = hashDir.getParent();
if (binDir == null) {
return NO_ROOTS;
}

if (!GradleFileUtils.BINARY_DIR_NAME.equals(binDir.getNameExt())) {
return NO_ROOTS;
}

FileObject artifactRoot = binDir.getParent();
if (artifactRoot == null) {
return NO_ROOTS;
}

FileObject srcDir = artifactRoot.getFileObject(GradleFileUtils.SOURCE_DIR_NAME);
if (srcDir == null) {
return NO_ROOTS;
}

String sourceFileName = GradleFileUtils.binaryToSourceName(binaryRootObj);
if (sourceFileName == null) {
return NO_ROOTS;
}

FileObject srcFile = GradleFileUtils.getFileFromASubDir(srcDir, sourceFileName);
return srcFile != null ? new FileObject[]{srcFile} : NO_ROOTS;
}

@Override
public void addChangeListener(ChangeListener l) {
CHANGES.addChangeListener(l);
}

@Override
public void removeChangeListener(ChangeListener l) {
CHANGES.removeChangeListener(l);
}
};

Result oldResult = cache.putIfAbsent(binaryRootObj, result);
return oldResult != null ? oldResult : result;
}

@Override
public SourceForBinaryQuery.Result findSourceRoots(URL binaryRoot) {
return findSourceRoots2(binaryRoot);
}
}
29 changes: 22 additions & 7 deletions src/org/netbeans/gradle/project/GradleClassPathProvider.java
Expand Up @@ -15,6 +15,7 @@
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.classpath.JavaClassPathConstants;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.gradle.project.model.NbDependency;
import org.netbeans.gradle.project.model.NbDependencyType;
Expand Down Expand Up @@ -65,14 +66,23 @@ private ClassPath getPaths(ClassPathType classPathType) {
return result;
}

public ClassPath getSourcePaths() {
public ClassPath getClassPaths(String type) {
// Test paths contain all paths
return getPaths(ClassPathType.SOURCES_FOR_TEST);
}

public ClassPath getCompilePaths() {
// Test paths contain all paths
return getPaths(ClassPathType.COMPILE_FOR_TEST);
if (ClassPath.SOURCE.equals(type)) {
return getPaths(ClassPathType.SOURCES_FOR_TEST);
}
else if (ClassPath.BOOT.equals(type)) {
return getPaths(ClassPathType.BOOT_FOR_TEST);
}
else if (ClassPath.COMPILE.equals(type)) {
return getPaths(ClassPathType.COMPILE_FOR_TEST);
}
else if (ClassPath.EXECUTE.equals(type)) {
return getPaths(ClassPathType.RUNTIME_FOR_TEST);
}
else {
return ClassPath.EMPTY;
}
}

@Override
Expand Down Expand Up @@ -173,6 +183,11 @@ else if (ClassPath.EXECUTE.equals(type)) {
? ClassPathType.RUNTIME_FOR_TEST
: ClassPathType.RUNTIME;
}
else if (JavaClassPathConstants.PROCESSOR_PATH.equals(type)) {
return fileType.isTest()
? ClassPathType.COMPILE_FOR_TEST
: ClassPathType.COMPILE;
}

return null;
}
Expand Down

0 comments on commit da9ddf1

Please sign in to comment.