diff --git a/biz.aQute.resolve/src/biz/aQute/resolve/AbstractResolveContext.java b/biz.aQute.resolve/src/biz/aQute/resolve/AbstractResolveContext.java index 44626be548..8719613ac9 100644 --- a/biz.aQute.resolve/src/biz/aQute/resolve/AbstractResolveContext.java +++ b/biz.aQute.resolve/src/biz/aQute/resolve/AbstractResolveContext.java @@ -100,6 +100,7 @@ public abstract class AbstractResolveContext extends ResolveContext { private Resource systemResource; private Resource inputResource; private Set blacklistedResources = new HashSet<>(); + private final Set blacklistedCapabilities = new HashSet<>(); private int level = 0; private Resource framework; private final AtomicBoolean reported = new AtomicBoolean(); @@ -285,10 +286,20 @@ protected ArrayList findProvidersFromRepositories(Requirement requir protected Collection findProviders(Repository repo, Requirement requirement) { Map> map = repo.findProviders(Collections.singleton(requirement)); Collection caps = map.get(requirement); - caps.removeIf(capability -> blacklistedResources.contains(capability.getResource())); + caps.removeIf(capability -> isBlacklisted(capability)); return caps; } + private boolean isBlacklisted(Capability capability) { + + boolean contains = blacklistedResources.contains(capability.getResource()); + if (contains) { + blacklistedCapabilities.add(capability); + } + + return contains; + } + private void setResourcePriority(int priority, Resource resource) { resourcePriorities.putIfAbsent(resource, priority); } @@ -695,6 +706,10 @@ public Set getBlackList() { return blacklistedResources; } + public Set getBlacklistedCapabilities() { + return blacklistedCapabilities; + } + public void setLevel(int n) { this.level = n; } diff --git a/biz.aQute.resolve/src/biz/aQute/resolve/BndResolutionException.java b/biz.aQute.resolve/src/biz/aQute/resolve/BndResolutionException.java new file mode 100644 index 0000000000..a71e26d8d5 --- /dev/null +++ b/biz.aQute.resolve/src/biz/aQute/resolve/BndResolutionException.java @@ -0,0 +1,38 @@ +package biz.aQute.resolve; + +import java.util.Collection; +import java.util.Set; + +import org.osgi.resource.Capability; +import org.osgi.resource.Requirement; +import org.osgi.resource.Resource; +import org.osgi.service.resolver.ResolutionException; + +/** + * A {@link ResolutionException} providing more details about why resolution has + * failed. + */ +public class BndResolutionException extends ResolutionException { + + private static final long serialVersionUID = 1L; + + private Set blackList; + private Set blacklistedCapabilities; + + public BndResolutionException(String message, Throwable cause, + Collection unresolvedRequirements, Set blackList, + Set blacklistedCapabilities) { + super(message, cause, unresolvedRequirements); + this.blackList = blackList; + this.blacklistedCapabilities = blacklistedCapabilities; + + } + + public Set getBlackList() { + return blackList; + } + + public Set getBlacklistedCapabilities() { + return blacklistedCapabilities; + } +} diff --git a/biz.aQute.resolve/src/biz/aQute/resolve/ResolveProcess.java b/biz.aQute.resolve/src/biz/aQute/resolve/ResolveProcess.java index 26745fdb61..c7f61234d0 100644 --- a/biz.aQute.resolve/src/biz/aQute/resolve/ResolveProcess.java +++ b/biz.aQute.resolve/src/biz/aQute/resolve/ResolveProcess.java @@ -287,10 +287,82 @@ public static String format(ResolutionException re, boolean reportOptional) { .forEach(formatGroup(f)); } + // 4. Check Blacklist + + if (re instanceof BndResolutionException detailedExc) { + printBlacklistDebugLog(chain, f, detailedExc); + } + return f.toString(); } } + /** + * Print -runblacklist related debug output if exists. + * + * @param unresolvedRequirements + * @param f + * @param detailedExc + */ + private static void printBlacklistDebugLog(List unresolvedRequirements, Formatter f, + BndResolutionException detailedExc) { + Set blackList = detailedExc.getBlackList(); + Set blacklistedCapabilities = detailedExc.getBlacklistedCapabilities(); + + if (blacklistedCapabilities != null && !blacklistedCapabilities.isEmpty()) { + + f.format( + "%n%nBlacklisted Capabilities: Some requirements could not be satisfied because of blacklisted capabilities in -runblacklist:%n"); + + printBlacklistSummary(unresolvedRequirements, f, blackList); + + f.format("%n%nAll blacklisted Capabilities:%n"); + + for (Capability cap : blacklistedCapabilities) { + f.format("'%s' providing capability '%s: %s' ignored%n", cap.getResource(), cap.getNamespace(), + cap.getAttributes() + .get(cap.getNamespace())); + } + + f.format("%n%nAll blacklisted Resources:%n"); + + for (Resource res : blackList) { + f.format("%s%n", res); + } + } + } + + /** + * Tries to determine which of the blacklisted capability (resource) is + * responsible for an unresolved requirement. + * + * @param unresolvedRequirements + * @param f + * @param blackList + */ + private static void printBlacklistSummary(List unresolvedRequirements, Formatter f, + Set blackList) { + for (Requirement req : unresolvedRequirements) { + + String namespace = req.getNamespace(); + String filter = req.getDirectives() + .get("filter"); + + for (Resource blacklistedRes : blackList) { + + List findCapability = ResourceUtils.findCapability(blacklistedRes, namespace, + filter); + if (!findCapability.isEmpty()) { + f.format( + "'%s' is ignored because it is blacklisted although providing required capability '%s: %s'%n", + blacklistedRes, namespace, filter); + } + + } + + } + } + /** * Prints a summary by transforming the requirements chain using * FilterParser which removes visual noise from the output and tries to make @@ -435,6 +507,20 @@ private static ResolutionException augment(Collection unresolved, R } } } catch (TimeoutException toe) {} + + if (context instanceof AbstractResolveContext arctx) { + Set blackList = arctx.getBlackList(); + Set blacklistedCapabilities = arctx.getBlacklistedCapabilities(); + + if (!blacklistedCapabilities.isEmpty()) { + return new BndResolutionException(re.getMessage(), re, list, blackList, + blacklistedCapabilities); + } else { + return new ResolutionException(re.getMessage(), re, list); + } + + } + return new ResolutionException(re.getMessage(), re, list); }