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 ad99e85b26 #5978: Maven/priming optimization (#5998)
ad99e85b26 is described below
commit ad99e85b260eb029462b4c3ae2cef022b1541b61
Author: Svatopluk Dedic <[email protected]>
AuthorDate: Wed Jun 14 09:25:44 2023 -0700
#5978: Maven/priming optimization (#5998)
#5978: priming builds are serialized, and check the updated model before
maven exec
---
.../netbeans/modules/nbcode/integration/layer.xml | 9 ++
.../modules/nbcode/integration/maven.properties | 19 +++
.../modules/java/lsp/server/protocol/Server.java | 7 +-
.../lsp/server/protocol/WorkspaceServiceImpl.java | 3 +
.../netbeans/modules/maven/NbMavenProjectImpl.java | 27 +++-
.../maven/problems/MavenModelProblemsProvider.java | 149 +++++++++++++++------
.../maven/problems/ProblemReporterImpl.java | 18 +++
.../modules/maven/problems/SanityBuildAction.java | 43 ++++--
8 files changed, 216 insertions(+), 59 deletions(-)
diff --git
a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
index 9bd333789a..44b70b59dd 100644
---
a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
+++
b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
@@ -21,6 +21,15 @@
-->
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN"
"http://www.netbeans.org/dtds/filesystem-1_2.dtd">
<filesystem>
+ <folder name="Preferences">
+ <folder name="org">
+ <folder name="netbeans">
+ <folder name="modules">
+ <file name="maven.properties" url="maven.properties"/>
+ </folder>
+ </folder>
+ </folder>
+ </folder>
<folder name="Services">
<folder name="NBLS">
<file name="general-node-commands.instance">
diff --git
a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/maven.properties
b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/maven.properties
new file mode 100644
index 0000000000..aca4699843
--- /dev/null
+++
b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/maven.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+
+primingBuild.snapshot.goals=install
+primingBuild.regular.goals=install
diff --git
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
index d4768d2a09..3cb748b10c 100644
---
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
+++
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
@@ -437,6 +437,8 @@ public final class Server {
return CompletableFuture.completedFuture(new Project[0]);
}
CompletableFuture<Project[]> f = new CompletableFuture<>();
+ LOG.log(Level.FINER, "Asked to open project(s): {0}",
Arrays.asList(projectCandidates));
+ LOG.log(Level.FINER, "Caller:", new Throwable());
SERVER_INIT_RP.post(() -> {
asyncOpenSelectedProjects0(f, projectCandidates, addWorkspace,
false);
});
@@ -612,7 +614,7 @@ public final class Server {
List<Project> toOpen = new ArrayList<>();
Map<Project, CompletableFuture<Void>> local = new HashMap<>();
synchronized (this) {
- LOG.log(Level.FINER, "{0}: Asked to open project(s): {1}", new
Object[]{ id, Arrays.asList(projects) });
+ LOG.log(Level.FINER, "{0}: Opening project(s): {1}", new
Object[]{ id, Arrays.asList(projects) });
for (Project p : projects) {
CompletableFuture<Void> pending = beingOpened.get(p);
if (pending != null) {
@@ -624,7 +626,7 @@ public final class Server {
}
beingOpened.putAll(local);
}
-
+ long t = System.currentTimeMillis();
LOG.log(Level.FINER, id + ": Opening projects: {0}",
Arrays.asList(toOpen));
// before the projects are officialy 'opened', try to prime the
projects
@@ -701,6 +703,7 @@ public final class Server {
}
}
f.complete(prjsRequested);
+ LOG.log(Level.INFO, "{0} projects opened in {1}ms", new
Object[] { prjsRequested.length, (System.currentTimeMillis() - t) });
}).exceptionally(e -> {
f.completeExceptionally(e);
return null;
diff --git
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
index b009ab7c3b..def77b1d82 100644
---
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
+++
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
@@ -60,6 +60,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Supplier;
+import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import java.util.stream.Collectors;
@@ -329,7 +330,9 @@ public final class WorkspaceServiceImpl implements
WorkspaceService, LanguageCli
if (file == null) {
return
CompletableFuture.completedFuture(Collections.emptyList());
}
+ long t = System.currentTimeMillis();
return
server.asyncOpenFileOwner(file).thenCompose(this::getTestRoots).thenCompose(testRoots
-> {
+ LOG.log(Level.INFO, "Project {2}: {0} test roots opened in
{1}ms", new Object[] { testRoots.size(), (System.currentTimeMillis() - t),
file});
BiFunction<FileObject,
Collection<TestMethodController.TestMethod>, Collection<TestSuiteInfo>> f =
(fo, methods) -> {
String url = Utils.toUri(fo);
Map<String, TestSuiteInfo> suite2infos = new
LinkedHashMap<>();
diff --git a/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java
b/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java
index 7d753e2185..d8a0bedca2 100644
--- a/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java
+++ b/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java
@@ -41,6 +41,7 @@ import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.WeakHashMap;
@@ -138,6 +139,8 @@ public final class NbMavenProjectImpl implements Project {
MavenProject old;
synchronized (NbMavenProjectImpl.this) {
old = project == null ? null : project.get();
+ LOG.log(Level.FINE, "Project {0} reloaded. Old project is:
{1}, new project {2}",
+ new Object[] { prj, System.identityHashCode(old ==
null ? this : old), System.identityHashCode(prj) });
if (old != null && MavenProjectCache.isFallbackproject(prj)) {
prj.setPackaging(old.getPackaging()); //#229366 preserve
packaging for broken projects to avoid changing lookup.
}
@@ -150,7 +153,7 @@ public final class NbMavenProjectImpl implements Project {
ACCESSOR.doFireReload(watcher);
reloadPossibleBrokenModules(old, prj);
}
- });
+ }, true);
private final FileObject fileObject;
private final FileObject folderFileObject;
private final File projectFile;
@@ -420,7 +423,7 @@ public final class NbMavenProjectImpl implements Project {
if (mp == null) {
// PENDING: should be the whole project load synchronized ?
mp = loadOriginalMavenProject(false);
- project = new SoftReference<MavenProject>(mp);
+ project = new SoftReference<>(mp);
if (hardReferencingMavenProject) {
hardRefProject = mp;
}
@@ -431,6 +434,20 @@ public final class NbMavenProjectImpl implements Project {
return mp;
}
+ /**
+ * Returns the original project, or waits for reload task if already
pending.
+ * @return possibly reloaded Maven project.
+ */
+ public MavenProject getFreshOriginalMavenProject() {
+ if (reloadTask.isFinished()) {
+ return getOriginalMavenProject();
+ } else {
+ LOG.log(Level.FINE, "Asked for project {0} being updated, waiting
for the refresh to complete.", projectFile);
+ reloadTask.waitFinished();
+ return getOriginalMavenProject();
+ }
+ }
+
/**
* Variants of the projects, possibly other than the ones with the
* <b>active configuration</b>
@@ -559,7 +576,8 @@ public final class NbMavenProjectImpl implements Project {
private void reloadPossibleBrokenModules(MavenProject preceding,
MavenProject p) {
// restrict to just poms that were marked as broken/incomplete.
if (!(MavenProjectCache.isFallbackproject(preceding) ||
-
preceding.getContextValue("org.netbeans.modules.maven.problems.primingNotDone")
!= Boolean.TRUE)) {
+ // the project is tagged by Boolean.TRUE, if a SanityBuildAction
was created for it.
+
preceding.getContextValue("org.netbeans.modules.maven.problems.primingNotDone")
== Boolean.TRUE)) {
return;
}
// but do not cascade from projects, which are themselves broken.
@@ -578,8 +596,9 @@ public final class NbMavenProjectImpl implements Project {
continue;
}
// the project may have more problems, more subtle, but now repair
just total breakage
- if (!MavenProjectCache.isFallbackproject(child)) {
+ if (!MavenProjectCache.isFallbackproject(child) &&
child.getContextValue("org.netbeans.modules.maven.problems.primingNotDone") !=
Boolean.TRUE) {
LOG.log(Level.FINE, "Project for module {0} is not a fallback,
skipping", modName);
+ continue;
}
FileObject dir = FileUtil.toFileObject(modPom.getParentFile());
if (dir == null) {
diff --git
a/java/maven/src/org/netbeans/modules/maven/problems/MavenModelProblemsProvider.java
b/java/maven/src/org/netbeans/modules/maven/problems/MavenModelProblemsProvider.java
index 7fb3806f06..6203ce7741 100644
---
a/java/maven/src/org/netbeans/modules/maven/problems/MavenModelProblemsProvider.java
+++
b/java/maven/src/org/netbeans/modules/maven/problems/MavenModelProblemsProvider.java
@@ -72,6 +72,7 @@ import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.util.lookup.Lookups;
import org.netbeans.modules.maven.InternalActionDelegate;
+import org.openide.util.Pair;
/**
* Suggests to run priming build. Also serves as a provider for Priming Build
action,
@@ -90,10 +91,19 @@ public class MavenModelProblemsProvider implements
ProjectProblemsProvider, Inte
private final PropertyChangeSupport support = new
PropertyChangeSupport(this);
private final Project project;
- private final AtomicBoolean projectListenerSet = new AtomicBoolean(false);
- private final AtomicReference<Collection<ProjectProblem>> problemsCache =
new AtomicReference<Collection<ProjectProblem>>();
private final PrimingActionProvider primingProvider = new
PrimingActionProvider();
+
private ProblemReporterImpl problemReporter;
+
+ // @GuardedBy(this)
+ private Pair<Collection<ProjectProblem>, Boolean> problemsCache = null;
+ // @GuardedBy(this)
+ private boolean projectListenerSet;
+
+ /**
+ * The Maven project that has been processed already.
+ */
+ private Reference<MavenProject> analysedProject = new
WeakReference<>(null);
private final PropertyChangeListener projectListener = new
PropertyChangeListener() {
@Override
@@ -125,6 +135,15 @@ public class MavenModelProblemsProvider implements
ProjectProblemsProvider, Inte
return prbs != null ? prbs : Collections.emptyList();
}
+ /**
+ * Flag set during creation of sanity build action. Usable only inside
synchronized
+ * section of the problem resolver.
+ */
+ private boolean sanityBuildStatus;
+
+ public boolean isSanityBuildNeeded() {
+ return doGetProblems1(true).second();
+ }
/**
* Compute problems. If 'sync' is true, the computation is done
synchronously. Caches results,
@@ -133,70 +152,110 @@ public class MavenModelProblemsProvider implements
ProjectProblemsProvider, Inte
* @return project problems.
*/
Collection<? extends ProjectProblem> doGetProblems(boolean sync) {
- final MavenProject prj =
project.getLookup().lookup(NbMavenProject.class).getMavenProject();
+ return doGetProblems1(sync).first();
+ }
+
+ /**
+ * Analyzes problem, returns list of problems and priming build status.
The returned {@link Pair}
+ * contains the list of problems and true/false whether the priming build
seems necessary. The last result
+ * is cached for the given maven model instance. If the project was
reloaded, the problems will be computed
+ * again for the new project instance. The call might block waiting on the
pending project reload. If `sync'
+ * is false, the method will just post in request processor and return
{@code null}.
+ *
+ * @param sync if the call should complete synchronously
+ */
+ private Pair<Collection<ProjectProblem>, Boolean> doGetProblems1(boolean
sync) {
+ final MavenProject updatedPrj =
((NbMavenProjectImpl)project).getFreshOriginalMavenProject();
+ Callable<Pair<Collection<ProjectProblem>, Boolean>> c;
+
synchronized (this) {
- LOG.log(Level.FINER, "Called getProblems for {0}", project);
//lazy adding listener only when someone asks for the problems the
first time
- if (projectListenerSet.compareAndSet(false, true)) {
+ if (!projectListenerSet) {
+ projectListenerSet = true;
//TODO do we check only when the project is opened?
problemReporter =
project.getLookup().lookup(NbMavenProjectImpl.class).getProblemReporter();
assert problemReporter != null;
project.getLookup().lookup(NbMavenProject.class).addPropertyChangeListener(projectListener);
}
-
+ MavenProject o = analysedProject.get();
+ LOG.log(Level.FINER, "Called getProblems for {0}, analysed = {1},
current = {2}",
+ new Object[] { project, o == null ? 0 :
System.identityHashCode(o), System.identityHashCode(updatedPrj) });
//for non changed project models, no need to recalculate, always
return the cached value
- Object wasprocessed =
prj.getContextValue(MavenModelProblemsProvider.class.getName());
- if (wasprocessed != null) {
- Collection<ProjectProblem> cached = problemsCache.get();
- LOG.log(Level.FINER, "Project was processed, cached is: {0}",
cached);
+ Object wasprocessed =
updatedPrj.getContextValue(MavenModelProblemsProvider.class.getName());
+ if (o == updatedPrj && wasprocessed != null) {
+ Pair<Collection<ProjectProblem>, Boolean> cached =
problemsCache;
+ LOG.log(Level.FINER, "getProblems: Project was processed,
cached is: {0}", cached);
if (cached != null) {
return cached;
}
}
- Callable<Collection<? extends ProjectProblem>> c = new
Callable<Collection<? extends ProjectProblem>>() {
- @Override
- public Collection<? extends ProjectProblem> call() throws
Exception {
- Object wasprocessed =
prj.getContextValue(MavenModelProblemsProvider.class.getName());
- if (wasprocessed != null) {
- Collection<ProjectProblem> cached =
problemsCache.get();
- LOG.log(Level.FINER, "Project was processed #2, cached
is: {0}", cached);
+
+ SanityBuildAction sba = cachedSanityBuild.get();
+ if (sba != null && sba.getPendingResult() == null) {
+ cachedSanityBuild.clear();
+ }
+ c = () -> {
+ // double check, the project may be invalidated during the
time.
+ MavenProject prj =
((NbMavenProjectImpl)project).getFreshOriginalMavenProject();
+ Object wasprocessed2 =
updatedPrj.getContextValue(MavenModelProblemsProvider.class.getName());
+ synchronized (MavenModelProblemsProvider.this) {
+ if (o == updatedPrj && wasprocessed2 != null) {
+ Pair<Collection<ProjectProblem>, Boolean> cached =
problemsCache;
+ LOG.log(Level.FINER, "getProblems: Project was
processed #2, cached is: {0}", cached);
if (cached != null) {
return cached;
}
}
- List<ProjectProblem> toRet = new ArrayList<>();
- MavenExecutionResult res =
MavenProjectCache.getExecutionResult(prj);
- if (res != null && res.hasExceptions()) {
- toRet.addAll(reportExceptions(res));
- }
- //#217286 doArtifactChecks can call FileOwnerQuery and
attempt to aquire the project mutex.
- toRet.addAll(doArtifactChecks(prj));
- //mark the project model as checked once and cached
-
prj.setContextValue(MavenModelProblemsProvider.class.getName(), new Object());
- synchronized(MavenModelProblemsProvider.this) {
- LOG.log(Level.FINER, "Project processing finished,
result is: {0}", toRet);
- problemsCache.set(toRet);
- }
- firePropertyChange();
- return toRet;
- }
- };
- if(sync || Boolean.getBoolean("test.reload.sync")) {
- try {
- return c.call();
- } catch (Exception ex) {
- Exceptions.printStackTrace(ex);
}
- } else {
- RP.submit(c);
+ int round = 0;
+ List<ProjectProblem> toRet = null;
+ while (round < 3) {
+ try {
+ synchronized (MavenModelProblemsProvider.this) {
+ sanityBuildStatus = false;
+ toRet = new ArrayList<>();
+ MavenExecutionResult res =
MavenProjectCache.getExecutionResult(prj);
+ if (res != null && res.hasExceptions()) {
+ toRet.addAll(reportExceptions(res));
+ }
+ //#217286 doArtifactChecks can call FileOwnerQuery
and attempt to aquire the project mutex.
+ toRet.addAll(doArtifactChecks(prj));
+ //mark the project model as checked once and cached
+
prj.setContextValue(MavenModelProblemsProvider.class.getName(), new Object());
+ LOG.log(Level.FINER, "getProblems: Project {1}
processing finished, result is: {0}",
+ new Object[] { toRet, prj });
+ problemsCache = Pair.of(toRet, sanityBuildStatus);
+ analysedProject = new WeakReference<>(prj);
+ }
+ firePropertyChange();
+ return Pair.of(toRet, sanityBuildStatus);
+ } catch (ProblemReporterImpl.ArtifactFoundException ex) {
+ round++;
+ LOG.log(Level.FINER, "getProblems: Project {1}
reported missing artifact that actually exists, restarting - {0} round",
+ new Object[] { round, prj });
+ // force reload, then wait for the reload to complete
+ NbMavenProject.fireMavenProjectReload(project);
+ prj =
((NbMavenProjectImpl)project).getFreshOriginalMavenProject();
+ }
+ }
+ return Pair.of(toRet, sanityBuildStatus);
+ };
+ }
+ if(sync || Boolean.getBoolean("test.reload.sync")) {
+ try {
+ return c.call();
+ } catch (Exception ex) {
+ Exceptions.printStackTrace(ex);
}
+ } else {
+ RP.submit(c);
}
// indicate that we do not know
- return null;
+ return Pair.of(null, true);
}
-
+
private void firePropertyChange() {
support.firePropertyChange(ProjectProblemsProvider.PROP_PROBLEMS,
null, null);
}
@@ -245,6 +304,7 @@ public class MavenModelProblemsProvider implements
ProjectProblemsProvider, Inte
//a.getFile should be already normalized
SourceForBinaryQuery.Result2 result =
SourceForBinaryQuery.findSourceRoots2(archiveUrl);
if (!result.preferSources() || /*
SourceForBinaryQuery.EMPTY_RESULT2.preferSources() so: */
result.getRoots().length == 0) {
+ LOG.log(Level.FINE, "Missing nonsibling
artifact: {0}", art);
missingNonSibling = true;
} // else #189442: typically a snapshot dep on
another project
}
@@ -306,13 +366,14 @@ public class MavenModelProblemsProvider implements
ProjectProblemsProvider, Inte
public SanityBuildAction createSanityBuildAction() {
synchronized (this) {
SanityBuildAction a = cachedSanityBuild.get();
+ sanityBuildStatus = true;
if (a != null) {
Future<ProjectProblemsProvider.Result> r =
a.getPendingResult();
if (r != null) {
return a;
}
}
- a = new SanityBuildAction(project);
+ a = new SanityBuildAction(project, this::isSanityBuildNeeded);
project.getLookup().lookup(NbMavenProject.class).getMavenProject().setContextValue("org.netbeans.modules.maven.problems.primingNotDone",
true);
cachedSanityBuild = new WeakReference<>(a);
return a;
diff --git
a/java/maven/src/org/netbeans/modules/maven/problems/ProblemReporterImpl.java
b/java/maven/src/org/netbeans/modules/maven/problems/ProblemReporterImpl.java
index def18e0380..575cdda1b8 100644
---
a/java/maven/src/org/netbeans/modules/maven/problems/ProblemReporterImpl.java
+++
b/java/maven/src/org/netbeans/modules/maven/problems/ProblemReporterImpl.java
@@ -195,12 +195,30 @@ public final class ProblemReporterImpl implements
ProblemReporter, Comparator<Pr
//a.getFile should be already normalized but the find() method can
pull tricks on us.
//#225008
File f = FileUtil.normalizeFile(a.getFile());
+ if (f.exists() && f.canRead()) {
+ throw new ArtifactFoundException(a, f);
+ }
if (missingArtifacts.add(f)) {
LOG.log(Level.FINE, "listening to {0} from {1}", new Object[]
{f, projectPOMFile});
FileUtil.addFileChangeListener(fcl, f);
}
}
}
+
+ /**
+ * Indicates that the cached data that report a missing artifact is
obsolete.
+ */
+ public static class ArtifactFoundException extends IllegalStateException {
+ private final Artifact artifact;
+ private final File artifactFile;
+
+ public ArtifactFoundException(Artifact artifact, File artifactFile) {
+ this.artifact = artifact;
+ this.artifactFile = artifactFile;
+ }
+ }
+
+
public Set<File> getMissingArtifactFiles() {
synchronized (reports) {
diff --git
a/java/maven/src/org/netbeans/modules/maven/problems/SanityBuildAction.java
b/java/maven/src/org/netbeans/modules/maven/problems/SanityBuildAction.java
index c0f88d3347..9c3b0c81de 100644
--- a/java/maven/src/org/netbeans/modules/maven/problems/SanityBuildAction.java
+++ b/java/maven/src/org/netbeans/modules/maven/problems/SanityBuildAction.java
@@ -20,12 +20,15 @@
package org.netbeans.modules.maven.problems;
import java.util.Arrays;
+import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectUtils;
import org.netbeans.modules.maven.TestChecker;
import org.netbeans.modules.maven.api.NbMavenProject;
import org.netbeans.modules.maven.api.execute.RunConfig.ReactorStyle;
@@ -33,13 +36,16 @@ import org.netbeans.modules.maven.api.execute.RunUtils;
import org.netbeans.modules.maven.execute.BeanRunConfig;
import org.netbeans.modules.maven.execute.MavenProxySupport;
import org.netbeans.modules.maven.execute.MavenProxySupport.ProxyResult;
+import org.netbeans.modules.maven.options.MavenSettings;
import static org.netbeans.modules.maven.problems.Bundle.*;
+import org.netbeans.spi.project.RootProjectProvider;
import org.netbeans.spi.project.ui.ProjectProblemResolver;
import org.netbeans.spi.project.ui.ProjectProblemsProvider;
import org.openide.execution.ExecutorTask;
import org.openide.filesystems.FileUtil;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
+import org.openide.util.NbPreferences;
/**
* Corrective action to run some target which can download plugins or parent
POMs.
@@ -47,11 +53,13 @@ import org.openide.util.NbBundle.Messages;
* to believe that there really is a problem with their project, not NetBeans.
*/
@Messages({"ACT_validate=Priming Build",
+ "ACT_PrimingComplete=Priming build was completed",
"ACT_start_validate=Priming build was started."})
public class SanityBuildAction implements ProjectProblemResolver {
private static final Logger LOG =
Logger.getLogger(SanityBuildAction.class.getName());
private final Project nbproject;
+ private final Supplier<Boolean> checkSupplier;
/**
* The priming build, which is currently pending or recently completed.
@@ -59,12 +67,14 @@ public class SanityBuildAction implements
ProjectProblemResolver {
*/
private volatile CompletableFuture<ProjectProblemsProvider.Result>
pendingResult;
- public SanityBuildAction(Project nbproject) {
+ public SanityBuildAction(Project nbproject, Supplier<Boolean>
checkSupplier) {
this.nbproject = nbproject;
+ this.checkSupplier = checkSupplier;
}
- public SanityBuildAction(Project nbproject,
Future<ProjectProblemsProvider.Result> otherResult) {
+ public SanityBuildAction(Project nbproject, Supplier<Boolean>
checkSupplier, Future<ProjectProblemsProvider.Result> otherResult) {
this.nbproject = nbproject;
+ this.checkSupplier = checkSupplier;
}
public Future<ProjectProblemsProvider.Result> getPendingResult() {
@@ -84,22 +94,35 @@ public class SanityBuildAction implements
ProjectProblemResolver {
return pendingResult;
}
final CompletableFuture<ProjectProblemsProvider.Result> publicResult =
new CompletableFuture<>();
-
+
Runnable toRet = new Runnable() {
@Override
public void run() {
+ /**
+ * From the appearance of the Sanity action, the project's
state may have changed. In that case the sanity build should not run maven
again.
+ */
+ if (!checkSupplier.get()) {
+ ProjectProblemsProvider.Result r =
ProjectProblemsProvider.Result.create(ProjectProblemsProvider.Status.RESOLVED,
ACT_start_validate());
+ if (r != null) {
+ LOG.log(Level.FINE, "Project {0} is OK before sanity
build action.", nbproject);
+ publicResult.complete(r);
+ return;
+ }
+ }
try {
LOG.log(Level.FINE, "Configuring sanity build");
BeanRunConfig config = new BeanRunConfig();
config.setExecutionDirectory(FileUtil.toFile(nbproject.getProjectDirectory()));
NbMavenProject mavenPrj =
nbproject.getLookup().lookup(NbMavenProject.class);
+ String goals;
if (mavenPrj != null
&& mavenPrj.getMavenProject().getVersion() != null
&&
mavenPrj.getMavenProject().getVersion().endsWith("SNAPSHOT")) {
- config.setGoals(Arrays.asList("--fail-at-end",
"install")); // NOI18N
+ goals =
NbPreferences.forModule(MavenSettings.class).get("primingBuild.snapshot.goals",
"install");
} else {
- config.setGoals(Arrays.asList("--fail-at-end",
"package")); // NOI18N
+ goals =
NbPreferences.forModule(MavenSettings.class).get("primingBuild.regular.goals",
"package");
}
+ config.setGoals(Arrays.asList("--fail-at-end", goals)); //
NOI18N
config.setReactorStyle(ReactorStyle.ALSO_MAKE);
config.setProperty(TestChecker.PROP_SKIP_TEST, "true");
//priming doesn't need test execution, just compilation
config.setProject(nbproject);
@@ -127,13 +150,15 @@ public class SanityBuildAction implements
ProjectProblemResolver {
return;
}
}
+ long t = System.currentTimeMillis();
LOG.log(Level.FINE, "Executing sanity build: goals = {0},
properties = {1}", new Object[] { config.getGoals(), config.getProperties() });
ExecutorTask et = RunUtils.run(config);
- et.addTaskListener(t -> {
+ if (et != null) {
+ et.waitFinished();
ProjectProblemsProvider.Result r =
ProjectProblemsProvider.Result.create(ProjectProblemsProvider.Status.RESOLVED,
ACT_start_validate());
- LOG.log(Level.FINE, "Sanity build finished.");
+ LOG.log(Level.FINE, "Sanity build of {0} finished,
took {1} ms.", new Object[] { nbproject, System.currentTimeMillis() - t});
publicResult.complete(r);
- });
+ }
} catch (RuntimeException | Error e) {
// always report completness, otherwise tasks that wait on
priming build could block indefinitely.
LOG.log(Level.FINE, "Sanity build failed", e);
@@ -153,7 +178,7 @@ public class SanityBuildAction implements
ProjectProblemResolver {
MavenModelProblemsProvider.RP.submit(toRet);
return publicResult;
}
-
+
@Override
public int hashCode() {
int hash = SanityBuildAction.class.hashCode();
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists