On Mon, 12 Sep 2016 20:07:37 +0200, Karl Heinz Marbaise <khmarba...@gmx.de> wrote:

Hi Robert,

On 12/09/16 19:42, Robert Scholte wrote:
Hi Karl Heinz,

We probably need to revisit this code. I think Aether is also capable in
generating these files...

Sure I appreciate any suggestions ..it was only my first state which worked ...This code should be improved of course...

I have a question conerning the repositoryManager which I currently use in DefaultProjectInstaller:

private File getLocalRepoFile( ProjectBuildingRequest buildingRequest, ArtifactRepository artifactRepository,
                                    Artifact artifact )
     {
String path = repositoryManager.getPathForLocalArtifact( buildingRequest, artifact );
         return new File( artifactRepository.getBasedir(), path );
     }

I'm not sure if this couldn't be made simpler ?


IIRC you can pickup the localRepository from the buildingRequest, but in case of a different localRepository (m-invoker-p and m-dependency-p need this), this is the best option you have. To ensure that the developer is aware of this, I've chosen to ask explicitly for the repository.

Robert

Kind regards
Karl Heinz Marbaise



Robert

On Mon, 12 Sep 2016 13:22:30 +0200, <khmarba...@apache.org> wrote:

Author: khmarbaise
Date: Mon Sep 12 11:22:29 2016
New Revision: 1760333

URL: http://svn.apache.org/viewvc?rev=1760333&view=rev
Log:
[MSHARED-593] Add interface to install a Maven Project

Added:

maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/


maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/ProjectInstaller.java


maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/ProjectInstallerRequest.java


maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/internal/


maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/internal/DefaultProjectInstaller.java


maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/internal/DualDigester.java

Modified:
    maven/shared/trunk/maven-artifact-transfer/pom.xml

Modified: maven/shared/trunk/maven-artifact-transfer/pom.xml
URL:
http://svn.apache.org/viewvc/maven/shared/trunk/maven-artifact-transfer/pom.xml?rev=1760333&r1=1760332&r2=1760333&view=diff

==============================================================================

--- maven/shared/trunk/maven-artifact-transfer/pom.xml (original)
+++ maven/shared/trunk/maven-artifact-transfer/pom.xml Mon Sep 12
11:22:29 2016
@@ -168,6 +168,17 @@
       <artifactId>maven-common-artifact-filters</artifactId>
       <version>3.0.0</version>
     </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+      <version>3.0.24</version>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-codec</groupId>
+      <artifactId>commons-codec</artifactId>
+      <version>1.6</version>
+    </dependency>
    <!-- Maven 3.0.x -->
     <dependency>

Added:
maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/ProjectInstaller.java

URL:
http://svn.apache.org/viewvc/maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/ProjectInstaller.java?rev=1760333&view=auto

==============================================================================

---
maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/ProjectInstaller.java
(added)
+++
maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/ProjectInstaller.java
Mon Sep 12 11:22:29 2016
@@ -0,0 +1,49 @@
+package org.apache.maven.shared.project.install;
+
+/*
+ * 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.IOException;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.project.ProjectBuildingRequest;
+import
org.apache.maven.shared.artifact.install.ArtifactInstallerException;
+
+/**
+ * This defines the interface to install a single Maven Project.
+ *
+ * @author Karl Heinz Marbaise <a
href="mailto:khmarba...@apache.org";>khmarba...@apache.org</a>
+ */
+public interface ProjectInstaller
+{
+    /**
+     * This will install a single project which may contain several
artifacts. Those artifacts will be installed into
+     * the appropriate repository.
+     *
+     * @param projectBuildingRequest {@link ProjectBuildingRequest}
+     * @param projectInstallerRequest {@link ProjectInstallerRequest}
+     * @param artifactRepository {@link ArtifactRepository}
+     * @throws IOException In case of problem to install project.
+     * @throws ArtifactInstallerException In case of problems to
install artifacts.
+     */
+    void installProject( ProjectBuildingRequest
projectBuildingRequest, ProjectInstallerRequest projectInstallerRequest,
+                         ArtifactRepository artifactRepository )
+        throws IOException, ArtifactInstallerException;
+
+}

Added:
maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/ProjectInstallerRequest.java

URL:
http://svn.apache.org/viewvc/maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/ProjectInstallerRequest.java?rev=1760333&view=auto

==============================================================================

