diff --git a/biz.aQute.bndlib/src/aQute/bnd/maven/support/packageinfo b/biz.aQute.bndlib/src/aQute/bnd/maven/support/packageinfo index e4869c59e8..eb994e33e0 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/maven/support/packageinfo +++ b/biz.aQute.bndlib/src/aQute/bnd/maven/support/packageinfo @@ -1 +1 @@ -version 3.1 +version 3.2.0 diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/Constants.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/Constants.java index d89044983a..2c52a44797 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/Constants.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/Constants.java @@ -258,6 +258,13 @@ public interface Constants { String REMOTEWORKSPACE = "-remoteworkspace"; + /** + * tag 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 RUNBLACKLIST = "-runblacklist"; String RUNREQUIRES = "-runrequires"; String RUNEE = "-runee"; diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/repository/BaseRepository.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/repository/BaseRepository.java index e409e1cd3f..d9d04ab1c1 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/repository/BaseRepository.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/repository/BaseRepository.java @@ -25,15 +25,20 @@ import aQute.bnd.exceptions.Exceptions; import aQute.bnd.osgi.resource.ResourceUtils; +import aQute.bnd.service.RepositoryPlugin; +import aQute.bnd.service.tags.Tagged; +import aQute.bnd.service.tags.Tags; /** * WARNING ! Not tested */ -public abstract class BaseRepository implements Repository { +public abstract class BaseRepository implements Repository, Tagged { private static final RequirementExpression[] EMPTY = new RequirementExpression[0]; static IdentityExpression all; private final PromiseFactory promiseFactory = new PromiseFactory( PromiseFactory.inlineExecutor()); + private Tags tags = RepositoryPlugin.DEFAULT_REPO_TAGS; + static { Requirement requireAll = ResourceUtils.createWildcardRequirement(); @@ -244,4 +249,12 @@ public RequirementBuilder addAttribute(String name, Object value) { }; } + @Override + public Tags getTags() { + return this.tags; + } + + protected void setTags(Tags tags) { + this.tags = tags; + } } diff --git a/biz.aQute.bndlib/src/aQute/bnd/service/Registry.java b/biz.aQute.bndlib/src/aQute/bnd/service/Registry.java index 584f8fa003..b149d81d09 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/service/Registry.java +++ b/biz.aQute.bndlib/src/aQute/bnd/service/Registry.java @@ -1,12 +1,40 @@ package aQute.bnd.service; import java.util.List; +import java.util.stream.Collectors; + +import aQute.bnd.service.tags.Tagged; /** * A registry for objects. */ public interface Registry { + + /** + * @param + * @param c + * @return all plugins matching the given class + */ List getPlugins(Class c); + /** + * @param + * @param c + * @param tags + * @return all plugins matching the given class and any of the given tags. + * If no tags are given, all plugins are returned without filtering. + */ + default List getPlugins(Class c, String... tags) { + + if (tags.length == 0) { + return getPlugins(c); + } + + return getPlugins(c).stream() + .filter(repo -> repo instanceof Tagged taggedRepo && taggedRepo.getTags() + .includesAny(tags)) + .collect(Collectors.toList()); + } + T getPlugin(Class c); } diff --git a/biz.aQute.bndlib/src/aQute/bnd/service/RepositoryPlugin.java b/biz.aQute.bndlib/src/aQute/bnd/service/RepositoryPlugin.java index 95f381fe09..36ff3e63b0 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/service/RepositoryPlugin.java +++ b/biz.aQute.bndlib/src/aQute/bnd/service/RepositoryPlugin.java @@ -9,7 +9,10 @@ import org.osgi.util.promise.Promise; +import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Processor; +import aQute.bnd.service.tags.Tagged; +import aQute.bnd.service.tags.Tags; import aQute.bnd.version.Version; /** @@ -18,7 +21,15 @@ * combination. It is also possible to put revisions in a repository if the * repository is not read only. */ -public interface RepositoryPlugin { +public interface RepositoryPlugin extends Tagged { + + /** + * Each repo has by default the tag {@link Constants#REPOTAGS_RESOLVE} if no + * tags are set at the repo definition in build.bnd That means it is + * consider + */ + Tags DEFAULT_REPO_TAGS = Tags.of(Constants.REPOTAGS_RESOLVE); + /** * Options used to steer the put operation */ @@ -167,6 +178,8 @@ default void success(File file, Map attrs) throws Exception { boolean progress(File file, int percentage) throws Exception; } + + /** * Return a URL to a matching version of the given bundle. *

@@ -276,4 +289,6 @@ default Promise sync() throws Exception { return null; }); } + + } diff --git a/biz.aQute.bndlib/src/aQute/bnd/service/package-info.java b/biz.aQute.bndlib/src/aQute/bnd/service/package-info.java index 366d1c0aaf..6a9f0a0594 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/service/package-info.java +++ b/biz.aQute.bndlib/src/aQute/bnd/service/package-info.java @@ -1,4 +1,4 @@ -@Version("4.8.0") +@Version("4.9.0") package aQute.bnd.service; import org.osgi.annotation.versioning.Version; diff --git a/biz.aQute.bndlib/src/aQute/bnd/service/repository/packageinfo b/biz.aQute.bndlib/src/aQute/bnd/service/repository/packageinfo index fec6063b13..486d8c8790 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/service/repository/packageinfo +++ b/biz.aQute.bndlib/src/aQute/bnd/service/repository/packageinfo @@ -1 +1 @@ -version 1.6 +version 1.7.0 diff --git a/biz.aQute.bndlib/src/aQute/bnd/service/tags/Tagged.java b/biz.aQute.bndlib/src/aQute/bnd/service/tags/Tagged.java new file mode 100644 index 0000000000..e14a1a5e72 --- /dev/null +++ b/biz.aQute.bndlib/src/aQute/bnd/service/tags/Tagged.java @@ -0,0 +1,21 @@ +package aQute.bnd.service.tags; + +/** + * Allows to add tags to implementing classes. Originally intended for tagging + * repositories. + */ +public interface Tagged { + + /** + * Dummy placeholder for "empty tags". + */ + String EMPTY_TAGS = "<>"; + + /** + * @return a non-null list of tags. Default is empty (meaning 'no tags'). + */ + default Tags getTags() { + return Tags.NO_TAGS; + } + +} diff --git a/biz.aQute.bndlib/src/aQute/bnd/service/tags/Tags.java b/biz.aQute.bndlib/src/aQute/bnd/service/tags/Tags.java new file mode 100644 index 0000000000..b1ca71a129 --- /dev/null +++ b/biz.aQute.bndlib/src/aQute/bnd/service/tags/Tags.java @@ -0,0 +1,163 @@ +package aQute.bnd.service.tags; + +import static java.util.Collections.unmodifiableSortedSet; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.stream.Collectors; + +/** + * A set of tags. A tag is a string-token which can be attached to an entity for + * categorization and filtering. Typically these entities then implement the + * {@link Tagged} interface. + */ +public class Tags implements Set { + private final SortedSet internalSet; + + public final static Tags NO_TAGS = of(); + + private Tags() { + this.internalSet = unmodifiableSortedSet(new TreeSet<>()); + } + + private Tags(Collection c) { + this.internalSet = unmodifiableSortedSet(new TreeSet<>(c)); + } + + @Override + public int size() { + return internalSet.size(); + } + + @Override + public boolean isEmpty() { + return internalSet.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return internalSet.contains(o); + } + + @Override + public Iterator iterator() { + return internalSet.iterator(); + } + + @Override + public Object[] toArray() { + return internalSet.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return internalSet.toArray(a); + } + + @Override + public boolean add(String s) { + return internalSet.add(s); + } + + @Override + public boolean remove(Object o) { + return internalSet.remove(o); + } + + @Override + public boolean containsAll(Collection c) { + return internalSet.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + return internalSet.addAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return internalSet.retainAll(c); + } + + @Override + public boolean removeAll(Collection c) { + return internalSet.removeAll(c); + } + + @Override + public void clear() { + internalSet.clear(); + } + + @Override + public boolean equals(Object o) { + return internalSet.equals(o); + } + + @Override + public int hashCode() { + return internalSet.hashCode(); + } + + @Override + public String toString() { + return internalSet.toString(); + } + + /** + * @param tags + * @return true if any of the given tags is included in the + * current set of tags, otherwise returns false. Also + * if the current set of tags is empty, also true is + * returned. + */ + public boolean includesAny(String... tags) { + + if (isEmpty()) { + // this is on purpose to maintain backwards compatibility for + // entities which do not handle tags yet and return an empty set. In + // other words: if the current set is + // empty that means "yes I match any of what you passed". + return true; + } + + for (String tag : tags) { + if (contains(tag)) { + return true; + } + } + + return false; + } + + /** + * @param name + * @return a Tags instance with the given tags. + */ + public static Tags of(String... name) { + return new Tags(Set.of(name)); + } + + /** + * Parses a comma-separated string of tags into a Tags object. + * + * @param csvTags + * @param defaultTags a default used when csvTags is null or blank + * @return populated Tags or the passed defaultTags. + */ + public static Tags parse(String csvTags, Tags defaultTags) { + if (csvTags == null || csvTags.isBlank()) { + return defaultTags; // default + } + + return new Tags(Arrays.stream(csvTags.split(",")) + .map(String::trim) + .collect(Collectors.toCollection(LinkedHashSet::new))); + } + +} diff --git a/biz.aQute.bndlib/src/aQute/bnd/service/tags/package-info.java b/biz.aQute.bndlib/src/aQute/bnd/service/tags/package-info.java new file mode 100644 index 0000000000..114baa10a6 --- /dev/null +++ b/biz.aQute.bndlib/src/aQute/bnd/service/tags/package-info.java @@ -0,0 +1,4 @@ +@Version("1.0.0") +package aQute.bnd.service.tags; + +import org.osgi.annotation.versioning.Version; diff --git a/biz.aQute.bndlib/src/aQute/lib/deployer/FileRepo.java b/biz.aQute.bndlib/src/aQute/lib/deployer/FileRepo.java index 6f50b0ddc9..61ec6dfe4d 100644 --- a/biz.aQute.bndlib/src/aQute/lib/deployer/FileRepo.java +++ b/biz.aQute.bndlib/src/aQute/lib/deployer/FileRepo.java @@ -1,5 +1,7 @@ package aQute.lib.deployer; +import static aQute.bnd.service.tags.Tags.parse; + import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -35,6 +37,8 @@ import aQute.bnd.service.RepositoryListenerPlugin; import aQute.bnd.service.RepositoryPlugin; import aQute.bnd.service.repository.SearchableRepository.ResourceDescriptor; +import aQute.bnd.service.tags.Tagged; +import aQute.bnd.service.tags.Tags; import aQute.bnd.version.Version; import aQute.lib.collections.SortedList; import aQute.lib.hex.Hex; @@ -75,7 +79,7 @@ */ @aQute.bnd.annotation.plugin.BndPlugin(name = "Filerepo", parameters = FileRepo.Config.class) -public class FileRepo implements Plugin, RepositoryPlugin, Refreshable, RegistryPlugin, Actionable, Closeable { +public class FileRepo implements Plugin, RepositoryPlugin, Refreshable, RegistryPlugin, Actionable, Closeable, Tagged { private final static Logger logger = LoggerFactory.getLogger(FileRepo.class); interface Config { @@ -143,6 +147,11 @@ interface Config { */ public final static String NAME = "name"; + /** + * A comma-separated list of tags. + */ + public final static String TAGS = "tags"; + /** * Should this file repo have an index? Either true or false (absent) */ @@ -252,6 +261,7 @@ interface Config { String name; boolean inited; boolean trace; + Tags tags = DEFAULT_REPO_TAGS; PersistentMap index; private boolean hasIndex; @@ -336,6 +346,7 @@ public void setProperties(Map map) { action = map.get(CMD_AFTER_ACTION); trace = Boolean.parseBoolean(map.get(TRACE)); + tags = parse(map.get(TAGS), DEFAULT_REPO_TAGS); } /** @@ -1048,4 +1059,9 @@ private ResourceDescriptor buildDescriptor(File f, Jar jar, byte[] digest, Strin public void setIndex(boolean b) { hasIndex = b; } + + @Override + public Tags getTags() { + return this.tags; + } } diff --git a/biz.aQute.bndlib/src/aQute/lib/deployer/packageinfo b/biz.aQute.bndlib/src/aQute/lib/deployer/packageinfo index c2664475cd..b1793a21a7 100644 --- a/biz.aQute.bndlib/src/aQute/lib/deployer/packageinfo +++ b/biz.aQute.bndlib/src/aQute/lib/deployer/packageinfo @@ -1 +1 @@ -version 1.0.1 \ No newline at end of file +version 1.1.0 \ No newline at end of file diff --git a/biz.aQute.repository/src/aQute/bnd/deployer/repository/LocalIndexedRepo.java b/biz.aQute.repository/src/aQute/bnd/deployer/repository/LocalIndexedRepo.java index 199b75597a..ad8fc823ed 100644 --- a/biz.aQute.repository/src/aQute/bnd/deployer/repository/LocalIndexedRepo.java +++ b/biz.aQute.repository/src/aQute/bnd/deployer/repository/LocalIndexedRepo.java @@ -40,6 +40,7 @@ import aQute.bnd.service.RepositoryListenerPlugin; import aQute.bnd.service.ResourceHandle; import aQute.bnd.service.ResourceHandle.Location; +import aQute.bnd.service.tags.Tags; import aQute.bnd.version.Version; import aQute.bnd.version.VersionRange; import aQute.lib.hex.Hex; @@ -61,6 +62,7 @@ public class LocalIndexedRepo extends AbstractIndexedRepo implements Refreshable public static final String PROP_PRETTY = "pretty"; public static final String PROP_OVERWRITE = "overwrite"; public static final String PROP_ONLYDIRS = "onlydirs"; + public static final String PROP_TAGS = "tags"; // not actually used (yet). Just to get some parameters interface Config { @@ -132,6 +134,8 @@ public synchronized void setProperties(Map map) { throw new IllegalArgumentException( String.format("Cannot create repository cache: '%s' already exists but is not directory.", cacheDir.getAbsolutePath())); + + super.setTags(Tags.parse(map.get(PROP_TAGS), DEFAULT_REPO_TAGS)); } @Override @@ -614,4 +618,5 @@ public String title(Object... target) throws Exception { public void close() {} + } diff --git a/biz.aQute.repository/src/aQute/bnd/deployer/repository/package-info.java b/biz.aQute.repository/src/aQute/bnd/deployer/repository/package-info.java index 70c3d89086..3949f66f82 100644 --- a/biz.aQute.repository/src/aQute/bnd/deployer/repository/package-info.java +++ b/biz.aQute.repository/src/aQute/bnd/deployer/repository/package-info.java @@ -1,4 +1,4 @@ -@Version("5.0.0") +@Version("5.1.0") package aQute.bnd.deployer.repository; import org.osgi.annotation.versioning.Version; diff --git a/biz.aQute.repository/src/aQute/bnd/repository/maven/pom/provider/BndPomRepository.java b/biz.aQute.repository/src/aQute/bnd/repository/maven/pom/provider/BndPomRepository.java index c6bc7856c9..1c2b6ab60d 100644 --- a/biz.aQute.repository/src/aQute/bnd/repository/maven/pom/provider/BndPomRepository.java +++ b/biz.aQute.repository/src/aQute/bnd/repository/maven/pom/provider/BndPomRepository.java @@ -1,6 +1,7 @@ package aQute.bnd.repository.maven.pom.provider; import static aQute.bnd.osgi.Constants.BSN_SOURCE_SUFFIX; +import static aQute.bnd.service.tags.Tags.parse; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; @@ -271,6 +272,7 @@ public boolean refresh() throws Exception { @Override public void setProperties(Map map) throws Exception { configuration = Converter.cnv(PomConfiguration.class, map); + super.setTags(parse(configuration.tags(), DEFAULT_REPO_TAGS)); } @Override @@ -507,4 +509,5 @@ private Archive trySources(String bsn, Version version) throws Exception { .getOther(Archive.JAR_EXTENSION, Archive.SOURCES_CLASSIFIER); } + } diff --git a/biz.aQute.repository/src/aQute/bnd/repository/maven/pom/provider/PomConfiguration.java b/biz.aQute.repository/src/aQute/bnd/repository/maven/pom/provider/PomConfiguration.java index 30a44a6987..b1ac8b3d38 100644 --- a/biz.aQute.repository/src/aQute/bnd/repository/maven/pom/provider/PomConfiguration.java +++ b/biz.aQute.repository/src/aQute/bnd/repository/maven/pom/provider/PomConfiguration.java @@ -93,4 +93,9 @@ public interface PomConfiguration { */ boolean dependencyManagement(boolean deflt); + /** + * @return a comma separated list of tags. + */ + String tags(); + } diff --git a/biz.aQute.repository/src/aQute/bnd/repository/maven/pom/provider/package-info.java b/biz.aQute.repository/src/aQute/bnd/repository/maven/pom/provider/package-info.java index e4e783ee1f..0d50e3104f 100644 --- a/biz.aQute.repository/src/aQute/bnd/repository/maven/pom/provider/package-info.java +++ b/biz.aQute.repository/src/aQute/bnd/repository/maven/pom/provider/package-info.java @@ -1,4 +1,4 @@ -@Version("2.1.0") +@Version("2.2.0") package aQute.bnd.repository.maven.pom.provider; import org.osgi.annotation.versioning.Version; diff --git a/biz.aQute.repository/src/aQute/bnd/repository/maven/provider/Configuration.java b/biz.aQute.repository/src/aQute/bnd/repository/maven/provider/Configuration.java index 14fa4a320f..c311b257c0 100644 --- a/biz.aQute.repository/src/aQute/bnd/repository/maven/provider/Configuration.java +++ b/biz.aQute.repository/src/aQute/bnd/repository/maven/provider/Configuration.java @@ -76,4 +76,9 @@ public interface Configuration { * Extensions for files that contain multiple JARs */ String multi(); + + /** + * @return a comma separated list of tags. + */ + String tags(); } diff --git a/biz.aQute.repository/src/aQute/bnd/repository/maven/provider/MavenBndRepository.java b/biz.aQute.repository/src/aQute/bnd/repository/maven/provider/MavenBndRepository.java index b750ef71a1..84b9c462a3 100644 --- a/biz.aQute.repository/src/aQute/bnd/repository/maven/provider/MavenBndRepository.java +++ b/biz.aQute.repository/src/aQute/bnd/repository/maven/provider/MavenBndRepository.java @@ -1,6 +1,7 @@ package aQute.bnd.repository.maven.provider; import static aQute.bnd.osgi.Constants.BSN_SOURCE_SUFFIX; +import static aQute.bnd.service.tags.Tags.parse; import java.io.Closeable; import java.io.File; @@ -773,6 +774,7 @@ public void setProperties(Map map) throws Exception { configuration = Converter.cnv(Configuration.class, map); name = configuration.name("Maven"); localRepo = IO.getFile(configuration.local(MAVEN_REPO_LOCAL)); + super.setTags(parse(configuration.tags(), DEFAULT_REPO_TAGS)); } @Override @@ -1074,4 +1076,5 @@ public String getStatus() { public boolean isRemote() { return remote; } + } diff --git a/biz.aQute.repository/src/aQute/bnd/repository/osgi/OSGiRepository.java b/biz.aQute.repository/src/aQute/bnd/repository/osgi/OSGiRepository.java index bbcc47c6dc..75f35e57a6 100644 --- a/biz.aQute.repository/src/aQute/bnd/repository/osgi/OSGiRepository.java +++ b/biz.aQute.repository/src/aQute/bnd/repository/osgi/OSGiRepository.java @@ -1,5 +1,7 @@ package aQute.bnd.repository.osgi; +import static aQute.bnd.service.tags.Tags.parse; + import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -66,6 +68,8 @@ interface Config { String name(); + String tags(); + int poll_time(int pollTimeInSecs); } @@ -296,6 +300,8 @@ public File getRoot() throws Exception { @Override public void setProperties(Map map) throws Exception { config = Converter.cnv(Config.class, map); + + super.setTags(parse(config.tags(), DEFAULT_REPO_TAGS)); } @Override @@ -410,4 +416,5 @@ private void status(String s) { .concat(s); } } + } diff --git a/biz.aQute.repository/src/aQute/bnd/repository/osgi/packageinfo b/biz.aQute.repository/src/aQute/bnd/repository/osgi/packageinfo index 3ef1862dd5..d96c0b8c06 100644 --- a/biz.aQute.repository/src/aQute/bnd/repository/osgi/packageinfo +++ b/biz.aQute.repository/src/aQute/bnd/repository/osgi/packageinfo @@ -1 +1 @@ -version 1.1.1 \ No newline at end of file +version 1.2.0 \ No newline at end of file diff --git a/biz.aQute.repository/src/aQute/bnd/repository/p2/provider/P2Config.java b/biz.aQute.repository/src/aQute/bnd/repository/p2/provider/P2Config.java index 5cab944037..76ab6513a5 100644 --- a/biz.aQute.repository/src/aQute/bnd/repository/p2/provider/P2Config.java +++ b/biz.aQute.repository/src/aQute/bnd/repository/p2/provider/P2Config.java @@ -32,6 +32,11 @@ public interface P2Config { */ String location(String string); + /** + * @return a comma separated list of tags. + */ + String tags(); + /** * If not set or false, this assumes a P2 repository, i.e. the url points to * a P2 repository directory. If set to true, the url is assumed to point to diff --git a/biz.aQute.repository/src/aQute/bnd/repository/p2/provider/P2Repository.java b/biz.aQute.repository/src/aQute/bnd/repository/p2/provider/P2Repository.java index 3803bfaf52..44bc2056a9 100644 --- a/biz.aQute.repository/src/aQute/bnd/repository/p2/provider/P2Repository.java +++ b/biz.aQute.repository/src/aQute/bnd/repository/p2/provider/P2Repository.java @@ -1,5 +1,7 @@ package aQute.bnd.repository.p2.provider; +import static aQute.bnd.service.tags.Tags.parse; + import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -108,6 +110,7 @@ public String getLocation() { public void setProperties(Map map) throws Exception { this.config = Converter.cnv(P2Config.class, map); this.name = this.config.name("p2-" + config.url()); + super.setTags(parse(config.tags(), DEFAULT_REPO_TAGS)); } @Override @@ -193,4 +196,5 @@ public String title(Object... target) throws Exception { return null; } + } diff --git a/biz.aQute.repository/src/aQute/bnd/repository/p2/provider/package-info.java b/biz.aQute.repository/src/aQute/bnd/repository/p2/provider/package-info.java index 61e5c7bb43..864b955a3d 100644 --- a/biz.aQute.repository/src/aQute/bnd/repository/p2/provider/package-info.java +++ b/biz.aQute.repository/src/aQute/bnd/repository/p2/provider/package-info.java @@ -1,4 +1,4 @@ -@Version("1.4.0") +@Version("1.5.0") package aQute.bnd.repository.p2.provider; import org.osgi.annotation.versioning.Version; 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 ff6813a434..dd7667493a 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 @@ -1,17 +1,24 @@ package aQute.bnd.repository.maven.provider; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; +import java.util.ArrayList; import java.util.Formatter; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.osgi.service.repository.Repository; import aQute.bnd.build.Workspace; +import aQute.bnd.osgi.Constants; +import aQute.bnd.service.tags.Tagged; import aQute.bnd.test.jupiter.InjectTemporaryDirectory; import aQute.http.testservers.HttpTestServer.Config; import aQute.lib.io.IO; @@ -57,6 +64,42 @@ public void testEnv() throws Exception { assertNotNull(workspace); assertNotNull(repo); System.out.println(workspace.getBase()); + + // check repo tags + // we expect all repos to be returned for the 'resolve' tag by default + // if a repo has no tag specified + List repos = workspace.getPlugins(Repository.class); + List resolveRepos = workspace.getPlugins(Repository.class, Constants.REPOTAGS_RESOLVE); + assertEquals(repos, resolveRepos); + + Repository repo = repos.get(0); + assertTrue(repo instanceof Tagged); + assertEquals(1, ((Tagged) repo).getTags() + .size()); + assertEquals(Constants.REPOTAGS_RESOLVE, new ArrayList<>(((Tagged) repo).getTags()).get(0)); + + } + + @Test + public void testRepoWithDifferentTag() throws Exception { + // similar as testEnv() + // but override the tag with a different one and repeat the tests + config(Map.of("tags", " foo,bar , a ")); + + List resolveRepos = workspace.getPlugins(Repository.class, Constants.REPOTAGS_RESOLVE); + assertTrue(resolveRepos.isEmpty()); + + List repos = workspace.getPlugins(Repository.class); + Repository repo = repos.get(0); + assertTrue(repo instanceof Tagged); + assertEquals(3, ((Tagged) repo).getTags() + .size()); + + // make sure tags are sorted consistently (alphabetically) + assertEquals("a", new ArrayList<>(((Tagged) repo).getTags()).get(0)); + assertEquals("bar", new ArrayList<>(((Tagged) repo).getTags()).get(1)); + assertEquals("foo", new ArrayList<>(((Tagged) repo).getTags()).get(2)); + } void config(Map override) throws Exception { @@ -74,7 +117,12 @@ void config(Map override) throws Exception { sb.format(" name=test; \\\n", MavenBndRepository.class.getName()); sb.format(" local=%s; \\\n", config.get("local")); sb.format(" releaseUrl=%s; \\\n", config.get("releaseUrl")); - sb.format(" index=%s\n", config.get("index")); + sb.format(" index=%s; \\\n", config.get("index")); + + String tags = config.get("tags"); + if (tags != null && !tags.isBlank()) { + sb.format(" tags=\"%s\"\n", tags); + } build.getParentFile() .mkdirs(); diff --git a/biz.aQute.resolve/src/biz/aQute/resolve/BndrunResolveContext.java b/biz.aQute.resolve/src/biz/aQute/resolve/BndrunResolveContext.java index ab26577420..019c4d5d7c 100644 --- a/biz.aQute.resolve/src/biz/aQute/resolve/BndrunResolveContext.java +++ b/biz.aQute.resolve/src/biz/aQute/resolve/BndrunResolveContext.java @@ -1,5 +1,6 @@ package biz.aQute.resolve; + import java.io.File; import java.io.InputStream; import java.net.URI; @@ -369,6 +370,7 @@ private Processor loadRepositories() throws Exception { name = repo.toString(); } repoNameMap.put(name, repo); + } // Create the result list @@ -402,12 +404,12 @@ private List getAllRepos() { List allRepos; if (project != null && !project.isStandalone()) { allRepos = project.getWorkspace() - .getPlugins(Repository.class); + .getPlugins(Repository.class, Constants.REPOTAGS_RESOLVE); allRepos.removeIf(WorkspaceRepositoryMarker.class::isInstance); WorkspaceResourcesRepository wr = new WorkspaceResourcesRepository(project.getWorkspace()); allRepos.add(wr); } else { - allRepos = registry.getPlugins(Repository.class); + allRepos = registry.getPlugins(Repository.class, Constants.REPOTAGS_RESOLVE); } return allRepos; } diff --git a/bndtools.core/_plugin.xml b/bndtools.core/_plugin.xml index c44c5e31a1..64401dbdc3 100644 --- a/bndtools.core/_plugin.xml +++ b/bndtools.core/_plugin.xml @@ -839,6 +839,7 @@ helpUrl="https://bnd.bndtools.org/plugins/filerepo.html"> + @@ -849,6 +850,7 @@ helpUrl="https://bnd.bndtools.org/plugins/osgirepo.html"> + + + @@ -918,6 +922,7 @@ name="P2Repository" helpUrl="https://bnd.bndtools.org/plugins/p2repo.html"> + @@ -925,8 +930,9 @@ + helpUrl="https://bnd.bndtools.org/plugins/pomrepo.html"> + diff --git a/bndtools.core/src/bndtools/editor/project/RepositoriesEditModel.java b/bndtools.core/src/bndtools/editor/project/RepositoriesEditModel.java index 96be58a6e5..270262b398 100644 --- a/bndtools.core/src/bndtools/editor/project/RepositoriesEditModel.java +++ b/bndtools.core/src/bndtools/editor/project/RepositoriesEditModel.java @@ -1,5 +1,6 @@ package bndtools.editor.project; + import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -13,6 +14,7 @@ import aQute.bnd.build.Workspace; import aQute.bnd.build.model.BndEditModel; import aQute.bnd.build.model.clauses.HeaderClause; +import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Processor; import aQute.bnd.service.RepositoryPlugin; import bndtools.central.Central; @@ -30,7 +32,7 @@ class RepositoriesEditModel { RepositoriesEditModel(BndEditModel model) { this.model = model; this.pluginOrder = model.getWorkspace() - .getPlugins(Repository.class); + .getPlugins(Repository.class, Constants.REPOTAGS_RESOLVE); this.standalone = model.getStandaloneLinks(); this.runrepos = model.getRunRepos(); this.ignoreStandalone = model.getIgnoreStandalone(); @@ -44,6 +46,7 @@ class RepositoriesEditModel { List remains = new ArrayList<>(pluginOrder); for (String name : runrepos) { + Repository r = find(name); if (r != null) { actualOrder.add(r); @@ -55,6 +58,7 @@ class RepositoriesEditModel { } } + private Repository find(String sought) { for (Repository r : pluginOrder) { String name = toName(r); diff --git a/bndtools.core/src/bndtools/editor/workspace/PluginPropertiesPage.java b/bndtools.core/src/bndtools/editor/workspace/PluginPropertiesPage.java index d397967a58..8683d418cf 100644 --- a/bndtools.core/src/bndtools/editor/workspace/PluginPropertiesPage.java +++ b/bndtools.core/src/bndtools/editor/workspace/PluginPropertiesPage.java @@ -1,6 +1,10 @@ package bndtools.editor.workspace; import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.jface.fieldassist.ControlDecoration; @@ -15,6 +19,7 @@ import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.program.Program; import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; @@ -153,6 +158,30 @@ public void widgetSelected(SelectionEvent e) { changed = true; } }); + } + + else if ("combo".equals(propertyType)) { + final Combo combobox = new Combo(fieldContainer, SWT.BORDER); + combobox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + + String options = propertyElement.getAttribute("options"); + if (options != null && !options.isBlank()) { + Collection optionValues = parseTrimmed(options); + combobox.setItems(optionValues.toArray(new String[0])); + } + + if (value != null) + combobox.setText(value); + + combobox.addModifyListener(e -> { + String value1 = combobox.getText(); + if (value1 == null || value1.length() == 0) + properties.remove(name); + else + properties.put(name, value1); + changed = true; + }); + } else { final Text text = new Text(fieldContainer, SWT.BORDER); text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); @@ -234,4 +263,13 @@ public void performHelp() { } } + static Collection parseTrimmed(String csvString) { + if (csvString == null || csvString.isBlank()) { + return List.of(); // empty + } + + return Arrays.stream(csvString.split(",")) + .map(String::trim) + .collect(Collectors.toList()); + } }