| package org.apache.maven.plugins.site.deploy; |
| |
| /* |
| * 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.artifact.manager.WagonManager; |
| import org.apache.maven.doxia.site.decoration.inheritance.URIPathDescriptor; |
| import org.apache.maven.execution.MavenExecutionRequest; |
| import org.apache.maven.execution.MavenSession; |
| import org.apache.maven.model.DistributionManagement; |
| import org.apache.maven.model.Site; |
| import org.apache.maven.plugin.MojoExecutionException; |
| import org.apache.maven.plugin.logging.Log; |
| import org.apache.maven.plugins.annotations.Component; |
| import org.apache.maven.plugins.annotations.Parameter; |
| import org.apache.maven.plugins.site.AbstractSiteMojo; |
| import org.apache.maven.project.MavenProject; |
| import org.apache.maven.settings.Proxy; |
| import org.apache.maven.settings.Server; |
| import org.apache.maven.settings.Settings; |
| import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest; |
| import org.apache.maven.settings.crypto.SettingsDecrypter; |
| import org.apache.maven.settings.crypto.SettingsDecryptionResult; |
| import org.apache.maven.wagon.CommandExecutionException; |
| import org.apache.maven.wagon.CommandExecutor; |
| import org.apache.maven.wagon.ConnectionException; |
| import org.apache.maven.wagon.ResourceDoesNotExistException; |
| 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.PlexusConstants; |
| import org.codehaus.plexus.PlexusContainer; |
| import org.codehaus.plexus.component.configurator.ComponentConfigurationException; |
| import org.codehaus.plexus.component.configurator.ComponentConfigurator; |
| import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException; |
| import org.codehaus.plexus.component.repository.exception.ComponentLookupException; |
| import org.codehaus.plexus.configuration.PlexusConfiguration; |
| import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; |
| import org.codehaus.plexus.context.Context; |
| import org.codehaus.plexus.context.ContextException; |
| import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable; |
| import org.codehaus.plexus.util.StringUtils; |
| import org.codehaus.plexus.util.xml.Xpp3Dom; |
| |
| import java.io.File; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Set; |
| |
| /** |
| * Abstract base class for deploy mojos. |
| * Since 2.3 this includes {@link SiteStageMojo} and {@link SiteStageDeployMojo}. |
| * |
| * @author ltheussl |
| * @since 2.3 |
| */ |
| public abstract class AbstractDeployMojo |
| extends AbstractSiteMojo |
| implements Contextualizable |
| { |
| /** |
| * Directory containing the generated project sites and report distributions. |
| * |
| * @since 2.3 |
| */ |
| @Parameter( alias = "outputDirectory", defaultValue = "${project.reporting.outputDirectory}", required = true ) |
| private File inputDirectory; |
| |
| /** |
| * Whether to run the "chmod" command on the remote site after the deploy. |
| * Defaults to "true". |
| * |
| * @since 2.1 |
| */ |
| @Parameter( property = "maven.site.chmod", defaultValue = "true" ) |
| private boolean chmod; |
| |
| /** |
| * The mode used by the "chmod" command. Only used if chmod = true. |
| * Defaults to "g+w,a+rX". |
| * |
| * @since 2.1 |
| */ |
| @Parameter( property = "maven.site.chmod.mode", defaultValue = "g+w,a+rX" ) |
| private String chmodMode; |
| |
| /** |
| * The options used by the "chmod" command. Only used if chmod = true. |
| * Defaults to "-Rf". |
| * |
| * @since 2.1 |
| */ |
| @Parameter( property = "maven.site.chmod.options", defaultValue = "-Rf" ) |
| private String chmodOptions; |
| |
| /** |
| * Set this to 'true' to skip site deployment. |
| * |
| * @since 3.0 |
| */ |
| @Parameter( property = "maven.site.deploy.skip", defaultValue = "false" ) |
| private boolean skipDeploy; |
| |
| /** |
| */ |
| @Component |
| private WagonManager wagonManager; // maven-compat |
| |
| /** |
| * The current user system settings for use in Maven. |
| */ |
| @Parameter( defaultValue = "${settings}", readonly = true ) |
| private Settings settings; |
| |
| /** |
| * @since 3.0-beta-2 |
| */ |
| @Parameter( defaultValue = "${session}", readonly = true ) |
| protected MavenSession mavenSession; |
| |
| private String topDistributionManagementSiteUrl; |
| |
| private Site deploySite; |
| |
| private PlexusContainer container; |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void execute() |
| throws MojoExecutionException |
| { |
| if ( skip && isDeploy() ) |
| { |
| getLog().info( "maven.site.skip = true: Skipping site deployment" ); |
| return; |
| } |
| |
| if ( skipDeploy && isDeploy() ) |
| { |
| getLog().info( "maven.site.deploy.skip = true: Skipping site deployment" ); |
| return; |
| } |
| |
| deployTo( new Repository( getDeploySite().getId(), getDeploySite().getUrl() ) ); |
| } |
| |
| /** |
| * Make sure the given URL ends with a slash. |
| * |
| * @param url a String |
| * @return if url already ends with '/' it is returned unchanged. |
| * Otherwise a '/' character is appended. |
| */ |
| protected static String appendSlash( final String url ) |
| { |
| if ( url.endsWith( "/" ) ) |
| { |
| return url; |
| } |
| else |
| { |
| return url + "/"; |
| } |
| } |
| |
| |
| /** |
| * Detect if the mojo is staging or deploying. |
| * |
| * @return <code>true</code> if the mojo is for deploy and not staging (local or deploy) |
| */ |
| protected abstract boolean isDeploy(); |
| |
| /** |
| * Get the top distribution management site url, used for module relative path calculations. |
| * This should be a top-level URL, ie above modules and locale sub-directories. Each deploy mojo |
| * can tweak algorithm to determine this top site by implementing determineTopDistributionManagementSiteUrl(). |
| * |
| * @return the site for deployment |
| * @throws MojoExecutionException in case of issue |
| * @see #determineTopDistributionManagementSiteUrl() |
| */ |
| protected String getTopDistributionManagementSiteUrl() |
| throws MojoExecutionException |
| { |
| if ( topDistributionManagementSiteUrl == null ) |
| { |
| topDistributionManagementSiteUrl = determineTopDistributionManagementSiteUrl(); |
| |
| if ( !isDeploy() ) |
| { |
| getLog().debug( "distributionManagement.site.url relative path: " + getDeployModuleDirectory() ); |
| } |
| } |
| return topDistributionManagementSiteUrl; |
| } |
| |
| protected abstract String determineTopDistributionManagementSiteUrl() |
| throws MojoExecutionException; |
| |
| /** |
| * Get the site used for deployment, with its id to look up credential settings and the target URL for the deploy. |
| * This should be a top-level URL, ie above modules and locale sub-directories. Each deploy mojo |
| * can tweak algorithm to determine this deploy site by implementing determineDeploySite(). |
| * |
| * @return the site for deployment |
| * @throws MojoExecutionException in case of issue |
| * @see #determineDeploySite() |
| */ |
| protected Site getDeploySite() |
| throws MojoExecutionException |
| { |
| if ( deploySite == null ) |
| { |
| deploySite = determineDeploySite(); |
| } |
| return deploySite; |
| } |
| |
| protected abstract Site determineDeploySite() |
| throws MojoExecutionException; |
| |
| /** |
| * Find the relative path between the distribution URLs of the top site and the current project. |
| * |
| * @return the relative path or "./" if the two URLs are the same. |
| * @throws MojoExecutionException in case of issue |
| */ |
| protected String getDeployModuleDirectory() |
| throws MojoExecutionException |
| { |
| String to = getSite( project ).getUrl(); |
| |
| getLog().debug( "Mapping url source calculation: " ); |
| String from = getTopDistributionManagementSiteUrl(); |
| |
| String relative = siteTool.getRelativePath( to, from ); |
| |
| // SiteTool.getRelativePath() uses File.separatorChar, |
| // so we need to convert '\' to '/' in order for the URL to be valid for Windows users |
| relative = relative.replace( '\\', '/' ); |
| |
| return ( "".equals( relative ) ) ? "./" : relative; |
| } |
| |
| /** |
| * Use wagon to deploy the generated site to a given repository. |
| * |
| * @param repository the repository to deploy to. |
| * This needs to contain a valid, non-null {@link Repository#getId() id} |
| * to look up credentials for the deploy, and a valid, non-null |
| * {@link Repository#getUrl() scm url} to deploy to. |
| * @throws MojoExecutionException if the deploy fails. |
| */ |
| private void deployTo( final Repository repository ) |
| throws MojoExecutionException |
| { |
| if ( !inputDirectory.exists() ) |
| { |
| throw new MojoExecutionException( "The site does not exist, please run site:site first" ); |
| } |
| |
| if ( getLog().isDebugEnabled() ) |
| { |
| getLog().debug( "Deploying to '" + repository.getUrl() + "',\n Using credentials from server id '" |
| + repository.getId() + "'" ); |
| } |
| |
| deploy( inputDirectory, repository ); |
| } |
| |
| private void deploy( final File directory, final Repository repository ) |
| throws MojoExecutionException |
| { |
| // TODO: work on moving this into the deployer like the other deploy methods |
| final Wagon wagon = getWagon( repository, wagonManager ); |
| |
| try |
| { |
| configureWagon( wagon, repository.getId(), settings, container, getLog() ); |
| |
| SettingsDecrypter settingsDecrypter = container.lookup( SettingsDecrypter.class ); |
| |
| ProxyInfo proxyInfo = getProxy( repository, settingsDecrypter ); |
| |
| push( directory, repository, wagon, proxyInfo, getLocales(), getDeployModuleDirectory() ); |
| |
| if ( chmod ) |
| { |
| chmod( wagon, repository, chmodOptions, chmodMode ); |
| } |
| } |
| catch ( ComponentLookupException cle ) |
| { |
| throw new MojoExecutionException( "Unable to lookup SettingsDecrypter: " + cle.getMessage(), cle ); |
| } |
| catch ( TransferFailedException e ) |
| { |
| throw new MojoExecutionException( "Unable to configure Wagon: '" + repository.getProtocol() + "'", e ); |
| } |
| finally |
| { |
| try |
| { |
| wagon.disconnect(); |
| } |
| catch ( ConnectionException e ) |
| { |
| getLog().error( "Error disconnecting wagon - ignored", e ); |
| } |
| } |
| } |
| |
| private Wagon getWagon( final Repository repository, final WagonManager manager ) |
| throws MojoExecutionException |
| { |
| final Wagon wagon; |
| |
| try |
| { |
| wagon = manager.getWagon( repository ); |
| } |
| catch ( UnsupportedProtocolException e ) |
| { |
| String shortMessage = "Unsupported protocol: '" + repository.getProtocol() + "' for site deployment to " |
| + "distributionManagement.site.url=" + repository.getUrl() + "."; |
| String longMessage = |
| "\n" + shortMessage + "\n" + "Currently supported protocols are: " + getSupportedProtocols() + ".\n" |
| + " Protocols may be added through wagon providers.\n" + " For more information, see " |
| + "https://maven.apache.org/plugins/maven-site-plugin/examples/adding-deploy-protocol.html"; |
| |
| getLog().error( longMessage ); |
| |
| throw new MojoExecutionException( shortMessage ); |
| } |
| catch ( TransferFailedException e ) |
| { |
| throw new MojoExecutionException( "Unable to configure Wagon: '" + repository.getProtocol() + "'", e ); |
| } |
| |
| if ( !wagon.supportsDirectoryCopy() ) |
| { |
| throw new MojoExecutionException( |
| "Wagon protocol '" + repository.getProtocol() + "' doesn't support directory copying" ); |
| } |
| |
| return wagon; |
| } |
| |
| private String getSupportedProtocols() |
| { |
| try |
| { |
| Set<String> protocols = container.lookupMap( Wagon.class ).keySet(); |
| |
| return StringUtils.join( protocols.iterator(), ", " ); |
| } |
| catch ( ComponentLookupException e ) |
| { |
| // in the unexpected case there is a problem when instantiating a wagon provider |
| getLog().error( e ); |
| } |
| return ""; |
| } |
| |
| private void push( final File inputDirectory, final Repository repository, final Wagon wagon, |
| final ProxyInfo proxyInfo, final List<Locale> localesList, final String relativeDir ) |
| throws MojoExecutionException |
| { |
| AuthenticationInfo authenticationInfo = wagonManager.getAuthenticationInfo( repository.getId() ); |
| getLog().debug( "authenticationInfo with id '" + repository.getId() + "': " |
| + ( ( authenticationInfo == null ) ? "-" : authenticationInfo.getUserName() ) ); |
| |
| try |
| { |
| if ( getLog().isDebugEnabled() ) |
| { |
| Debug debug = new Debug(); |
| |
| wagon.addSessionListener( debug ); |
| |
| wagon.addTransferListener( debug ); |
| } |
| |
| if ( proxyInfo != null ) |
| { |
| getLog().debug( "connect with proxyInfo" ); |
| wagon.connect( repository, authenticationInfo, proxyInfo ); |
| } |
| else if ( proxyInfo == null && authenticationInfo != null ) |
| { |
| getLog().debug( "connect with authenticationInfo and without proxyInfo" ); |
| wagon.connect( repository, authenticationInfo ); |
| } |
| else |
| { |
| getLog().debug( "connect without authenticationInfo and without proxyInfo" ); |
| wagon.connect( repository ); |
| } |
| |
| getLog().info( "Pushing " + inputDirectory ); |
| |
| // Default is first in the list |
| final String defaultLocale = localesList.get( 0 ).getLanguage(); |
| |
| for ( Locale locale : localesList ) |
| { |
| if ( locale.getLanguage().equals( defaultLocale ) ) |
| { |
| // TODO: this also uploads the non-default locales, |
| // is there a way to exclude directories in wagon? |
| getLog().info( " >>> to " + appendSlash( repository.getUrl() ) + relativeDir ); |
| |
| wagon.putDirectory( inputDirectory, relativeDir ); |
| } |
| else |
| { |
| getLog().info( " >>> to " + appendSlash( repository.getUrl() ) + locale.getLanguage() + "/" |
| + relativeDir ); |
| |
| wagon.putDirectory( new File( inputDirectory, locale.getLanguage() ), |
| locale.getLanguage() + "/" + relativeDir ); |
| } |
| } |
| } |
| catch ( ResourceDoesNotExistException | TransferFailedException | AuthorizationException | ConnectionException |
| | AuthenticationException e ) |
| { |
| throw new MojoExecutionException( "Error uploading site", e ); |
| } |
| } |
| |
| private static void chmod( final Wagon wagon, final Repository repository, final String chmodOptions, |
| final String chmodMode ) |
| throws MojoExecutionException |
| { |
| try |
| { |
| if ( wagon instanceof CommandExecutor ) |
| { |
| CommandExecutor exec = (CommandExecutor) wagon; |
| exec.executeCommand( "chmod " + chmodOptions + " " + chmodMode + " " + repository.getBasedir() ); |
| } |
| // else ? silently ignore, FileWagon is not a CommandExecutor! |
| } |
| catch ( CommandExecutionException e ) |
| { |
| throw new MojoExecutionException( "Error uploading site", e ); |
| } |
| } |
| |
| /** |
| * Get proxy information. |
| * <p> |
| * Get the <code>ProxyInfo</code> of the proxy associated with the <code>host</code> |
| * and the <code>protocol</code> of the given <code>repository</code>. |
| * </p> |
| * <p> |
| * Extract from <a href="https://docs.oracle.com/javase/1.5.0/docs/guide/net/properties.html"> |
| * J2SE Doc : Networking Properties - nonProxyHosts</a> : "The value can be a list of hosts, |
| * each separated by a |, and in addition a wildcard character (*) can be used for matching" |
| * </p> |
| * <p> |
| * Defensively support comma (",") and semi colon (";") in addition to pipe ("|") as separator. |
| * </p> |
| * |
| * @param repository the Repository to extract the ProxyInfo from |
| * @param wagonManager the WagonManager used to connect to the Repository |
| * @return a ProxyInfo object instantiated or <code>null</code> if no matching proxy is found |
| */ |
| public static ProxyInfo getProxyInfo( Repository repository, WagonManager wagonManager ) |
| { |
| ProxyInfo proxyInfo = wagonManager.getProxy( repository.getProtocol() ); |
| |
| if ( proxyInfo == null ) |
| { |
| return null; |
| } |
| |
| String host = repository.getHost(); |
| String nonProxyHostsAsString = proxyInfo.getNonProxyHosts(); |
| for ( String nonProxyHost : StringUtils.split( nonProxyHostsAsString, ",;|" ) ) |
| { |
| if ( StringUtils.contains( nonProxyHost, "*" ) ) |
| { |
| // Handle wildcard at the end, beginning or middle of the nonProxyHost |
| final int pos = nonProxyHost.indexOf( '*' ); |
| String nonProxyHostPrefix = nonProxyHost.substring( 0, pos ); |
| String nonProxyHostSuffix = nonProxyHost.substring( pos + 1 ); |
| // prefix* |
| if ( StringUtils.isNotEmpty( nonProxyHostPrefix ) && host.startsWith( nonProxyHostPrefix ) |
| && StringUtils.isEmpty( nonProxyHostSuffix ) ) |
| { |
| return null; |
| } |
| // *suffix |
| if ( StringUtils.isEmpty( nonProxyHostPrefix ) && StringUtils.isNotEmpty( nonProxyHostSuffix ) |
| && host.endsWith( nonProxyHostSuffix ) ) |
| { |
| return null; |
| } |
| // prefix*suffix |
| if ( StringUtils.isNotEmpty( nonProxyHostPrefix ) && host.startsWith( nonProxyHostPrefix ) |
| && StringUtils.isNotEmpty( nonProxyHostSuffix ) && host.endsWith( nonProxyHostSuffix ) ) |
| { |
| return null; |
| } |
| } |
| else if ( host.equals( nonProxyHost ) ) |
| { |
| return null; |
| } |
| } |
| return proxyInfo; |
| } |
| |
| /** |
| * Get proxy information. |
| * |
| * @param repository the Repository to extract the ProxyInfo from |
| * @param settingsDecrypter settings password decrypter |
| * @return a ProxyInfo object instantiated or <code>null</code> if no matching proxy is found. |
| */ |
| private ProxyInfo getProxy( Repository repository, SettingsDecrypter settingsDecrypter ) |
| { |
| String protocol = repository.getProtocol(); |
| String url = repository.getUrl(); |
| |
| getLog().debug( "repository protocol " + protocol ); |
| |
| String originalProtocol = protocol; |
| // olamy: hackish here protocol (wagon hint in fact !) is dav |
| // but the real protocol (transport layer) is http(s) |
| // and it's the one use in wagon to find the proxy arghhh |
| // so we will check both |
| if ( StringUtils.equalsIgnoreCase( "dav", protocol ) && url.startsWith( "dav:" ) ) |
| { |
| url = url.substring( 4 ); |
| if ( url.startsWith( "http" ) ) |
| { |
| try |
| { |
| URL urlSite = new URL( url ); |
| protocol = urlSite.getProtocol(); |
| getLog().debug( "found dav protocol so transform to real transport protocol " + protocol ); |
| } |
| catch ( MalformedURLException e ) |
| { |
| getLog().warn( "fail to build URL with " + url ); |
| } |
| } |
| } |
| else |
| { |
| getLog().debug( "getProxy 'protocol': " + protocol ); |
| } |
| |
| if ( mavenSession != null && protocol != null ) |
| { |
| MavenExecutionRequest request = mavenSession.getRequest(); |
| |
| if ( request != null ) |
| { |
| List<Proxy> proxies = request.getProxies(); |
| |
| if ( proxies != null ) |
| { |
| for ( Proxy proxy : proxies ) |
| { |
| if ( proxy.isActive() && ( protocol.equalsIgnoreCase( proxy.getProtocol() ) |
| || originalProtocol.equalsIgnoreCase( proxy.getProtocol() ) ) ) |
| { |
| SettingsDecryptionResult result = |
| settingsDecrypter.decrypt( new DefaultSettingsDecryptionRequest( proxy ) ); |
| proxy = result.getProxy(); |
| |
| ProxyInfo proxyInfo = new ProxyInfo(); |
| proxyInfo.setHost( proxy.getHost() ); |
| // so hackish for wagon the protocol is https for site dav: |
| // dav:https://dav.codehaus.org/mojo/ |
| proxyInfo.setType( protocol ); //proxy.getProtocol() ); |
| proxyInfo.setPort( proxy.getPort() ); |
| proxyInfo.setNonProxyHosts( proxy.getNonProxyHosts() ); |
| proxyInfo.setUserName( proxy.getUsername() ); |
| proxyInfo.setPassword( proxy.getPassword() ); |
| |
| getLog().debug( "found proxyInfo " |
| + ( "host:port " + proxyInfo.getHost() + ":" + proxyInfo.getPort() |
| + ", " + proxyInfo.getUserName() ) ); |
| |
| return proxyInfo; |
| } |
| } |
| } |
| } |
| } |
| getLog().debug( "getProxy 'protocol': " + protocol + " no ProxyInfo found" ); |
| return null; |
| } |
| |
| /** |
| * Configure the Wagon with the information from serverConfigurationMap ( which comes from settings.xml ) |
| * |
| * @todo Remove when {@link WagonManager#getWagon(Repository) is available}. It's available in Maven 2.0.5. |
| */ |
| private static void configureWagon( Wagon wagon, String repositoryId, Settings settings, PlexusContainer container, |
| Log log ) |
| throws TransferFailedException |
| { |
| log.debug( " configureWagon " ); |
| |
| // MSITE-25: Make sure that the server settings are inserted |
| for ( Server server : settings.getServers() ) |
| { |
| String id = server.getId(); |
| |
| log.debug( "configureWagon server " + id ); |
| |
| if ( id != null && id.equals( repositoryId ) && ( server.getConfiguration() != null ) ) |
| { |
| final PlexusConfiguration plexusConf = |
| new XmlPlexusConfiguration( (Xpp3Dom) server.getConfiguration() ); |
| |
| ComponentConfigurator componentConfigurator = null; |
| try |
| { |
| componentConfigurator = |
| (ComponentConfigurator) container.lookup( ComponentConfigurator.ROLE, "basic" ); |
| componentConfigurator.configureComponent( wagon, plexusConf, container.getContainerRealm() ); |
| } |
| catch ( final ComponentLookupException e ) |
| { |
| throw new TransferFailedException( |
| "While configuring wagon for \'" + repositoryId + "\': Unable to lookup wagon configurator." |
| + " Wagon configuration cannot be applied.", e ); |
| } |
| catch ( ComponentConfigurationException e ) |
| { |
| throw new TransferFailedException( "While configuring wagon for \'" + repositoryId |
| + "\': Unable to apply wagon configuration.", e ); |
| } |
| finally |
| { |
| if ( componentConfigurator != null ) |
| { |
| try |
| { |
| container.release( componentConfigurator ); |
| } |
| catch ( ComponentLifecycleException e ) |
| { |
| log.error( "Problem releasing configurator - ignoring: " + e.getMessage() ); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void contextualize( Context context ) |
| throws ContextException |
| { |
| container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY ); |
| } |
| |
| /** |
| * Extract the distributionManagement site from the given MavenProject. |
| * |
| * @param project the MavenProject. Not null. |
| * @return the project site. Not null. |
| * Also site.getUrl() and site.getId() are guaranteed to be not null. |
| * @throws MojoExecutionException if any of the site info is missing. |
| */ |
| protected static Site getSite( final MavenProject project ) |
| throws MojoExecutionException |
| { |
| final DistributionManagement distributionManagement = project.getDistributionManagement(); |
| |
| if ( distributionManagement == null ) |
| { |
| throw new MojoExecutionException( "Missing distribution management in project " + getFullName( project ) ); |
| } |
| |
| final Site site = distributionManagement.getSite(); |
| |
| if ( site == null ) |
| { |
| throw new MojoExecutionException( "Missing site information in the distribution management of the project " |
| + getFullName( project ) ); |
| } |
| |
| if ( site.getUrl() == null || site.getId() == null ) |
| { |
| throw new MojoExecutionException( "Missing site data: specify url and id for project " |
| + getFullName( project ) ); |
| } |
| |
| return site; |
| } |
| |
| private static String getFullName( MavenProject project ) |
| { |
| return project.getName() + " (" + project.getGroupId() + ':' + project.getArtifactId() + ':' |
| + project.getVersion() + ')'; |
| } |
| |
| /** |
| * Extract the distributionManagement site of the top level parent of the given MavenProject. |
| * This climbs up the project hierarchy and returns the site of the last project |
| * for which {@link #getSite(org.apache.maven.project.MavenProject)} returns a site that resides in the |
| * same site. Notice that it doesn't take into account if the parent is in the reactor or not. |
| * |
| * @param project the MavenProject. Not <code>null</code>. |
| * @return the top level site. Not <code>null</code>. |
| * Also site.getUrl() and site.getId() are guaranteed to be not <code>null</code>. |
| * @throws MojoExecutionException if no site info is found in the tree. |
| * @see URIPathDescriptor#sameSite(java.net.URI) |
| */ |
| protected MavenProject getTopLevelProject( MavenProject project ) |
| throws MojoExecutionException |
| { |
| Site site = getSite( project ); |
| |
| MavenProject parent = project; |
| |
| while ( parent.getParent() != null ) |
| { |
| MavenProject oldProject = parent; |
| // MSITE-585, MNG-1943 |
| parent = siteTool.getParentProject( parent, reactorProjects, localRepository ); |
| |
| Site oldSite = site; |
| |
| try |
| { |
| site = getSite( parent ); |
| } |
| catch ( MojoExecutionException e ) |
| { |
| return oldProject; |
| } |
| |
| // MSITE-600 |
| URIPathDescriptor siteURI = new URIPathDescriptor( URIEncoder.encodeURI( site.getUrl() ), "" ); |
| URIPathDescriptor oldSiteURI = new URIPathDescriptor( URIEncoder.encodeURI( oldSite.getUrl() ), "" ); |
| |
| if ( !siteURI.sameSite( oldSiteURI.getBaseURI() ) ) |
| { |
| return oldProject; |
| } |
| } |
| |
| return parent; |
| } |
| |
| private static class URIEncoder |
| { |
| private static final String MARK = "-_.!~*'()"; |
| private static final String RESERVED = ";/?:@&=+$,"; |
| |
| private static String encodeURI( final String uriString ) |
| { |
| final char[] chars = uriString.toCharArray(); |
| final StringBuilder uri = new StringBuilder( chars.length ); |
| |
| // MSITE-750: wagon dav: pseudo-protocol |
| if ( uriString.startsWith( "dav:http" ) ) |
| { |
| // transform dav:http to dav-http |
| chars[3] = '-'; |
| } |
| |
| for ( char c : chars ) |
| { |
| if ( ( c >= '0' && c <= '9' ) || ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) |
| || MARK.indexOf( c ) != -1 || RESERVED.indexOf( c ) != -1 ) |
| { |
| uri.append( c ); |
| } |
| else |
| { |
| uri.append( '%' ); |
| uri.append( Integer.toHexString( (int) c ) ); |
| } |
| } |
| return uri.toString(); |
| } |
| } |
| } |