This is an automated email from the ASF dual-hosted git repository.

sdedic pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 1715954033 Allow to find precise output folder for each language. 
(#4287)
1715954033 is described below

commit 1715954033e443c043f2e9845d449f4fbf70d883
Author: Svatopluk Dedic <svatopluk.de...@oracle.com>
AuthorDate: Mon Jul 11 10:56:40 2022 +0200

    Allow to find precise output folder for each language. (#4287)
    
    Allow to find precise output folder for each language.
---
 .../gradle/tooling/NbProjectInfoBuilder.java       | 96 +++++++++++++++++++---
 .../modules/gradle/cache/ProjectInfoDiskCache.java |  2 +-
 java/gradle.java/apichanges.xml                    | 13 +++
 java/gradle.java/manifest.mf                       |  2 +-
 .../gradle/java/api/GradleJavaProjectBuilder.java  |  5 ++
 .../gradle/java/api/GradleJavaSourceSet.java       | 26 ++++++
 .../gradle/java/queries/GradleSourceForBinary.java | 52 ++++++++++--
 7 files changed, 176 insertions(+), 20 deletions(-)

diff --git 
a/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NbProjectInfoBuilder.java
 
b/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NbProjectInfoBuilder.java
index 346fe53226..ff2e93c938 100644
--- 
a/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NbProjectInfoBuilder.java
+++ 
b/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NbProjectInfoBuilder.java
@@ -22,12 +22,14 @@ package org.netbeans.modules.gradle.tooling;
 import groovy.lang.MissingPropertyException;
 import java.io.File;
 import java.io.Serializable;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import static java.util.Arrays.asList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -58,6 +60,7 @@ import org.gradle.api.attributes.Attribute;
 import org.gradle.api.attributes.AttributeContainer;
 import org.gradle.api.distribution.DistributionContainer;
 import org.gradle.api.file.ConfigurableFileCollection;
+import org.gradle.api.file.DirectoryProperty;
 import org.gradle.api.initialization.IncludedBuild;
 import org.gradle.api.plugins.JavaPlatformPlugin;
 import org.gradle.api.specs.Specs;
@@ -267,6 +270,29 @@ class NbProjectInfoBuilder {
                 .forEach(e -> 
nbprops.put(e.getKey().substring(NB_PREFIX.length()), 
String.valueOf(e.getValue())));
         model.getInfo().put("nbprops", nbprops);
     }
+    
+    private Path longestPrefixPath(List<Path> files) {
+        if (files.size() < 2) {
+            return null;
+        }
+        Path first = files.get(0);
+        Path result = null;
+        Path root = first.getRoot();
+        int count = first.getNameCount();
+        for (int i = 1; i <= count; i++) {
+            Path match = root != null ? root.resolve(first.subpath(0, i)) : 
first.subpath(0, i);
+            
+            for (int pi = 1; pi < files.size(); pi++) {
+                Path p = files.get(pi);
+                if (!p.startsWith(match)) {
+                    return result;
+                }
+            }
+            result = match;
+        }
+        // if all paths (more than one) are the same, something is strange.
+        return null;
+    }
 
     private void detectSources(NbProjectInfoModel model) {
         long time = System.currentTimeMillis();
@@ -277,15 +303,36 @@ class NbProjectInfoBuilder {
         boolean hasKotlin = 
project.getPlugins().hasPlugin("org.jetbrains.kotlin.android") ||
                             
project.getPlugins().hasPlugin("org.jetbrains.kotlin.js") ||
                             
project.getPlugins().hasPlugin("org.jetbrains.kotlin.jvm");
-
+        Map<String, Boolean> available = new HashMap<>();
+        available.put("java", hasJava);
+        available.put("groovy", hasGroovy);
+        available.put("kotlin", hasKotlin);
+        
         if (hasJava) {
             SourceSetContainer sourceSets = (SourceSetContainer) 
getProperty(project, "sourceSets");
             if (sourceSets != null) {
                 model.getInfo().put("sourcesets", 
storeSet(sourceSets.getNames()));
                 for(SourceSet sourceSet: sourceSets) {
                     String propBase = "sourceset_" + sourceSet.getName() + "_";
+                    
+                    Set<File> outDirs = new LinkedHashSet<>();
+                    sinceGradle("4.0", () -> {
+                        // classesDirs is just an iterable
+                        for (File dir: (ConfigurableFileCollection) 
getProperty(sourceSet, "output", "classesDirs")) {
+                            outDirs.add(dir);
+                        }
+                    });
+                    beforeGradle("4.0", () -> {
+                        outDirs.add((File)getProperty(sourceSet, "output", 
"classesDir"));
+                    });
+                    
+                    List<Path> outPaths = 
outDirs.stream().map(File::toPath).collect(Collectors.toList());
+                    // find the longest common prefix:
+                    Path base = longestPrefixPath(outPaths);
+                    
                     for(String lang: new String[] {"JAVA", "GROOVY", "SCALA", 
"KOTLIN"}) {
-                        Task compileTask = 
project.getTasks().findByName(sourceSet.getCompileTaskName(lang.toLowerCase()));
+                        String langId = lang.toLowerCase();
+                        Task compileTask = 
project.getTasks().findByName(sourceSet.getCompileTaskName(langId));
                         if (compileTask != null) {
                             model.getInfo().put(
                                     propBase + lang + "_source_compatibility",
@@ -307,6 +354,39 @@ class NbProjectInfoBuilder {
                             }
                             model.getInfo().put(propBase + lang + 
"_compiler_args", new ArrayList<>(compilerArgs));
                         }
+                        if (Boolean.TRUE.equals(available.get(langId))) {
+                            model.getInfo().put(propBase + lang, 
storeSet(getProperty(sourceSet, langId, "srcDirs")));
+                            DirectoryProperty dirProp = 
(DirectoryProperty)getProperty(sourceSet, langId, "classesDirectory");
+                            if (dirProp != null) {
+                                File outDir;
+                                
+                                if (dirProp.isPresent()) {
+                                    outDir = dirProp.get().getAsFile();
+                                } else {
+                                    // kotlin plugin uses some weird late 
binding, so it has the output item, but it cannot be resolved to a 
+                                    // concrete file path at this time. Let's 
make an approximation from 
+                                    Path candidate = null;
+                                    if (base != null) {
+                                        Path prefix = base.resolve(langId);
+                                        // assume the language has just one 
output dir in the source set:
+                                        for (int i = 0; i < outPaths.size(); 
i++) {
+                                            Path p = outPaths.get(i);
+                                            if (p.startsWith(prefix)) {
+                                                if (candidate != null) {
+                                                    candidate = null;
+                                                    break;
+                                                } else {
+                                                    candidate = p;
+                                                }
+                                            }
+                                        }
+                                    }
+                                    outDir = candidate != null ? 
candidate.toFile() : new File("");
+                                }
+                                
+                                model.getInfo().put(propBase + lang + 
"_output_classes", outDir);
+                            }
+                        }
                     }
    
                     model.getInfo().put(propBase + "JAVA", 
storeSet(getProperty(sourceSet, "java", "srcDirs")));
@@ -320,17 +400,7 @@ class NbProjectInfoBuilder {
                     if (hasKotlin) {
                         model.getInfo().put(propBase + "KOTLIN", 
storeSet(getProperty(getProperty(sourceSet, "kotlin"), "srcDirs")));
                     }
-                    sinceGradle("4.0", () -> {
-                        Set<File> dirs = new LinkedHashSet<>();
-                        // classesDirs is just an iterable
-                        for (File dir: (ConfigurableFileCollection) 
getProperty(sourceSet, "output", "classesDirs")) {
-                            dirs.add(dir);
-                        }
-                        model.getInfo().put(propBase + "output_classes", dirs);
-                    });
-                    beforeGradle("4.0", () -> {
-                        model.getInfo().put(propBase + "output_classes", 
Collections.singleton(getProperty(sourceSet, "output", "classesDir")));
-                    });
+                    model.getInfo().put(propBase + "output_classes", outDirs);
                     model.getInfo().put(propBase + "output_resources", 
sourceSet.getOutput().getResourcesDir());
                     sinceGradle("5.2", () -> {
                         model.getInfo().put(propBase + "GENERATED", 
storeSet(getProperty(sourceSet, "output", "generatedSourcesDirs", "files")));
diff --git 
a/extide/gradle/src/org/netbeans/modules/gradle/cache/ProjectInfoDiskCache.java 
b/extide/gradle/src/org/netbeans/modules/gradle/cache/ProjectInfoDiskCache.java
index 127130c78d..b28c2902dc 100644
--- 
a/extide/gradle/src/org/netbeans/modules/gradle/cache/ProjectInfoDiskCache.java
+++ 
b/extide/gradle/src/org/netbeans/modules/gradle/cache/ProjectInfoDiskCache.java
@@ -45,7 +45,7 @@ import org.netbeans.modules.gradle.spi.GradleFiles;
 public final class ProjectInfoDiskCache extends AbstractDiskCache<GradleFiles, 
QualifiedProjectInfo> {
 
     // Increase this number if new info is gathered from the projects.
-    private static final int COMPATIBLE_CACHE_VERSION = 22;
+    private static final int COMPATIBLE_CACHE_VERSION = 23;
     private static final String INFO_CACHE_FILE_NAME = "project-info.ser"; 
//NOI18N
     private static final Map<GradleFiles, ProjectInfoDiskCache> DISK_CACHES = 
Collections.synchronizedMap(new WeakHashMap<>());
 
diff --git a/java/gradle.java/apichanges.xml b/java/gradle.java/apichanges.xml
index f77b1ba1bd..dfd5b57876 100644
--- a/java/gradle.java/apichanges.xml
+++ b/java/gradle.java/apichanges.xml
@@ -83,6 +83,19 @@ is the proper place.
     <!-- ACTUAL CHANGES BEGIN HERE: -->
 
     <changes>
+        <change id="sourceset-lang-output">
+            <api name="gradle.java.api"/>
+            <summary>Support for per-language output directories</summary>
+            <version major="1" minor="19"/>
+            <date day="28" month="6" year="2022"/>
+            <author login="sdedic"/>
+            <compatibility semantic="compatible" addition="yes" 
deprecation="no"/>
+            <description>
+                Each language plugin typically generates output to a specific 
directory. The mapping
+                allows more precise output-to-source mapping.
+            </description>
+            <class package="org.netbeans.modules.gradle.java.api" 
name="GradleJavaSourceSet"/>
+        </change>
         <change id="nested-class-locations">
             <api name="gradle.java.api"/>
             <summary>Location can represent nested classes</summary>
diff --git a/java/gradle.java/manifest.mf b/java/gradle.java/manifest.mf
index 6a3ea04484..e378d4e486 100644
--- a/java/gradle.java/manifest.mf
+++ b/java/gradle.java/manifest.mf
@@ -3,4 +3,4 @@ AutoUpdate-Show-In-Client: false
 OpenIDE-Module: org.netbeans.modules.gradle.java
 OpenIDE-Module-Layer: org/netbeans/modules/gradle/java/layer.xml
 OpenIDE-Module-Localizing-Bundle: 
org/netbeans/modules/gradle/java/Bundle.properties
-OpenIDE-Module-Specification-Version: 1.18
+OpenIDE-Module-Specification-Version: 1.19
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaProjectBuilder.java
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaProjectBuilder.java
index cc0136ac25..652b2eca17 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaProjectBuilder.java
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaProjectBuilder.java
@@ -99,6 +99,11 @@ final class GradleJavaProjectBuilder implements 
ProjectInfoExtractor.Result {
                     if (compArgs != null) {
                         compilerArgs.put(lang, 
Collections.unmodifiableList(compArgs));
                     }
+                    // if detected, note the output dirs for individual 
language(s).
+                    File f = (File)info.get("sourceset_" + name + "_" + 
lang.name() + "_output_classes");
+                    if (f != null) {
+                        sourceSet.outputs.put(lang, f);
+                    }
                 }
                 sourceSet.sourcesCompatibility = 
Collections.unmodifiableMap(sourceComp);
                 sourceSet.targetCompatibility = 
Collections.unmodifiableMap(targetComp);
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaSourceSet.java
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaSourceSet.java
index 061348190d..fad03f4e87 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaSourceSet.java
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaSourceSet.java
@@ -78,6 +78,7 @@ public final class GradleJavaSourceSet implements 
Serializable {
     private static final String DEFAULT_SOURCE_COMPATIBILITY = "1.5"; //NOI18N
 
     Map<SourceType, Set<File>> sources = new EnumMap<>(SourceType.class);
+    Map<SourceType, File> outputs = new EnumMap<>(SourceType.class);
     String name;
     String runtimeConfigurationName;
     String compileConfigurationName;
@@ -365,6 +366,31 @@ public final class GradleJavaSourceSet implements 
Serializable {
     public Set<File> getOutputClassDirs() {
         return outputClassDirs != null ? outputClassDirs : 
Collections.<File>emptySet();
     }
+    
+    /**
+     * Represents an unknown value. This is different from a value that is not 
present,
+     * i.e. an output directory for a language that is not used in the project.
+     * @since 1.19
+     */
+    public static final File UNKNOWN = new File("");
+    
+    /**
+     * Returns output directories for the given source type in the sourceset. 
Returns
+     * null, if the source type has no output directories. Returns UNKNOWN, if 
the 
+     * output location is not known.
+     * 
+     * @param srcType language type
+     * @return location or {@code null}.
+     * @since 1.19
+     */
+    public File getOutputClassDir(SourceType srcType) {
+        File f = outputs.get(srcType);
+        if (UNKNOWN.equals(f)) {
+            // make the value canonical, so == can be used.
+            return UNKNOWN;
+        }
+        return f;
+    }
 
     /**
      * Return the directory of resources output.
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/queries/GradleSourceForBinary.java
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/queries/GradleSourceForBinary.java
index e27921c790..962f079351 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/queries/GradleSourceForBinary.java
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/queries/GradleSourceForBinary.java
@@ -32,6 +32,7 @@ import java.io.File;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.EnumMap;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.List;
@@ -53,13 +54,49 @@ import org.openide.util.WeakListeners;
  * @author Laszlo Kishalmi
  */
 public class GradleSourceForBinary implements 
SourceForBinaryQueryImplementation2 {
+    
+    private static Map<SourceType, String> sourceMimeTypes = new 
EnumMap<>(SourceType.class);
+    
+    static {
+        sourceMimeTypes.put(JAVA, "text/x-java");
+        sourceMimeTypes.put(GROOVY, "text/x-groovy");
+        sourceMimeTypes.put(SCALA, "text/x-scala");
+        sourceMimeTypes.put(KOTLIN, "text/x-kotlin");
+    }
 
     private final Project project;
     private final Map<URL, Res> cache = new HashMap<>();
-
+    
     public GradleSourceForBinary(Project project) {
         this.project = project;
     }
+    
+    private static final EnumSet<SourceType> ALL_LANGUAGES;
+    
+    static {
+        EnumSet<SourceType> s = EnumSet.allOf(SourceType.class);
+        s.remove(SourceType.RESOURCES);
+        s.remove(SourceType.GENERATED);
+        
+        ALL_LANGUAGES = s;
+    }
+    
+    private Result languageSourceForOutput(GradleJavaSourceSet ss, File 
outputDir) {
+        
+        for (SourceType st : ALL_LANGUAGES) {
+            File f = ss.getOutputClassDir(st);
+            if (outputDir.equals(f)) {
+                // special case for java here; Java replaces its classpath 
entries by corresponding cache entries with
+                // indexed sources (.sig files) so that it tracks not compiled 
source changes. Other languages do not generate
+                // the expected files.
+                // The proper solution will be to change java implementation 
to use output folder as a fallback if nothing
+                // is found in the cache; then this special case may be 
removed.
+                boolean canPreferSource = st == SourceType.JAVA;
+                return new Res(project, ss.getName(), EnumSet.of(RESOURCES), 
canPreferSource);
+            }
+        }
+        return new Res(project, ss.getName(), ALL_LANGUAGES, false);
+    }
 
     @Override
     public Result findSourceRoots2(URL binaryRoot) {
@@ -76,8 +113,7 @@ public class GradleSourceForBinary implements 
SourceForBinaryQueryImplementation
                                 File outputDir = 
ss.getCompilerArgs(JAVA).contains("--module-source-path") ? //NOI18N
                                         root.getParentFile() : root;
                                 if 
(ss.getOutputClassDirs().contains(outputDir)) {
-                                    ret = new Res(project, ss.getName(), 
EnumSet.of(JAVA, GROOVY, SCALA, KOTLIN, GENERATED));
-                                    break;
+                                    return languageSourceForOutput(ss, 
outputDir);
                                 }
                                 if ((ret == null) && 
root.equals(ss.getOutputResources())) {
                                     ret = new Res(project, ss.getName(), 
EnumSet.of(RESOURCES));
@@ -122,11 +158,17 @@ public class GradleSourceForBinary implements 
SourceForBinaryQueryImplementation
         private final Set<SourceType> sourceTypes;
         private final PropertyChangeListener listener;
         private final ChangeSupport support = new ChangeSupport(this);
-
+        private final boolean preferSources;
+        
         public Res(Project project, String sourceSet, Set<SourceType> 
sourceTypes) {
+            this(project, sourceSet, sourceTypes, true);
+        }
+
+        public Res(Project project, String sourceSet, Set<SourceType> 
sourceTypes, boolean preferSources) {
             this.project = project;
             this.sourceSet = sourceSet;
             this.sourceTypes = sourceTypes;
+            this.preferSources = preferSources;
             listener = (PropertyChangeEvent evt) -> {
                 if 
(NbGradleProject.PROP_PROJECT_INFO.equals(evt.getPropertyName())) {
                     support.fireChange();
@@ -137,7 +179,7 @@ public class GradleSourceForBinary implements 
SourceForBinaryQueryImplementation
 
         @Override
         public boolean preferSources() {
-            return true;
+            return preferSources;
         }
 
         @Override


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org
For additional commands, e-mail: commits-h...@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to