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.GregorianCalendar;
026import java.util.TimeZone;
027
028import org.apache.maven.artifact.Artifact;
029import org.apache.maven.artifact.deployer.ArtifactDeploymentException;
030import org.apache.maven.artifact.repository.ArtifactRepository;
031import org.apache.maven.artifact.repository.RepositoryRequest;
032import org.apache.maven.artifact.repository.metadata.Metadata;
033import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
034import org.apache.maven.artifact.repository.metadata.RepositoryMetadataResolutionException;
035import org.apache.maven.artifact.repository.metadata.Snapshot;
036import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
037import org.apache.maven.artifact.repository.metadata.Versioning;
038import org.apache.maven.artifact.resolver.ArtifactResolutionException;
039import org.codehaus.plexus.component.annotations.Component;
040import org.codehaus.plexus.util.StringUtils;
041
042/**
043 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
044 * @author <a href="mailto:mmaczka@interia.pl">Michal Maczka</a>
045 */
046@Component( role = ArtifactTransformation.class, hint = "snapshot" )
047public class SnapshotTransformation
048    extends AbstractVersionTransformation
049{
050    private static final String DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT = "yyyyMMdd.HHmmss";
051
052    private static final TimeZone DEFAULT_SNAPSHOT_TIME_ZONE = TimeZone.getTimeZone( "Etc/UTC" );
053
054    private String deploymentTimestamp;
055
056    public void transformForResolve( Artifact artifact, RepositoryRequest request )
057        throws ArtifactResolutionException
058    {
059        // Only select snapshots that are unresolved (eg 1.0-SNAPSHOT, not 1.0-20050607.123456)
060        if ( artifact.isSnapshot() && artifact.getBaseVersion().equals( artifact.getVersion() ) )
061        {
062            try
063            {
064                String version = resolveVersion( artifact, request );
065                artifact.updateVersion( version, request.getLocalRepository() );
066            }
067            catch ( RepositoryMetadataResolutionException e )
068            {
069                throw new ArtifactResolutionException( e.getMessage(), artifact, e );
070            }
071        }
072    }
073
074    public void transformForInstall( Artifact artifact, ArtifactRepository localRepository )
075    {
076        if ( artifact.isSnapshot() )
077        {
078            Snapshot snapshot = new Snapshot();
079            snapshot.setLocalCopy( true );
080            RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata( artifact, snapshot );
081
082            artifact.addMetadata( metadata );
083        }
084    }
085
086    public void transformForDeployment( Artifact artifact, ArtifactRepository remoteRepository,
087                                        ArtifactRepository localRepository )
088        throws ArtifactDeploymentException
089    {
090        if ( artifact.isSnapshot() )
091        {
092            Snapshot snapshot = new Snapshot();
093
094            snapshot.setTimestamp( getDeploymentTimestamp() );
095
096            // we update the build number anyway so that it doesn't get lost. It requires the timestamp to take effect
097            try
098            {
099                int buildNumber = resolveLatestSnapshotBuildNumber( artifact, localRepository, remoteRepository );
100
101                snapshot.setBuildNumber( buildNumber + 1 );
102            }
103            catch ( RepositoryMetadataResolutionException e )
104            {
105                throw new ArtifactDeploymentException( "Error retrieving previous build number for artifact '"
106                    + artifact.getDependencyConflictId() + "': " + e.getMessage(), e );
107            }
108
109            RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata( artifact, snapshot );
110
111            artifact.setResolvedVersion(
112                constructVersion( metadata.getMetadata().getVersioning(), artifact.getBaseVersion() ) );
113
114            artifact.addMetadata( metadata );
115        }
116    }
117
118    public String getDeploymentTimestamp()
119    {
120        if ( deploymentTimestamp == null )
121        {
122            deploymentTimestamp = getUtcDateFormatter().format( new Date() );
123        }
124        return deploymentTimestamp;
125    }
126
127    protected String constructVersion( Versioning versioning, String baseVersion )
128    {
129        String version = null;
130        Snapshot snapshot = versioning.getSnapshot();
131        if ( snapshot != null )
132        {
133            if ( snapshot.getTimestamp() != null && snapshot.getBuildNumber() > 0 )
134            {
135                String newVersion = snapshot.getTimestamp() + "-" + snapshot.getBuildNumber();
136                version = StringUtils.replace( baseVersion, Artifact.SNAPSHOT_VERSION, newVersion );
137            }
138            else
139            {
140                version = baseVersion;
141            }
142        }
143        return version;
144    }
145
146    private int resolveLatestSnapshotBuildNumber( Artifact artifact, ArtifactRepository localRepository,
147                                                  ArtifactRepository remoteRepository )
148        throws RepositoryMetadataResolutionException
149    {
150        RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata( artifact );
151
152        getLogger().info( "Retrieving previous build number from " + remoteRepository.getId() );
153        repositoryMetadataManager.resolveAlways( metadata, localRepository, remoteRepository );
154
155        int buildNumber = 0;
156        Metadata repoMetadata = metadata.getMetadata();
157        if ( ( repoMetadata != null )
158            && ( repoMetadata.getVersioning() != null && repoMetadata.getVersioning().getSnapshot() != null ) )
159        {
160            buildNumber = repoMetadata.getVersioning().getSnapshot().getBuildNumber();
161        }
162        return buildNumber;
163    }
164
165    public static DateFormat getUtcDateFormatter()
166    {
167        DateFormat utcDateFormatter = new SimpleDateFormat( DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT );
168        utcDateFormatter.setCalendar( new GregorianCalendar() );
169        utcDateFormatter.setTimeZone( DEFAULT_SNAPSHOT_TIME_ZONE );
170        return utcDateFormatter;
171    }
172
173}