Author: tchemit Date: 2010-06-19 00:28:10 +0200 (Sat, 19 Jun 2010) New Revision: 718 Url: http://nuiton.org/repositories/revision/maven-helper-plugin/718 Log: Evolution #691: Add a CheckCentralSafe goal Added: trunk/src/main/java/org/nuiton/helper/plugin/CheckCentralSafePlugin.java Modified: trunk/pom.xml Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2010-06-02 10:28:20 UTC (rev 717) +++ trunk/pom.xml 2010-06-18 22:28:10 UTC (rev 718) @@ -34,7 +34,7 @@ <parent> <groupId>org.nuiton</groupId> <artifactId>mavenpom4redmine</artifactId> - <version>2.1.5</version> + <version>2.2-SNAPSHOT</version> </parent> <artifactId>maven-helper-plugin</artifactId> @@ -268,6 +268,11 @@ </exclusion> </exclusions> </dependency> + <!--dependency> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-project-info-reports-plugin</artifactId> + <version>2.2</version> + </dependency--> </dependencies> @@ -310,6 +315,9 @@ <properties> + <!-- deploy releases on nuiton-central-releases repository --> + <release.repository>${nuiton.central.release.repository}</release.repository> + <plexusMailSender.version>1.0-alpha-2</plexusMailSender.version> <javadoc.version>2.7</javadoc.version> Added: trunk/src/main/java/org/nuiton/helper/plugin/CheckCentralSafePlugin.java =================================================================== --- trunk/src/main/java/org/nuiton/helper/plugin/CheckCentralSafePlugin.java (rev 0) +++ trunk/src/main/java/org/nuiton/helper/plugin/CheckCentralSafePlugin.java 2010-06-18 22:28:10 UTC (rev 718) @@ -0,0 +1,533 @@ +/* + * #%L + * Maven helper plugin + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2009 - 2010 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +package org.nuiton.helper.plugin; + + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.ArtifactUtils; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.manager.WagonConfigurationException; +import org.apache.maven.artifact.manager.WagonManager; +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.artifact.repository.ArtifactRepositoryPolicy; +import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; +import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; +import org.apache.maven.artifact.repository.metadata.Metadata; +import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata; +import org.apache.maven.artifact.resolver.ArtifactNotFoundException; +import org.apache.maven.artifact.resolver.ArtifactResolutionException; +import org.apache.maven.artifact.resolver.ArtifactResolver; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; +import org.apache.maven.settings.Proxy; +import org.apache.maven.wagon.ConnectionException; +import org.apache.maven.wagon.TransferFailedException; +import org.apache.maven.wagon.UnsupportedProtocolException; +import org.apache.maven.wagon.Wagon; +import org.apache.maven.wagon.authentication.AuthenticationException; +import org.apache.maven.wagon.authentication.AuthenticationInfo; +import org.apache.maven.wagon.authorization.AuthorizationException; +import org.apache.maven.wagon.observers.Debug; +import org.apache.maven.wagon.proxy.ProxyInfo; +import org.apache.maven.wagon.repository.Repository; +import org.codehaus.plexus.util.StringUtils; +import org.nuiton.plugin.AbstractPlugin; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * Check all dependencies are in central repository. + * + * @author tchemit <chemit@codelutin.com> + * @goal check-central-safe + * @phase initialize + * @requiresProject true + * @requiresOnline true + * @requiresDependencyResolution runtime + * @since 1.2.5 + */ +public class CheckCentralSafePlugin extends AbstractPlugin { +//} implements LogEnabled { + + /** + * Project. + * + * @parameter default-value="${project}" + * @required + * @readonly + * @since 1.1.0 + */ + protected MavenProject project; + + /** + * Active proxy from settings. + * + * @parameter default-value="${settings.activeProxy}" + * @required + * @readonly + * @since 1.1.0 + */ + protected Proxy proxy; + + /** + * A flag to activate verbose mode. + * + * @parameter expression="${helper.verbose}" default-value="${maven.verbose}" + * @since 1.1.0 + */ + protected boolean verbose; + + /** + * A flag to fail if project is not central safe. + * + * @parameter expression="${helper.failIfNotSafe}" default-value="false" + * @since 1.1.0 + */ + protected boolean failIfNotSafe; + + /** + * A flag to execute only once the mojo. + * <p/> + * <b>Note:</b> By default, value is {@code true} since it is not necessary + * to inject twice secrets in session. + * + * @parameter expression="${helper.runOnce}" default-value="true" + * @since 1.1.0 + */ + protected boolean runOnce; + + /** + * Local Repository. + * + * @parameter expression="${localRepository}" + * @required + * @readonly + * @since 1.0.0 + */ + protected ArtifactRepository localRepository; + + /** + * @component + * @readonly + */ + protected ArtifactRepositoryFactory artifactRepositoryFactory; + + /** + * Artifact Factory component. + * + * @component + * @readonly + */ + protected ArtifactFactory factory; + + /** + * @component + * @readonly + */ + protected ArtifactResolver resolver; + + /** + * @component + * @readonly + */ + protected WagonManager wagonManager; + + /** + * Authorized Remote Repository. + * + * @since 1.0.0 + */ + protected List<ArtifactRepository> remoteRepositories; + + /** + * Extra Remote Repository urls to authorized separated by comma. + * + * @parameter expression="${extraRepositories}" + * @since 1.0.0 + */ + protected String extraRepositories; + + /** + * Dependencies of the project. + * + * @parameter expression="${project.artifacts}" + * @required + * @readonly + * @since 1.1.0 + */ + protected Set artifacts; + + @Override + public boolean checkSkip() { + if (runOnce) { + + // compute the unique key refering to parameters of plugin + + StringBuilder buffer = new StringBuilder("check-central-safe##"); + buffer.append(project.getArtifactId()); + + // check if plugin was already done. + + String key = buffer.toString(); + + if (verbose) { + getLog().info("check if already done for key : " + key); + } + Object value = project.getProperties().get(key); + if (value != null) { + // ok was already done + getLog().info("Goal was already executed, will skip goal."); + return false; + } + long timestamp = System.nanoTime(); + project.getProperties().put(key, timestamp + ""); + if (verbose) { + getLog().info("Adding cache key " + key + + " with timestamp " + timestamp); + } + } + return true; + } + + @Override + public void init() throws Exception { + + Log log = getLog(); + + if (log.isDebugEnabled()) { + + // always be verbose in debug mode + setVerbose(true); + } + + remoteRepositories = new ArrayList<ArtifactRepository>(); + + ArtifactRepositoryLayout repositoryLayout = new DefaultRepositoryLayout(); + ArtifactRepositoryPolicy always = new ArtifactRepositoryPolicy( + true, + ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, + ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN); + + ArtifactRepository remoteRepo; + + remoteRepo = artifactRepositoryFactory.createArtifactRepository( + "central", + "http://repo1.maven.org/maven2/", + repositoryLayout, + always, + always); + + log.info("Will use " + remoteRepo); + remoteRepositories.add(remoteRepo); + + if (!StringUtils.isEmpty(extraRepositories)) { + for (String url : extraRepositories.split(",")) { + url = url.trim(); + remoteRepo = artifactRepositoryFactory.createArtifactRepository( + url, + url, + repositoryLayout, + always, + always); + + log.info("Will use " + remoteRepo); + remoteRepositories.add(remoteRepo); + } + } + + for (Iterator<Artifact> iterator = artifacts.iterator(); iterator.hasNext();) { + Artifact artifact = iterator.next(); + + if (project.getArtifactId().equals(artifact.getArtifactId()) && + project.getGroupId().equals(artifact.getGroupId()) && + project.getVersion().equals(artifact.getVersion())) { + + if (log.isDebugEnabled()) { + log.debug("Skip artifact of the project : " + artifact); + } + iterator.remove(); + continue; + } + + // let says the artifact is NOT resolved + artifact.setResolved(false); + } + + if (isVerbose()) { + log.info("Detected artifacts : "); + for (Object artifact : artifacts) { + log.info(" - " + artifact); + + } + } + } + + @Override + protected void doAction() throws Exception { + + Log log = getLog(); + + checkDependenciesOnCentral(); + + boolean safe = artifacts.isEmpty(); + + if (safe) { + log.info("All dependencies are central safe."); + return; + } + + log.warn("There is " + artifacts.size() + " none central safe dependencie(s) :"); + for (Object artifact : artifacts) { + log.warn(" - " + artifact); + } + if (failIfNotSafe) { + throw new MojoFailureException("There is still some none central safe artifacts"); + } + } + + protected void checkDependenciesOnCentral() throws Exception { + + Log log = getLog(); + + for (ArtifactRepository repository : remoteRepositories) { + + Wagon wagon = getWagon(repository); + try { + if (verbose) { + log.info("Will use repository " + repository); + } + + for (Iterator<Artifact> itr = artifacts.iterator(); itr.hasNext();) { + Artifact artifact = itr.next(); + + if (verbose) { + log.info("check artifact : " + artifact); + } + + boolean resolved = + dependencyExistsInRepo(wagon, repository, artifact); + + if (resolved) { + artifact.setResolved(true); + + itr.remove(); + log.info(artifact + " resolved by " + repository); + } else { + if (log.isDebugEnabled()) { + log.debug("artifact was not resolved by " + repository); + } + } + } + } finally { + if (log.isDebugEnabled()) { + log.debug("Will disconnect wagon : " + wagon); + } + disconnect(wagon); + } + } + } + + @Override + public MavenProject getProject() { + return project; + } + + @Override + public void setProject(MavenProject project) { + this.project = project; + } + + @Override + public boolean isVerbose() { + return verbose; + } + + @Override + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + public void setRunOnce(boolean runOnce) { + this.runOnce = runOnce; + } + + protected Wagon getWagon(ArtifactRepository repo) throws WagonConfigurationException, UnsupportedProtocolException, AuthenticationException, ConnectionException { + + Repository repository = new Repository(repo.getId(), repo.getUrl()); + Wagon wagon = wagonManager.getWagon(repository); + + wagon.setTimeout(1000); + + if (getLog().isDebugEnabled()) { + Debug debug = new Debug(); + + wagon.addSessionListener(debug); + wagon.addTransferListener(debug); + } + + // FIXME when upgrading to maven 3.x : this must be changed. + AuthenticationInfo auth = wagonManager.getAuthenticationInfo(repo.getId()); + + ProxyInfo proxyInfo = getProxyInfo(); + if (proxyInfo != null) { + wagon.connect(repository, auth, proxyInfo); + } else { + wagon.connect(repository, auth); + } + + return wagon; + } + + + public boolean dependencyExistsInRepo(Wagon wagon, ArtifactRepository repo, Artifact artifact) { + + Log log = getLog(); + + try { + + return wagon.resourceExists(StringUtils.replace(getDependencyUrlFromRepository(artifact, repo), repo.getUrl(), "")); + } catch (TransferFailedException e) { + if (log.isDebugEnabled()) { + log.error("Unable to determine if resource " + artifact + " exists in " + repo.getUrl(), e); + } else { + log.error("Unable to determine if resource " + artifact + " exists in " + repo.getUrl()); + } + return false; + } catch (AuthorizationException e) { + if (log.isDebugEnabled()) { + log.error("Unable to connect to: " + repo.getUrl(), e); + } else { + log.error("Unable to connect to: " + repo.getUrl()); + } + return false; + } catch (AbstractMethodError e) { + log.error("Wagon " + wagon.getClass().getName() + " does not support the resourceExists method"); + return false; + } finally { + disconnect(wagon); + } + } + + protected void disconnect(Wagon wagon) { + try { + wagon.disconnect(); + } + catch (ConnectionException e) { + Log log = getLog(); + if (log.isDebugEnabled()) { + log.error("Error disconnecting wagon - ignored", e); + } else { + log.error("Error disconnecting wagon - ignored"); + } + } + } + + /** + * @param artifact not null + * @param repo not null + * @return the artifact url in the given repo for the given artifact. If it is a snapshot artifact, the version + * will be the timestamp and the build number from the metadata. Could return null if the repo is blacklisted. + */ + public String getDependencyUrlFromRepository(Artifact artifact, ArtifactRepository repo) { + if (repo.isBlacklisted()) { + return null; + } + + Log log = getLog(); + Artifact copyArtifact = ArtifactUtils.copyArtifact(artifact); + // Try to get the last artifact repo name depending the snapshot version + if (!artifact.isSnapshot() || !repo.getSnapshots().isEnabled()) { + return repo.getUrl() + "/" + repo.pathOf(copyArtifact); + } + + if (artifact.getBaseVersion().equals(artifact.getVersion())) { + // Try to resolve it if not already done + if (artifact.getMetadataList() == null || artifact.getMetadataList().isEmpty()) { + try { + resolver.resolve(artifact, remoteRepositories, localRepository); + } catch (ArtifactResolutionException e) { + log.error("Artifact: " + artifact.getId() + " could not be resolved."); + } catch (ArtifactNotFoundException e) { + log.error("Artifact: " + artifact.getId() + " was not found."); + } + } + + for (Object o : artifact.getMetadataList()) { + + ArtifactMetadata m = (ArtifactMetadata) o; + + if (m instanceof SnapshotArtifactRepositoryMetadata) { + SnapshotArtifactRepositoryMetadata snapshotMetadata = (SnapshotArtifactRepositoryMetadata) m; + + Metadata metadata = snapshotMetadata.getMetadata(); + if (metadata.getVersioning() == null || metadata.getVersioning().getSnapshot() == null + || metadata.getVersioning().getSnapshot().isLocalCopy() + || metadata.getVersioning().getSnapshot().getTimestamp() == null) { + continue; + } + + // create the version according SnapshotTransformation + String version = + StringUtils.replace(copyArtifact.getVersion(), Artifact.SNAPSHOT_VERSION, + metadata.getVersioning().getSnapshot().getTimestamp()) + + "-" + metadata.getVersioning().getSnapshot().getBuildNumber(); + copyArtifact.setVersion(version); + } + } + } + + return repo.getUrl() + "/" + repo.pathOf(copyArtifact); + } + + /** + * Convenience method to map a <code>Proxy</code> object from the user system settings to a <code>ProxyInfo</code> + * object. + * + * @return a proxyInfo object instanced or null if no active proxy is define in the settings.xml + */ + private ProxyInfo getProxyInfo() { + ProxyInfo proxyInfo = null; + if (proxy != null && !StringUtils.isEmpty(proxy.getHost())) { + + proxyInfo = new ProxyInfo(); + proxyInfo.setHost(proxy.getHost()); + proxyInfo.setType(proxy.getProtocol()); + proxyInfo.setPort(proxy.getPort()); + proxyInfo.setNonProxyHosts(proxy.getNonProxyHosts()); + proxyInfo.setUserName(proxy.getUsername()); + proxyInfo.setPassword(proxy.getPassword()); + } + + return proxyInfo; + } + +} \ No newline at end of file Property changes on: trunk/src/main/java/org/nuiton/helper/plugin/CheckCentralSafePlugin.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL
participants (1)
-
tchemit@users.nuiton.org