You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@maven.apache.org by mi...@apache.org on 2003/06/25 14:33:11 UTC
cvs commit: maven/src/plugins-build/artifact/src/main/org/apache/maven/deploy DeployTool.java
michal 2003/06/25 05:33:11
Modified: src/plugins-build/artifact/src/main/org/apache/maven/deploy/deployers
SFtpDeployer.java
src/plugins-build/artifact/src/main/org/apache/maven/artifact/deployer
MavenDeployRequest.java
src/plugins-build/artifact/src/main/org/apache/maven/deploy
DeployTool.java
Added: src/plugins-build/artifact/src/main/org/apache/maven/deploy/deployers
ScpDeployer.java GenericSshDeployer.java
Log:
Added SCP deloyer.
Revision Changes Path
1.2 +35 -138 maven/src/plugins-build/artifact/src/main/org/apache/maven/deploy/deployers/SFtpDeployer.java
Index: SFtpDeployer.java
===================================================================
RCS file: /home/cvs/maven/src/plugins-build/artifact/src/main/org/apache/maven/deploy/deployers/SFtpDeployer.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SFtpDeployer.java 24 Jun 2003 22:22:54 -0000 1.1
+++ SFtpDeployer.java 25 Jun 2003 12:33:11 -0000 1.2
@@ -56,41 +56,28 @@
* ====================================================================
*/
-import java.io.File;
-
import org.apache.commons.lang.StringUtils;
import org.apache.maven.deploy.DeployRequest;
import org.apache.maven.deploy.exceptions.DeployException;
import com.jcraft.jsch.ChannelSftp;
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.Proxy;
-import com.jcraft.jsch.ProxyHTTP;
-import com.jcraft.jsch.ProxySOCKS5;
+import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
-import com.jcraft.jsch.UserInfo;
+import com.jcraft.jsch.SftpException;
/**
- * An ssh2 deployer that uses the JSch library and the JCE. We will first try to
- * use public keys for authentication and if that doesn't work then we fall back
- * to using the login and password of the user in question. NOTE: We are
- * assuming the standard port of 22.
- *
- * @author <a href="mailto:jason@zenplex.com">Jason van Zyl</a>
- * @version $Id$
- * @todo still have to account for differing setups for people deploying to
- * their own sites and to the central repository.
+ * An SSH2 SFTP deployer
+ *
+ * @author Michal Maczka
+ * @version $Revision$ $Date$
*/
-public class SFtpDeployer extends AbstractDeployer
+public class SFtpDeployer extends GenericSshDeployer
{
public final static String PROTOCOL = "sftp://";
-
public final static String SFTP_CHANNEL = "sftp";
- public final static int DEFAULT_SSH_PORT = 22;
- public final static int SOCKS5_PROXY_PORT = 1080;
- public final static int S_IFDIR = 0x4000;
+
/**
* @see Deployer#project
@@ -111,65 +98,12 @@
{
throw new DeployException("For sftp protocol remote group should be an integer");
}
+
+ Session session = getSession(request);
+ ChannelSftp channel = null;
try
{
- JSch jsch = new JSch();
-
- int port = request.getPort();
- if (port == DeployRequest.UNKNOWN_PORT)
- {
- port = DEFAULT_SSH_PORT;
- }
- String host = request.getHost();
- Session session = jsch.getSession(request.getUser(), host, port);
-
- String proxyHost = request.getProxyHost();
-
- if (proxyHost != null)
- {
- Proxy proxy = null;
- int proxyPort = request.getProxyPort();
- //if port == 1080 we will use SOCKS5 Proxy
- // otherwise will use HTTP Proxy
-
- if (proxyPort == SOCKS5_PROXY_PORT)
- {
- proxy = new ProxySOCKS5(proxyHost);
- ((ProxySOCKS5) proxy).setUserPasswd(
- request.getProxyUser(),
- request.getProxyPass());
- }
- else
- {
- proxy = new ProxyHTTP(proxyHost, proxyPort);
- ((ProxyHTTP) proxy).setUserPasswd(
- request.getProxyUser(),
- request.getProxyPass());
- }
- proxy.connect(session, host, port);
-
- }
-
- // Look for the private key and use it if available.
- if (request.getPrivateKey() != null)
- {
- File privateKey = new File(request.getPrivateKey());
-
- if (privateKey.exists())
- {
- System.out.println("Using private key: " + privateKey);
- jsch.addIdentity(
- privateKey.getAbsolutePath(),
- request.getPassphrase());
- }
- }
- // username and password will be given via UserInfo interface.
- UserInfo ui = new MavenUserInfo(request);
- session.setUserInfo(ui);
- session.connect();
-
- ChannelSftp channel =
- (ChannelSftp) session.openChannel(SFTP_CHANNEL);
+ channel = (ChannelSftp) session.openChannel(SFTP_CHANNEL);
channel.connect();
// iterate over all directories in the path. try to create
// directory
@@ -195,7 +129,7 @@
}
catch (Exception e)
{
- // file does not exists
+ // file most probably does not exists
channel.mkdir(dirs[i]);
channel.cd(dirs[i]);
}
@@ -210,75 +144,38 @@
}
}
- catch (Exception e)
+ catch (SftpException e)
{
- e.printStackTrace();
throw new DeployException(
"Cannot deploy. Reason: " + e.getMessage(),
e);
}
- }
-
- /**
- * MavenUserInfo class which returns the necessary name and password from
- * the POM to secure an ssh connection.
- */
- public class MavenUserInfo implements UserInfo
- {
-
- DeployRequest request;
-
- MavenUserInfo(DeployRequest request)
- {
- this.request = request;
- }
-
- public String getPassphrase()
- {
- return request.getPassphrase();
- }
-
- /* (non-Javadoc)
- * @see com.jcraft.jsch.UserInfo#getPassword()
- */
- public String getPassword()
- {
- return request.getPass();
- }
-
- /* (non-Javadoc)
- * @see com.jcraft.jsch.UserInfo#promptPassphrase(java.lang.String)
- */
- public boolean promptPassphrase(String arg0)
- {
- return true;
- }
-
- /* (non-Javadoc)
- * @see com.jcraft.jsch.UserInfo#promptPassword(java.lang.String)
- */
- public boolean promptPassword(String arg0)
- {
- return true;
- }
- /**
- * @see com.jcraft.jsch.UserInfo#promptYesNo(java.lang.String)
- */
- public boolean promptYesNo(String arg0)
+ catch (JSchException e)
{
- return true;
+ throw new DeployException(
+ "Cannot deploy. Reason: " + e.getMessage(),
+ e);
}
-
- /* (non-Javadoc)
- * @see com.jcraft.jsch.UserInfo#showMessage(java.lang.String)
- */
- public void showMessage(String message)
+ finally
{
- System.out.println(message);
-
+ try
+ {
+ channel.disconnect();
+ }
+ catch (Exception e)
+ {
+ //just ignore.
+ }
+ try
+ {
+ session.disconnect();
+ }
+ catch (Exception e)
+ {
+ // just ignore.
+ }
}
-
}
}
1.1 maven/src/plugins-build/artifact/src/main/org/apache/maven/deploy/deployers/ScpDeployer.java
Index: ScpDeployer.java
===================================================================
package org.apache.maven.deploy.deployers;
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache MavenSession" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache MavenSession", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* ====================================================================
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.maven.deploy.DeployRequest;
import org.apache.maven.deploy.exceptions.DeployException;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
/**
* An SSH2 SFTP deployer
*
* @author Michal Maczka
* @version $Revision: 1.1 $ $Date: 2003/06/25 12:33:11 $
*/
public class ScpDeployer extends GenericSshDeployer
{
public final static String PROTOCOL = "scp://";
public final static String EXEC_CHANNEL = "exec";
/**
* @see Deployer#project
*
* @todo better way of guessing what king of proxy server is used
*/
public void deploy(DeployRequest request) throws DeployException
{
Session session = getSession(request);
try
{
//String scpCmd = "scp -t " + request.getOutputFile() + "\n";
executeSimpleCommand(
session,
"mkdir -p " + request.getOutputDir() + "\n");
doCopy(session, request);
if (request.getGroup() != null)
{
executeSimpleCommand(
session,
"chgrp "
+ request.getGroup()
+ " "
+ request.getOutputFile()
+ "\n");
}
}
finally
{
try
{
session.disconnect();
}
catch (Exception e)
{
// just ignore.
}
}
}
/**
* Execute simple command
*/
private void executeSimpleCommand(Session session, String command)
throws DeployException
{
System.out.println("Executing command: " + command);
ChannelExec channel = null;
try
{
channel = (ChannelExec) session.openChannel(EXEC_CHANNEL);
channel.setCommand(command);
OutputStream out = channel.getOutputStream();
InputStream in = channel.getInputStream();
channel.connect();
}
catch (Exception e)
{
throw new DeployException(
"Cannot execute remote command: " + command);
}
finally
{
//when channel cannot be closed it is still ok. this "local"
//failure is not global failure
if (channel != null)
{
try
{
channel.disconnect();
}
catch (Exception e)
{
//ignore
}
}
}
}
/**
* Copy artifact file using streams (pipes)
*/
private void doCopy(Session session, DeployRequest request)
throws DeployException
{
try
{
String inputFile = request.getInputFile();
String outputFile = request.getOutputFile();
String outputDir = request.getOutputDir();
// exec 'scp -t rfile' remotely
String command = "scp -t " + outputDir + "/" + outputFile;
System.out.println("Executing command: " + command);
ChannelExec channel =
(ChannelExec) session.openChannel(EXEC_CHANNEL);
channel.setCommand(command);
// get I/O streams for remote scp
OutputStream out = channel.getOutputStream();
InputStream in = channel.getInputStream();
channel.connect();
byte[] tmp = new byte[1];
// wait for '\0'
do
{
in.read(tmp, 0, 1);
}
while (tmp[0] != 0);
// send "C0644 filesize filename", where filename should not include '/'
int filesize = (int) (new File(inputFile)).length();
command = "C0644 " + filesize + " ";
if (inputFile.lastIndexOf('/') > 0)
{
command += inputFile.substring(inputFile.lastIndexOf('/') + 1);
}
else
{
command += inputFile;
}
command += "\n";
out.write(command.getBytes());
out.flush();
// wait for '\0'
do
{
in.read(tmp, 0, 1);
}
while (tmp[0] != 0);
// send a content of inputFile
FileInputStream fis = new FileInputStream(inputFile);
byte[] buf = new byte[1024];
while (true)
{
int len = fis.read(buf, 0, buf.length);
if (len <= 0)
break;
out.write(buf, 0, len);
out.flush();
}
// send '\0'
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
// wait for '\0'
do
{
in.read(tmp, 0, 1);
}
while (tmp[0] != 0);
}
catch (FileNotFoundException e)
{
throw new DeployException(
"Input file was not found: " + request.getInputFile(),
e);
}
catch (IOException e)
{
throw new DeployException(
"IO error while sending file: " + request.getInputFile(),
e);
}
catch (JSchException e)
{
throw new DeployException(
"Error occured while copying file to remote host",
e);
}
}
}
1.1 maven/src/plugins-build/artifact/src/main/org/apache/maven/deploy/deployers/GenericSshDeployer.java
Index: GenericSshDeployer.java
===================================================================
package org.apache.maven.deploy.deployers;
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache MavenSession" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache MavenSession", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* ====================================================================
*/
import java.io.File;
import org.apache.maven.deploy.DeployRequest;
import org.apache.maven.deploy.exceptions.DeployException;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Proxy;
import com.jcraft.jsch.ProxyHTTP;
import com.jcraft.jsch.ProxySOCKS5;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
/**
* An ssh2 deployer that uses the JSch library and the JCE.
*
* This class deals with authetification stage of the process.
*
* We will first try to
* use public keys for authentication and if that doesn't work then we fall back
* to using the login and password of the user in question. NOTE: We are
* assuming the standard port of 22.
*
*
* @version $Id: GenericSshDeployer.java,v 1.1 2003/06/25 12:33:11 michal Exp $
* @todo still have to account for differing setups for people deploying to
* their own sites and to the central repository.
*/
public abstract class GenericSshDeployer extends AbstractDeployer
{
public final static int DEFAULT_SSH_PORT = 22;
public final static int SOCKS5_PROXY_PORT = 1080;
/**
* @see Deployer#project
*
* @todo better way of guessing what kind of proxy server is used
* by user
*/
public Session getSession(DeployRequest request) throws DeployException
{
try
{
JSch jsch = new JSch();
int port = request.getPort();
if (port == DeployRequest.UNKNOWN_PORT)
{
port = DEFAULT_SSH_PORT;
}
String host = request.getHost();
Session session = jsch.getSession(request.getUser(), host, port);
String proxyHost = request.getProxyHost();
if (proxyHost != null)
{
Proxy proxy = null;
int proxyPort = request.getProxyPort();
//if port == 1080 we will use SOCKS5 Proxy
// otherwise will use HTTP Proxy
if (proxyPort == SOCKS5_PROXY_PORT)
{
proxy = new ProxySOCKS5(proxyHost);
((ProxySOCKS5) proxy).setUserPasswd(
request.getProxyUser(),
request.getProxyPass());
}
else
{
proxy = new ProxyHTTP(proxyHost, proxyPort);
((ProxyHTTP) proxy).setUserPasswd(
request.getProxyUser(),
request.getProxyPass());
}
proxy.connect(session, host, port);
}
// Look for the private key and use it if available.
if (request.getPrivateKey() != null)
{
File privateKey = new File(request.getPrivateKey());
if (privateKey.exists())
{
System.out.println("Using private key: " + privateKey);
jsch.addIdentity(
privateKey.getAbsolutePath(),
request.getPassphrase());
}
}
// username and password will be given via UserInfo interface.
UserInfo ui = new MavenUserInfo(request);
session.setUserInfo(ui);
session.connect();
return session;
}
catch (Exception e)
{
e.printStackTrace();
throw new DeployException(
"Cannot connect. Reason: " + e.getMessage(),
e);
}
}
/**
* MavenUserInfo class which returns the necessary name and password from
* the POM to secure an ssh connection.
*/
public class MavenUserInfo implements UserInfo
{
DeployRequest request;
MavenUserInfo(DeployRequest request)
{
this.request = request;
}
public String getPassphrase()
{
return request.getPassphrase();
}
/* (non-Javadoc)
* @see com.jcraft.jsch.UserInfo#getPassword()
*/
public String getPassword()
{
return request.getPass();
}
/* (non-Javadoc)
* @see com.jcraft.jsch.UserInfo#promptPassphrase(java.lang.String)
*/
public boolean promptPassphrase(String arg0)
{
return true;
}
/* (non-Javadoc)
* @see com.jcraft.jsch.UserInfo#promptPassword(java.lang.String)
*/
public boolean promptPassword(String arg0)
{
return true;
}
/**
* @see com.jcraft.jsch.UserInfo#promptYesNo(java.lang.String)
*/
public boolean promptYesNo(String arg0)
{
return true;
}
/* (non-Javadoc)
* @see com.jcraft.jsch.UserInfo#showMessage(java.lang.String)
*/
public void showMessage(String message)
{
System.out.println(message);
}
}
}
1.6 +25 -21 maven/src/plugins-build/artifact/src/main/org/apache/maven/artifact/deployer/MavenDeployRequest.java
Index: MavenDeployRequest.java
===================================================================
RCS file: /home/cvs/maven/src/plugins-build/artifact/src/main/org/apache/maven/artifact/deployer/MavenDeployRequest.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- MavenDeployRequest.java 24 Jun 2003 22:22:55 -0000 1.5
+++ MavenDeployRequest.java 25 Jun 2003 12:33:11 -0000 1.6
@@ -95,13 +95,11 @@
String username =
(String) project.getContext().getVariable(
"maven.repo." + repository + ".username");
-
+
String password =
(String) project.getContext().getVariable(
"maven.repo." + repository + ".password");
- System.out.println(repository + " password: '" + password + "'");
-
String passphrase =
(String) project.getContext().getVariable(
"maven.repo." + repository + ".passphrase");
@@ -120,7 +118,7 @@
String remoteGroup =
(String) project.getContext().getVariable(
- "maven.repo." + repository + ".remote.group");
+ "maven.repo." + repository + ".group");
String proxyHost =
(String) project.getContext().getVariable(
@@ -142,26 +140,32 @@
setPassphrase(passphrase);
setPrivateKey(privateKey);
setGroup(remoteGroup);
- setUrl(url.trim());
-
- try
- {
- setPort(Integer.parseInt(port));
- }
- catch (Exception e)
+ setUrl(url);
+ setProxyHost(proxyHost);
+ setProxyUser(proxyUser);
+ setProxyPass(proxyPassword);
+ if (port != null)
{
+ try
+ {
- setProxyHost(proxyHost);
- setProxyUser(proxyUser);
- setProxyPass(proxyPassword);
- }
- try
- {
- setProxyPort(Integer.parseInt(proxyPort.trim()));
+ setPort(Integer.parseInt(port));
+ }
+ catch (Exception e)
+ {
+ //throw new DeployException("maven.repo." + repository + ".port should be an integer");
+ }
}
- catch (Exception e)
+ if (proxyPort != null)
{
-
+ try
+ {
+ setProxyPort(Integer.parseInt(proxyPort.trim()));
+ }
+ catch (Exception e)
+ {
+ //throw new DeployException("maven.repo." + repository + ".proxy.port should be an integer");
+ }
}
setInputFile(inputFile);
1.4 +6 -1 maven/src/plugins-build/artifact/src/main/org/apache/maven/deploy/DeployTool.java
Index: DeployTool.java
===================================================================
RCS file: /home/cvs/maven/src/plugins-build/artifact/src/main/org/apache/maven/deploy/DeployTool.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- DeployTool.java 24 Jun 2003 22:22:55 -0000 1.3
+++ DeployTool.java 25 Jun 2003 12:33:11 -0000 1.4
@@ -61,6 +61,7 @@
import org.apache.maven.deploy.deployers.FtpDeployer;
import org.apache.maven.deploy.deployers.HttpDeployer;
import org.apache.maven.deploy.deployers.SFtpDeployer;
+import org.apache.maven.deploy.deployers.ScpDeployer;
import org.apache.maven.deploy.exceptions.DeployException;
import org.apache.maven.deploy.exceptions.UnsupportedProtocolDeployException;
@@ -99,6 +100,10 @@
if (url.startsWith(SFtpDeployer.PROTOCOL))
{
deployer = new SFtpDeployer();
+ }
+ if (url.startsWith(ScpDeployer.PROTOCOL))
+ {
+ deployer = new ScpDeployer();
}
if (deployer == null)
{
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@maven.apache.org
For additional commands, e-mail: dev-help@maven.apache.org