diff --git a/biz.aQute.resolve/src/biz/aQute/resolve/BndrunResolveContext.java b/biz.aQute.resolve/src/biz/aQute/resolve/BndrunResolveContext.java
index 019c4d5d7c..907d93f5a7 100644
--- a/biz.aQute.resolve/src/biz/aQute/resolve/BndrunResolveContext.java
+++ b/biz.aQute.resolve/src/biz/aQute/resolve/BndrunResolveContext.java
@@ -266,7 +266,7 @@ void loadFramework(ResourceBuilder system) throws Exception {
String version = bsn.getValue()
.getVersion();
- log.log(LogService.LOG_INFO, "Using frameowork " + name + ";" + version);
+ log.log(LogService.LOG_INFO, "Using framework " + name + ";" + version);
if ("none".equals(name))
return;
diff --git a/biz.aQute.resolve/src/biz/aQute/resolve/InternalResolverLogger.java b/biz.aQute.resolve/src/biz/aQute/resolve/InternalResolverLogger.java
index 5e90b66333..943a5b1edf 100644
--- a/biz.aQute.resolve/src/biz/aQute/resolve/InternalResolverLogger.java
+++ b/biz.aQute.resolve/src/biz/aQute/resolve/InternalResolverLogger.java
@@ -1,6 +1,8 @@
package biz.aQute.resolve;
import org.apache.felix.resolver.Logger;
+import org.apache.felix.resolver.ResolutionError;
+import org.osgi.resource.Resource;
class InternalResolverLogger extends Logger {
@@ -15,4 +17,10 @@ public InternalResolverLogger(ResolverLogger logger) {
protected void doLog(int level, String msg, Throwable throwable) {
logger.log(level, msg, throwable);
}
+
+ @Override
+ public void logUsesConstraintViolation(Resource resource, ResolutionError error) {
+ logger.log(logger.getLogLevel(), String.format("Resource: %s, ResolutionError: %s", resource, error),
+ error.toException());
+ }
}
diff --git a/biz.aQute.resolve/src/biz/aQute/resolve/ResolverLogger.java b/biz.aQute.resolve/src/biz/aQute/resolve/ResolverLogger.java
index 6cef957b67..4e3a6b7862 100644
--- a/biz.aQute.resolve/src/biz/aQute/resolve/ResolverLogger.java
+++ b/biz.aQute.resolve/src/biz/aQute/resolve/ResolverLogger.java
@@ -10,11 +10,19 @@
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import aQute.bnd.exceptions.Exceptions;
+import aQute.bnd.osgi.Constants;
+import aQute.bnd.osgi.Processor;
+import aQute.lib.converter.Converter;
import aQute.lib.io.IO;
public class ResolverLogger implements LogService, AutoCloseable {
+ private static final Logger logger = LoggerFactory.getLogger(ResolverLogger.class);
+
public static final int DEFAULT_LEVEL = 4;
public static final int LOG_ERROR = 1;
@@ -52,6 +60,7 @@ public ResolverLogger(int level, PrintStream out) {
printer = IO.writer(out, UTF_8);
}
+
@Override
public void log(int level, String msg, Throwable throwable) {
switch (level) {
@@ -64,6 +73,7 @@ public void log(int level, String msg, Throwable throwable) {
printLog(msg, throwable);
if (throwable != null) {
throwable.printStackTrace(printer);
+ logger.debug("", throwable);
}
break;
case LOG_INFO :
@@ -87,10 +97,13 @@ public void log(int level, String msg, Throwable throwable) {
private void printLog(String msg, Throwable throwable) {
printer.print(msg);
+ logger.debug(msg);
if (throwable != null) {
printer.print(" (");
printer.print(throwable);
printer.print(")");
+
+ logger.debug("({})", String.valueOf(throwable));
}
printer.println();
}
@@ -106,6 +119,9 @@ public String getLog() {
} else {
StringBuilder sb = new StringBuilder(10000);
+ sb.append("Log level:")
+ .append(getLogLevel())
+ .append(" ");
sb.append("Log too large. Split from ")
.append(file.getAbsolutePath())
.append("\nsize ")
@@ -140,6 +156,17 @@ public void close() {
}
}
+ /**
+ * like {@link #close()} but it deletes the logfile regardless of
+ * {@link #keepLogFile}
+ */
+ public void closeAndDeleteLogfile() {
+ IO.close(printer);
+ if (file != null) {
+ IO.delete(file);
+ }
+ }
+
public void setKeepLogFileTillExit(boolean keep) {
this.keepLogFile = keep;
}
@@ -162,4 +189,35 @@ public void log(ServiceReference sr, int level, String message) {
public void log(ServiceReference sr, int level, String message, Throwable exception) {
log(level, message, exception);
}
+
+ /**
+ * @param processor
+ * @param keepLogFileTillJvmExit if true the logfile is kept
+ * until JVM exit, otherwise deleted immediately after resolve
+ * finishes
+ * @return a new logger
+ */
+ public static ResolverLogger newLogger(Processor processor, boolean keepLogFileTillJvmExit) {
+ if (processor == null) {
+ ResolverLogger logger = new ResolverLogger();
+ logger.setKeepLogFileTillExit(keepLogFileTillJvmExit);
+ return logger;
+ }
+
+ try {
+ Integer level = Converter.cnv(Integer.class,
+ processor.getProperty(Constants.RESOLVEDEBUG, Integer.toString(DEFAULT_LEVEL)));
+ if (level != null) {
+ ResolverLogger logger = new ResolverLogger(level);
+ logger.setKeepLogFileTillExit(keepLogFileTillJvmExit);
+ return logger;
+ }
+ ResolverLogger logger = new ResolverLogger(DEFAULT_LEVEL);
+ logger.setKeepLogFileTillExit(keepLogFileTillJvmExit);
+ return logger;
+ } catch (Exception e) {
+ throw Exceptions.duck(e);
+ }
+
+ }
}
diff --git a/biz.aQute.resolve/src/biz/aQute/resolve/RunResolution.java b/biz.aQute.resolve/src/biz/aQute/resolve/RunResolution.java
index 9a24e7e31c..b8b12eca62 100644
--- a/biz.aQute.resolve/src/biz/aQute/resolve/RunResolution.java
+++ b/biz.aQute.resolve/src/biz/aQute/resolve/RunResolution.java
@@ -98,7 +98,8 @@ public static RunResolution resolve(Project project, Processor actualProperties,
Collection callbacks, ResolverLogger resolverLogger) {
if (callbacks == null)
callbacks = Collections.emptyList();
- ResolverLogger logger = resolverLogger == null ? new ResolverLogger() : resolverLogger;
+ ResolverLogger logger = resolverLogger == null ? ResolverLogger.newLogger(actualProperties, false)
+ : resolverLogger;
try {
try {
ResolveProcess resolve = new ResolveProcess();
diff --git a/biz.aQute.resolve/test/biz/aQute/resolve/ResolveTest.java b/biz.aQute.resolve/test/biz/aQute/resolve/ResolveTest.java
index fe63a8b3ec..3b62536f33 100644
--- a/biz.aQute.resolve/test/biz/aQute/resolve/ResolveTest.java
+++ b/biz.aQute.resolve/test/biz/aQute/resolve/ResolveTest.java
@@ -2,6 +2,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -765,4 +766,32 @@ public void testDot() throws Exception {
}
}
+ /**
+ * This test triggers a Uses constraint violation. And we want to check that
+ * it gets logged via
+ * {@link InternalResolverLogger#logUsesConstraintViolation(Resource, org.apache.felix.resolver.ResolutionError)}
+ */
+ @Test
+ public void testResolveUsesConstraintErrorLogging() throws Exception {
+ File f = IO.getFile("testdata/repo-usesconstrainterror/run.bndrun");
+
+ try (Run run = Run.createRun(null, f)) {
+
+ RunResolution resolution = RunResolution.resolve(run, null);
+ assertFalse(resolution.isOK());
+ assertNotNull(resolution.exception);
+ System.out.println(resolution.exception);
+ assertTrue(resolution.exception.getMessage()
+ .contains(
+ "Uses constraint violation. Unable to resolve resource BundleC [BundleC version=1.0.0.SNAPSHOT] "
+ + "because it is exposed to package 'com.example.util.internal' from resources "
+ + "BundleA2 [BundleA2 version=1.0.0.SNAPSHOT] and "
+ + "BundleA [BundleA version=1.0.0.SNAPSHOT] via two dependency chains."),
+ resolution.exception.getMessage());
+
+ // Log level set via -resolvedebug: 1 in run.bndrun
+ assertTrue(resolution.log.startsWith("Log level:1"));
+ }
+ }
+
}
diff --git a/biz.aQute.resolve/testdata/repo-usesconstrainterror/BundleA.jar b/biz.aQute.resolve/testdata/repo-usesconstrainterror/BundleA.jar
new file mode 100644
index 0000000000..febf516f74
Binary files /dev/null and b/biz.aQute.resolve/testdata/repo-usesconstrainterror/BundleA.jar differ
diff --git a/biz.aQute.resolve/testdata/repo-usesconstrainterror/BundleA2.jar b/biz.aQute.resolve/testdata/repo-usesconstrainterror/BundleA2.jar
new file mode 100644
index 0000000000..2a9a1fbd77
Binary files /dev/null and b/biz.aQute.resolve/testdata/repo-usesconstrainterror/BundleA2.jar differ
diff --git a/biz.aQute.resolve/testdata/repo-usesconstrainterror/BundleB.jar b/biz.aQute.resolve/testdata/repo-usesconstrainterror/BundleB.jar
new file mode 100644
index 0000000000..96ed07c527
Binary files /dev/null and b/biz.aQute.resolve/testdata/repo-usesconstrainterror/BundleB.jar differ
diff --git a/biz.aQute.resolve/testdata/repo-usesconstrainterror/BundleC.jar b/biz.aQute.resolve/testdata/repo-usesconstrainterror/BundleC.jar
new file mode 100644
index 0000000000..bdec813c6f
Binary files /dev/null and b/biz.aQute.resolve/testdata/repo-usesconstrainterror/BundleC.jar differ
diff --git a/biz.aQute.resolve/testdata/repo-usesconstrainterror/index.xml b/biz.aQute.resolve/testdata/repo-usesconstrainterror/index.xml
new file mode 100644
index 0000000000..5bf2c6acc1
--- /dev/null
+++ b/biz.aQute.resolve/testdata/repo-usesconstrainterror/index.xml
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/biz.aQute.resolve/testdata/repo-usesconstrainterror/run.bndrun b/biz.aQute.resolve/testdata/repo-usesconstrainterror/run.bndrun
new file mode 100644
index 0000000000..cf466da40b
--- /dev/null
+++ b/biz.aQute.resolve/testdata/repo-usesconstrainterror/run.bndrun
@@ -0,0 +1,7 @@
+-standalone: ${.}/index.xml
+-runfw: org.apache.felix.framework
+-runee: JavaSE-17
+-resolvedebug: 1
+-runrequires: \
+ bnd.identity;id=BundleC,\
+ bnd.identity;id=BundleB
diff --git a/bndtools.core/src/org/bndtools/core/resolve/ResolveOperation.java b/bndtools.core/src/org/bndtools/core/resolve/ResolveOperation.java
index c4744ebdbe..aa62a771c7 100644
--- a/bndtools.core/src/org/bndtools/core/resolve/ResolveOperation.java
+++ b/bndtools.core/src/org/bndtools/core/resolve/ResolveOperation.java
@@ -50,13 +50,14 @@ public void run(IProgressMonitor monitor) {
try {
coordinate(() -> {
- logger = new ResolverLogger();
+ Project run = model.getOwner(Project.class)
+ .orElse(null);
+
+ logger = ResolverLogger.newLogger(run, true);
List operationCallbacks = new ArrayList<>(callbacks.size() + 1);
operationCallbacks.addAll(callbacks);
operationCallbacks.add(new ResolutionProgressCallback(monitor));
- Project run = model.getOwner(Project.class)
- .orElse(null);
RunResolution resolution = RunResolution.resolve(run,
model.getProperties(),
@@ -115,4 +116,5 @@ private void coordinate(RunnableWithException inCoordination) throws Exception {
}
}
+
}
diff --git a/bndtools.core/src/org/bndtools/core/resolve/ui/ResolutionFailurePanel.java b/bndtools.core/src/org/bndtools/core/resolve/ui/ResolutionFailurePanel.java
index 564d70e073..ade1184389 100644
--- a/bndtools.core/src/org/bndtools/core/resolve/ui/ResolutionFailurePanel.java
+++ b/bndtools.core/src/org/bndtools/core/resolve/ui/ResolutionFailurePanel.java
@@ -137,6 +137,7 @@ else if (composite.isDisposed())
// kind of silly
//
String diagnostic = ResolveProcess.format(resolutionException, false);
+ diagnostic += "\n\nresolvedebug log: " + resolutionResult.getLog();
processingErrorsText.setText(diagnostic);
sectUnresolved.setExpanded(true);
diff --git a/bndtools.core/src/org/bndtools/core/resolve/ui/ResolutionResultsWizardPage.java b/bndtools.core/src/org/bndtools/core/resolve/ui/ResolutionResultsWizardPage.java
index 3a772d8bca..25be1906b7 100644
--- a/bndtools.core/src/org/bndtools/core/resolve/ui/ResolutionResultsWizardPage.java
+++ b/bndtools.core/src/org/bndtools/core/resolve/ui/ResolutionResultsWizardPage.java
@@ -87,7 +87,7 @@ public void setResult(ResolutionResult result) {
public void recalculate() {
try {
result.getLogger()
- .close();
+ .closeAndDeleteLogfile();
ResolveOperation resolver = new ResolveOperation(model);
getContainer().run(true, true, resolver);
setResult(resolver.getResult());
diff --git a/bndtools.core/src/org/bndtools/core/resolve/ui/ResolutionWizard.java b/bndtools.core/src/org/bndtools/core/resolve/ui/ResolutionWizard.java
index 6601a13a94..e4278a6517 100644
--- a/bndtools.core/src/org/bndtools/core/resolve/ui/ResolutionWizard.java
+++ b/bndtools.core/src/org/bndtools/core/resolve/ui/ResolutionWizard.java
@@ -77,7 +77,7 @@ public void dispose() {
.getLogger() != null) {
resultsPage.getResult()
.getLogger()
- .close();
+ .closeAndDeleteLogfile();
}
super.dispose();
}