[MGPG-3, MGPG-6, MGPG-7, MGPG-5] Bunch of fixes for GPG that have been sitting on my hard drive.
(Patch from Christian Schulte of MGPG-3 is in there)


git-svn-id: https://svn.apache.org/repos/asf/maven/plugins/trunk@577872 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 40b9ba3..ff57d19 100644
--- a/pom.xml
+++ b/pom.xml
@@ -48,6 +48,11 @@
       <version>1.2</version>
     </dependency>
 
+    <dependency>
+      <groupId>org.apache.maven.plugins</groupId>
+      <artifactId>maven-deploy-plugin</artifactId>
+      <version>2.3</version>
+    </dependency>
 
     <dependency>
       <groupId>commons-lang</groupId>
diff --git a/src/main/java/org/apache/maven/plugin/gpg/AscArtifactMetadata.java b/src/main/java/org/apache/maven/plugin/gpg/AscArtifactMetadata.java
new file mode 100644
index 0000000..8cf74b8
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/gpg/AscArtifactMetadata.java
@@ -0,0 +1,107 @@
+package org.apache.maven.plugin.gpg;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.AbstractArtifactMetadata;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadataStoreException;
+import org.apache.maven.project.artifact.ProjectArtifactMetadata;
+import org.codehaus.plexus.util.FileUtils;
+
+public class AscArtifactMetadata extends AbstractArtifactMetadata
+{
+    File file;
+    boolean isPom;
+    
+    public AscArtifactMetadata( Artifact artifact,
+                               File file,
+                               boolean isPom )
+    {
+        super( artifact );
+        this.file = file;
+        this.isPom = isPom;
+    }
+
+    public String getBaseVersion() 
+    {
+        return artifact.getBaseVersion();
+    }
+
+    public Object getKey() 
+    {
+        return "gpg signature " + artifact.getGroupId() + ":" + artifact.getArtifactId() 
+            + ":" + artifact.getType() + ":" + artifact.getClassifier() +
+            (isPom ? ":pom" : "");
+    }
+    
+    private String getFilename()
+    {
+        StringBuffer buf = new StringBuffer( getArtifactId() );
+        buf.append( "-" ).append( artifact.getVersion() );
+        if ( isPom ) 
+        {
+            buf.append( ".pom" );
+        } 
+        else
+        {
+            if ( artifact.getClassifier() != null
+                 && !"".equals( artifact.getClassifier() ) )
+            {
+                buf.append( "-" ).append( artifact.getClassifier() );
+            }
+            buf.append( "." ).append( artifact.getType() );
+        }
+        buf.append( ".asc" );
+        return buf.toString();
+    }
+
+    public String getLocalFilename( ArtifactRepository repository )
+    {
+        return getFilename();
+    }
+
+    public String getRemoteFilename()
+    {
+        return getFilename();
+    }
+
+    public void merge( ArtifactMetadata metadata ) 
+    {
+        AscArtifactMetadata m = (AscArtifactMetadata) metadata;
+        if ( !m.file.equals( file ) )
+        {
+            throw new IllegalStateException( "Cannot add two different pieces of metadata for: "
+                                             + getKey() );
+        }
+    }
+
+    public void storeInLocalRepository( ArtifactRepository localRepository,
+                                       ArtifactRepository remoteRepository )
+        throws RepositoryMetadataStoreException 
+    {
+        File destination = new File( localRepository.getBasedir(),
+                                     localRepository.pathOfLocalRepositoryMetadata( this, remoteRepository ) );
+
+        try
+        {
+            FileUtils.copyFile( file, destination );
+        }
+        catch ( IOException e )
+        {
+            throw new RepositoryMetadataStoreException( "Error copying ASC to the local repository.", e );
+        }
+    }
+
+    public boolean storedInArtifactVersionDirectory() 
+    {
+        return true;
+    }
+
+    public String toString()
+    {
+        return getFilename();
+    }
+}
diff --git a/src/main/java/org/apache/maven/plugin/gpg/GpgSignAttachedMojo.java b/src/main/java/org/apache/maven/plugin/gpg/GpgSignAttachedMojo.java
index 35b9def..888adf1 100644
--- a/src/main/java/org/apache/maven/plugin/gpg/GpgSignAttachedMojo.java
+++ b/src/main/java/org/apache/maven/plugin/gpg/GpgSignAttachedMojo.java
@@ -62,7 +62,6 @@
 public class GpgSignAttachedMojo
     extends AbstractMojo
 {
-    public static final String SIGNATURE_EXTENSION = ".asc";
     private static final String DEFAULT_EXCLUDES[] = new String[] {
         "**/*.md5",
         "**/*.sha1",
@@ -145,6 +144,9 @@
      * @readonly
      */
     protected Settings settings;
+    
+    
+    private GpgSigner signer = new GpgSigner();
 
 
     public void execute()
@@ -185,7 +187,7 @@
             }
             try 
             {
-                pass = getPassphrase();
+                pass = signer.getPassphrase(project);
             }
             catch (IOException e) 
             {
@@ -198,6 +200,10 @@
         // What we need to generateSignatureForArtifact here
         // ----------------------------------------------------------------------------
 
+        signer.setInteractive(settings.isInteractiveMode());
+        signer.setKeyName(keyname);
+        signer.setUseAgent(useAgent);
+        
         List signingBundles = new ArrayList();
 
         if ( !"pom".equals( project.getPackaging() ) )
@@ -208,7 +214,7 @@
 
             File projectArtifact = project.getArtifact().getFile();
 
-            File projectArtifactSignature = generateSignatureForArtifact( projectArtifact, pass );
+            File projectArtifactSignature = signer.generateSignatureForArtifact( projectArtifact, pass );
 
             if ( projectArtifactSignature != null )
             {
@@ -231,7 +237,7 @@
             throw new MojoExecutionException( "Error copying POM for signing.", e );
         }
 
-        File pomSignature = generateSignatureForArtifact( pomToSign, pass );
+        File pomSignature = signer.generateSignatureForArtifact( pomToSign, pass );
 
         if ( pomSignature != null )
         {
@@ -248,7 +254,7 @@
 
             File file = artifact.getFile();
 
-            File signature = generateSignatureForArtifact( file, pass );
+            File signature = signer.generateSignatureForArtifact( file, pass );
 
             if ( signature != null )
             {
@@ -286,88 +292,7 @@
             }
         }
     }
-
-    private File generateSignatureForArtifact( File file , String pass)
-        throws MojoExecutionException
-    {
-        File signature = new File( file + SIGNATURE_EXTENSION );
-
-        if ( signature.exists() )
-        {
-            signature.delete();
-        }
-
-        Commandline cmd = new Commandline();
-
-        cmd.setExecutable( "gpg" + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" ) );
-
-        if ( useAgent )
-        {
-            cmd.createArgument().setValue( "--use-agent" );
-        }
-        else
-        {
-            cmd.createArgument().setValue( "--no-use-agent" );
-        }
-
-        InputStream in = null;
-        if ( null != pass) 
-        {
-            cmd.createArgument().setValue( "--passphrase-fd" );
-
-            cmd.createArgument().setValue( "0" );
-
-            // Prepare the input stream which will be used to pass the passphrase to the executable
-            in = new ByteArrayInputStream( pass.getBytes() );
-        }
-
-        if ( null != keyname)
-        {
-            cmd.createArgument().setValue( "--local-user" );
-
-            cmd.createArgument().setValue( keyname );
-        }
-
-        cmd.createArgument().setValue( "--armor" );
-
-        cmd.createArgument().setValue( "--detach-sign" );
-        
-        if ( !settings.isInteractiveMode() )
-        {
-            cmd.createArgument().setValue( "--no-tty" );
-        }
-        
-        cmd.createArgument().setFile( file );
-
-
-        try
-        {
-            int exitCode = CommandLineUtils.executeCommandLine( cmd, in, new DefaultConsumer(), new DefaultConsumer() );
-
-            if ( exitCode != 0 )
-            {
-                throw new MojoExecutionException( "Exit code: " + exitCode );
-            }
-        }
-        catch ( CommandLineException e )
-        {
-            throw new MojoExecutionException( "Unable to execute gpg command", e );
-        }
-
-        return signature;
-    }
-
     
-    private MavenProject findReactorProject(MavenProject prj) {
-        if ( prj.getParent() != null )
-        {
-            if ( prj.getParent().getBasedir() != null && prj.getParent().getBasedir().exists() )
-            {
-                return findReactorProject( prj.getParent() );
-            }
-        }
-        return prj;
-    }
     /**
      * Tests whether or not a name matches against at least one exclude
      * pattern.
@@ -388,87 +313,4 @@
         return false;
     }
     
-    protected String getPassphrase() throws IOException
-    {
-        String pass = project.getProperties().getProperty("gpg.passphrase");
-        if (pass == null) 
-        {
-            MavenProject prj2 = findReactorProject(project);
-            pass = prj2.getProperties().getProperty("gpg.passphrase");
-        }
-        if (pass == null) 
-        {
-            //TODO: with JDK 1.6, we could call System.console().readPassword("GPG Passphrase: ", null);
-            
-            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
-            while (System.in.available() != 0)
-            {
-                //there's some junk already on the input stream, consume it
-                //so we can get the real passphrase
-                System.in.read();
-            }
-            
-            System.out.print("GPG Passphrase:  ");
-            MaskingThread thread = new MaskingThread();
-            thread.start();
-    
-    
-            pass = in.readLine();
-    
-            // stop masking
-            thread.stopMasking();
-        }
-        findReactorProject(project).getProperties().setProperty("gpg.passphrase", pass);
-        return pass;
-    }
-    
-    
-    // based on ideas from http://java.sun.com/developer/technicalArticles/Security/pwordmask/
-    class MaskingThread extends Thread
-    {
-        private volatile boolean stop;
-
-       /**
-        * Begin masking until asked to stop.
-        */
-        public void run()
-        {
-            //this needs to be high priority to make sure the characters don't
-            //really get to the screen.
-            
-            int priority = Thread.currentThread().getPriority();
-            Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
-
-            try {
-                stop = false;
-                while(!stop)
-                { 
-                    //print a backspace + * to overwrite anything they type
-                    System.out.print("\010*");
-                    try
-                    {
-                        //attempt masking at this rate
-                        Thread.sleep(1);
-                    }
-                    catch (InterruptedException iex)
-                    {
-                        Thread.currentThread().interrupt();
-                        return;
-                    }
-                }
-            }
-            finally
-            {
-                // restore the original priority
-                Thread.currentThread().setPriority(priority);
-            }
-        }
-
-        /**
-         * Instruct the thread to stop masking.
-         */
-        public void stopMasking() {
-            this.stop = true;
-        }
-    }    
 }
