[ https://issues.apache.org/jira/browse/MNG-6869?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17686737#comment-17686737 ]
ASF GitHub Bot commented on MNG-6869: ------------------------------------- mthmulders commented on code in PR #995: URL: https://github.com/apache/maven/pull/995#discussion_r1101938159 ########## 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: > [...] 1 step too much [...] Just to verify: are you referring to the fact that this code actually _downloads_ a file (e.g., it could've been an HTTP HEAD request), or to the fact that the `--status` verifies if artifact resolution works? In the case of the former: is a remote repository required to support an HTTP HEAD request? Could we rely on the fact that if HTTP HEAD is OK, HTTP GET will be OK, too? > 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)