Author: xavier
Date: Wed Nov 28 15:05:25 2007
New Revision: 599186

URL: http://svn.apache.org/viewvc?rev=599186&view=rev
Log:
NEW: support atomic publish operation (IVY-492) (with contribution from Geoff 
Reedy)

Added:
    incubator/ivy/core/trunk/test/java/org/apache/ivy/core/publish/
    
incubator/ivy/core/trunk/test/java/org/apache/ivy/core/publish/PublishEngineTest.java
   (with props)
Modified:
    incubator/ivy/core/trunk/CHANGES.txt
    
incubator/ivy/core/trunk/src/java/org/apache/ivy/core/publish/PublishEngine.java
    
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/repository/file/FileRepository.java
    
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java
    
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResourceResolver.java
    
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java
    
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DependencyResolver.java
    
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DualResolver.java
    
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/FileSystemResolver.java
    
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/RepositoryResolver.java
    
incubator/ivy/core/trunk/test/java/org/apache/ivy/plugins/resolver/FileSystemResolverTest.java

Modified: incubator/ivy/core/trunk/CHANGES.txt
URL: 
http://svn.apache.org/viewvc/incubator/ivy/core/trunk/CHANGES.txt?rev=599186&r1=599185&r2=599186&view=diff
==============================================================================
--- incubator/ivy/core/trunk/CHANGES.txt (original)
+++ incubator/ivy/core/trunk/CHANGES.txt Wed Nov 28 15:05:25 2007
@@ -43,11 +43,12 @@
        Emmanuel Pellereau
        Roshan Punnoose
        Damon Rand
+       Geoff Reedy
        Christian Riege
-       Jean-Baptiste Quenot
        Andreas Sahlbach
        John Shields
        Johan Stuyts
+       Jean-Baptiste Quenot
        Tjeerd Verhagen
        John Williams
        Jaroslaw Wypychowski
@@ -82,6 +83,7 @@
 - IMPROVEMENT: Make the root attribute in the ivyrep resolver mandatory 
(IVY-625)
 - IMPROVEMENT: New text representation for main module metadata concepts 
(IVY-649)
 
+- NEW: support atomic publish operation (IVY-492) (with contribution from 
Geoff Reedy)
 - NEW: latest compatible conflict manager (IVY-648)
 - NEW: Add a task/code to create M2 POM files from Ivy configurations (IVY-416)
 - NEW: [Build] Publish the ivy sources (IVY-646) (thanks to Nicolas Lalevée)

Modified: 
incubator/ivy/core/trunk/src/java/org/apache/ivy/core/publish/PublishEngine.java
URL: 
http://svn.apache.org/viewvc/incubator/ivy/core/trunk/src/java/org/apache/ivy/core/publish/PublishEngine.java?rev=599186&r1=599185&r2=599186&view=diff
==============================================================================
--- 
incubator/ivy/core/trunk/src/java/org/apache/ivy/core/publish/PublishEngine.java
 (original)
+++ 
incubator/ivy/core/trunk/src/java/org/apache/ivy/core/publish/PublishEngine.java
 Wed Nov 28 15:05:25 2007
@@ -176,37 +176,48 @@
                         extraArtifacts[i].getExtraAttributes()));
             }
         }