---
maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/ProjectInstallerRequest.java
(added)
+++
maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/ProjectInstallerRequest.java
Mon Sep 12 11:22:29 2016
@@ -0,0 +1,90 @@
+package org.apache.maven.shared.project.install;
+
+/*
+ * 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 org.apache.maven.project.MavenProject;
+
+/**
+ * @author Robert Scholte
+ */
+public class ProjectInstallerRequest
+{
+    // From AbstractInstallMojo
+
+    private boolean createChecksum;
+
+    private boolean updateReleaseInfo;
+
+    // From InstallMojo
+
+    private MavenProject project;
+
+    /**
+     * @return the createChecksum
+     */
+    public boolean isCreateChecksum()
+    {
+        return createChecksum;
+    }
+
+    /**
+     * @param createChecksum the createChecksum to set
+     */
+    public ProjectInstallerRequest setCreateChecksum( boolean
createChecksum )
+    {
+        this.createChecksum = createChecksum;
+        return this;
+    }
+
+    /**
+     * @return the updateReleaseInfo
+     */
+    public boolean isUpdateReleaseInfo()
+    {
+        return updateReleaseInfo;
+    }
+
+    /**
+     * @param updateReleaseInfo the updateReleaseInfo to set
+     */
+    public ProjectInstallerRequest setUpdateReleaseInfo( boolean
updateReleaseInfo )
+    {
+        this.updateReleaseInfo = updateReleaseInfo;
+        return this;
+    }
+
+    /**
+     * @return the project
+     */
+    public MavenProject getProject()
+    {
+        return project;
+    }
+
+    /**
+     * @param project the project to set
+     */
+    public ProjectInstallerRequest setProject( MavenProject project )
+    {
+        this.project = project;
+        return this;
+    }
+
+}

Added:
maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/internal/DefaultProjectInstaller.java

URL:
http://svn.apache.org/viewvc/maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/internal/DefaultProjectInstaller.java?rev=1760333&view=auto

==============================================================================

