blob: 769fbe1a95f35ab248d94117ad95ede007113d92 [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.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.maven.scm.ChangeFile;
import org.apache.maven.scm.ChangeSet;
import org.apache.maven.scm.CommandParameter;
import org.apache.maven.scm.CommandParameters;
import org.apache.maven.scm.ScmException;
import org.apache.maven.scm.ScmFile;
import org.apache.maven.scm.ScmFileSet;
import org.apache.maven.scm.ScmRevision;
import org.apache.maven.scm.command.add.AddScmResult;
import org.apache.maven.scm.command.blame.BlameScmResult;
import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
import org.apache.maven.scm.command.checkin.CheckInScmResult;
import org.apache.maven.scm.command.checkout.CheckOutScmResult;
import org.apache.maven.scm.command.export.ExportScmResult;
import org.apache.maven.scm.command.login.LoginScmResult;
import org.apache.maven.scm.command.remove.RemoveScmResult;
import org.apache.maven.scm.command.status.StatusScmResult;
import org.apache.maven.scm.command.tag.TagScmResult;
import org.apache.maven.scm.command.update.UpdateScmResult;
import org.apache.maven.scm.provider.AbstractScmProvider;
import org.apache.maven.scm.provider.ScmProviderRepository;
import org.apache.maven.scm.provider.accurev.cli.AccuRevCommandLine;
import org.apache.maven.scm.provider.accurev.command.add.AccuRevAddCommand;
import org.apache.maven.scm.provider.accurev.command.blame.AccuRevBlameCommand;
import org.apache.maven.scm.provider.accurev.command.changelog.AccuRevChangeLogCommand;
import org.apache.maven.scm.provider.accurev.command.checkin.AccuRevCheckInCommand;
import org.apache.maven.scm.provider.accurev.command.checkout.AccuRevCheckOutCommand;
import org.apache.maven.scm.provider.accurev.command.export.AccuRevExportCommand;
import org.apache.maven.scm.provider.accurev.command.login.AccuRevLoginCommand;
import org.apache.maven.scm.provider.accurev.command.remove.AccuRevRemoveCommand;
import org.apache.maven.scm.provider.accurev.command.status.AccuRevStatusCommand;
import org.apache.maven.scm.provider.accurev.command.tag.AccuRevTagCommand;
import org.apache.maven.scm.provider.accurev.command.update.AccuRevUpdateCommand;
import org.apache.maven.scm.provider.accurev.command.update.AccuRevUpdateScmResult;
import org.apache.maven.scm.provider.accurev.util.QuotedPropertyParser;
import org.apache.maven.scm.repository.ScmRepositoryException;
import org.apache.maven.scm.repository.UnknownRepositoryStructure;
import org.codehaus.plexus.util.StringUtils;
/**
* AccuRev integration with Maven SCM
*
* @plexus.component role="org.apache.maven.scm.provider.ScmProvider" role-hint="accurev"
*/
public class AccuRevScmProvider
extends AbstractScmProvider
{
public static final String ACCUREV_EXECUTABLE_PROPERTY = "accurevExe";
public static final String TAG_FORMAT_PROPERTY = "tagFormat";
public static final String SYSTEM_PROPERTY_PREFIX = "maven.scm.accurev.";
public String getScmType()
{
return "accurev";
}
/**
* The basic url parsing approach is to be as loose as possible. If you specify as per the docs you'll get what you
* expect. If you do something else the result is undefined. Don't use "/" "\" or "@" as the delimiter,
*/
public ScmProviderRepository makeProviderScmRepository( String scmSpecificUrl, char delimiter )
throws ScmRepositoryException
{
List<String> validationMessages = new ArrayList<String>();
String[] tokens = StringUtils.split( scmSpecificUrl, Character.toString( delimiter ) );
// [[user][/pass]@host[:port]][:stream][:\project\dir]
String basisStream = null;
String projectPath = null;
int port = AccuRev.DEFAULT_PORT;
String host = null;
String user = null;
String password = null;
Map<String, String> properties = new HashMap<String, String>();
properties.put( TAG_FORMAT_PROPERTY, AccuRevScmProviderRepository.DEFAULT_TAG_FORMAT );
properties.put( ACCUREV_EXECUTABLE_PROPERTY, AccuRev.DEFAULT_ACCUREV_EXECUTABLE );
fillSystemProperties( properties );
int i = 0;
while ( i < tokens.length )
{
int at = tokens[i].indexOf( '@' );
// prefer "/", better not have a "/" or a "\\" in your password.
int slash = tokens[i].indexOf( '/' );
slash = slash < 0 ? tokens[i].indexOf( '\\' ) : slash;
int qMark = tokens[i].indexOf( '?' );
if ( qMark == 0 )
{
QuotedPropertyParser.parse( tokens[i].substring( 1 ), properties );
}
else if ( slash == 0 )
{
// this is the project path
projectPath = tokens[i].substring( 1 );
break;
}
else if ( ( slash > 0 || ( at >= 0 ) ) && host == null && user == null )
{
// user/pass@host
int len = tokens[i].length();
if ( at >= 0 && len > at )
{
// everything after the "@"
host = tokens[i].substring( at + 1 );
}
if ( slash > 0 )
{
// user up to /
user = tokens[i].substring( 0, slash );
// pass between / and @
password = tokens[i].substring( slash + 1, at < 0 ? len : at );
}
else
{
// no /, user from beginning to @
user = tokens[i].substring( 0, at < 0 ? len : at );
}
}
else if ( host != null && tokens[i].matches( "^[0-9]+$" ) )
{
// only valid entry with all digits is the port specification.
port = Integer.parseInt( tokens[i] );
}
else
{
basisStream = tokens[i];
}
i++;
}
if ( i < tokens.length )
{
validationMessages.add( "Unknown tokens in URL " + scmSpecificUrl );
}
AccuRevScmProviderRepository repo = new AccuRevScmProviderRepository();
repo.setLogger( getLogger() );
if ( !StringUtils.isEmpty( user ) )
{
repo.setUser( user );
}
if ( !StringUtils.isEmpty( password ) )
{
repo.setPassword( password );
}
if ( !StringUtils.isEmpty( basisStream ) )
{
repo.setStreamName( basisStream );
}
if ( !StringUtils.isEmpty( projectPath ) )
{
repo.setProjectPath( projectPath );
}
if ( !StringUtils.isEmpty( host ) )
{
repo.setHost( host );
}
repo.setPort( port );
repo.setTagFormat( properties.get( TAG_FORMAT_PROPERTY ) );
AccuRevCommandLine accuRev = new AccuRevCommandLine( host, port );
accuRev.setLogger( getLogger() );
accuRev.setExecutable( properties.get( ACCUREV_EXECUTABLE_PROPERTY ) );
repo.setAccuRev( accuRev );
return repo;
}
private void fillSystemProperties( Map<String, String> properties )
{
Set<String> propertyKeys = properties.keySet();
for ( String key : propertyKeys )
{
String systemPropertyKey = SYSTEM_PROPERTY_PREFIX + key;
String systemProperty = System.getProperty( systemPropertyKey );
if ( systemProperty != null )
{
properties.put( key, systemProperty );
}
}
}
@Override
protected LoginScmResult login( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
throws ScmException
{
if ( getLogger().isDebugEnabled() )
{
getLogger().debug( repository.toString() );
}
AccuRevLoginCommand command = new AccuRevLoginCommand( getLogger() );
return command.login( repository, fileSet, parameters );
}
@Override
protected CheckOutScmResult checkout( ScmProviderRepository repository, ScmFileSet fileSet,
CommandParameters parameters )
throws ScmException
{
// workaround deprecated behaviour
// TODO pull up to AbstractScmProvider
AccuRevScmProviderRepository accuRevRepo = (AccuRevScmProviderRepository) repository;
if ( !repository.isPersistCheckout() && accuRevRepo.shouldUseExportForNonPersistentCheckout() )
{
ExportScmResult result = export( repository, fileSet, parameters );
if ( result.isSuccess() )
{
return new CheckOutScmResult( result.getCommandLine(), result.getExportedFiles(),
accuRevRepo.getExportRelativePath() );
}
else
{
return new CheckOutScmResult( result.getCommandLine(), result.getProviderMessage(),
result.getCommandOutput(), false );
}
}
AccuRevCheckOutCommand command = new AccuRevCheckOutCommand( getLogger() );
return command.checkout( repository, fileSet, parameters );
}
@Override
protected CheckInScmResult checkin( ScmProviderRepository repository, ScmFileSet fileSet,
CommandParameters parameters )
throws ScmException
{
AccuRevCheckInCommand command = new AccuRevCheckInCommand( getLogger() );
return command.checkIn( repository, fileSet, parameters );
}
@Override
public ScmProviderRepository makeProviderScmRepository( File path )
throws ScmRepositoryException, UnknownRepositoryStructure
{
// TODO: accurev info with current dir = "path", find workspace. Find use-case for this.
return super.makeProviderScmRepository( path );
}
@Override
public AddScmResult add( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
throws ScmException
{
AccuRevAddCommand command = new AccuRevAddCommand( getLogger() );
return command.add( repository, fileSet, parameters );
}
@Override
protected TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
throws ScmException
{
AccuRevTagCommand command = new AccuRevTagCommand( getLogger() );
return command.tag( repository, fileSet, parameters );
}
@Override
protected StatusScmResult status( ScmProviderRepository repository, ScmFileSet fileSet,
CommandParameters parameters )
throws ScmException
{
AccuRevStatusCommand command = new AccuRevStatusCommand( getLogger() );
return command.status( repository, fileSet, parameters );
}
@Override
protected UpdateScmResult update( ScmProviderRepository repository, ScmFileSet fileSet,
CommandParameters parameters )
throws ScmException
{
AccuRevScmProviderRepository accurevRepo = (AccuRevScmProviderRepository) repository;
AccuRevUpdateCommand command = new AccuRevUpdateCommand( getLogger() );
UpdateScmResult result = command.update( repository, fileSet, parameters );
if ( result.isSuccess() && parameters.getBoolean( CommandParameter.RUN_CHANGELOG_WITH_UPDATE ) )
{
AccuRevUpdateScmResult accuRevResult = (AccuRevUpdateScmResult) result;
ScmRevision fromRevision = new ScmRevision( accuRevResult.getFromRevision() );
ScmRevision toRevision = new ScmRevision( accuRevResult.getToRevision() );
parameters.setScmVersion( CommandParameter.START_SCM_VERSION, fromRevision );
parameters.setScmVersion( CommandParameter.END_SCM_VERSION, toRevision );
AccuRevVersion startVersion = accurevRepo.getAccuRevVersion( fromRevision );
AccuRevVersion endVersion = accurevRepo.getAccuRevVersion( toRevision );
if ( startVersion.getBasisStream().equals( endVersion.getBasisStream() ) )
{
ChangeLogScmResult changeLogResult = changelog( repository, fileSet, parameters );
if ( changeLogResult.isSuccess() )
{
result.setChanges( changeLogResult.getChangeLog().getChangeSets() );
}
else
{
getLogger().warn( "Changelog from " + fromRevision + " to " + toRevision + " failed" );
}
}
else
{
String comment = "Cross stream update result from " + startVersion + " to " + endVersion;
String author = "";
List<ScmFile> files = result.getUpdatedFiles();
List<ChangeFile> changeFiles = new ArrayList<ChangeFile>( files.size() );
for ( ScmFile scmFile : files )
{
changeFiles.add( new ChangeFile( scmFile.getPath() ) );
}
ChangeSet dummyChangeSet = new ChangeSet( new Date(), comment, author, changeFiles );
// different streams invalidates the change log, insert a dummy change instead.
List<ChangeSet> changeSets = Collections.singletonList( dummyChangeSet );
result.setChanges( changeSets );
}
}
return result;
}
@Override
protected ExportScmResult export( ScmProviderRepository repository, ScmFileSet fileSet,
CommandParameters parameters )
throws ScmException
{
AccuRevExportCommand command = new AccuRevExportCommand( getLogger() );
return command.export( repository, fileSet, parameters );
}
@Override
protected ChangeLogScmResult changelog( ScmProviderRepository repository, ScmFileSet fileSet,
CommandParameters parameters )
throws ScmException
{
AccuRevChangeLogCommand command = new AccuRevChangeLogCommand( getLogger() );
return command.changelog( repository, fileSet, parameters );
}
@Override
protected RemoveScmResult remove( ScmProviderRepository repository, ScmFileSet fileSet,
CommandParameters parameters )
throws ScmException
{
AccuRevRemoveCommand command = new AccuRevRemoveCommand( getLogger() );
return command.remove( repository, fileSet, parameters );
}
/** {@inheritDoc} */
@Override
protected BlameScmResult blame( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
throws ScmException
{
AccuRevBlameCommand blameCommand = new AccuRevBlameCommand( getLogger() );
return blameCommand.blame( repository, fileSet, parameters );
}
}