From 7e6f9727772aba82840652078a21259bcfa621e4 Mon Sep 17 00:00:00 2001
From: Tim Enderling <T.Enderling@intershop.de>
Date: Wed, 17 Jul 2013 00:40:58 +0200
Subject: [PATCH] Added conditional omission of Ivy artifacts in ivy-publish
 plugin (something in the course of GRADLE-756, the starter into GRADLE-1982).
 The idea is borrowed from org.gradle.api.Task.onlyIf(Closure). During
 normalization of the IvyPublication and for generating the descriptor, the
 artifacts are filtered by their onlyIf spec. Also added a minimal integration
 test.

---
 ...IvyPublishArtifactCustomisationIntegTest.groovy | 42 ++++++++++++++++++++++
 .../org/gradle/api/publish/ivy/IvyArtifact.java    | 33 +++++++++++++++++
 .../org/gradle/api/publish/ivy/IvyArtifactSet.java |  9 +++++
 .../ivy/internal/artifact/DefaultIvyArtifact.java  | 27 +++++++++++++-
 .../internal/artifact/DefaultIvyArtifactSet.java   | 12 +++++++
 .../publication/DefaultIvyModuleDescriptor.java    |  2 +-
 .../publication/DefaultIvyPublication.java         |  2 +-
 7 files changed, 124 insertions(+), 3 deletions(-)

diff --git a/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishArtifactCustomisationIntegTest.groovy b/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishArtifactCustomisationIntegTest.groovy
index c3f6854..279a3d8 100644
--- a/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishArtifactCustomisationIntegTest.groovy
+++ b/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishArtifactCustomisationIntegTest.groovy
@@ -286,6 +286,48 @@ class IvyPublishArtifactCustomisationIntegTest extends AbstractIvyPublishIntegTe
         failure.assertHasCause("Invalid publication 'ivy': artifact file is a directory")
     }
 
