blob: 96c5298554eaf0a8ab89f7692cd4399455bf79df [file] [log] [blame]
package org.apache.maven.scm.provider.clearcase.command.checkout;
/*
* 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.io.FileWriter;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.apache.maven.scm.ScmException;
import org.apache.maven.scm.ScmFileSet;
import org.apache.maven.scm.ScmVersion;
import org.apache.maven.scm.command.checkout.AbstractCheckOutCommand;
import org.apache.maven.scm.command.checkout.CheckOutScmResult;
import org.apache.maven.scm.provider.ScmProviderRepository;
import org.apache.maven.scm.provider.clearcase.command.ClearCaseCommand;
import org.apache.maven.scm.provider.clearcase.repository.ClearCaseScmProviderRepository;
import org.apache.maven.scm.providers.clearcase.settings.Settings;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;
/**
* @author <a href="mailto:wim.deblauwe@gmail.com">Wim Deblauwe</a>
* @author <a href="mailto:frederic.mura@laposte.net">Frederic Mura</a>
*/
public class ClearCaseCheckOutCommand
extends AbstractCheckOutCommand
implements ClearCaseCommand
{
private Settings settings = null;
// ----------------------------------------------------------------------
// AbstractCheckOutCommand Implementation
// ----------------------------------------------------------------------
protected CheckOutScmResult executeCheckOutCommand( ScmProviderRepository repository, ScmFileSet fileSet,
ScmVersion version )
throws ScmException
{
getLogger().debug( "executing checkout command..." );
ClearCaseScmProviderRepository repo = (ClearCaseScmProviderRepository) repository;
File workingDirectory = fileSet.getBasedir();
if ( version != null )
{
getLogger().debug( version.getType() + ": " + version.getName() );
}
getLogger().debug( "Running with CLEARCASE " + settings.getClearcaseType() );
ClearCaseCheckOutConsumer consumer = new ClearCaseCheckOutConsumer( getLogger() );
CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
int exitCode;
Commandline cl;
String projectDirectory = "";
try
{
// Since clearcase only wants to checkout to a non-existent directory, first delete the working dir if it already exists
FileUtils.deleteDirectory( workingDirectory );
// First create the view
String viewName = getUniqueViewName( repo, workingDirectory.getAbsolutePath() );
String streamIdentifier = getStreamIdentifier(repo.getStreamName(), repo.getVobName());
cl = createCreateViewCommandLine( workingDirectory, viewName, streamIdentifier );
getLogger().info( "Executing: " + cl.getWorkingDirectory().getAbsolutePath() + ">>" + cl.toString() );
exitCode = CommandLineUtils.executeCommandLine( cl, new CommandLineUtils.StringStreamConsumer(), stderr );
if ( exitCode == 0 )
{
File configSpecLocation;
if ( !repo.isAutoConfigSpec() )
{
configSpecLocation = repo.getConfigSpec();
if ( version != null && StringUtils.isNotEmpty( version.getName() ) )
{
// Another config spec is needed in this case.
//
// One option how to implement this would be to use a name convention for the config specs,
// e.g. the tag name could be appended to the original config spec name.
// If the config spec from the SCM URL would be \\myserver\configspecs\someproj.txt
// and the tag name would be mytag, the new config spec location could be
// \\myserver\configspecs\someproj-mytag.txt
//
throw new UnsupportedOperationException(
"Building on a label not supported with user-specified config specs" );
}
}
else
{
// write config spec to temp file
String configSpec = createConfigSpec( repo.getLoadDirectory(), version );
getLogger().info( "Created config spec for view '" + viewName + "':\n" + configSpec );
configSpecLocation = writeTemporaryConfigSpecFile( configSpec, viewName );
// When checking out from ClearCase, the directory structure of the
// SCM system is repeated within the checkout directory. E.g. if you check out the
// project "my/project" to "/some/dir", the project sources are actually checked out
// to "my/project/some/dir".
projectDirectory = repo.getLoadDirectory();
// strip off leading / to make the path relative
if ( projectDirectory.startsWith( "/" ) )
{
projectDirectory = projectDirectory.substring( 1 );
}
}
cl = createUpdateConfigSpecCommandLine( workingDirectory, configSpecLocation, viewName );
getLogger().info( "Executing: " + cl.getWorkingDirectory().getAbsolutePath() + ">>" + cl.toString() );
exitCode = CommandLineUtils.executeCommandLine( cl, consumer, stderr );
}
}
catch ( CommandLineException ex )
{
throw new ScmException( "Error while executing clearcase command.", ex );
}
catch ( IOException ex )
{
throw new ScmException( "Error while deleting working directory.", ex );
}
if ( exitCode != 0 )
{
return new CheckOutScmResult( cl.toString(), "The cleartool command failed.", stderr.getOutput(), false );
}
return new CheckOutScmResult( cl.toString(), consumer.getCheckedOutFiles(), projectDirectory );
}
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
/**
* Creates a temporary config spec file with the given contents that will be
* deleted on VM exit.
*
* @param configSpecContents The contents for the file
* @param viewName The name of the view; used to determine an appropriate file
* name
*/
protected File writeTemporaryConfigSpecFile( String configSpecContents, String viewName )
throws IOException
{
File configSpecLocation = File.createTempFile( "configspec-" + viewName, ".txt" );
FileWriter fw = new FileWriter( configSpecLocation );
try
{
fw.write( configSpecContents );
}
finally
{
try
{
fw.close();
}
catch ( IOException e )
{
// ignore
}
}
configSpecLocation.deleteOnExit();
return configSpecLocation;
}
/**
* Creates a config spec that loads the given loadDirectory and uses the
* given version tag
*
* @param loadDirectory the VOB directory to be loaded
* @param version ClearCase label type; notice that branch types are not
* supported
* @return Config Spec as String
*/
protected String createConfigSpec( String loadDirectory, ScmVersion version )
{
// create config spec
StringBuffer configSpec = new StringBuffer();
configSpec.append( "element * CHECKEDOUT\n" );
if ( version != null && StringUtils.isNotEmpty( version.getName() ) )
{
configSpec.append( "element * " + version.getName() + "\n" );
configSpec.append( "element -directory * /main/LATEST\n" );
}
else
{
configSpec.append( "element * /main/LATEST\n" );
}
configSpec.append( "load " + loadDirectory + "\n" );
return configSpec.toString();
}
// private static Commandline createDeleteViewCommandLine( ClearCaseScmProviderRepository repository,
// File workingDirectory )
// {
// Commandline command = new Commandline();
//
// command.setWorkingDirectory( workingDirectory.getAbsolutePath() );
//
// command.setExecutable( "cleartool" );
//
// command.createArgument().setValue( "rmview" );
// command.createArgument().setValue( "-force" );
// command.createArgument().setValue( "-tag" );
// if ( isClearCaseLT() )
// {
// command.createArgument().setValue( getViewStore() );
// }
// else
// {
// command.createArgument().setValue( getUniqueViewName( repository, workingDirectory.getAbsolutePath() ) );
// }
//
// return command;
// }
protected Commandline createCreateViewCommandLine( File workingDirectory, String viewName, String streamIdentifier)
throws IOException
{
Commandline command = new Commandline();
// We have to execute from 1 level up from the working dir, since we had to delete the working dir
command.setWorkingDirectory( workingDirectory.getParentFile().getAbsolutePath() );
command.setExecutable( "cleartool" );
command.createArgument().setValue( "mkview" );
command.createArgument().setValue( "-snapshot" );
command.createArgument().setValue( "-tag" );
command.createArgument().setValue( viewName );
if (isClearCaseUCM())
{
command.createArgument().setValue( "-stream" );
command.createArgument().setValue( streamIdentifier );
}
if ( !isClearCaseLT() )
{
if ( useVWS() )
{
command.createArgument().setValue( "-vws" );
command.createArgument().setValue( getViewStore() + viewName + ".vws" );
}
}
command.createArgument().setValue( workingDirectory.getCanonicalPath() );
return command;
}
/**
* Format the stream identifier for ClearCaseUCM
* @param streamName
* @param vobName
* @return the formatted stream identifier if the two parameter are not null
*/
protected String getStreamIdentifier(String streamName, String vobName)
{
if (streamName == null || vobName == null)
return null;
return "stream:" + streamName + "@" + vobName;
}
protected Commandline createUpdateConfigSpecCommandLine( File workingDirectory, File configSpecLocation,
String viewName )
{
Commandline command = new Commandline();
command.setWorkingDirectory( workingDirectory.getAbsolutePath() );
command.setExecutable( "cleartool" );
command.createArgument().setValue( "setcs" );
command.createArgument().setValue( "-tag" );
command.createArgument().setValue( viewName );
command.createArgument().setValue( configSpecLocation.getAbsolutePath() );
return command;
}
private String getUniqueViewName( ClearCaseScmProviderRepository repository, String absolutePath )
{
String uniqueId;
int lastIndexBack = absolutePath.lastIndexOf( '\\' );
int lastIndexForward = absolutePath.lastIndexOf( '/' );
if ( lastIndexBack != -1 )
{
uniqueId = absolutePath.substring( lastIndexBack + 1 );
}
else
{
uniqueId = absolutePath.substring( lastIndexForward + 1 );
}
return repository.getViewName( uniqueId );
}
protected String getViewStore()
{
String result = null;
if ( settings.getViewstore() != null )
{
result = settings.getViewstore();
}
if ( result == null )
{
result = "\\\\" + getHostName() + "\\viewstore\\";
}
else
{
// If ClearCase LT are use, the View store is identify by the
// username.
if ( isClearCaseLT() )
{
result = result + getUserName() + "\\";
}
}
return result;
}
protected boolean isClearCaseLT()
{
return ClearCaseScmProviderRepository.CLEARCASE_LT.equals(settings.getClearcaseType());
}
protected boolean isClearCaseUCM()
{
return ClearCaseScmProviderRepository.CLEARCASE_UCM.equals(settings.getClearcaseType());
}
/**
* @return the value of the setting property 'useVWS'
*/
protected boolean useVWS()
{
return settings.isUseVWSParameter();
}
private String getHostName()
{
String hostname;
try
{
hostname = InetAddress.getLocalHost().getHostName();
}
catch ( UnknownHostException e )
{
// Should never happen
throw new RuntimeException( e );
}
return hostname;
}
private String getUserName()
{
String username;
username = System.getProperty( "user.name" );
return username;
}
public void setSettings(Settings settings) {
this.settings = settings;
}
}