ArtifactSpec supports tagging. Common classifiers and tags defined.
diff --git a/ide/project.dependency/src/org/netbeans/modules/project/dependency/ArtifactSpec.java b/ide/project.dependency/src/org/netbeans/modules/project/dependency/ArtifactSpec.java
index 0bdc541..fb80df8 100644
--- a/ide/project.dependency/src/org/netbeans/modules/project/dependency/ArtifactSpec.java
+++ b/ide/project.dependency/src/org/netbeans/modules/project/dependency/ArtifactSpec.java
@@ -22,7 +22,10 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.Objects;
+import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.annotations.common.NonNull;
@@ -45,10 +48,58 @@
* The version specified is further classified by {@link VersionKind}, to
* distinguish versions possibly from repositories, development versions and
* floating versions.
+ * <p>
+ * The ArtifactSpec may provide additional tags, that can further describe the artifact,
+ * but those tags are not part of "identity" of the artifact, for dependencies or build
+ * systems, only
+ * <ul>
+ * <li>group
+ * <li>artifact
+ * <li>version
+ * <li>classifier
+ * <Li>extension
+ * </ul>
+ * are important.
*
* @author sdedic
*/
public final class ArtifactSpec<T> {
+
+ /**
+ * A tag for an artifact with basic output of the project's code/contents.
+ * You almost never want this, usually you want {@code null} classifier to
+ * identify the <b>default</b> output. But in rare cases you really do want
+ * to avoid post-processing or shading, this (abstract) classifier should
+ * identify an artifact before those steps.
+ * <p>
+ * If used in a query, a non-tagged artifact may be returned if the implementation
+ * does not support the tag.
+ */
+ public static final String TAG_BASE = "<basic>"; // NOI18N
+
+ /**
+ * Tag for an artifact, that eventually contains dependencies bundled in. If used
+ * in a query, an ordinary (non-tagged) artifact may be returned from the query in case
+ * the implementation does not support the tag. Implementations may use additional, more
+ * specific tags on the returned artifacts.
+ */
+ public static final String TAG_SHADED = "<shaded>";
+
+ /**
+ * Classifier for an artifact that contains sources.
+ */
+ public static final String CLASSIFIER_SOURCES = "sources"; // NOI18N
+
+ /**
+ * Classifier for an artifact that contains test code
+ */
+ public static final String CLASSIFIER_TESTS = "tests"; // NOI18N
+
+ /**
+ * Classifier for an artifact that contains test sources.
+ */
+ public static final String CLASSIFIER_TEST_SOURCES = "test-sources"; // NOI18N
+
static final Logger LOG = Logger.getLogger(ProjectDependencies.class.getName());
/**
@@ -74,10 +125,14 @@
private final String classifier;
private final boolean optional;
private final URI location;
+
+ // note: tags is NOT a part of hascode / equals, as externally only the classifier
+ // is visible, e.g. to the build system.
+ private final Set<String> tags;
private FileObject localFile;
final T data;
- ArtifactSpec(VersionKind kind, String groupId, String artifactId, String versionSpec, String type, String classifier, boolean optional, URI location, FileObject localFile, T impl) {
+ ArtifactSpec(VersionKind kind, String groupId, String artifactId, String versionSpec, String type, String classifier, boolean optional, URI location, FileObject localFile, Set<String> tags, T impl) {
this.kind = kind;
this.groupId = groupId;
this.artifactId = artifactId;
@@ -88,6 +143,7 @@
this.type = type;
this.location = location;
this.localFile = localFile;
+ this.tags = tags == null ? Collections.emptySet() : tags;
}
public T getData() {
@@ -120,6 +176,10 @@
}
return f == FileUtil.getConfigRoot() ? null : f;
}
+
+ public boolean hasTag(String tag) {
+ return tags.contains(tag);
+ }
public URI getLocation() {
return location;
@@ -238,23 +298,25 @@
// should not happen
}
}
- return new ArtifactSpec<V>(VersionKind.REGULAR, groupId, artifactId, versionSpec, type, classifier, optional, uri, localFile, data);
+ return new ArtifactSpec<V>(VersionKind.REGULAR, groupId, artifactId, versionSpec, type, classifier, optional, uri, localFile, Collections.emptySet(), data);
}
public static <V> ArtifactSpec<V> createSnapshotSpec(
@NonNull String groupId, @NonNull String artifactId,
@NullAllowed String type, @NullAllowed String classifier,
@NonNull String versionSpec, boolean optional, @NullAllowed FileObject localFile, @NonNull V data) {
- URL u = URLMapper.findURL(localFile, URLMapper.EXTERNAL);
URI uri = null;
- if (u != null) {
- try {
- uri = u.toURI();
- } catch (URISyntaxException ex) {
- // should not happen
+ if (localFile != null) {
+ URL u = URLMapper.findURL(localFile, URLMapper.EXTERNAL);
+ if (u != null) {
+ try {
+ uri = u.toURI();
+ } catch (URISyntaxException ex) {
+ // should not happen
+ }
}
}
- return new ArtifactSpec<V>(VersionKind.SNAPSHOT, groupId, artifactId, versionSpec, type, classifier, optional, uri, localFile, data);
+ return new ArtifactSpec<V>(VersionKind.SNAPSHOT, groupId, artifactId, versionSpec, type, classifier, optional, uri, localFile, Collections.emptySet(), data);
}
public static final <T> Builder<T> builder(String group, String artifact, String version, T projectData) {
@@ -272,6 +334,7 @@
private boolean optional;
private FileObject localFile;
private URI location;
+ private Set<String> tags;
public Builder(String groupId, String artifactId, String versionSpec, T data) {
this.groupId = groupId;
@@ -299,6 +362,25 @@
this.localFile = localFile;
return this;
}
+
+ public Builder tag(String tag) {
+ if (tags == null) {
+ tags = new HashSet<>();
+ }
+ tags.add(tag);
+ return this;
+ }
+
+ public Builder tags(String... tags) {
+ if (tags == null || tags.length == 0) {
+ return this;
+ } else {
+ for (String t : tags) {
+ tag(t);
+ }
+ return this;
+ }
+ }
/**
* Forces the local file reference. Unlike {@link #localFile}, if {@code null} is
@@ -319,7 +401,7 @@
}
public ArtifactSpec build() {
- return new ArtifactSpec(kind, groupId, artifactId, versionSpec, type, classifier, optional, location, localFile, data);
+ return new ArtifactSpec(kind, groupId, artifactId, versionSpec, type, classifier, optional, location, localFile, tags, data);
}
}
}
diff --git a/ide/project.dependency/src/org/netbeans/modules/project/dependency/ProjectArtifactsQuery.java b/ide/project.dependency/src/org/netbeans/modules/project/dependency/ProjectArtifactsQuery.java
index f92840b..1d8a41b 100644
--- a/ide/project.dependency/src/org/netbeans/modules/project/dependency/ProjectArtifactsQuery.java
+++ b/ide/project.dependency/src/org/netbeans/modules/project/dependency/ProjectArtifactsQuery.java
@@ -19,9 +19,13 @@
package org.netbeans.modules.project.dependency;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.stream.Collectors;
@@ -43,7 +47,15 @@
* <p>
* By default the query will return artifacts produced by project's compilation (incl. packaging, in maven terminology) -
* but the exact meaning depends on a build system used, and the project's settings and the active configuration.
- *
+ * <p>
+ * Different project output are marked by different <b>classifiers</b>. Some special, abstract classifiers may
+ * be defined that should be handled by implementations specific for each build system.
+ * <ul>
+ * <li>{@link Filter#CLASSIFIER_BUNDLED} - describes a product with all dependencies included, such as the output of
+ * <b>shade or shadow plugins</b> in Gradle or Maven. Since the plugins behave differently (maven replaces the original artifact,
+ * while gradle attaches a new one), this meta-classiifer allows to pick the appropriate artifact despite its real classifier depends
+ * on project type. If there are more bundles (shadows),
+ * </ul>
* @author sdedic
*/
public final class ProjectArtifactsQuery {
@@ -140,6 +152,7 @@
List<ArtifactSpec> updateResults() {
boolean changes = false;
+ // accept only first matching artifact.
Collection<ArtifactSpec> specs = new LinkedHashSet<>();
for (E<?> e : delegates) {
Collection<ArtifactSpec> ex = e.findExcludedArtifacts();
@@ -213,25 +226,27 @@
* perhaps determined by the configured packaging with <b>no classifier</b>. It it possible
* to list artifacts of all types and/or artifacts with any classifier in one query.
*/
- public static class Filter {
+ public static final class Filter {
/**
* Represents all types of artifacts. The query will return all build products
*/
- public static final String TYPE_ALL = "all"; // NOI18N
+ public static final String TYPE_ALL = "<all>"; // NOI18N
/**
* Will return artifacts with any classifier.
*/
- public static final String CLASSIFIER_ANY = "any"; // NOI18N
+ public static final String CLASSIFIER_ANY = "<any>"; // NOI18N
+ private final Set<String> tags;
private final String classifier;
private final String artifactType;
private final ProjectActionContext buildContext;
- Filter(String artifactType, String classifier, ProjectActionContext buildContext) {
+ Filter(String artifactType, String classifier, Set<String> tags, ProjectActionContext buildContext) {
this.classifier = classifier;
this.artifactType = artifactType;
this.buildContext = buildContext;
+ this.tags = tags == null ? Collections.emptySet() : Collections.unmodifiableSet(tags);
}
/**
@@ -245,6 +260,14 @@
public String getClassifier() {
return classifier;
}
+
+ public Set<String> getTags() {
+ return tags;
+ }
+
+ public boolean hasTag(String t) {
+ return tags.contains(t);
+ }
/**
* The desired artifact type. Only artifacts with tha type will be returned. {@link #TYPE_ALL} means that artifacts
@@ -274,7 +297,7 @@
*/
@NonNull
public static Filter newQuery(@NullAllowed String artifactType) {
- return new Filter(artifactType, null, null);
+ return new Filter(artifactType, null, null, null);
}
/**
@@ -286,6 +309,20 @@
*/
@NonNull
public static Filter newQuery(@NullAllowed String artifactType, @NullAllowed String classifier, @NullAllowed ProjectActionContext buildContext) {
- return new Filter(artifactType, classifier, buildContext);
+ return new Filter(artifactType, classifier, null, buildContext);
+ }
+
+ /**
+ * Creates a Filter with the specified properties
+ * @param artifactType the desired type; use {@code null} for the default artifact type (i.e. defined by packaging)
+ * @param classifier the desired classifier; use {@code null} for no classifier
+ * @param buildContext the action context
+ * @return Filter instance.
+ */
+ @NonNull
+ public static Filter newQuery(@NullAllowed String artifactType, @NullAllowed String classifier, @NullAllowed ProjectActionContext buildContext, String... tags) {
+ return new Filter(artifactType, classifier,
+ tags == null || tags.length == 0 ? null : new HashSet<>(Arrays.asList(tags)),
+ buildContext);
}
}
diff --git a/ide/project.dependency/src/org/netbeans/modules/project/dependency/spi/ProjectArtifactsImplementation.java b/ide/project.dependency/src/org/netbeans/modules/project/dependency/spi/ProjectArtifactsImplementation.java
index 198350a..339cc78 100644
--- a/ide/project.dependency/src/org/netbeans/modules/project/dependency/spi/ProjectArtifactsImplementation.java
+++ b/ide/project.dependency/src/org/netbeans/modules/project/dependency/spi/ProjectArtifactsImplementation.java
@@ -41,7 +41,8 @@
public Result evaluate(ProjectArtifactsQuery.Filter query);
/**
- * Returns evaluation order of this Implementation. If the Implementation needs to post-process
+ * Returns evaluation order of this Implementation. Implementations ordered
+ * later may remove artifacts generated by earlier ones.
*
* @return
*/