+    def "can skip artifacts specifying an onlyIf closure"() {
+        given:
+        executer.withArguments('-i')
+        createBuildScripts("""
+            publications {
+                ivy(IvyPublication) {      
+                    configurations {
+                        foo {}
+                        bar {}
+                        "default" {
+                            extend "foo"
+                        }
+                    }
+                    artifact("customFile.txt") {
+                        name "customFile"
+                        classifier "classified"
+                        conf "foo,bar"
+                    }              
+                    artifact(customDocsTask.outputFile) {
+                        name "docs"
+                        extension "htm"
+                        builtBy customDocsTask
+                        onlyIf { false }
+                    }
+                    artifact(customJar) {
+                        extension "war"
+                        type "web-archive"
+                        conf "*"
+                    } 
+                }
+            }
+""")
+        when:
+        succeeds 'publish'
+
+        then:
+        module.assertPublished()
+        module.assertArtifactsPublished("ivy-2.4.xml", "ivyPublish-2.4.war", "customFile-2.4-classified.txt")        
+        !module.ivy.artifacts.find { it.name == "docs" }
+        module.ivy.artifacts*.name as Set == ["ivyPublish", "customFile"] as Set        
+    }
+    
     private createBuildScripts(def publications, def append = "") {
         file("customFile.txt") << "some content"
         settingsFile << "rootProject.name = 'ivyPublish'"
diff --git a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/IvyArtifact.java b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/IvyArtifact.java
index 1c0f784..d0d493e 100644
--- a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/IvyArtifact.java
+++ b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/IvyArtifact.java
@@ -19,6 +19,9 @@ package org.gradle.api.publish.ivy;
 import org.gradle.api.Buildable;
 import org.gradle.api.Incubating;
 import org.gradle.api.Nullable;
+import org.gradle.api.specs.Spec;
+
+import groovy.lang.Closure;
 
 import java.io.File;
 
@@ -102,4 +105,34 @@ public interface IvyArtifact extends Buildable {
      * @param tasks The tasks. These are evaluated as per {@link org.gradle.api.Task#dependsOn(Object...)}.
      */
     void builtBy(Object... tasks);
+    
+    /**
+     * <p>Add the artifact only if the given closure returns true. The closure will be evaluated at task execution
+     * time, not during configuration. The closure will be passed a single parameter, this artifact. If the closure returns
+     * false, the artifact will be not be included in the descriptor and will not be published.</p>
+     *
+     * <p>You may add multiple such predicates. The artifact is omitted if any of the predicates return false.</p>
+     *
+     * <p>A typical usage is to skip archive tasks if no content is available to be archived and then omit the corresponding artifacts.</p> 
+     *
+     * @param onlyIfClosure code to execute to determine if artifact should be included
+     */
+    void onlyIf(Closure onlyIfClosure);
+
+    /**
+     * <p>Add the artifact only if the given spec is satisfied. The spec will be evaluated at task execution time, not
+     * during configuration. If the Spec is not satisfied, the artifact will be not be included in the descriptor and will not be published.</p>
+     *
+     * <p>You may add multiple such predicates. The task is skipped if any of the predicates return false.</p>
+     *
+     * <p>A typical usage is to skip archive tasks if no content is available to be archived and then omit the corresponding artifacts.</p> 
+     *
+     * @param onlyIfSpec specifies if a task should be run
+     */
+    void onlyIf(Spec<? super IvyArtifact> onlyIfSpec);
+
+	/**
+     * <p>Returns a spec that determines if the artifact should be included or omitted from publication. Never null.</p> 
+     */    
+    Spec<? super IvyArtifact> getOnlyIf();
 }
diff --git a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/IvyArtifactSet.java b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/IvyArtifactSet.java
index f56860b..ebba870 100644
--- a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/IvyArtifactSet.java
+++ b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/IvyArtifactSet.java
@@ -59,4 +59,13 @@ public interface IvyArtifactSet extends DomainObjectSet<IvyArtifact> {
      * @param config An action to configure the values of the constructed {@link IvyArtifact}.
      */
      IvyArtifact artifact(Object source, Action<? super IvyArtifact> config);
+     
+    
+     /**
+      * Returns the subset of artifacts, for which the onlyIf spec/closure currently returns true 
+      * (including artifacts with no onlyIf spec/closure defined). The closures/specs are executed 
+      * on every call of this method and the method may thus return different result sets at different times.
+      *  
+      */
+     IvyArtifactSet toSetFilteredByOnlyIf();
 }
diff --git a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/artifact/DefaultIvyArtifact.java b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/artifact/DefaultIvyArtifact.java
index d9b1ef1..25e19c9 100644
--- a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/artifact/DefaultIvyArtifact.java
+++ b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/artifact/DefaultIvyArtifact.java
@@ -16,11 +16,15 @@
 
 package org.gradle.api.publish.ivy.internal.artifact;
 
+import org.gradle.api.specs.AndSpec;
 import org.gradle.api.internal.tasks.DefaultTaskDependency;
 import org.gradle.api.publish.ivy.IvyArtifact;
+import org.gradle.api.specs.Spec;
 import org.gradle.api.tasks.TaskDependency;
 import org.gradle.util.GUtil;
 
+import groovy.lang.Closure;
+
 import java.io.File;
 
 public class DefaultIvyArtifact implements IvyArtifact {
@@ -31,7 +35,8 @@ public class DefaultIvyArtifact implements IvyArtifact {
     private String type;
     private String classifier;
     private String conf;
-
+    private AndSpec<IvyArtifact> onlyIfSpec = new AndSpec<IvyArtifact>(createNewOnlyIfSpec());
+    
     public DefaultIvyArtifact(File file, String name, String extension, String type, String classifier) {
         this.file = file;
         this.name = name;
@@ -98,4 +103,24 @@ public class DefaultIvyArtifact implements IvyArtifact {
     public String toString() {
         return String.format("%s %s:%s:%s:%s", getClass().getSimpleName(), getName(), getType(), getExtension(), getClassifier());
     }
+
+    public void onlyIf(Closure onlyIfClosure) {
+        this.onlyIfSpec = this.onlyIfSpec.and(onlyIfClosure);
+    }
+
+    public void onlyIf(Spec<? super IvyArtifact> onlyIfSpec) {       
+        this.onlyIfSpec = this.onlyIfSpec.and(onlyIfSpec);
+    }
+    
+    private AndSpec<IvyArtifact> createNewOnlyIfSpec() {
+        return new AndSpec<IvyArtifact>(new Spec<IvyArtifact>() {
+            public boolean isSatisfiedBy(IvyArtifact element) {
+                return element == DefaultIvyArtifact.this;
+            }
+        });
+    }
+    
+    public Spec<? super IvyArtifact> getOnlyIf() {
+        return onlyIfSpec;
+    }
 }
diff --git a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/artifact/DefaultIvyArtifactSet.java b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/artifact/DefaultIvyArtifactSet.java
index 9dd4c6b..8de90a4 100644
--- a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/artifact/DefaultIvyArtifactSet.java
+++ b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/artifact/DefaultIvyArtifactSet.java
@@ -59,6 +59,18 @@ public class DefaultIvyArtifactSet extends DefaultDomainObjectSet<IvyArtifact> i
     public FileCollection getFiles() {
         return files;
     }
+    
+    public DefaultIvyArtifactSet toSetFilteredByOnlyIf() {
+        DefaultIvyArtifactSet filtered = new DefaultIvyArtifactSet(publicationName, ivyArtifactParser);
+        
+        for (IvyArtifact ivyArtifact : this) {
+            if (ivyArtifact.getOnlyIf().isSatisfiedBy(ivyArtifact)) {
+                filtered.add(ivyArtifact);
+            }
+        }
+        
+        return filtered;
+    }
 
     private class ArtifactsFileCollection extends AbstractFileCollection {
 
diff --git a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/publication/DefaultIvyModuleDescriptor.java b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/publication/DefaultIvyModuleDescriptor.java
index 60da380..886e013 100644
--- a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/publication/DefaultIvyModuleDescriptor.java
+++ b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/publication/DefaultIvyModuleDescriptor.java
@@ -63,7 +63,7 @@ public class DefaultIvyModuleDescriptor implements IvyModuleDescriptorInternal {
     }
 
     public Set<IvyArtifact> getArtifacts() {
-        return ivyPublication.getArtifacts();
+        return ivyPublication.getArtifacts().toSetFilteredByOnlyIf();
     }
 
     public Set<IvyDependencyInternal> getDependencies() {
diff --git a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/publication/DefaultIvyPublication.java b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/publication/DefaultIvyPublication.java
index 27c85e6..b5dfd2d 100644
--- a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/publication/DefaultIvyPublication.java
+++ b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/publication/DefaultIvyPublication.java
@@ -183,7 +183,7 @@ public class DefaultIvyPublication implements IvyPublicationInternal {
     }
 
     public IvyNormalizedPublication asNormalisedPublication() {
-        return new IvyNormalizedPublication(name, getIdentity(), getDescriptorFile(), ivyArtifacts);
+        return new IvyNormalizedPublication(name, getIdentity(), getDescriptorFile(), ivyArtifacts.toSetFilteredByOnlyIf());
     }
 
     private File getDescriptorFile() {
-- 
1.8.1.msysgit.1