diff --git a/src/main/java/org/apache/maven/plugin/gpg/GpgSigner.java b/src/main/java/org/apache/maven/plugin/gpg/GpgSigner.java
new file mode 100644
index 0000000..39d30a7
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/gpg/GpgSigner.java
@@ -0,0 +1,241 @@
+package org.apache.maven.plugin.gpg;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.apache.commons.lang.SystemUtils;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.cli.CommandLineException;
+import org.codehaus.plexus.util.cli.CommandLineUtils;
+import org.codehaus.plexus.util.cli.Commandline;
+import org.codehaus.plexus.util.cli.DefaultConsumer;
+
+/*
+ * 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.
+ */
+
+public class GpgSigner 
+{
+    public static final String SIGNATURE_EXTENSION = ".asc";
+    
+    
+    private boolean useAgent;
+    private boolean isInteractive = true;
+    private String keyname;
+    
+    public GpgSigner()
+    {
+    }
+    
+    
+    public void setInteractive(boolean b)
+    {
+        isInteractive = b;
+    }
+    
+    public void setUseAgent(boolean b)
+    {
+        useAgent = b;
+    }
+    
+    public void setKeyName(String s) 
+    {
+        keyname = s;
+    }
+    
+    
+    public File generateSignatureForArtifact( File file , String pass)
+        throws MojoExecutionException
+    {
+        File signature = new File( file + SIGNATURE_EXTENSION );
+    
+        if ( signature.exists() )
+        {
+            signature.delete();
+        }
+    
+        Commandline cmd = new Commandline();
+    
+        cmd.setExecutable( "gpg" + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" ) );
+    
+        if ( useAgent )
+        {
+            cmd.createArgument().setValue( "--use-agent" );
+        }
+        else
+        {
+            cmd.createArgument().setValue( "--no-use-agent" );
+        }
+    
+        InputStream in = null;
+        if ( null != pass) 
+        {
+            cmd.createArgument().setValue( "--passphrase-fd" );
+    
+            cmd.createArgument().setValue( "0" );
+    
+            // Prepare the input stream which will be used to pass the passphrase to the executable
+            in = new ByteArrayInputStream( pass.getBytes() );
+        }
+    
+        if ( null != keyname)
+        {
+            cmd.createArgument().setValue( "--local-user" );
+    
+            cmd.createArgument().setValue( keyname );
+        }
+    
+        cmd.createArgument().setValue( "--armor" );
+    
+        cmd.createArgument().setValue( "--detach-sign" );
+        
+        if ( !isInteractive )
+        {
+            cmd.createArgument().setValue( "--no-tty" );
+        }
+        
+        cmd.createArgument().setFile( file );
+    
+    
+        try
+        {
+            int exitCode = CommandLineUtils.executeCommandLine( cmd, in, new DefaultConsumer(), new DefaultConsumer() );
+    
+            if ( exitCode != 0 )
+            {
+                throw new MojoExecutionException( "Exit code: " + exitCode );
+            }
+        }
+        catch ( CommandLineException e )
+        {
+            throw new MojoExecutionException( "Unable to execute gpg command", e );
+        }
+    
+        return signature;
+    }
+    
+    
+    private MavenProject findReactorProject(MavenProject prj) {
+        if ( prj.getParent() != null )
+        {
+            if ( prj.getParent().getBasedir() != null && prj.getParent().getBasedir().exists() )
+            {
+                return findReactorProject( prj.getParent() );
+            }
+        }
+        return prj;
+    }
+    
+    
+    public String getPassphrase(MavenProject project) throws IOException
+    {
+        String pass = null;
+        
+        if (project != null) {
+            pass = project.getProperties().getProperty("gpg.passphrase");
+            if (pass == null) 
+            {
+                MavenProject prj2 = findReactorProject(project);
+                pass = prj2.getProperties().getProperty("gpg.passphrase");
+            }
+        }
+        if (pass == null) 
+        {
+            //TODO: with JDK 1.6, we could call System.console().readPassword("GPG Passphrase: ", null);
+            
+            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+            while (System.in.available() != 0)
+            {
+                //there's some junk already on the input stream, consume it
+                //so we can get the real passphrase
+                System.in.read();
+            }
+            
+            System.out.print("GPG Passphrase:  ");
+            MaskingThread thread = new MaskingThread();
+            thread.start();
+    
+    
+            pass = in.readLine();
+    
+            // stop masking
+            thread.stopMasking();
+        }
+        if (project != null) {
+            findReactorProject(project).getProperties().setProperty("gpg.passphrase", pass);
+        }
+        return pass;
+    }
+    
+    
+    // based on ideas from http://java.sun.com/developer/technicalArticles/Security/pwordmask/
+    class MaskingThread extends Thread
+    {
+        private volatile boolean stop;
+
+       /**
+        * Begin masking until asked to stop.
+        */
+        public void run()
+        {
+            //this needs to be high priority to make sure the characters don't
+            //really get to the screen.
+            
+            int priority = Thread.currentThread().getPriority();
+            Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
+
+            try {
+                stop = false;
+                while(!stop)
+                { 
+                    //print a backspace + * to overwrite anything they type
+                    System.out.print("\010*");
+                    try
+                    {
+                        //attempt masking at this rate
+                        Thread.sleep(1);
+                    }
+                    catch (InterruptedException iex)
+                    {
+                        Thread.currentThread().interrupt();
+                        return;
+                    }
+                }
+            }
+            finally
+            {
+                // restore the original priority
+                Thread.currentThread().setPriority(priority);
+            }
+        }
+
+        /**
+         * Instruct the thread to stop masking.
+         */
+        public void stopMasking() {
+            this.stop = true;
+        }
+    }    
+    
+
+}
diff --git a/src/main/java/org/apache/maven/plugin/gpg/SignAndDeployFileMojo.java b/src/main/java/org/apache/maven/plugin/gpg/SignAndDeployFileMojo.java
new file mode 100644
index 0000000..a7eb1e7
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/gpg/SignAndDeployFileMojo.java
@@ -0,0 +1,369 @@
+package org.apache.maven.plugin.gpg;
+
+/*
+ * 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.
+ */
+
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.deployer.ArtifactDeployer;
+import org.apache.maven.artifact.deployer.ArtifactDeploymentException;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.handler.DefaultArtifactHandler;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.deploy.DeployFileMojo;
+import org.apache.maven.project.artifact.AttachedArtifact;
+import org.apache.maven.settings.Settings;
+
+
+/**
+ * @author Daniel Kulp
+ * @goal sign-and-deploy-file
+ * @requiresProject false
+ */
+public class SignAndDeployFileMojo extends DeployFileMojo {
+    /**
+     * The passphrase to use when signing.
+     *
+     * @parameter expression="${gpg.passphrase}"
+     */
+    private String passphrase;
+
+    /**
+     * The "name" of the key to sign with.  Passed to gpg as --local-user.
+     * 
+     * @parameter expression="${gpg.keyname}"
+     */
+    private String keyname;
+
+
+    /**
+     * Passes --use-agent or --no-use-agent to gpg.   If using an agent,
+     * the password is optional as the agent will provide it.
+     * 
+     * @parameter expression="${gpg.useagent}" default-value="false"
+     * @required
+     */
+    private boolean useAgent;
+
+    
+    /**
+     * @parameter expression="${settings}"
+     * @required
+     * @readonly
+     */
+    protected Settings settings;
+    
+    
+    /**
+     * Maven ArtifactHandlerManager
+     *
+     * @component
+     * @required
+     * @readonly
+     */
+    private ArtifactHandlerManager artifactHandlerManager;
+    
+    
+    /* stuff I need to copy since the plugin:plugin doesn't support inheritance outside
+     * the current jar
+     */
+    /**
+     * @parameter expression="${component.org.apache.maven.artifact.deployer.ArtifactDeployer}"
+     * @required
+     * @readonly
+     */
+    private ArtifactDeployer deployer;
+    /**
+     * @parameter expression="${localRepository}"
+     * @required
+     * @readonly
+     */
+    private ArtifactRepository localRepository;
+    /**
+     * GroupId of the artifact to be deployed.  Retrieved from POM file if specified.
+     *
+     * @parameter expression="${groupId}"
+     */
+    private String groupId;
+    /**
+     * ArtifactId of the artifact to be deployed.  Retrieved from POM file if specified.
+     *
+     * @parameter expression="${artifactId}"
+     */
+    private String artifactId;
+    /**
+     * Version of the artifact to be deployed.  Retrieved from POM file if specified.
+     *
+     * @parameter expression="${version}"
+     */
+    private String version;
+    /**
+     * Type of the artifact to be deployed.  Retrieved from POM file if specified.
+     *
+     * @parameter expression="${packaging}"
+     */
+    private String packaging;
+    /**
+     * Description passed to a generated POM file (in case of generatePom=true)
+     *
+     * @parameter expression="${generatePom.description}"
+     */
+    private String description;
+    /**
+     * File to be deployed.
+     *
+     * @parameter expression="${file}"
+     * @required
+     */
+    private File file;
+    /**
+     * Server Id to map on the &lt;id&gt; under &lt;server&gt; section of settings.xml
+     * In most cases, this parameter will be required for authentication.
+     *
+     * @parameter expression="${repositoryId}" default-value="remote-repository"
+     * @required
+     */
+    private String repositoryId;
+    /**
+     * The type of remote repository layout to deploy to. Try <i>legacy</i> for 
+     * a Maven 1.x-style repository layout.
+     * 
+     * @parameter expression="${repositoryLayout}" default-value="default"
+     * @required
+     */
+    private String repositoryLayout;
+    /**
+     * Map that contains the layouts
+     *
+     * @component role="org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout"
+     */
+    private Map repositoryLayouts;
+    /**
+     * URL where the artifact will be deployed. <br/>
+     * ie ( file://C:\m2-repo or scp://host.com/path/to/repo )
+     *
+     * @parameter expression="${url}"
+     * @required
+     */
+    private String url;
+    /**
+     * Component used to create an artifact
+     *
+     * @component
+     */
+    private ArtifactFactory artifactFactory;
+    /**
+     * Component used to create a repository
+     *
+     * @component
+     */
+    private ArtifactRepositoryFactory repositoryFactory;
+    /**
+     * Location of an existing POM file to be deployed alongside the main
+     * artifact, given by the ${file} parameter.
+     * 
+     * @parameter expression="${pomFile}"
+     */
+    private File pomFile;
+    /**
+     * Upload a POM for this artifact.  Will generate a default POM if none is
+     * supplied with the pomFile argument.
+     *
+     * @parameter expression="${generatePom}" default-value="true"
+     */
+    private boolean generatePom;
+    /**
+     * Add classifier to the artifact
+     *
+     * @parameter expression="${classifier}";
+     */
+    private String classifier;
+    /**
+     * Whether to deploy snapshots with a unique version or not.
+     *
+     * @parameter expression="${uniqueVersion}" default-value="true"
+     */
+    private boolean uniqueVersion;
+    
+    
+    
+    
+    private final GpgSigner signer = new GpgSigner();
+    
+    
+    
+    public void execute()
+    throws MojoExecutionException
+    {
+        ArtifactHandler handler = new DefaultArtifactHandler( "asc" );
+        Map map = new HashMap();
+        map.put( "asc", handler );
+        artifactHandlerManager.addHandlers( map );
+        
+        
+        copyToParent();
+        ArtifactDeployer deployer = getDeployer();
+        signer.setInteractive( settings.isInteractiveMode() );
+        signer.setKeyName( keyname );
+        signer.setUseAgent( useAgent );
+        
+        setDeployer( new SignedArtifactDeployer( deployer, passphrase ) );
+        super.execute();
+    }
+    
+    /* this sucks.  The plugin:plugin won't find properties in parent classes unless 
+     * they exist in the same compilation unit.  Thus, we need to declare our own and 
+     * copy them to the parent.  HOWEVER, the DeployFileMojo doesn't have public setters.
+     * Thus, we need to do crappy field copies.
+     */
+    private void copyToParent()
+    throws MojoExecutionException 
+    {
+        this.setDeployer( deployer );
+        this.setLocalRepository( localRepository );
+        
+        setDeployFileMojoField( "groupId", groupId );
+        setDeployFileMojoField( "artifactId", artifactId );
+        setDeployFileMojoField( "version", version );
+        setDeployFileMojoField( "packaging", packaging );
+        setDeployFileMojoField( "description", description );
+        setDeployFileMojoField( "file", file );
+        setDeployFileMojoField( "repositoryId", repositoryId );
+        setDeployFileMojoField( "repositoryLayout", repositoryLayout );
+        setDeployFileMojoField( "repositoryLayouts", repositoryLayouts );
+        setDeployFileMojoField( "url", url );
+        setDeployFileMojoField( "artifactFactory", artifactFactory );
+        setDeployFileMojoField( "repositoryFactory", repositoryFactory );
+        setDeployFileMojoField( "pomFile", pomFile );
+        setDeployFileMojoField( "generatePom", Boolean.valueOf( generatePom ) );
+        setDeployFileMojoField( "classifier", classifier );
+        setDeployFileMojoField( "uniqueVersion", Boolean.valueOf( uniqueVersion ) );
+    }
+    
+    private void setDeployFileMojoField( String name, Object value )
+    throws MojoExecutionException 
+    {
+        try {
+            Field f = DeployFileMojo.class.getDeclaredField( name );
+            f.setAccessible( true );
+            f.set( this, value );
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException( "Could not set field " + name, e );
+        }
+    }
+
+    public void setDeployer( ArtifactDeployer deployer )
+    {
+        this.deployer = deployer;
+        super.setDeployer( deployer );
+    }
+
+    public void setLocalRepository( ArtifactRepository localRepository )
+    {
+        this.localRepository = localRepository;
+        super.setLocalRepository( localRepository );
+    }
+    
+    private class SignedArtifactDeployer implements ArtifactDeployer 
+    {
+        ArtifactDeployer deployer;
+        String pass;
+        
+        public SignedArtifactDeployer( ArtifactDeployer dep, String passphrase )
+            throws MojoExecutionException
+        {
+            deployer = dep;
+            pass = passphrase;
+            if ( !useAgent && null == pass )
+            {
+                if ( !settings.isInteractiveMode() )
+                {
+                    throw new MojoExecutionException( "Cannot obtain passphrase in batch mode" );
+                }
+                try 
+                {
+                    pass = signer.getPassphrase( null );
+                }
+                catch (IOException e) 
+                {
+                    throw new MojoExecutionException( "Exception reading password", e );
+                }
+            }
+        }
+
+        public void deploy( File source, Artifact artifact,
+                           ArtifactRepository deploymentRepository,
+                           ArtifactRepository localRepository ) 
+        throws ArtifactDeploymentException 
+        {
+            try
+            {
+                File fileSig = signer.generateSignatureForArtifact( source, pass );
+                ArtifactMetadata metadata = new AscArtifactMetadata( artifact, fileSig, false );
+                artifact.addMetadata( metadata );
+                
+                if ( !generatePom
+                    && pomFile != null )
+                {
+                    fileSig = signer.generateSignatureForArtifact( pomFile, pass );
+                    metadata = new AscArtifactMetadata( artifact, fileSig, true );
+                    artifact.addMetadata( metadata );
+                }
+                
+                deployer.deploy( source, artifact, deploymentRepository, localRepository );
+            }
+            catch (MojoExecutionException e )
+            {
+                throw new ArtifactDeploymentException( e.getMessage(), e);
+            }
+            
+        }
+
+        public void deploy( String basedir, String finalName,
+                            Artifact artifact,
+                            ArtifactRepository deploymentRepository,
+                            ArtifactRepository localRepository ) 
+        throws ArtifactDeploymentException 
+        {
+            String extension = artifact.getArtifactHandler().getExtension();
+            File source = new File( basedir, finalName + "." + extension );
+            deploy( source, artifact, deploymentRepository, localRepository );
+        }
+    }
+    
+    
+    
+
+}