001package org.apache.maven.repository.legacy.resolver.transform;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.text.DateFormat;
023import java.text.SimpleDateFormat;
024import java.util.Date;
025import java.util.TimeZone;
026
027import org.apache.maven.artifact.Artifact;
028import org.apache.maven.artifact.deployer.ArtifactDeploymentException;
029import org.apache.maven.artifact.repository.ArtifactRepository;
030import org.apache.maven.artifact.repository.RepositoryRequest;
031import org.apache.maven.artifact.repository.metadata.Metadata;
032import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
033import org.apache.maven.artifact.repository.metadata.RepositoryMetadataResolutionException;
034import org.apache.maven.artifact.repository.metadata.Snapshot;
035import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
036import org.apache.maven.artifact.repository.metadata.Versioning;
037import org.apache.maven.artifact.resolver.ArtifactResolutionException;
038import org.codehaus.plexus.component.annotations.Component;
039import org.codehaus.plexus.util.StringUtils;
040
041/**
042 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
043 * @author <a href="mailto:mmaczka@interia.pl">Michal Maczka</a>
044 */
045@Component( role = ArtifactTransformation.class, hint = "snapshot" )
046public class SnapshotTransformation
047    extends AbstractVersionTransformation
048{
049    private String deploymentTimestamp;
050
051    private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" );
052
053    private static final String UTC_TIMESTAMP_PATTERN = "yyyyMMdd.HHmmss";
054
055    public void transformForResolve( Artifact artifact, RepositoryRequest request )
056        throws ArtifactResolutionException
057    {
058        // Only select snapshots that are unresolved (eg 1.0-SNAPSHOT, not 1.0-20050607.123456)
059        if ( artifact.isSnapshot() && artifact.getBaseVersion().equals( artifact.getVersion() ) )
060        {
061            try
062            {
063                String version = resolveVersion( artifact, request );
064                artifact.updateVersion( version, request.getLocalRepository() );
065            }
066            catch ( RepositoryMetadataResolutionException e )
067            {
068                throw new ArtifactResolutionException( e.getMessage(), artifact, e );
069            }
070        }
071    }
072
073    public void transformForInstall( Artifact artifact, ArtifactRepository localRepository )
074    {
075        if ( artifact.isSnapshot() )
076        {
077            Snapshot snapshot = new Snapshot();
078            snapshot.setLocalCopy( true );
079            RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata( artifact, snapshot );
080
081            artifact.addMetadata( metadata );
082        }
083    }
084
085    public void transformForDeployment( Artifact artifact, ArtifactRepository remoteRepository,
086                                        ArtifactRepository localRepository )
087        throws ArtifactDeploymentException
088    {
089        if ( artifact.isSnapshot() )
090        {
091            Snapshot snapshot = new Snapshot();
092
093            snapshot.setTimestamp( getDeploymentTimestamp() );
094
095            // we update the build number anyway so that it doesn't get lost. It requires the timestamp to take effect
096            try
097            {
098                int buildNumber = resolveLatestSnapshotBuildNumber( artifact, localRepository, remoteRepository );
099
100                snapshot.setBuildNumber( buildNumber + 1 );
101            }
102            catch ( RepositoryMetadataResolutionException e )
103            {
104                throw new ArtifactDeploymentException( "Error retrieving previous build number for artifact '"
105                    + artifact.getDependencyConflictId() + "': " + e.getMessage(), e );
106            }
107
108            RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata( artifact, snapshot );
109
110            artifact.setResolvedVersion(
111                constructVersion( metadata.getMetadata().getVersioning(), artifact.getBaseVersion() ) );
112
113            artifact.addMetadata( metadata );
114        }
115    }
116
117    public String getDeploymentTimestamp()
118    {
119        if ( deploymentTimestamp == null )
120        {
121            deploymentTimestamp = getUtcDateFormatter().format( new Date() );
122        }
123        return deploymentTimestamp;
124    }
125
126    protected String constructVersion( Versioning versioning, String baseVersion )
127    {
128        String version = null;
129        Snapshot snapshot = versioning.getSnapshot();
130        if ( snapshot != null )
131        {
132            if ( snapshot.getTimestamp() != null && snapshot.getBuildNumber() > 0 )
133            {
134                String newVersion = snapshot.getTimestamp() + "-" + snapshot.getBuildNumber();
135                version = StringUtils.replace( baseVersion, Artifact.SNAPSHOT_VERSION, newVersion );
136            }
137            else
138            {
139                version = baseVersion;
140            }
141        }
142        return version;
143    }
144
145    private int resolveLatestSnapshotBuildNumber( Artifact artifact, ArtifactRepository localRepository,
146                                                  ArtifactRepository remoteRepository )
147        throws RepositoryMetadataResolutionException
148    {
149        RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata( artifact );
150
151        getLogger().info( "Retrieving previous build number from " + remoteRepository.getId() );
152        repositoryMetadataManager.resolveAlways( metadata, localRepository, remoteRepository );
153
154        int buildNumber = 0;
155        Metadata repoMetadata = metadata.getMetadata();
156        if ( ( repoMetadata != null )
157            && ( repoMetadata.getVersioning() != null && repoMetadata.getVersioning().getSnapshot() != null ) )
158        {
159            buildNumber = repoMetadata.getVersioning().getSnapshot().getBuildNumber();
160        }
161        return buildNumber;
162    }
163
164    public static DateFormat getUtcDateFormatter()
165    {
166        DateFormat utcDateFormatter = new SimpleDateFormat( UTC_TIMESTAMP_PATTERN );
167        utcDateFormatter.setTimeZone( UTC_TIME_ZONE );
168        return utcDateFormatter;
169    }
170
171}