| package org.apache.maven.scm.provider.hg; |
| |
| /* |
| * 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 org.apache.maven.scm.ScmException; |
| import org.apache.maven.scm.ScmFileSet; |
| import org.apache.maven.scm.ScmFileStatus; |
| import org.apache.maven.scm.ScmResult; |
| import org.apache.maven.scm.log.DefaultLog; |
| import org.apache.maven.scm.log.ScmLogger; |
| import org.apache.maven.scm.provider.hg.command.HgCommand; |
| import org.apache.maven.scm.provider.hg.command.HgConsumer; |
| import org.codehaus.plexus.util.cli.CommandLineException; |
| import org.codehaus.plexus.util.cli.CommandLineUtils; |
| import org.codehaus.plexus.util.cli.Commandline; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Common code for executing hg commands. |
| * |
| * @author <a href="mailto:thurner.rupert@ymono.net">thurner rupert</a> |
| */ |
| public class HgUtils |
| { |
| /** |
| * Map between command and its valid exit codes |
| */ |
| private static final Map exitCodeMap = new HashMap(); |
| |
| /** |
| * Default exit codes for entries not in exitCodeMap |
| */ |
| private static final List defaultExitCodes = new ArrayList(); |
| |
| /** Setup exit codes*/ |
| static |
| { |
| defaultExitCodes.add( new Integer( 0 ) ); |
| |
| //Diff is different |
| List diffExitCodes = new ArrayList(); |
| diffExitCodes.add( new Integer( 0 ) ); //No difference |
| diffExitCodes.add( new Integer( 1 ) ); //Conflicts in merge-like or changes in diff-like |
| diffExitCodes.add( new Integer( 2 ) ); //Unrepresentable diff changes |
| exitCodeMap.put( HgCommand.DIFF_CMD, diffExitCodes ); |
| } |
| |
| public static ScmResult execute( HgConsumer consumer, ScmLogger logger, File workingDir, String[] cmdAndArgs ) |
| throws ScmException |
| { |
| try |
| { |
| //Build commandline |
| Commandline cmd = buildCmd( workingDir, cmdAndArgs ); |
| logger.info( "EXECUTING: " + cmd ); |
| |
| //Execute command |
| int exitCode = executeCmd( consumer, cmd ); |
| |
| //Return result |
| List exitCodes = defaultExitCodes; |
| if ( exitCodeMap.containsKey( cmdAndArgs[0] ) ) |
| { |
| exitCodes = (List) exitCodeMap.get( cmdAndArgs[0] ); |
| } |
| boolean success = exitCodes.contains( new Integer( exitCode ) ); |
| |
| //On failure (and not due to exceptions) - run diagnostics |
| String providerMsg = "Execution of hg command succeded"; |
| if ( !success ) |
| { |
| HgConfig config = new HgConfig( workingDir ); |
| providerMsg = "\nEXECUTION FAILED" + "\n Execution of cmd : " + cmdAndArgs[0] + |
| " failed with exit code: " + exitCode + "." + "\n Working directory was: " + "\n " + |
| workingDir.getAbsolutePath() + config.toString( workingDir ) + "\n"; |
| logger.error( providerMsg ); |
| } |
| |
| return new ScmResult( cmd.toString(), providerMsg, consumer.getStdErr(), success ); |
| } |
| catch ( ScmException se ) |
| { |
| String msg = "EXECUTION FAILED" + "\n Execution failed before invoking the Hg command. Last exception:" + |
| "\n " + se.getMessage(); |
| |
| //Add nested cause if any |
| if ( se.getCause() != null ) |
| { |
| msg += "\n Nested exception:" + "\n " + se.getCause().getMessage(); |
| } |
| |
| //log and return |
| logger.error( msg ); |
| throw se; |
| } |
| } |
| |
| static Commandline buildCmd( File workingDir, String[] cmdAndArgs ) |
| throws ScmException |
| { |
| Commandline cmd = new Commandline(); |
| cmd.setExecutable( HgCommand.EXEC ); |
| cmd.setWorkingDirectory( workingDir.getAbsolutePath() ); |
| cmd.addArguments( cmdAndArgs ); |
| |
| if ( !workingDir.exists() ) |
| { |
| boolean success = workingDir.mkdirs(); |
| if ( !success ) |
| { |
| String msg = "Working directory did not exist" + " and it couldn't be created: " + workingDir; |
| throw new ScmException( msg ); |
| } |
| } |
| return cmd; |
| } |
| |
| static int executeCmd( HgConsumer consumer, Commandline cmd ) |
| throws ScmException |
| { |
| final int exitCode; |
| try |
| { |
| exitCode = CommandLineUtils.executeCommandLine( cmd, consumer, consumer ); |
| } |
| catch ( CommandLineException ex ) |
| { |
| throw new ScmException( "Command could not be executed: " + cmd, ex ); |
| } |
| return exitCode; |
| } |
| |
| public static ScmResult execute( File workingDir, String[] cmdAndArgs ) |
| throws ScmException |
| { |
| ScmLogger logger = new DefaultLog(); |
| return execute( new HgConsumer( logger ), logger, workingDir, cmdAndArgs ); |
| } |
| |
| public static String[] expandCommandLine( String[] cmdAndArgs, ScmFileSet additionalFiles ) |
| { |
| List filesList = additionalFiles.getFileList(); |
| String[] cmd = new String[filesList.size() + cmdAndArgs.length]; |
| |
| // Copy command into array |
| System.arraycopy( cmdAndArgs, 0, cmd, 0, cmdAndArgs.length ); |
| |
| // Add files as additional parameter into the array |
| int i = 0; |
| for ( Iterator iterator = filesList.iterator(); iterator.hasNext(); i++ ) |
| { |
| File scmFile = (File) iterator.next(); |
| String file = scmFile.getPath().replace( '\\', File.separatorChar ); |
| cmd[i + cmdAndArgs.length] = file; |
| |
| } |
| |
| return cmd; |
| } |
| |
| public static int getCurrentRevisionNumber( ScmLogger logger, File workingDir ) |
| throws ScmException |
| { |
| |
| String[] revCmd = new String[]{HgCommand.REVNO_CMD}; |
| HgRevNoConsumer consumer = new HgRevNoConsumer( logger ); |
| HgUtils.execute( consumer, logger, workingDir, revCmd ); |
| |
| return consumer.getCurrentRevisionNumber(); |
| } |
| |
| /** |
| * Get current (working) revision. |
| * <p/> |
| * Resolve revision to the last integer found in the command output. |
| */ |
| private static class HgRevNoConsumer |
| extends HgConsumer |
| { |
| |
| private int revNo; |
| |
| HgRevNoConsumer( ScmLogger logger ) |
| { |
| super( logger ); |
| } |
| |
| public void doConsume( ScmFileStatus status, String line ) |
| { |
| try |
| { |
| revNo = Integer.valueOf( line ).intValue(); |
| } |
| catch ( NumberFormatException e ) |
| { |
| // ignore |
| } |
| } |
| |
| int getCurrentRevisionNumber() |
| { |
| return revNo; |
| } |
| } |
| } |