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

lkishalmi 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 efe78c6  Option to skip CoS copying of class files when the target is 
already newer, such as from an external compilation (#504)
efe78c6 is described below

commit efe78c621c81b2f8d66402d94da62d1f9d6c447b
Author: Jesse Glick <jgl...@apache.org>
AuthorDate: Thu Oct 29 17:23:41 2020 -0400

    Option to skip CoS copying of class files when the target is already newer, 
such as from an external compilation (#504)
    
    * Issue #227791: skip CoS copying of class files when the target is already 
newer, such as from an external compilation.
    
    * Reducing log levels. INFO is too chatty.
    
    * Gating modified behavior with a system property
    
    * Trailing space
    
    * Stray space
    
    * Dead code
    
    * Documenting system property
    
    Co-authored-by: Jesse Glick <jgl...@netbeans.org>
---
 java/java.source.base/arch.xml                     |  42 +++++++-
 .../source/usages/BuildArtifactMapperImpl.java     | 118 +++++++++++++++------
 .../modules/maven/cos/CopyResourcesOnSave.java     |   3 +-
 .../org/netbeans/modules/maven/cos/CosChecker.java |   4 +-
 4 files changed, 129 insertions(+), 38 deletions(-)

diff --git a/java/java.source.base/arch.xml b/java/java.source.base/arch.xml
index d9b2d94..b23dbb7 100644
--- a/java/java.source.base/arch.xml
+++ b/java/java.source.base/arch.xml
@@ -803,9 +803,19 @@
         </question>
 -->
  <answer id="exec-property">
-  <p>
-   XXX no answer for exec-property
-  </p>
+  <ul>
+   <li>
+    <api type="export" group="systemproperty" 
name="org.netbeans.modules.java.source.usages.BuildArtifactMapperImpl.COMPARE_TIMESTAMPS"
 category="private">
+     <p>
+      If set to <code>true</code>,
+      <code>*.class</code> files generated by external build processes
+      will not be overwritten by the IDE’s Java parser
+      when running in “compile-on-save” mode
+      unless the class files are older than the corresponding source file.
+     </p>
+    </api>
+   </li>
+  </ul>
  </answer>
 
 
@@ -1308,4 +1318,30 @@
   </p>
  </answer>
 
+
+
+
+<!--
+        <question id="resources-preferences" when="final">
+            Does your module uses preferences via Preferences API? Does your 
module use NbPreferences or
+            or regular JDK Preferences ? Does it read, write or both ? 
+            Does it share preferences with other modules ? If so, then why ?
+            <hint>
+                You may use
+                    &lt;api type="export" group="preferences"
+                    name="preference node name" category="private"&gt;
+                    description of individual keys, where it is used, what it
+                    influences, whether the module reads/write it, etc.
+                    &lt;/api&gt;
+                Due to XML ID restrictions, rather than 
/org/netbeans/modules/foo give the "name" as org.netbeans.modules.foo.
+                Note that if you use NbPreferences this name will then be the 
same as the code name base of the module.
+            </hint>
+        </question>
+-->
+ <answer id="resources-preferences">
+  <p>
+   XXX no answer for resources-preferences
+  </p>
+ </answer>
+
 </api-answers>
diff --git 
a/java/java.source.base/src/org/netbeans/modules/java/source/usages/BuildArtifactMapperImpl.java
 
b/java/java.source.base/src/org/netbeans/modules/java/source/usages/BuildArtifactMapperImpl.java
index bff4a62..e4a046d 100644
--- 
a/java/java.source.base/src/org/netbeans/modules/java/source/usages/BuildArtifactMapperImpl.java
+++ 
b/java/java.source.base/src/org/netbeans/modules/java/source/usages/BuildArtifactMapperImpl.java
@@ -30,7 +30,9 @@ import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 import java.net.MalformedURLException;
 import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URL;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -97,7 +99,7 @@ public class BuildArtifactMapperImpl {
 //    private static final Map<URL, File> source2Target = new HashMap<URL, 
File>();
     private static final Map<URL, Set<ArtifactsUpdated>> source2Listener = new 
HashMap<URL, Set<ArtifactsUpdated>>();
 
-    private static final long MINIMAL_TIMESTAMP = 2000L;
+    private static final boolean COMPARE_TIMESTAMPS = 
Boolean.getBoolean(BuildArtifactMapperImpl.class.getName() + 
".COMPARE_TIMESTAMPS"); //NOI18N
 
     public static synchronized void addArtifactsUpdatedListener(URL 
sourceRoot, ArtifactsUpdated listener) {
         Set<ArtifactsUpdated> listeners = source2Listener.get(sourceRoot);
@@ -230,14 +232,21 @@ public class BuildArtifactMapperImpl {
         }
     }
     
-    private static void copyFile(File updatedFile, File target) throws 
IOException {
+    private static boolean copyFile(File updatedFile, File target, URL 
sourceFile) throws IOException {
         final File parent = target.getParentFile();
         if (parent != null && !parent.exists()) {
             if (!parent.mkdirs()) {
                 throw new IOException("Cannot create folder: " + 
parent.getAbsolutePath());
             }
         }
-            
+
+        if (targetNewerThanSourceFile(target, sourceFile)) {
+            LOG.log(Level.FINER, "#227791: declining to overwrite {0} with 
{1}", new Object[] {target, updatedFile});
+            return false;
+        } else {
+            LOG.log(Level.FINER, "#227791: proceeding to overwrite {0} with 
{1}", new Object[] {target, updatedFile});
+        }
+
         InputStream ins = null;
         OutputStream out = null;
 
@@ -246,9 +255,10 @@ public class BuildArtifactMapperImpl {
             out = new FileOutputStream(target);
 
             FileUtil.copy(ins, out);
-            //target.setLastModified(MINIMAL_TIMESTAMP); see 156153
+            return true;
         } catch (FileNotFoundException fnf) {
             LOG.log(Level.INFO, "Cannot open file.", fnf);   //NOI18N
+            return false;
         } finally {
             if (ins != null) {
                 try {
@@ -304,30 +314,31 @@ public class BuildArtifactMapperImpl {
         }
     }
 
-    private static void copyRecursively(File source, File target) throws 
IOException {
-        if (source.isDirectory()) {
-            if (target.exists() && !target.isDirectory()) {
-                throw new IOException("Cannot create folder: " + 
target.getAbsolutePath() + ", already exists as a file.");
-            }
+    private static void copyRecursively(File source, File target, URL 
sourceURL) throws IOException {
+        if (target.exists() && !target.isDirectory()) {
+            throw new IOException("Cannot create folder: " + 
target.getAbsolutePath() + ", already exists as a file.");
+        }
 
-            File[] listed = source.listFiles();
-            
-            if (listed == null) {
-                return ;
-            }
-            
-            for (File f : listed) {
-                String name = f.getName();
-                if (name.endsWith(SIG))
-                    name = name.substring(0, name.length() - 
FileObjects.SIG.length()) + FileObjects.CLASS;
-                copyRecursively(f, new File(target, name));
-            }
-        } else {
-            if (target.isDirectory()) {
-                throw new IOException("Cannot create file: " + 
target.getAbsolutePath() + ", already exists as a folder.");
-            }
+        File[] listed = source.listFiles();
 
-            copyFile(source, target);
+        if (listed == null) {
+            return ;
+        }
+
+        for (File f : listed) {
+            String name = f.getName();
+            if (name.endsWith(SIG))
+                name = name.substring(0, name.length() - 
FileObjects.SIG.length()) + FileObjects.CLASS;
+            File newTarget = new File(target, name);
+            if (f.isDirectory()) {
+                copyRecursively(f, newTarget, new URL(sourceURL, name + '/'));
+            } else {
+                if (newTarget.isDirectory()) {
+                    throw new IOException("Cannot create file: " + 
newTarget.getAbsolutePath() + ", already exists as a folder.");
+                }
+
+                copyFile(f, newTarget, new URL(sourceURL, name));
+            }
         }
     }
 
@@ -783,7 +794,8 @@ public class BuildArtifactMapperImpl {
                         return null;
                     }
 
-                    copyRecursively(index, targetFolder);
+                    LOG.log(Level.FINER, "#227791: copying {0} to {1} given 
sources in {2}", new Object[] {index, targetFolder, srURL});
+                    copyRecursively(index, targetFolder, srURL);
                 }
 
                 if (copyResources) {
@@ -837,8 +849,13 @@ public class BuildArtifactMapperImpl {
                 }
                 File toDelete = resolveFile(targetFolder, relPath);
 
-                toDelete.delete();
-                updatedFiles.add(toDelete);
+                if (targetNewerThanSourceFile(toDelete, new 
URL(ctx.getSourceRoot(), relPath))) {
+                    LOG.log(Level.FINER, "#227791: declining to delete {0}", 
toDelete);
+                } else {
+                    LOG.log(Level.FINER, "#227791: proceeding to delete {0}", 
toDelete);
+                    toDelete.delete();
+                    updatedFiles.add(toDelete);
+                }
             }
 
             for (File updatedFile : updated) {
@@ -853,8 +870,9 @@ public class BuildArtifactMapperImpl {
                 File target = resolveFile(targetFolder, relPath);              
          
 
                 try {
-                    copyFile(updatedFile, target);
-                    updatedFiles.add(target);
+                    if (copyFile(updatedFile, target, new 
URL(ctx.getSourceRoot(), relPath))) {
+                        updatedFiles.add(target);
+                    }
                 } catch (IOException ex) {
                     Exceptions.printStackTrace(ex);
                 }
@@ -877,7 +895,43 @@ public class BuildArtifactMapperImpl {
             return new File(targetFolder, TAG_UPDATE_RESOURCES).exists();
         }
     }
-    
+
+    private static boolean targetNewerThanSourceFile(File target, URL 
approximateSource) {
+        if (!COMPARE_TIMESTAMPS) {
+            LOG.finest("#227791: timestamp comparison disabled");
+            return false;
+        }
+        if (!"file".equals(approximateSource.getProtocol())) {
+            LOG.log(Level.FINER, "#227791: ignoring non-file-based source 
{0}", approximateSource);
+            return false;
+        }
+        if (!target.isFile()) {
+            LOG.log(Level.FINER, "#227791: {0} does not even exist", target);
+            return false;
+        }
+        long targetLastMod = target.lastModified();
+        File mockSrc;
+        try {
+            mockSrc = BaseUtilities.toFile(approximateSource.toURI());
+        } catch (URISyntaxException x) {
+            LOG.log(Level.FINER, "#227791: cannot convert " + 
approximateSource, x);
+            return false;
+        }
+        File src = new File(mockSrc.getParentFile(), 
mockSrc.getName().replaceFirst("([$].+)*[.]sig$", ".java"));
+        if (!src.isFile()) {
+            LOG.log(Level.FINER, "#227791: could not locate estimated source 
file {0}", src);
+            return false;
+        }
+        long sourceLastMod = src.lastModified();
+        if (targetLastMod > sourceLastMod) {
+            LOG.log(Level.FINE, "#227791: skipping delete/overwrite since {0} 
@{1,time,yyyy-MM-dd'T'HH:mm:ssZ} is newer than {2} 
@{3,time,yyyy-MM-dd'T'HH:mm:ssZ}", new Object[] {target, targetLastMod, src, 
sourceLastMod});
+            return true;
+        } else {
+            LOG.log(Level.FINER, "#227791: {0} 
@{1,time,yyyy-MM-dd'T'HH:mm:ssZ} is older than {2} 
@{3,time,yyyy-MM-dd'T'HH:mm:ssZ}", new Object[] {target, targetLastMod, src, 
sourceLastMod});
+            return false;
+        }
+    }
+
     @ServiceProvider(service = CompileOnSaveAction.Provider.class, position = 
Integer.MAX_VALUE)
     public static final class Provider implements CompileOnSaveAction.Provider 
{
         //@GuardedBy("normCache")
diff --git 
a/java/maven/src/org/netbeans/modules/maven/cos/CopyResourcesOnSave.java 
b/java/maven/src/org/netbeans/modules/maven/cos/CopyResourcesOnSave.java
index 36dd20a..7abbb9d 100644
--- a/java/maven/src/org/netbeans/modules/maven/cos/CopyResourcesOnSave.java
+++ b/java/maven/src/org/netbeans/modules/maven/cos/CopyResourcesOnSave.java
@@ -36,6 +36,7 @@ import org.apache.maven.model.Resource;
 import org.codehaus.plexus.util.DirectoryScanner;
 import org.netbeans.api.project.FileOwnerQuery;
 import org.netbeans.api.project.Project;
+import org.netbeans.modules.java.api.common.project.BaseActionProvider;
 import org.netbeans.modules.maven.api.FileUtilities;
 import org.netbeans.modules.maven.api.NbMavenProject;
 import org.netbeans.modules.maven.api.execute.RunUtils;
@@ -350,7 +351,7 @@ public class CopyResourcesOnSave extends FileChangeAdapter {
         FileObject target;
         //now figure the destination output folder
         File fil = nbproj.getOutputDirectory(test);
-        File stamp = new File(fil, CosChecker.NB_COS);
+        File stamp = new File(fil, BaseActionProvider.AUTOMATIC_BUILD_TAG);
         if (stamp.exists()) {
             target = FileUtil.toFileObject(fil);
         } else {
diff --git a/java/maven/src/org/netbeans/modules/maven/cos/CosChecker.java 
b/java/maven/src/org/netbeans/modules/maven/cos/CosChecker.java
index c1a59d8..3e024a5 100644
--- a/java/maven/src/org/netbeans/modules/maven/cos/CosChecker.java
+++ b/java/maven/src/org/netbeans/modules/maven/cos/CosChecker.java
@@ -41,6 +41,7 @@ import org.netbeans.api.project.Project;
 import org.netbeans.api.project.ProjectUtils;
 import org.netbeans.api.project.SourceGroup;
 import org.netbeans.api.project.ui.OpenProjects;
+import org.netbeans.modules.java.api.common.project.BaseActionProvider;
 import org.netbeans.modules.maven.ActionProviderImpl;
 import org.netbeans.modules.maven.api.Constants;
 import org.netbeans.modules.maven.api.NbMavenProject;
@@ -77,7 +78,6 @@ import org.openide.util.Utilities;
 @ProjectServiceProvider(service={PrerequisitesChecker.class, 
LateBoundPrerequisitesChecker.class}, projectType="org-netbeans-modules-maven")
 public class CosChecker implements PrerequisitesChecker, 
LateBoundPrerequisitesChecker {
 
-    static final String NB_COS = ".netbeans_automatic_build"; //NOI18N
     private static final Logger LOG = 
Logger.getLogger(CosChecker.class.getName());
     static final RequestProcessor RP = new RequestProcessor(CosChecker.class);
     // a maven property name denoting that the old, javarunner based execution 
is to be used.    
@@ -355,7 +355,7 @@ public class CosChecker implements PrerequisitesChecker, 
LateBoundPrerequisitesC
         }
         File fl = new File(path);
         fl = FileUtil.normalizeFile(fl);
-        return  new File(fl, NB_COS);
+        return new File(fl, BaseActionProvider.AUTOMATIC_BUILD_TAG);
     }
 
     /**


---------------------------------------------------------------------
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