blob: 9c6e4672ca7f1871e2251b4ac046e6cc7dc452ca [file] [log] [blame]
package org.apache.maven.scm.provider.accurev;
/*
* 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 java.io.File;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.maven.scm.ScmVersion;
import org.apache.maven.scm.log.ScmLogger;
import org.apache.maven.scm.provider.ScmProviderRepositoryWithHost;
import org.apache.maven.scm.provider.accurev.util.WorkspaceUtils;
import org.codehaus.plexus.util.StringUtils;
/**
*
*/
public class AccuRevScmProviderRepository
extends ScmProviderRepositoryWithHost
{
public static final String DEFAULT_TAG_FORMAT = "%s";
private AccuRev accurev;
private String streamName;
private String projectPath;
private String tagFormat = DEFAULT_TAG_FORMAT;
private ScmLogger logger;
public AccuRevScmProviderRepository()
{
super();
// True is a more sensible default (ie for tck tests)
// TODO raise jira so tck tests properly handle setPersist
setPersistCheckout( true );
setShouldUseExportForNonPersistentCheckout( true );
}
public String getTagFormat()
{
return tagFormat;
}
public void setTagFormat( String tagFormat )
{
if ( tagFormat == null || !tagFormat.contains( "%s" ) )
{
throw new IllegalArgumentException( "tagFormat must contain '%s' to be replaced" );
}
this.tagFormat = tagFormat;
}
public String getStreamName()
{
return streamName;
}
public void setStreamName( String streamName )
{
this.streamName = streamName;
}
public String getProjectPath()
{
return projectPath;
}
public void setProjectPath( String projectPath )
{
this.projectPath = projectPath;
setCheckoutRelativePath( projectPath );
}
public AccuRev getAccuRev()
{
return this.accurev;
}
public void setAccuRev( AccuRev accurev )
{
this.accurev = accurev;
}
/**
* @param info
* @return true if info indicates a root of the workspace.
*/
public boolean isWorkSpaceRoot( AccuRevInfo info )
{
String p = getProjectPath();
return ( p != null && WorkspaceUtils.isSameFile( info.getBasedir(), new File( info.getTop(), p ) ) )
|| isWorkSpaceTop( info );
}
public boolean isWorkSpaceTop( AccuRevInfo info )
{
return info.isWorkSpaceTop();
}
String tagToStream( String tagName )
{
return String.format( getTagFormat(), tagName );
}
String streamToTag( String streamName )
{
tagFormat = getTagFormat();
// TODO - strictly we should quote either side of the %s
String tagPatternString = tagToStream( "(.*)" );
Pattern tagPattern = Pattern.compile( tagPatternString );
Matcher tagMatcher = tagPattern.matcher( streamName );
if ( tagMatcher.matches() )
{
return tagMatcher.group( 1 );
}
else
{
return streamName;
}
}
public void setLogger( ScmLogger logger )
{
this.logger = logger;
}
// TODO raise JIRA to pull up these methods to ScmProviderRepository
private String checkoutRelativePath;
private boolean shouldUseExportForNonPersistentCheckout = true;
/**
* The relative path of the directory of the checked out project in comparison to the checkout directory, or an
* empty String in case the checkout directory equals the project directory.
* <p/>
* With most SCMs, this is just an empty String, meaning that the checkout directory equals the project directory.
* But there are cases (e.g. ClearCase) where within the checkout directory, the directory structure of the SCM
* system is repeated. E.g. if you check out the project "my/project" to "/some/dir", the project sources are
* actually checked out to "some/dir/my/project". In this example, relativePathProjectDirectory would contain
* "my/project".
*/
public String getCheckoutRelativePath()
{
if ( this.checkoutRelativePath == null )
{
return "";
}
return this.checkoutRelativePath;
}
public void setCheckoutRelativePath( String checkoutRelativePath )
{
this.checkoutRelativePath = checkoutRelativePath;
}
/**
* Relative project path for export
*
* @return default same as {@link #getCheckoutRelativePath()}
*/
public String getExportRelativePath()
{
return getCheckoutRelativePath();
}
/**
* When checkout is not expected to be refreshed or committed, should export be used instead? Perforce, Clearcase
* and AccuRev store their meta-data about file status within the server rather than files in the source tree. This
* makes checkouts within checkouts (eg release:perform) difficult. Typically there is a way to do a lightweight
* export instead which can be implemented as the "export" command. This is a hint to downstream applications that
* "export" is available and should be used in preference to "checkout" in cases where "update" and "commit" are not
* intended to be used. (ie release:perform)
*
* @return false by default
*/
public boolean shouldUseExportForNonPersistentCheckout()
{
return this.shouldUseExportForNonPersistentCheckout;
}
public void setShouldUseExportForNonPersistentCheckout( boolean shouldUseExportForNonPersistentCheckout )
{
this.shouldUseExportForNonPersistentCheckout = shouldUseExportForNonPersistentCheckout;
}
public String getDepotRelativeProjectPath()
{
return "/./" + ( projectPath == null ? "" : projectPath );
}
public AccuRevVersion getAccuRevVersion( ScmVersion scmVersion )
{
String tran = null;
String basisStream = null;
if ( scmVersion == null )
{
basisStream = getStreamName();
}
else
{
String name = StringUtils.clean( scmVersion.getName() );
String[] versionComponents = name.split( "[/\\\\]", 2 );
basisStream = versionComponents[0];
if ( basisStream.length() == 0 )
{
// Use the default stream from the URL
basisStream = getStreamName();
}
else
{
// name is a tag name - convert to a stream.
basisStream = tagToStream( basisStream );
}
if ( versionComponents.length == 2 && versionComponents[1].length() > 0 )
{
tran = versionComponents[1];
}
}
return new AccuRevVersion( basisStream, tran );
}
public String getSnapshotName( String tagName )
{
return tagToStream( tagName );
}
public String getRevision( String streamName, Date date )
{
return getRevision( streamName, AccuRev.ACCUREV_TIME_SPEC.format( date == null ? new Date() : date ) );
}
public String getRevision( String stream, long fromTranId )
{
return getRevision( stream, Long.toString( fromTranId ) );
}
public String getRevision( String streamName, String transaction )
{
return streamToTag( streamName ) + "/" + transaction;
}
public String getWorkSpaceRevision( String workspace )
throws AccuRevException
{
return getRevision( workspace, Long.toString( getCurrentTransactionId( workspace ) ) );
}
public Transaction getDepotTransaction( String stream, String tranSpec )
throws AccuRevException
{
if ( tranSpec == null )
{
tranSpec = "now";
}
List<Transaction> transactions = getAccuRev().history( stream, tranSpec, null, 1, true, true );
if ( transactions == null || transactions.isEmpty() )
{
logger.warn( "Unable to find transaction for tranSpec=" + tranSpec );
return null;
}
else
{
return transactions.get( 0 );
}
}
public String getDepotTransactionId( String stream, String tranSpec )
throws AccuRevException
{
Transaction t = getDepotTransaction( stream, tranSpec );
return t == null ? tranSpec : Long.toString( t.getTranId() );
}
private long getCurrentTransactionId( String workSpaceName )
throws AccuRevException
{
// AccuRev does not have a way to get at this workspace info by name.
// So we have to do it the hard way...
AccuRev accuRev = getAccuRev();
Map<String, WorkSpace> workSpaces = accuRev.showWorkSpaces();
WorkSpace workspace = workSpaces.get( workSpaceName );
if ( workspace == null )
{
// Must be a reftree
workSpaces = accuRev.showRefTrees();
workspace = workSpaces.get( workSpaceName );
}
if ( workspace == null )
{
throw new AccuRevException( "Can't find workspace " + workSpaceName );
}
return workspace.getTransactionId();
}
public String toString()
{
StringBuilder buff = new StringBuilder( "AccuRevScmProviderRepository" );
buff.append( " user=" );
buff.append( getUser() );
buff.append( " pass=" );
buff.append( getPassword() == null ? "null" : StringUtils.repeat( "*", getPassword().length() ) );
buff.append( " host=" );
buff.append( getHost() );
buff.append( " port=" );
buff.append( getPort() );
buff.append( " stream=" );
buff.append( getStreamName() );
buff.append( " projectPath=" );
buff.append( getProjectPath() );
return buff.toString();
}
public static String formatTimeSpec( Date when )
{
if ( when == null )
{
return "now";
}
return AccuRev.ACCUREV_TIME_SPEC.format( when );
}
}