-        // for each declared published artifact in this descriptor, do:
-        for (Iterator iter = artifactsSet.iterator(); iter.hasNext();) {
-            Artifact artifact = (Artifact) iter.next();
-            // 1) copy the artifact using src patterns and resolver
-            boolean published = false;
-            for (Iterator iterator = srcArtifactPattern.iterator(); 
iterator.hasNext()
-                    && !published;) {
-                String pattern = (String) iterator.next();
-                published = publish(
-                    artifact, settings.substitute(pattern), resolver, 
options.isOverwrite());
-            }
-            if (!published) {
-                Message.info("missing artifact " + artifact + ":");
-                for (Iterator iterator = srcArtifactPattern.iterator(); 
iterator.hasNext();) {
+        boolean successfullyPublished = false;
+        try {
+            resolver.beginPublishTransaction(md.getModuleRevisionId(), 
options.isOverwrite());
+            // for each declared published artifact in this descriptor, do:
+            for (Iterator iter = artifactsSet.iterator(); iter.hasNext();) {
+                Artifact artifact = (Artifact) iter.next();
+                // 1) copy the artifact using src patterns and resolver
+                boolean published = false;
+                for (Iterator iterator = srcArtifactPattern.iterator(); 
iterator.hasNext()
+                        && !published;) {
                     String pattern = (String) iterator.next();
-                    Message.info("\t" + new 
File(IvyPatternHelper.substitute(pattern, artifact))
-                            + " file does not exist");
+                    published = publish(
+                        artifact, settings.substitute(pattern), resolver, 
options.isOverwrite());
+                }
+                if (!published) {
+                    Message.info("missing artifact " + artifact + ":");
+                    for (Iterator iterator = srcArtifactPattern.iterator(); 
iterator.hasNext();) {
+                        String pattern = (String) iterator.next();
+                        Message.info("\t"
+                                + new 
File(IvyPatternHelper.substitute(pattern, artifact))
+                                + " file does not exist");
+                    }
+                    missing.add(artifact);
+                }
+            }
+            if (options.getSrcIvyPattern() != null) {
+                Artifact artifact = MDArtifact.newIvyArtifact(md);
+                if (!publish(
+                        artifact, options.getSrcIvyPattern(), resolver, 
options.isOverwrite())) {
+                    Message.info("missing ivy file for "
+                            + md.getModuleRevisionId()
+                            + ": "
+                            + new 
File(IvyPatternHelper.substitute(options.getSrcIvyPattern(),
+                                artifact)) + " file does not exist");
+                    missing.add(artifact);
                 }
-                missing.add(artifact);
             }
-        }
-        if (options.getSrcIvyPattern() != null) {
-            Artifact artifact = MDArtifact.newIvyArtifact(md);
-            if (!publish(artifact, options.getSrcIvyPattern(), resolver, 
options.isOverwrite())) {
-                Message.info("missing ivy file for "
-                        + md.getModuleRevisionId()
-                        + ": "
-                        + new File(IvyPatternHelper
-                                .substitute(options.getSrcIvyPattern(), 
artifact))
-                        + " file does not exist");
-                missing.add(artifact);
+            resolver.commitPublishTransaction();
+            successfullyPublished = true;
+        } finally {
+            if (!successfullyPublished) {
+                resolver.abortPublishTransaction();
             }
         }
         return missing;

Modified: 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/repository/file/FileRepository.java
URL: 
http://svn.apache.org/viewvc/incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/repository/file/FileRepository.java?rev=599186&r1=599185&r2=599186&view=diff
==============================================================================
--- 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/repository/file/FileRepository.java
 (original)
+++ 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/repository/file/FileRepository.java
 Wed Nov 28 15:05:25 2007
@@ -35,6 +35,8 @@
 
     private boolean local = true;
 
+    private File transactionDirectory;
+
     public FileRepository() {
         baseDir = null;
     }
@@ -55,6 +57,14 @@
     public void put(File source, String destination, boolean overwrite) throws 
IOException {
         fireTransferInitiated(getResource(destination), 
TransferEvent.REQUEST_PUT);
         copy(source, getFile(destination), overwrite);
+    }
+    
+    public void move(File src, File dest) {
+        src.renameTo(dest);
+    }
+
+    public void delete(File f) {
+        FileUtil.forceDelete(f);
     }
 
     private void copy(File src, File destination, boolean overwrite) throws 
IOException {

Modified: 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java
URL: 
http://svn.apache.org/viewvc/incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java?rev=599186&r1=599185&r2=599186&view=diff
==============================================================================
--- 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java
 (original)
+++ 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java
 Wed Nov 28 15:05:25 2007
@@ -17,6 +17,7 @@
  */
 package org.apache.ivy.plugins.resolver;
 
+import java.io.IOException;
 import java.util.Map;
 
 import org.apache.ivy.core.IvyContext;
@@ -51,7 +52,7 @@
 
     /**
      * True if parsed ivy files should be validated against xsd, false if they 
should not, null if
-     * default behaviour should be used
+     * default behaviur should be used
      */
     private Boolean validate = null;
 
@@ -309,5 +310,19 @@
         }
         return matcher.getMatcher(changingPattern);
     }
+    
+    public void abortPublishTransaction() throws IOException {
+        /* Default implementation is a no-op */
+    }
+
+    public void commitPublishTransaction() throws IOException {
+        /* Default implementation is a no-op */
+    }
+
+    public void beginPublishTransaction(
+            ModuleRevisionId module, boolean overwrite) throws IOException {
+        /* Default implementation is a no-op */
+    }
+
 
 }

Modified: 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResourceResolver.java
URL: 
http://svn.apache.org/viewvc/incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResourceResolver.java?rev=599186&r1=599185&r2=599186&view=diff
==============================================================================
--- 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResourceResolver.java
 (original)
+++ 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResourceResolver.java
 Wed Nov 28 15:05:25 2007
@@ -126,6 +126,10 @@
         
         for (ListIterator iter = sorted.listIterator(sorted.size()); 
iter.hasPrevious();) {
             ResolvedResource rres = (ResolvedResource) iter.previous();
+            if (filterNames(new 
ArrayList(Collections.singleton(rres.getRevision()))).isEmpty()) {
+                Message.debug("\t" + name + ": filtered by name: " + rres);
+                continue;
+            }
             if ((date != null && rres.getLastModified() > date.getTime())) {
                 Message.verbose("\t" + name + ": too young: " + rres);
                 rejected.add(rres.getRevision() + " (" + 
rres.getLastModified() + ")");
@@ -209,7 +213,7 @@
         tokenValues.put(IvyPatternHelper.TYPE_KEY, "ivy");
         tokenValues.put(IvyPatternHelper.EXT_KEY, "xml");
         findTokenValues(names, getIvyPatterns(), tokenValues, token);
-        getSettings().filterIgnore(names);
+        filterNames(names);
         return names;
     }
 
@@ -221,6 +225,21 @@
         tokenValues.put(IvyPatternHelper.TYPE_KEY, "jar");
         tokenValues.put(IvyPatternHelper.EXT_KEY, "jar");
         findTokenValues(names, getArtifactPatterns(), tokenValues, token);
+        filterNames(names);
+        return names;
+    }
+
+    /**
+     * Filters names before returning them in the findXXXNames or 
findTokenValues method.
+     * <p>
+     * Remember to call the super implementation when overriding this method.
+     * </p>
+     * 
+     * @param names
+     *            the list to filter.
+     * @return the filtered list
+     */
+    protected Collection filterNames(Collection names) {
         getSettings().filterIgnore(names);
         return names;
     }

Modified: 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java
URL: 
http://svn.apache.org/viewvc/incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java?rev=599186&r1=599185&r2=599186&view=diff
==============================================================================
--- 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java
 (original)
+++ 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java
 Wed Nov 28 15:05:25 2007
@@ -28,6 +28,7 @@
 
 import org.apache.ivy.core.module.descriptor.Artifact;
 import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
+import org.apache.ivy.core.module.id.ModuleRevisionId;
 import org.apache.ivy.core.report.ArtifactDownloadReport;
 import org.apache.ivy.core.report.DownloadReport;
 import org.apache.ivy.core.report.DownloadStatus;
@@ -229,10 +230,28 @@
     }
 
     public void publish(Artifact artifact, File src, boolean overwrite) throws 
IOException {
+
+        getFirstResolver().publish(artifact, src, overwrite);
+    }
+
+    public void abortPublishTransaction() throws IOException {
+        getFirstResolver().abortPublishTransaction();
+    }
+
+    public void beginPublishTransaction(
+            ModuleRevisionId module, boolean overwrite) throws IOException {
+        getFirstResolver().beginPublishTransaction(module, overwrite);
+    }
+
+    public void commitPublishTransaction() throws IOException {
+        getFirstResolver().commitPublishTransaction();
+    }
+
+    private DependencyResolver getFirstResolver() {
         if (chain.isEmpty()) {
             throw new IllegalStateException("invalid chain resolver with no 
sub resolver");
         }
-        ((DependencyResolver) chain.get(0)).publish(artifact, src, overwrite);
+        return ((DependencyResolver) chain.get(0));
     }
 
     public boolean isReturnFirst() {

Modified: 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DependencyResolver.java
URL: 
http://svn.apache.org/viewvc/incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DependencyResolver.java?rev=599186&r1=599185&r2=599186&view=diff
==============================================================================
--- 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DependencyResolver.java
 (original)
+++ 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DependencyResolver.java
 Wed Nov 28 15:05:25 2007
@@ -24,6 +24,7 @@
 
 import org.apache.ivy.core.module.descriptor.Artifact;
 import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
+import org.apache.ivy.core.module.id.ModuleRevisionId;
 import org.apache.ivy.core.report.DownloadReport;
 import org.apache.ivy.core.resolve.DownloadOptions;
 import org.apache.ivy.core.resolve.ResolveData;
@@ -62,6 +63,10 @@
     boolean exists(Artifact artifact);
 
     void publish(Artifact artifact, File src, boolean overwrite) throws 
IOException;
+    
+    void beginPublishTransaction(ModuleRevisionId module, boolean overwrite) 
throws IOException;
+    void abortPublishTransaction() throws IOException;
+    void commitPublishTransaction() throws IOException;
 
     /**
      * Reports last resolve failure as Messages

Modified: 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DualResolver.java
URL: 
http://svn.apache.org/viewvc/incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DualResolver.java?rev=599186&r1=599185&r2=599186&view=diff
==============================================================================
--- 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DualResolver.java
 (original)
+++ 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DualResolver.java
 Wed Nov 28 15:05:25 2007
@@ -23,6 +23,7 @@
 
 import org.apache.ivy.core.module.descriptor.Artifact;
 import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
+import org.apache.ivy.core.module.id.ModuleRevisionId;
 import org.apache.ivy.core.report.DownloadReport;
 import org.apache.ivy.core.resolve.DownloadOptions;
 import org.apache.ivy.core.resolve.ResolveData;
@@ -116,6 +117,24 @@
         } else {
             artifactResolver.publish(artifact, src, overwrite);
         }
+    }
+
+    public void abortPublishTransaction() throws IOException {
+        ivyResolver.abortPublishTransaction();
+        artifactResolver.abortPublishTransaction();
+    }
+
+
+    public void beginPublishTransaction(
+            ModuleRevisionId module, boolean overwrite) throws IOException {
+        ivyResolver.beginPublishTransaction(module, overwrite);
+        artifactResolver.beginPublishTransaction(module, overwrite);
+    }
+
+
+    public void commitPublishTransaction() throws IOException {
+        ivyResolver.commitPublishTransaction();
+        artifactResolver.commitPublishTransaction();
     }
 
     public void dumpSettings() {

Modified: 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/FileSystemResolver.java
URL: 
http://svn.apache.org/viewvc/incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/FileSystemResolver.java?rev=599186&r1=599185&r2=599186&view=diff
==============================================================================
--- 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/FileSystemResolver.java
 (original)
+++ 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/FileSystemResolver.java
 Wed Nov 28 15:05:25 2007
@@ -17,11 +17,37 @@
  */
 package org.apache.ivy.plugins.resolver;
 
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.ivy.core.IvyPatternHelper;
+import org.apache.ivy.core.module.descriptor.Artifact;
+import org.apache.ivy.core.module.id.ModuleRevisionId;
 import org.apache.ivy.plugins.repository.file.FileRepository;
+import org.apache.ivy.util.Message;
 
 /**
  */
 public class FileSystemResolver extends RepositoryResolver {
+
+    private static final String TRANSACTION_DESTINATION_SUFFIX = ".part";
+    private static final Pattern TRANSACTION_PATTERN = 
+        Pattern.compile("(.*\\[revision\\])[/\\\\][^/\\\\]+");
+    
+    private String transactional = "auto"; // one of 'auto', 'true' or 'false'
+    
+    private Boolean supportTransaction;
+    private String baseTransactionPattern;
+
+    private boolean overwriteTransaction = false;
+    private File transactionTempDir;
+    private File transactionDestDir;
+    
     public FileSystemResolver() {
         setRepository(new FileRepository());
     }
@@ -40,6 +66,148 @@
 
     private FileRepository getFileRepository() {
         return (FileRepository) getRepository();
+    }
+    
+
+    protected String getDestination(String pattern, Artifact artifact, 
ModuleRevisionId mrid) {
+        if (supportTransaction() && !overwriteTransaction) {
+            return IvyPatternHelper.substitute(
+                pattern, 
+                ModuleRevisionId.newInstance(
+                    mrid, mrid.getRevision() + 
TRANSACTION_DESTINATION_SUFFIX), 
+                artifact);
+        } else {
+            return super.getDestination(pattern, artifact, mrid);
+        }
+    }
+
+    public void abortPublishTransaction() throws IOException {
+        if (supportTransaction() && !overwriteTransaction) {
+            if (transactionTempDir == null) {
+                throw new IllegalStateException("no current transaction!");
+            }
+            getFileRepository().delete(transactionTempDir);
+            Message.info("\tpublish aborted: deleted " + transactionTempDir);
+            closeTransaction();
+        }
+    }
+
+    public void commitPublishTransaction() throws IOException {
+        if (supportTransaction() && !overwriteTransaction) {
+            if (transactionTempDir == null) {
+                throw new IllegalStateException("no current transaction!");
+            }
+            Message.info("\tpublish commited: moved " + transactionTempDir 
+                + " \n\t\tto " + transactionDestDir);
+            getFileRepository().move(transactionTempDir, transactionDestDir);
+        }
+    }
+
+    public void beginPublishTransaction(
+            ModuleRevisionId module, boolean overwrite) throws IOException {
+        if (supportTransaction()) {
+            if (transactionTempDir != null) {
+                throw new IllegalStateException("a transaction is only started 
and not closed!");
+            }
+            overwriteTransaction = overwrite;
+            if (overwriteTransaction) {
+                unsupportedTransaction("overwrite transaction not supported 
yet");
+            } else {
+                initTransaction(module);
+            }
+        }
+    }
+    
+    protected Collection filterNames(Collection values) {
+        if (supportTransaction()) {
+            values =  super.filterNames(values);
+            for (Iterator iterator = values.iterator(); iterator.hasNext();) {
+                String v = (String) iterator.next();
+                if (v.endsWith(TRANSACTION_DESTINATION_SUFFIX)) {
+                    iterator.remove();
+                }
+            }
+            return values;
+        } else {
+            return super.filterNames(values);
+        }
+    }
+    
+    public boolean supportTransaction() {
+        if ("false".equals(transactional)) {
+            return false;
+        }
+        checkSupportTransaction();
+        return supportTransaction.booleanValue();
+    }
+
+    private void closeTransaction() {
+        transactionTempDir = null;
+        transactionDestDir = null;
+    }
+    
+    private void checkSupportTransaction() {
+        if (supportTransaction == null) {
+            List ivyPatterns = getIvyPatterns();
+            List artifactPatterns = getArtifactPatterns();
+            
+            if (ivyPatterns.size() > 0) {
+                String pattern = (String) ivyPatterns.get(0);
+                Matcher m = TRANSACTION_PATTERN.matcher(pattern);
+                if (!m.matches()) {
+                    unsupportedTransaction("ivy pattern does not use revision 
as last directory");
+                    return;
+                } else {
+                    baseTransactionPattern = m.group(1);
+                }
+            }
+            if (artifactPatterns.size() > 0) {
+                String pattern = (String) artifactPatterns.get(0);
+                Matcher m = TRANSACTION_PATTERN.matcher(pattern);
+                if (!m.matches()) {
+                    unsupportedTransaction("ivy pattern does not use revision 
as last directory");
+                    return;
+                } else if (baseTransactionPattern != null) {
+                    if (!baseTransactionPattern.equals(m.group(1))) {
+                        unsupportedTransaction("ivy pattern and artifact 
pattern "
+                            + "do not use the same directory for revision");
+                        return;
+                    }
+                } else {
+                    baseTransactionPattern = m.group(1);
+                }
+            }
+            supportTransaction = Boolean.TRUE;
+        }
+    }
+
+    private void unsupportedTransaction(String msg) {
+        String fullMsg = getName() + " do not support transaction. " + msg;
+        if ("true".equals(transactional)) {
+            throw new IllegalStateException(fullMsg 
+                + ". Set transactional attribute to 'auto' or 'false' or fix 
the problem.");
+        } else {
+            Message.verbose(fullMsg);
+            supportTransaction = Boolean.FALSE;
+        }
+    }
+
+    private void initTransaction(ModuleRevisionId module) {
+        transactionTempDir = new File(IvyPatternHelper.substitute(
+            baseTransactionPattern, 
+            ModuleRevisionId.newInstance(
+                module, module.getRevision() + 
TRANSACTION_DESTINATION_SUFFIX)));
+        transactionDestDir = new File(IvyPatternHelper.substitute(
+            baseTransactionPattern, 
+            module));
+    }
+
+    public String getTransactional() {
+        return transactional;
+    }
+
+    public void setTransactional(String transactional) {
+        this.transactional = transactional;
     }
 
 }

Modified: 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/RepositoryResolver.java
URL: 
http://svn.apache.org/viewvc/incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/RepositoryResolver.java?rev=599186&r1=599185&r2=599186&view=diff
==============================================================================
--- 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/RepositoryResolver.java
 (original)
+++ 
incubator/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/RepositoryResolver.java
 Wed Nov 28 15:05:25 2007
@@ -20,6 +20,7 @@
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
@@ -161,12 +162,16 @@
             mrid = convertM2IdForResourceSearch(mrid);
         }
 
-        String dest = IvyPatternHelper.substitute(destPattern, mrid, artifact);
+        String dest = getDestination(destPattern, artifact, mrid);
 
         put(artifact, src, dest, overwrite);
         Message.info("\tpublished " + artifact.getName() + " to " + 
hidePassword(dest));
     }
 
+    protected String getDestination(String pattern, Artifact artifact, 
ModuleRevisionId mrid) {
+        return IvyPatternHelper.substitute(pattern, mrid, artifact);
+    }
+
     private void put(Artifact artifact, File src, String dest, boolean 
overwrite)
             throws IOException {
         repository.put(artifact, src, dest, overwrite);
@@ -211,11 +216,11 @@
             String[] values = ResolverHelper.listTokenValues(repository, 
partiallyResolvedPattern,
                 token);
             if (values != null) {
-                names.addAll(Arrays.asList(values));
+                names.addAll(filterNames(new 
ArrayList(Arrays.asList(values))));
             }
         }
     }
-
+    
     public String getTypeName() {
         return "repository";
     }
@@ -242,4 +247,5 @@
     public void setAlwaysCheckExactRevision(boolean alwaysCheckExactRevision) {
         this.alwaysCheckExactRevision = 
Boolean.valueOf(alwaysCheckExactRevision);
     }
+
 }

Added: 
incubator/ivy/core/trunk/test/java/org/apache/ivy/core/publish/PublishEngineTest.java
URL: 
http://svn.apache.org/viewvc/incubator/ivy/core/trunk/test/java/org/apache/ivy/core/publish/PublishEngineTest.java?rev=599186&view=auto
==============================================================================
--- 
incubator/ivy/core/trunk/test/java/org/apache/ivy/core/publish/PublishEngineTest.java
 (added)
+++ 
incubator/ivy/core/trunk/test/java/org/apache/ivy/core/publish/PublishEngineTest.java
 Wed Nov 28 15:05:25 2007
@@ -0,0 +1,143 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.ivy.core.publish;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.apache.ivy.core.cache.CacheManager;
+import org.apache.ivy.core.event.EventManager;
+import org.apache.ivy.core.module.descriptor.Artifact;
+import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
+import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor;
+import org.apache.ivy.core.module.id.ModuleRevisionId;
+import org.apache.ivy.core.resolve.ResolveData;
+import org.apache.ivy.core.resolve.ResolveEngine;
+import org.apache.ivy.core.resolve.ResolveOptions;
+import org.apache.ivy.core.resolve.ResolvedModuleRevision;
+import org.apache.ivy.core.settings.IvySettings;
+import org.apache.ivy.core.sort.SortEngine;
+import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter;
+import org.apache.ivy.plugins.resolver.FileSystemResolver;
+import org.apache.ivy.util.FileUtil;
+
+public class PublishEngineTest extends TestCase {
+    protected void setUp() throws Exception {
+        FileUtil.forceDelete(new File("build/test/publish"));
+    }
+    protected void tearDown() throws Exception {
+        FileUtil.forceDelete(new File("build/test/publish"));
+    }
+
+    public void testAtomicity() throws Exception {
+        IvySettings settings = new IvySettings();
+        final PublishEngine engine = new PublishEngine(settings);
+        final int[] counter = new int[] {0};
+        
+        final DefaultModuleDescriptor md = DefaultModuleDescriptor
+            .newDefaultInstance(ModuleRevisionId.parse("#A;1.0"));
+        final FileSystemResolver resolver = new FileSystemResolver() {
+            public void publish(Artifact artifact, File src, boolean 
overwrite) throws IOException {
+                super.publish(artifact, src, overwrite);
+                synchronized (PublishEngineTest.this) {
+                    counter[0] ++;
+                }
+                sleepSilently(50);
+                synchronized (PublishEngineTest.this) {
+                    counter[0] ++;
+                }
+            }
+        };
+        resolver.setName("test");
+        resolver.setSettings(settings);
+        
resolver.addIvyPattern("build/test/publish/repo/[module]/[revision]/[artifact].[ext]");
+        
resolver.addArtifactPattern("build/test/publish/repo/[module]/[revision]/[artifact].[ext]");
+        
+        FileUtil.copy(
+            new File("test/repositories/1/org1/mod1.1/jars/mod1.1-1.0.jar"), 
+            new File("build/test/publish/module/A.jar"), null);
+        XmlModuleDescriptorWriter.write(md, new 
File("build/test/publish/module/ivy.xml"));
+
+        resolveAndAssertNotFound(settings, resolver, "#A;latest.integration", 
"before publishing");
+
+        // run publish asynchronously
+        new Thread() {
+            public void run() {
+                try {
+                    engine.publish(
+                        md, 
+                        Arrays.asList(new String[] 
{"build/test/publish/module/[artifact].[ext]"}), 
+                        resolver, 
+                        new 
PublishOptions().setSrcIvyPattern("build/test/publish/module/[artifact].[ext]"));
+                    synchronized (PublishEngineTest.this) {
+                        counter[0] ++;
+                    }
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }.start();
+
+        while(true) {
+            sleepSilently(5);
+            synchronized (this) {
+                if (counter[0] == 5) {
+                    break;
+                } else if (counter[0] < 4) {
+                    resolveAndAssertNotFound(settings, resolver, 
+                        "#A;latest.integration", "after "+(counter[0] / 2)+" 
artifacts published");
+                }
+            }
+        }
+        resolveAndAssertFound(settings, resolver, "#A;1.0");
+    }
+    private void resolveAndAssertNotFound(
+            IvySettings settings, FileSystemResolver resolver, String module, 
String context)
+            throws ParseException {
+        ResolvedModuleRevision rmr = resolveModule(settings, resolver, module);
+        assertNull("module found " + context + ". module="+rmr, rmr);
+    }
+
+    private void resolveAndAssertFound(
+            IvySettings settings, FileSystemResolver resolver, String module)
+            throws ParseException {
+        ResolvedModuleRevision rmr = resolveModule(settings, resolver, module);
+        assertNotNull(rmr);
+        assertEquals(module, rmr.getId().toString());
+    }
+    private ResolvedModuleRevision resolveModule(
+            IvySettings settings, FileSystemResolver resolver, String module)
+            throws ParseException {
+        return resolver.getDependency(
+            new DefaultDependencyDescriptor(ModuleRevisionId.parse(module), 
false), 
+            new ResolveData(
+                new ResolveEngine(settings, new EventManager(), new 
SortEngine(settings)), 
+                new ResolveOptions().setCache(
+                    new CacheManager(settings, new 
File("build/test/publish/cache")))));
+    }
+    private void sleepSilently(int timeout) {
+        try {
+            Thread.sleep(timeout);
+        } catch (InterruptedException e) {
+        }
+    }
+}

Propchange: 
incubator/ivy/core/trunk/test/java/org/apache/ivy/core/publish/PublishEngineTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: 
incubator/ivy/core/trunk/test/java/org/apache/ivy/plugins/resolver/FileSystemResolverTest.java
URL: 
http://svn.apache.org/viewvc/incubator/ivy/core/trunk/test/java/org/apache/ivy/plugins/resolver/FileSystemResolverTest.java?rev=599186&r1=599185&r2=599186&view=diff
==============================================================================
--- 
incubator/ivy/core/trunk/test/java/org/apache/ivy/plugins/resolver/FileSystemResolverTest.java
 (original)
+++ 
incubator/ivy/core/trunk/test/java/org/apache/ivy/plugins/resolver/FileSystemResolverTest.java
 Wed Nov 28 15:05:25 2007
@@ -567,18 +567,54 @@
             Artifact artifact = new DefaultArtifact(mrid, new Date(), 
"myartifact", "mytype",
                     "myext");
             File src = new File("test/repositories/ivysettings.xml");
-            resolver.publish(ivyArtifact, src, false);
-            resolver.publish(artifact, src, false);
+            boolean successfullyPublished = false;
+            resolver.beginPublishTransaction(mrid, false);
+            try {
+                resolver.publish(ivyArtifact, src, false);
+                resolver.publish(artifact, src, false);
+                resolver.commitPublishTransaction();
+                successfullyPublished = true;
+            } finally {
+                if (!successfullyPublished)
+                    resolver.abortPublishTransaction();
+            }
 
             assertTrue(new 
File("test/repositories/1/myorg/mymodule/myrevision/ivy.xml").exists());
             assertTrue(new File(
                     
"test/repositories/1/myorg/mymodule/mytypes/myartifact-myrevision.myext")
                     .exists());
         } finally {
-            Delete del = new Delete();
-            del.setProject(new Project());
-            del.setDir(new File("test/repositories/1/myorg"));
-            del.execute();
+            FileUtil.forceDelete(new File("test/repositories/1/myorg"));
+        }
+    }
+
+    public void testAbortTransaction() throws Exception {
+        try {
+            FileSystemResolver resolver = new FileSystemResolver();
+            resolver.setName("test");
+            resolver.setSettings(settings);
+
+            resolver.addIvyPattern(
+                
"test/repositories/1/[organisation]/[module]/[revision]/[artifact].[ext]");
+            resolver.addArtifactPattern(
+                 
"test/repositories/1/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]");
+
+            ModuleRevisionId mrid = ModuleRevisionId.newInstance("myorg", 
"mymodule", "myrevision");
+            Artifact ivyArtifact = new DefaultArtifact(mrid, new Date(), 
"ivy", "ivy", "xml");
+            Artifact artifact = new DefaultArtifact(mrid, new Date(), 
"myartifact", "mytype",
+                    "myext");
+            File src = new File("test/repositories/ivysettings.xml");
+            resolver.beginPublishTransaction(mrid, false);
+            resolver.publish(ivyArtifact, src, false);
+            resolver.publish(artifact, src, false);
+            resolver.abortPublishTransaction();
+
+            assertFalse(new 
File("test/repositories/1/myorg/mymodule/myrevision/ivy.xml").exists());
+            assertFalse(new File(
+                    
"test/repositories/1/myorg/mymodule/mytypes/myartifact-myrevision.myext")
+                    .exists());
+        } finally {
+            FileUtil.forceDelete(new File("test/repositories/1/myorg"));
         }
     }
 


Reply via email to