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 + <api type="export" group="preferences" + name="preference node name" category="private"> + description of individual keys, where it is used, what it + influences, whether the module reads/write it, etc. + </api> + 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