diff --git a/biz.aQute.bndlib/src/aQute/bnd/build/Project.java b/biz.aQute.bndlib/src/aQute/bnd/build/Project.java index aed616d9d3..88405ca7fa 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/build/Project.java +++ b/biz.aQute.bndlib/src/aQute/bnd/build/Project.java @@ -637,6 +637,8 @@ public List getBundles(Strategy strategyx, String spec, String source decorator.decorate(bundles, true); } + List repos = getRepositories(repoTagsBySource(source)); + List result = new ArrayList<>(); try { for (Entry entry : bundles.entrySet()) { @@ -649,12 +651,12 @@ public List getBundles(Strategy strategyx, String spec, String source boolean triedGetBundle = false; if (bsn.indexOf('*') >= 0) { - return getBundlesWildcard(bsn, versionRange, strategyx, attrs); + return getBundlesWildcard(bsn, versionRange, strategyx, attrs, repos); } if (versionRange != null) { if (versionRange.equals(VERSION_ATTR_LATEST) || versionRange.equals(VERSION_ATTR_SNAPSHOT)) { - found = getBundle(bsn, versionRange, strategyx, attrs); + found = getBundle(bsn, versionRange, strategyx, attrs, repos); triedGetBundle = true; } } @@ -693,7 +695,7 @@ public List getBundles(Strategy strategyx, String spec, String source found = new Container(this, bsn, "file", Container.TYPE.EXTERNAL, f, error, attrs, null); } } else if (!triedGetBundle) { - found = getBundle(bsn, versionRange, strategyx, attrs); + found = getBundle(bsn, versionRange, strategyx, attrs, repos); } } @@ -727,6 +729,25 @@ public List getBundles(Strategy strategyx, String spec, String source return result; } + private String[] repoTagsBySource(String source) { + + if (source == null) { + return null; + } + + if (Constants.BUILDPATH.equals(source)) { + return new String[] { + Constants.REPOTAGS_COMPILE + }; + } else if (Constants.TESTPATH.equals(source)) { + return new String[] { + Constants.REPOTAGS_COMPILE, Constants.REPOTAGS_TEST + }; + } + // TODO how to determine tag "debug" + return null; + } + /** * Just calls a new method with a default parm. * @@ -750,6 +771,13 @@ Collection getBundles(Strategy strategy, String spec) throws Exceptio public List getBundlesWildcard(String bsnPattern, String range, Strategy strategyx, Map attrs) throws Exception { + List plugins = getRepositories(); + return getBundlesWildcard(bsnPattern, range, strategyx, attrs, plugins); + } + + private List getBundlesWildcard(String bsnPattern, String range, Strategy strategyx, + Map attrs, List repos) throws Exception { + if (VERSION_ATTR_SNAPSHOT.equals(range) || VERSION_ATTR_PROJECT.equals(range)) return Collections.singletonList(new Container(this, bsnPattern, range, TYPE.ERROR, null, "Cannot use snapshot or project version with wildcard matches", null, null)); @@ -773,8 +801,7 @@ public List getBundlesWildcard(String bsnPattern, String range, Strat SortedMap> providerMap = new TreeMap<>(); - List plugins = getRepositories(); - for (RepositoryPlugin plugin : plugins) { + for (RepositoryPlugin plugin : repos) { if (repoFilter != null && !repoFilter.match(plugin)) continue; @@ -822,11 +849,13 @@ public List getBundlesWildcard(String bsnPattern, String range, Strat DownloadBlocker downloadBlocker = new DownloadBlocker(this); File bundle = repo.get(bsn, version, attrs, downloadBlocker); + if (bundle != null && !bundle.getName() .endsWith(".lib")) { containers .add(new Container(this, bsn, range, Container.TYPE.REPO, bundle, null, attrs, downloadBlocker)); } + } return containers; @@ -1253,6 +1282,14 @@ public void release(String name, boolean test) throws Exception { public Container getBundle(String bsn, String range, Strategy strategy, Map attrs) throws Exception { + List plugins = getRepositories(); + return getBundle(bsn, range, strategy, attrs, plugins); + + } + + private Container getBundle(String bsn, String range, Strategy strategy, Map attrs, + List repos) throws Exception { + if (range == null) range = "0"; if (attrs == null) { @@ -1278,7 +1315,7 @@ public Container getBundle(String bsn, String range, Strategy strategy, Map plugins = getRepositories(); + if (useStrategy == Strategy.EXACT) { if (!Verifier.isVersion(range)) @@ -1288,7 +1325,8 @@ public Container getBundle(String bsn, String range, Strategy strategy, Map versions = new TreeMap<>(); - for (RepositoryPlugin plugin : plugins) { + + for (RepositoryPlugin plugin : repos) { if (repoFilter != null && !repoFilter.match(plugin)) continue; @@ -1382,8 +1421,7 @@ public Container getBundle(String bsn, String range, Strategy strategy, Map getRepositories() { - return workspace.getRepositories(); + public List getRepositories(String... tags) { + return workspace.getRepositories(tags); } /** diff --git a/biz.aQute.bndlib/src/aQute/bnd/build/Workspace.java b/biz.aQute.bndlib/src/aQute/bnd/build/Workspace.java index 1e8a2efaef..869f5829be 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/build/Workspace.java +++ b/biz.aQute.bndlib/src/aQute/bnd/build/Workspace.java @@ -98,6 +98,7 @@ import aQute.bnd.service.repository.Prepare; import aQute.bnd.service.repository.RepositoryDigest; import aQute.bnd.service.repository.SearchableRepository.ResourceDescriptor; +import aQute.bnd.service.tags.Tags; import aQute.bnd.stream.MapStream; import aQute.bnd.url.MultiURLConnectionHandler; import aQute.bnd.util.home.Home; @@ -720,6 +721,32 @@ public List getRepositories() { return data.repositories.get(); } + /** + * @param tags list tags to filter. null means all. + * @return matching repositories. + */ + public List getRepositories(String... tags) { + + if (tags == null) { + return data.repositories.get(); + } + + Tags activeTags = Tags.parse(getProperty(Constants.ACTIVETAGS), Tags.of(Constants.REPOTAGS_RESOLVE)); + + return data.repositories.get() + .stream() + .filter(repo -> { + Tags repotags = repo.getTags(); + + if (repotags == null || !activeTags.includesAny(tags) || repotags.includesAny(tags)) { + return true; + } + + return false; + }) + .toList(); + } + private List initRepositories() { List plugins = getPlugins(RepositoryPlugin.class); for (RepositoryPlugin repo : plugins) { diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/Constants.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/Constants.java index 346d838dae..cd67b36ca4 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/Constants.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/Constants.java @@ -258,12 +258,16 @@ public interface Constants { String REMOTEWORKSPACE = "-remoteworkspace"; + String ACTIVETAGS = "-activetags"; /** - * tag for repos which should be used for Resolving bundles. This is also + * tags for repos which should be used for Resolving bundles. This is also * the default tag for all repos which not have specified tags (also for bc * reasons) */ String REPOTAGS_RESOLVE = "resolve"; + String REPOTAGS_COMPILE = "compile"; + String REPOTAGS_TEST = "test"; + String REPOTAGS_DEBUG = "debug"; String RUNBLACKLIST = "-runblacklist"; String RUNREQUIRES = "-runrequires"; diff --git a/biz.aQute.bndlib/src/aQute/bnd/service/tags/Tags.java b/biz.aQute.bndlib/src/aQute/bnd/service/tags/Tags.java index 24a4e7c4c1..6cc2743677 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/service/tags/Tags.java +++ b/biz.aQute.bndlib/src/aQute/bnd/service/tags/Tags.java @@ -111,7 +111,24 @@ public String toString() { return internalSet.toString(); } + + /** + * Returns {@code true} if this entity should take part in any of the + * caller-requested tags. + * + * // @formatter:off + * Semantics – in precedence order + * -------------------------------- + * 1. **Legacy wildcard** – if this entity has no tags at all, it matches + * every tag (backwards compatibility). + * 2. **Negative tag overrides** – if the entity contains a literal tag + * {@code "no" + tag} it is excluded from that phase, regardless + * of all other rules (example 'nocompile'. + * 3. **Positive tag match** – if the entity contains a tag that matches a + * requested glob, it is included. + * // @formatter:on + * * @param tags (globs) * @return true if any of the given tags is included in the * current set of tags, otherwise returns false. Also @@ -128,9 +145,11 @@ public boolean includesAny(String... tags) { return true; } + for (String tagGlob : tags) { + if (matchesAny(new Glob(tagGlob))) { - return true; + return true; // success } } @@ -138,11 +157,13 @@ public boolean includesAny(String... tags) { } + private boolean matchesAny(Glob glob) { return internalSet.stream() .anyMatch(s -> glob.matches(s)); } + /** * @param name * @return a Tags instance with the given tags. diff --git a/biz.aQute.repository/test/aQute/bnd/repository/maven/provider/WorkspaceTest.java b/biz.aQute.repository/test/aQute/bnd/repository/maven/provider/WorkspaceTest.java index 6838756b81..1dbf815a30 100644 --- a/biz.aQute.repository/test/aQute/bnd/repository/maven/provider/WorkspaceTest.java +++ b/biz.aQute.repository/test/aQute/bnd/repository/maven/provider/WorkspaceTest.java @@ -11,9 +11,12 @@ import java.util.List; import java.util.Map; +import org.assertj.core.api.SoftAssertions; +import org.assertj.core.api.junit.jupiter.SoftAssertionsExtension; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.osgi.service.repository.Repository; import aQute.bnd.build.Workspace; @@ -25,6 +28,7 @@ import aQute.lib.io.IO; import aQute.maven.provider.FakeNexus; +@ExtendWith(SoftAssertionsExtension.class) public class WorkspaceTest { @InjectTemporaryDirectory File tmp; @@ -80,6 +84,10 @@ public void testEnv() throws Exception { assertTrue(((Tagged) repo).getTags() .includesAny(Constants.REPOTAGS_RESOLVE)); + // same for 'compile' tag + List compileRepos = workspace.getPlugins(Repository.class, Constants.REPOTAGS_RESOLVE); + assertEquals(repos, compileRepos); + } @Test @@ -146,4 +154,59 @@ public void testTagDisplay() { assertEquals("foo", Tags.print(Tags.of(Tagged.EMPTY_TAGS, "foo"))); assertEquals("bar,foo", Tags.print(Tags.of(Tagged.EMPTY_TAGS, "foo", "bar"))); } + + @Test + public void testTags(SoftAssertions softly) { + + softly.assertThat(Tags.of() + .includesAny("resolve")) + .isTrue(); + + softly.assertThat(Tags.of() + .includesAny("compile")) + .isTrue(); + + softly.assertThat(Tags.of("resolve") + .includesAny("resolve")) + .isTrue(); + + + softly.assertThat(Tags.of("resolve", "compile") + .includesAny("resolve")) + .isTrue(); + + softly.assertThat(Tags.of("resolve", "compile") + .includesAny("compile")) + .isTrue(); + + softly.assertThat(Tags.of("resolve", "compile") + .includesAny("compile", "resolve")) + .isTrue(); + + softly.assertThat(Tags.of("resolve", "compile") + .includesAny("resolve", "compile")) + .isTrue(); + + softly.assertThat(Tags.of("resolve", "compile", "somethingelse") + .includesAny("resolve", "compile")) + .isTrue(); + + // negative + softly.assertThat(Tags.of("resolve", "nocompile") + .includesAny("resolve")) + .isTrue(); + + softly.assertThat(Tags.of("resolve", "nocompile") + .includesAny("compile")) + .isFalse(); + + softly.assertThat(Tags.of("noresolve", "nocompile") + .includesAny("resolve")) + .isFalse(); + + softly.assertThat(Tags.of("noresolve", "nocompile") + .includesAny("compile")) + .isFalse(); + + } } diff --git a/biz.aQute.resolve/test/biz/aQute/resolve/RunResolutionTest.java b/biz.aQute.resolve/test/biz/aQute/resolve/RunResolutionTest.java index b88652ace0..492b350cba 100644 --- a/biz.aQute.resolve/test/biz/aQute/resolve/RunResolutionTest.java +++ b/biz.aQute.resolve/test/biz/aQute/resolve/RunResolutionTest.java @@ -591,7 +591,7 @@ public MyBndrun(Workspace workspace, File propertiesFile) throws Exception { } @Override - public List getRepositories() { + public List getRepositories(String... tags) { return getPlugins(RepositoryPlugin.class); } diff --git a/bndtools.core/_plugin.xml b/bndtools.core/_plugin.xml index 320715e2bd..9a32568246 100644 --- a/bndtools.core/_plugin.xml +++ b/bndtools.core/_plugin.xml @@ -826,7 +826,7 @@ helpUrl="https://bnd.bndtools.org/plugins/filerepo.html"> - + @@ -837,7 +837,7 @@ helpUrl="https://bnd.bndtools.org/plugins/osgirepo.html"> - + - + - + @@ -909,7 +909,7 @@ name="P2Repository" helpUrl="https://bnd.bndtools.org/plugins/p2repo.html"> - + @@ -919,7 +919,7 @@ name="Maven POM Repository" helpUrl="https://bnd.bndtools.org/plugins/pomrepo.html"> - +