[ 
https://issues.apache.org/jira/browse/MNG-6869?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17687063#comment-17687063
 ] 

ASF GitHub Bot commented on MNG-6869:
-------------------------------------

rfscholte commented on code in PR #995:
URL: https://github.com/apache/maven/pull/995#discussion_r1102729377


##########
maven-embedder/src/main/java/org/apache/maven/cli/MavenStatusCommand.java:
##########
@@ -0,0 +1,217 @@
+/*
+ * 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.maven.cli;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.services.ArtifactResolver;
+import org.apache.maven.api.services.ArtifactResolverException;
+import org.apache.maven.api.services.ArtifactResolverResult;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.execution.DefaultMavenExecutionResult;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenExecutionRequestPopulationException;
+import org.apache.maven.execution.MavenExecutionRequestPopulator;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
+import org.apache.maven.internal.impl.DefaultArtifactCoordinate;
+import org.apache.maven.internal.impl.DefaultSession;
+import org.apache.maven.internal.impl.DefaultSessionFactory;
+import org.apache.maven.session.scope.internal.SessionScope;
+import org.codehaus.plexus.PlexusContainer;
+import 
org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.transfer.ArtifactNotFoundException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MavenStatusCommand {
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(MavenStatusCommand.class);
+
+    /**
+     * In order to verify artifacts can be downloaded from the remote 
repositories we want to resolve an actual
+     * artifact. The Apache Maven artifact was chosen as it eventually, be it 
by proxy, mirror or directly, will be
+     * gathered from the central repository. The version is chosen arbitrarily 
since any listed should work.
+     */
+    public static final Artifact APACHE_MAVEN_ARTIFACT =
+            new DefaultArtifact("org.apache.maven", "apache-maven", null, 
"pom", "3.8.6");
+
+    private final MavenExecutionRequestPopulator 
mavenExecutionRequestPopulator;
+    private final ArtifactResolver artifactResolver;
+    private final RemoteRepositoryConnectionVerifier 
remoteRepositoryConnectionVerifier;
+    private final DefaultSessionFactory defaultSessionFactory;
+    private final DefaultRepositorySystemSessionFactory repoSession;
+    private final MavenRepositorySystem repositorySystem;
+    private final PlexusContainer container;
+    private final SessionScope sessionScope;
+    private Path tempLocalRepository;
+
+    public MavenStatusCommand(final PlexusContainer container) throws 
ComponentLookupException {
+        this.container = container;
+        this.remoteRepositoryConnectionVerifier = new 
RemoteRepositoryConnectionVerifier(container);
+        this.mavenExecutionRequestPopulator = 
container.lookup(MavenExecutionRequestPopulator.class);
+        this.artifactResolver = container.lookup(ArtifactResolver.class);
+        this.defaultSessionFactory = 
container.lookup(DefaultSessionFactory.class);
+        this.repoSession = 
container.lookup(DefaultRepositorySystemSessionFactory.class);
+        this.sessionScope = container.lookup(SessionScope.class);
+        this.repositorySystem = container.lookup(MavenRepositorySystem.class);
+    }
+
+    public List<String> verify(final MavenExecutionRequest cliRequest) throws 
MavenExecutionRequestPopulationException {
+        final MavenExecutionRequest mavenExecutionRequest = 
mavenExecutionRequestPopulator.populateDefaults(cliRequest);
+
+        final ArtifactRepository localRepository = 
cliRequest.getLocalRepository();
+
+        final List<String> localRepositoryIssues =
+                
verifyLocalRepository(Paths.get(URI.create(localRepository.getUrl())));
+
+        // We overwrite the local repository with a temporary folder to avoid 
using a cached version of the artifact.
+        setTemporaryLocalRepositoryPathOnRequest(cliRequest);
+
+        final List<String> remoteRepositoryIssues =
+                
verifyRemoteRepositoryConnections(cliRequest.getRemoteRepositories(), 
mavenExecutionRequest);
+        final List<String> artifactResolutionIssues = 
verifyArtifactResolution(mavenExecutionRequest);
+
+        cleanupTempFiles();
+
+        // Collect all issues into a single list
+        return Stream.of(localRepositoryIssues, remoteRepositoryIssues, 
artifactResolutionIssues)
+                .flatMap(Collection::stream)
+                .collect(Collectors.toList());
+    }
+
+    private void cleanupTempFiles() {
+        if (tempLocalRepository != null) {
+            try (Stream<Path> files = Files.walk(tempLocalRepository)) {
+                files.sorted(Comparator.reverseOrder()) // Sort in reverse 
order so that directories are deleted last
+                        .map(Path::toFile)
+                        .forEach(File::delete);
+            } catch (IOException ioe) {
+                LOGGER.debug("Failed to delete temporary local repository", 
ioe);
+            }
+        }
+    }
+
+    private void setTemporaryLocalRepositoryPathOnRequest(final 
MavenExecutionRequest request) {
+        try {
+            tempLocalRepository = 
Files.createTempDirectory("mvn-status").toAbsolutePath();
+            request.setLocalRepositoryPath(tempLocalRepository.toString());
+            
request.setLocalRepository(repositorySystem.createLocalRepository(request, 
tempLocalRepository.toFile()));
+        } catch (Exception ex) {
+            LOGGER.debug("Could not create temporary local repository", ex);
+            LOGGER.warn("Artifact resolution test is less accurate as it may 
use earlier resolution results.");
+        }
+    }
+
+    private List<String> verifyRemoteRepositoryConnections(
+            final List<ArtifactRepository> remoteRepositories, final 
MavenExecutionRequest mavenExecutionRequest) {
+        final List<String> issues = new ArrayList<>();
+
+        for (ArtifactRepository remoteRepository : remoteRepositories) {
+            final RepositorySystemSession repositorySession = 
repoSession.newRepositorySession(mavenExecutionRequest);
+            remoteRepositoryConnectionVerifier
+                    .verifyConnectionToRemoteRepository(repositorySession, 
remoteRepository)
+                    .ifPresent(issues::add);
+        }
+
+        return issues;
+    }
+
+    private List<String> verifyArtifactResolution(final MavenExecutionRequest 
mavenExecutionRequest) {

Review Comment:
   It depends on what you define as "artifact resolution works". I'm not 
interested if the implementation is correct. I wish there's a way to only 
confirm that the connection works. It is about returning questions on 
StackOverflow that say Maven can't download things, but it is just that it 
cannot reach a repository. Possible rootcauses are missing proxies (or 
misconfigured) and misconfigured mirrors. Maybe @michael-o or @cstamas can 
think of a low-level reliable way to conform this.





> New flag to verify the status
> -----------------------------
>
>                 Key: MNG-6869
>                 URL: https://issues.apache.org/jira/browse/MNG-6869
>             Project: Maven
>          Issue Type: New Feature
>            Reporter: Robert Scholte
>            Assignee: Maarten Mulders
>            Priority: Major
>
> While working on INFRA-19861 we had issues with invalid changes in the 
> settings.xml.
> This was detected too late. After installation {{mvn --version}} is called, 
> but it will only show the version of Maven.
> It would be better to have a flag that verifies it a bit more:
> - can Maven read/write to the local repository
> - can Maven access all predefined repositories? (does the proxy work?)
> This gives a much better feedback if Maven can do its job.
> Current workaround: call something like {{mvn help:evaluate 
> -Dexpression=settings.localRepository -q -DforceStdout}}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to