This is an automated email from the ASF dual-hosted git repository.
mbalin pushed a commit to branch delivery
in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/delivery by this push:
new 4d6c0e9f2c #4923: access to gradle internal APIs is protected from
failing the project load, just logs a notification.
new 31c6618dc5 Merge pull request #4936 from
sdedic/gradle/internals-wrapped
4d6c0e9f2c is described below
commit 4d6c0e9f2c16b1c8384ada1d03a1dd7f2caa38b7
Author: Svata Dedic <[email protected]>
AuthorDate: Mon Nov 7 18:25:22 2022 +0100
#4923: access to gradle internal APIs is protected from failing the project
load, just logs a notification.
---
.../gradle/tooling/GradleInternalAdapter.java | 209 +++++++++++++++++++++
.../gradle/tooling/NbProjectInfoBuilder.java | 79 ++++----
2 files changed, 241 insertions(+), 47 deletions(-)
diff --git
a/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/GradleInternalAdapter.java
b/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/GradleInternalAdapter.java
new file mode 100644
index 0000000000..515cfc7f1b
--- /dev/null
+++
b/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/GradleInternalAdapter.java
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ */
+package org.netbeans.modules.gradle.tooling;
+
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Supplier;
+import org.gradle.api.NamedDomainObjectContainer;
+import org.gradle.api.Project;
+import org.gradle.api.internal.plugins.PluginManagerInternal;
+import org.gradle.api.internal.plugins.PluginRegistry;
+import org.gradle.api.internal.project.ProjectInternal;
+import org.gradle.api.internal.provider.PropertyInternal;
+import org.gradle.api.internal.provider.ProviderInternal;
+import org.gradle.api.internal.provider.ValueSupplier;
+import org.gradle.api.logging.LogLevel;
+import org.gradle.api.logging.Logger;
+import org.gradle.api.logging.Logging;
+import org.gradle.api.reflect.HasPublicType;
+import org.gradle.plugin.use.PluginId;
+import org.gradle.util.VersionNumber;
+import
org.netbeans.modules.gradle.tooling.NbProjectInfoBuilder.ExceptionCallable;
+import org.netbeans.modules.gradle.tooling.NbProjectInfoBuilder.ValueAndType;
+
+/**
+ * Adapts to various Gradle implementations. As *.internal.* interfaces may
change between
+ * releases, operations on them may be customized by this Adapter. The adapter
should be compiled
+ * against the Gradle distribution shipped with NetBeans, but should use
reflection to access
+ * the relevant data if the internal API changes between versions.
+ *
+ * @author sdedic
+ */
+public class GradleInternalAdapter {
+ private static final Logger LOG =
Logging.getLogger(NbProjectInfoBuilder.class);
+
+ private final Project project;
+ private final VersionNumber gradleVersion;
+ /**
+ * Accummulates error messages, so that just one problem is logger a given
type of error.
+ */
+ private Set<String> reportedIncompatibilities = new HashSet<>();
+
+ protected NbProjectInfoModel model;
+
+ /**
+ * Guards {@link #pluginManager} and {@link #registry} initialization
+ */
+ protected boolean pluginsInitialized;
+ protected PluginManagerInternal pluginManager;
+ protected PluginRegistry registry;
+
+ public GradleInternalAdapter(Project project) {
+ this.project = project;
+ this.gradleVersion =
VersionNumber.parse(project.getGradle().getGradleVersion());
+ }
+
+ boolean initPlugins() {
+ if (!pluginsInitialized) {
+ if (project.getPluginManager() instanceof PluginManagerInternal) {
+ pluginManager =
(PluginManagerInternal)project.getPluginManager();
+ }
+ if (project instanceof ProjectInternal) {
+ registry = safeCall(() ->
((ProjectInternal)project).getServices().get(PluginRegistry.class), "plugin
registry").orElse(null);
+ } else {
+ registry = null;
+ }
+ }
+ return pluginManager != null;
+ }
+
+ public void setModel(NbProjectInfoModel model) {
+ this.model = model;
+ }
+
+ protected boolean isFixedValue(String description,
ValueSupplier.ExecutionTimeValue etv) {
+ return etv.isFixedValue();
+ }
+
+ public boolean isMutableType(Object potentialValue) {
+ if (potentialValue instanceof PropertyInternal) {
+ return true;
+ } else if ((potentialValue instanceof NamedDomainObjectContainer) &&
(potentialValue instanceof HasPublicType)) {
+ return true;
+ } else if (potentialValue instanceof Iterable || potentialValue
instanceof Map) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean hasPluginManager() {
+ return initPlugins();
+ }
+
+ public ValueAndType findPropertyValueInternal(String propName, Object val)
{
+ return safeCall(() -> {
+ if (val instanceof ProviderInternal) {
+ ProviderInternal provided = (ProviderInternal)val;
+ ValueSupplier.ExecutionTimeValue etv;
+ try {
+ etv = provided.calculateExecutionTimeValue();
+ } catch (RuntimeException ex) {
+ // probably expected, ignore
+ return new ValueAndType(provided.getType());
+ }
+ if (isFixedValue("property " + propName, etv)) {
+ return new ValueAndType(provided.getType(),
etv.getFixedValue());
+ } else {
+ return new ValueAndType(provided.getType());
+ }
+ } else {
+ return new ValueAndType(val != null ? val.getClass() : null,
val);
+ }
+ }, "property " + propName).orElse(null);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T extends Throwable> void sneakyThrow(Throwable exception)
throws T {
+ throw (T) exception;
+ }
+
+ private <T, E extends Throwable> T sinceGradleOrDefault(String version,
NbProjectInfoBuilder.ExceptionCallable<T, E> c, Supplier<T> def) {
+ if (gradleVersion.compareTo(VersionNumber.parse(version)) >= 0) {
+ try {
+ return c.call();
+ } catch (RuntimeException | Error e) {
+ throw e;
+ } catch (Throwable t) {
+ sneakyThrow(t);
+ return null;
+ }
+ } else {
+ return def.get();
+ }
+ }
+
+ public Optional<PluginId> findPluginId(Class fc) {
+ if (!initPlugins()) {
+ return Optional.empty();
+ }
+ // with Gradle 7.1+, plugins can be better enumerated. Prior to 7.1 I
can only get IDs for registry-supplied plugins.
+ Optional<PluginId> id = sinceGradleOrDefault("7.1", () -> safeCall(()
-> (PluginId)pluginManager.findPluginIdForClass(fc).orElse(null), "plugins"),
Optional::empty); // NOI18N
+ if (id.isPresent() || registry == null) {
+ return id;
+ }
+ return safeCall(() -> registry.findPluginForClass(fc).orElse(null),
"plugin class " + fc.getName());
+ }
+
+ private void noteAndLogError(Throwable ex, String description) {
+ String msg = "Error inspecting " + (description == null ? "project" :
description);
+ model.noteProblem(msg + ": " + ex.toString());
+ LOG.log(LogLevel.LIFECYCLE, msg, ex);
+ }
+
+ protected <T, E extends Throwable> Optional<T>
safeCall(ExceptionCallable<T, E> sup, String description) {
+ try {
+ return Optional.ofNullable(sup.call());
+ } catch (RuntimeException ex) {
+ noteAndLogError(ex, description);
+ return Optional.empty();
+ } catch (Error ex) {
+ if (reportedIncompatibilities.add(ex.toString())) {
+ noteAndLogError(ex, description);
+ }
+ return Optional.empty();
+ } catch (Throwable t) {
+ sneakyThrow(t);
+ return null;
+ }
+ }
+
+ public static class Gradle76 extends GradleInternalAdapter {
+ private static Optional<Method> refHasValue;
+
+ public Gradle76(Project project) {
+ super(project);
+ }
+
+ @Override
+ protected boolean isFixedValue(String description,
ValueSupplier.ExecutionTimeValue etv) {
+ if (refHasValue == null) {
+ refHasValue = safeCall(() ->
ValueSupplier.ExecutionTimeValue.class.getMethod("hasFixedValue"), "Gradle 7.6+
ExecutionTimeValue");
+ }
+ if (refHasValue.isPresent()) {
+ return safeCall(() -> (Boolean)refHasValue.get().invoke(etv),
description).orElse(false);
+ } else {
+ return false;
+ }
+ }
+ }
+}
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 63fd8dbf86..dae86ef964 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
@@ -85,12 +85,7 @@ 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.internal.plugins.PluginManagerInternal;
-import org.gradle.api.internal.plugins.PluginRegistry;
-import org.gradle.api.internal.project.ProjectInternal;
-import org.gradle.api.internal.provider.PropertyInternal;
import org.gradle.api.internal.provider.ProviderInternal;
-import org.gradle.api.internal.provider.ValueSupplier.ExecutionTimeValue;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.plugins.ExtensionAware;
@@ -183,14 +178,34 @@ class NbProjectInfoBuilder {
final Project project;
final VersionNumber gradleVersion;
+ final GradleInternalAdapter adapter;
+
+ public static final class ValueAndType {
+ final Class type;
+ final Optional<Object> value;
+
+ public ValueAndType(Class type, Object value) {
+ this.type = type;
+ this.value = Optional.of(value);
+ }
+
+ public ValueAndType(Class type) {
+ this.type = type;
+ this.value = Optional.empty();
+ }
+ }
NbProjectInfoBuilder(Project project) {
this.project = project;
this.gradleVersion =
VersionNumber.parse(project.getGradle().getGradleVersion());
+ // checked that version 7.6.0 > 7.6.0-rc-1 in the VersionNumber order
+ this.adapter = sinceGradleOrDefault("7.6.0-rc-1", () -> new
GradleInternalAdapter.Gradle76(project), () -> new
GradleInternalAdapter(project));
}
+
+ private NbProjectInfoModel model = new NbProjectInfoModel();
public NbProjectInfo buildAll() {
- NbProjectInfoModel model = new NbProjectInfoModel();
+ adapter.setModel(model);
runAndRegisterPerf(model, "meta", this::detectProjectMetadata);
detectProps(model);
detectLicense(model);
@@ -217,7 +232,7 @@ class NbProjectInfoBuilder {
storeGlobalTypes(model);
return model;
}
-
+
@SuppressWarnings("null")
private void detectDistributions(NbProjectInfoModel model) {
if (project.getPlugins().hasPlugin("distribution")) {
@@ -365,29 +380,15 @@ class NbProjectInfoBuilder {
* @param model
*/
private void detectAdditionalPlugins(NbProjectInfoModel model) {
- final PluginManagerInternal pmi;
- PluginRegistry reg;
- if (project.getPluginManager() instanceof PluginManagerInternal) {
- pmi = (PluginManagerInternal)project.getPluginManager();
- } else {
+ if (!adapter.hasPluginManager()) {
return;
}
- if (project instanceof ProjectInternal) {
- reg =
((ProjectInternal)project).getServices().get(PluginRegistry.class);
- } else {
- reg = null;
- }
LOG.lifecycle("Detecting additional plugins");
final Set<String> plugins = new LinkedHashSet<>();
project.getPlugins().matching((Plugin p) -> {
for (Class c = p.getClass(); c != null && c != Object.class; c =
c.getSuperclass()) {
- Class fc = c;
- // with Gradle 7.1+, plugins can be better enumerated. Prior
to 7.1 I can only get IDs for registry-supplied plugins.
- Optional<PluginId> id = sinceGradleOrDefault("7.1", () ->
pmi.findPluginIdForClass(fc), Optional::empty); // NOI18N
- if (!id.isPresent() && reg != null) {
- id = reg.findPluginForClass(c);
- }
+ Optional<PluginId> id = adapter.findPluginId(c);
if (id.isPresent()) {
LOG.info("Plugin: {} -> {}", id.get(), p);
plugins.add(id.get().getId());
@@ -537,14 +538,7 @@ class NbProjectInfoBuilder {
}
private boolean isMutableType(Object potentialValue) {
- if (potentialValue instanceof PropertyInternal) {
- return true;
- } else if ((potentialValue instanceof NamedDomainObjectContainer) &&
(potentialValue instanceof HasPublicType)) {
- return true;
- } else if (potentialValue instanceof Iterable || potentialValue
instanceof Map) {
- return true;
- }
- return false;
+ return adapter.isMutableType(potentialValue);
}
private void inspectObjectAndValues0(Class clazz, Object object, String
prefix, Map<String, Map<String, String>> globalTypes, Map<String, String>
propertyTypes, Map<String, Object> defaultValues, Set<String> excludes, boolean
type) {
@@ -640,24 +634,15 @@ class NbProjectInfoBuilder {
// Provider must NOT be asked for a value, otherwise it might
run a Task in order to compute
// the value.
try {
+ value = mclazz.getProperty(object, propName);
if (Provider.class.isAssignableFrom(t)) {
- Object potentialValue = mclazz.getProperty(object,
propName);
- if (potentialValue instanceof ProviderInternal) {
- ProviderInternal provided = (ProviderInternal)
potentialValue;
- t = provided.getType();
- ExecutionTimeValue etv;
- etv = provided.calculateExecutionTimeValue();
- if (etv.isFixedValue()) {
- value = etv.getFixedValue();
- }
- } else {
- value = potentialValue;
- if (value != null) {
- t = value.getClass();
+ ValueAndType vt =
adapter.findPropertyValueInternal(propName, value);
+ if (vt != null) {
+ t = vt.type;
+ if (vt.value.isPresent()) {
+ value = vt.value.get();
}
}
- } else {
- value = mclazz.getProperty(object, propName);
}
} catch (RuntimeException ex) {
// just ignore - the property value cannot be obtained
@@ -1611,7 +1596,7 @@ class NbProjectInfoBuilder {
.collect(Collectors.toSet());
}
- private interface ExceptionCallable<T, E extends Throwable> {
+ interface ExceptionCallable<T, E extends Throwable> {
public T call() throws E;
}
---------------------------------------------------------------------
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