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(); }