---
maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/internal/DefaultProjectInstaller.java
(added)
+++
maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/internal/DefaultProjectInstaller.java
Mon Sep 12 11:22:29 2016
@@ -0,0 +1,275 @@
+package org.apache.maven.shared.project.install.internal;
+
+/*
+ * 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.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.project.artifact.ProjectArtifact;
+import org.apache.maven.project.artifact.ProjectArtifactMetadata;
+import org.apache.maven.shared.artifact.install.ArtifactInstaller;
+import
org.apache.maven.shared.artifact.install.ArtifactInstallerException;
+import org.apache.maven.shared.project.install.ProjectInstaller;
+import org.apache.maven.shared.project.install.ProjectInstallerRequest;
+import org.apache.maven.shared.repository.RepositoryManager;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.util.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This will install a whole project into the appropriate repository.
+ *
+ * @author Karl Heinz Marbaise <a
href="mailto:khmarba...@apache.org";>khmarba...@apache.org</a>
+ */
+@Component( role = ProjectInstaller.class )
+public class DefaultProjectInstaller
+    implements ProjectInstaller
+{
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(
DefaultProjectInstaller.class );
+
+    @Inject
+    private ArtifactInstaller installer;
+
+    @Inject
+    private RepositoryManager repositoryManager;
+
+    private final DualDigester digester = new DualDigester();
+
+    public void installProject( ProjectBuildingRequest
buildingRequest, ProjectInstallerRequest request,
+ ArtifactRepository artifactRepository )
+        throws IOException, ArtifactInstallerException
+    {
+
+        MavenProject project = request.getProject();
+        boolean createChecksum = request.isCreateChecksum();
+        boolean updateReleaseInfo = request.isUpdateReleaseInfo();
+
+        Artifact artifact = project.getArtifact();
+        String packaging = project.getPackaging();
+        File pomFile = project.getFile();
+
+        List<Artifact> attachedArtifacts =
project.getAttachedArtifacts();
+
+        // TODO: push into transformation
+        boolean isPomArtifact = "pom".equals( packaging );
+
+        ProjectArtifactMetadata metadata;
+
+        if ( updateReleaseInfo )
+        {
+            artifact.setRelease( true );
+        }
+
+        Collection<File> metadataFiles = new LinkedHashSet<File>();
+
+        if ( isPomArtifact )
+        {
+ // installer.install( pomFile, artifact, localRepository );
+            installer.install( buildingRequest,
Collections.<Artifact>singletonList( new ProjectArtifact( project ) ) );
+            installChecksums( buildingRequest, artifactRepository,
artifact, createChecksum );
+            addMetaDataFilesForArtifact( artifactRepository,
artifact, metadataFiles, createChecksum );
+        }
+        else
+        {
+ metadata = new ProjectArtifactMetadata( artifact, pomFile );
+            artifact.addMetadata( metadata );
+
+            File file = artifact.getFile();
+
+            // Here, we have a temporary solution to MINSTALL-3
(isDirectory() is true if it went through compile
+            // but not package). We are designing in a proper
solution for Maven 2.1
+            if ( file != null && file.isFile() )
+            {
+                installer.install( buildingRequest,
Collections.<Artifact>singletonList( artifact ) );
+                installChecksums( buildingRequest,
artifactRepository, artifact, createChecksum );
+                addMetaDataFilesForArtifact( artifactRepository,
artifact, metadataFiles, createChecksum );
+            }
+            else if ( !attachedArtifacts.isEmpty() )
+            {
+                throw new IllegalArgumentException( "The packaging
plugin for this project did not assign "
+                    + "a main file to the project but it has
attachments. Change packaging to 'pom'." );
+            }
+            else
+            {
+                // CHECKSTYLE_OFF: LineLength
+                throw new IllegalArgumentException( "The packaging
for this project did not assign a file to the build artifact" );
+                // CHECKSTYLE_ON: LineLength
+            }
+        }
+
+        for ( Artifact attached : attachedArtifacts )
+        {
+            // installer.install( attached.getFile(), attached,
localRepository );
+            installer.install( buildingRequest,
Collections.singletonList( attached ) );
+            installChecksums( buildingRequest, artifactRepository,
attached, createChecksum );
+            addMetaDataFilesForArtifact( artifactRepository,
attached, metadataFiles, createChecksum );
+        }
+
+        installChecksums( metadataFiles );
+    }
+
+    /**
+     * Installs the checksums for the specified artifact if this has
been enabled in the plugin configuration. This
+     * method creates checksums for files that have already been
installed to the local repo to account for on-the-fly
+     * generated/updated files. For example, in Maven 2.0.4- the
<code>ProjectArtifactMetadata</code> did not install
+     * the original POM file (cf. MNG-2820). While the plugin
currently requires Maven 2.0.6, we continue to hash the
+     * installed POM for robustness with regard to future changes
like re-introducing some kind of POM filtering.
+     *
+     * @param artifact The artifact for which to create checksums,
must not be <code>null</code>.
+     * @param createChecksum {@code true} if checksum should be
created, otherwise {@code false}.
+     * @throws IOException If the checksums could not be installed.
+     */
+    private void installChecksums( ProjectBuildingRequest
buildingRequest, ArtifactRepository artifactRepository,
+                                   Artifact artifact, boolean
createChecksum )
+        throws IOException
+    {
+        if ( !createChecksum )
+        {
+            return;
+        }
+
+        File artifactFile = getLocalRepoFile( buildingRequest,
artifactRepository, artifact );
+        installChecksums( artifactFile );
+    }
+
+    // CHECKSTYLE_OFF: LineLength
+    protected void addMetaDataFilesForArtifact( ArtifactRepository
artifactRepository, Artifact artifact,
+                                                Collection<File>
targetMetadataFiles, boolean createChecksum )
+    // CHECKSTYLE_ON: LineLength
+    {
+        if ( !createChecksum )
+        {
+            return;
+        }
+
+        Collection<ArtifactMetadata> metadatas =
artifact.getMetadataList();
+        if ( metadatas != null )
+        {
+            for ( ArtifactMetadata metadata : metadatas )
+            {
+                File metadataFile = getLocalRepoFile(
artifactRepository, metadata );
+                targetMetadataFiles.add( metadataFile );
+            }
+        }
+    }
+
+    /**
+     * Installs the checksums for the specified metadata files.
+     *
+     * @param metadataFiles The collection of metadata files to
install checksums for, must not be <code>null</code>.
+     * @throws IOException If the checksums could not be installed.
+     */
+    protected void installChecksums( Collection<File> metadataFiles )
+        throws IOException
+    {
+        for ( File metadataFile : metadataFiles )
+        {
+            installChecksums( metadataFile );
+        }
+    }
+
+    /**
+     * Installs the checksums for the specified file (if it exists).
+     *
+     * @param installedFile The path to the already installed file in
the local repo for which to generate checksums,
+     *            must not be <code>null</code>.
+     * @throws IOException In case of errors. Could not install
checksums.
+     */
+    private void installChecksums( File installedFile )
+        throws IOException
+    {
+        boolean signatureFile = installedFile.getName().endsWith(
".asc" );
+        if ( installedFile.isFile() && !signatureFile )
+        {
+            LOGGER.debug( "Calculating checksums for " +
installedFile );
+            digester.calculate( installedFile );
+ installChecksum( installedFile, ".md5", digester.getMd5() );
+            installChecksum( installedFile, ".sha1",
digester.getSha1() );
+        }
+    }
+
+    /**
+     * Installs a checksum for the specified file.
+     *
+     * @param installedFile The base path from which the path to the
checksum files is derived by appending the given
+     *            file extension, must not be <code>null</code>.
+     * @param ext The file extension (including the leading dot) to
use for the checksum file, must not be
+     *            <code>null</code>.
+     * @param checksum the checksum to write
+     * @throws IOException If the checksum could not be installed.
+     */
+    private void installChecksum( File installedFile, String ext,
String checksum )
+        throws IOException
+    {
+        File checksumFile = new File( installedFile.getAbsolutePath()
+ ext );
+        LOGGER.debug( "Installing checksum to " + checksumFile );
+        try
+        {
+            // noinspection ResultOfMethodCallIgnored
+            checksumFile.getParentFile().mkdirs();
+            FileUtils.fileWrite( checksumFile.getAbsolutePath(),
"UTF-8", checksum );
+        }
+        catch ( IOException e )
+        {
+            throw new IOException( "Failed to install checksum to " +
checksumFile, e );
+        }
+    }
+
+    /**
+     * Gets the path of the specified artifact within the local
repository. Note that the returned path need not exist
+     * (yet).
+     *
+     * @param artifact The artifact whose local repo path should be
determined, must not be <code>null</code>.
+     * @return The absolute path to the artifact when installed,
never <code>null</code>.
+     */
+    private File getLocalRepoFile( ProjectBuildingRequest
buildingRequest, ArtifactRepository artifactRepository,
+                                   Artifact artifact )
+    {
+        String path = repositoryManager.getPathForLocalArtifact(
buildingRequest, artifact );
+        return new File( artifactRepository.getBasedir(), path );
+    }
+
+    /**
+     * Gets the path of the specified artifact metadata within the
local repository. Note that the returned path need
+     * not exist (yet).
+     *
+     * @param metadata The artifact metadata whose local repo path
should be determined, must not be <code>null</code>.
+     * @return The absolute path to the artifact metadata when
installed, never <code>null</code>.
+     */
+    private File getLocalRepoFile( ArtifactRepository
artifactRepository, ArtifactMetadata metadata )
+    {
+        String path =
artifactRepository.pathOfLocalRepositoryMetadata( metadata,
artifactRepository );
+        return new File( artifactRepository.getBasedir(), path );
+    }
+
+}

Added:
maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/internal/DualDigester.java

URL:
http://svn.apache.org/viewvc/maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/internal/DualDigester.java?rev=1760333&view=auto

==============================================================================

---
maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/internal/DualDigester.java
(added)
+++
maven/shared/trunk/maven-artifact-transfer/src/main/java/org/apache/maven/shared/project/install/internal/DualDigester.java
Mon Sep 12 11:22:29 2016
@@ -0,0 +1,112 @@
+package org.apache.maven.shared.project.install.internal;
+
+/*
+ * 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.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import org.apache.commons.codec.binary.Hex;
+import org.codehaus.plexus.util.IOUtil;
+
+
+/**
+ * Calculates md5 and sha1 digest.
+ * <p/>
+ * Todo: Consider using a thread to calculate one of the digests when
the files are large; it's fairly slow !
+ *
+ * @author Kristian Rosenvold
+ */
+public class DualDigester
+{
+    private final MessageDigest md5 = getDigester( "MD5" );
+
+    private final MessageDigest sh1 = getDigester( "SHA-1" );
+
+    private static final int BUFSIZE = 65536 * 2;
+
+    private final byte[] buffer = new byte[BUFSIZE];
+
+    static MessageDigest getDigester( String algorithm )
+    {
+        try
+        {
+            return MessageDigest.getInstance( algorithm );
+        }
+        catch ( NoSuchAlgorithmException e )
+        {
+            throw new RuntimeException( "Unable to initialize digest
" + algorithm + " : " + e.getMessage() );
+        }
+    }
+
+    public void calculate( File file ) throws IOException
+    {
+        FileInputStream fis = null;
+
+        try
+        {
+            fis = new FileInputStream( file );
+            calculate( fis );
+            fis.close();
+            fis = null;
+        }
+        catch ( IOException e )
+        {
+            throw new IOException( "Failed to calculate digest
checksum for " + file, e );
+        }
+        finally
+        {
+            IOUtil.close( fis );
+        }
+    }
+
+    void calculate( InputStream stream )
+        throws IOException
+    {
+        md5.reset();
+        sh1.reset();
+        update( stream );
+    }
+
+    public String getMd5()
+    {
+        return Hex.encodeHexString( md5.digest() );
+    }
+
+    public String getSha1()
+    {
+        return Hex.encodeHexString( sh1.digest() );
+    }
+
+    private void update( InputStream is )
+        throws IOException
+    {
+        int size = is.read( buffer, 0, BUFSIZE );
+        while ( size >= 0 )
+        {
+            md5.update( buffer, 0, size );
+            sh1.update( buffer, 0, size );
+            size = is.read( buffer, 0, BUFSIZE );
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@maven.apache.org
For additional commands, e-mail: dev-h...@maven.apache.org




Mit freundlichem Gruß
Karl-Heinz Marbaise

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@maven.apache.org
For additional commands, e-mail: dev-h...@maven.apache.org

Reply via email to