1 package org.apache.maven.scm.provider.jazz.command.diff; 2 3 /* 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 import java.io.File; 23 import java.util.HashMap; 24 import java.util.List; 25 import java.util.Map; 26 27 import org.apache.maven.scm.ScmException; 28 import org.apache.maven.scm.ScmFile; 29 import org.apache.maven.scm.ScmFileSet; 30 import org.apache.maven.scm.ScmFileStatus; 31 import org.apache.maven.scm.ScmVersion; 32 import org.apache.maven.scm.command.diff.AbstractDiffCommand; 33 import org.apache.maven.scm.command.diff.DiffScmResult; 34 import org.apache.maven.scm.command.status.StatusScmResult; 35 import org.apache.maven.scm.provider.ScmProviderRepository; 36 import org.apache.maven.scm.provider.jazz.command.JazzConstants; 37 import org.apache.maven.scm.provider.jazz.command.JazzScmCommand; 38 import org.apache.maven.scm.provider.jazz.command.consumer.DebugLoggerConsumer; 39 import org.apache.maven.scm.provider.jazz.command.consumer.ErrorConsumer; 40 import org.apache.maven.scm.provider.jazz.command.status.JazzStatusCommand; 41 42 // The Maven SCM plugin "diff" goal may have different interpretations in RTC depending on how 43 // the user is using RTC. In one instance, the user may expect the diff to report back on the differences between 44 // the local 'sandbox' and their connected repository workspace (ie. What files are 'unresolved'). 45 // Other users may want the diff the report back the differences between their connected repository workspace 46 // and the stream that it flows with (ie. What files are 'outgoing' / 'incoming'). 47 // As a first step, we would have to figure out how to distinguish between these two use cases when using this goal. 48 49 // Whilst, the above is true, based upon the SVN implementation, its diff does a difference 50 // between the local working copy (sandbox) vs's repository (workspace repository). 51 // 52 // So this implementation will compare the sandbox with the workspace repository (even if there is 53 // a valid flow target). As the "scm diff" command does not support this direct comparison (I have 54 // had an Enhancement Work Item opened to do so), we will call the "scm status" command to get all 55 // of the change files, and then iterate through all of them to get a diff of all of them. The combined 56 // output of all of the various diffs will then be returned as a single output operation. 57 // -Chris 24/02/12 58 59 // The following RTC commands may be useful however it retrieving the required information. 60 // 61 // 1. RTC "compare" command: Compare two workspaces/streams/baselines/snapshots, showing differing baselines and 62 // change sets. 63 // See the following links for additional information on the RTC "compare" command: 64 // RTC 2.0.0.2: 65 // http://publib.boulder.ibm.com/infocenter/rtc/v2r0m0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_compare.html 66 // RTC 3.0: 67 // http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_compare.html 68 // RTC 3.0.1: 69 // http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0m1/topic/com.ibm.team.scm.doc/topics/r_scm_cli_compare.html 70 // 71 // 2. RTC "diff" command: Compare two states of a file. 72 // See the following links for additional information on the RTC "diff" command: 73 // RTC 2.0.0.2: 74 // http://publib.boulder.ibm.com/infocenter/rtc/v2r0m0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_diff.html 75 // RTC 3.0: 76 // http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_diff.html 77 // RTC 3.0.1: 78 // http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0m1/topic/com.ibm.team.scm.doc/topics/r_scm_cli_diff.html 79 // 80 // 3. RTC "status" command: Show modification status of items in a workspace. 81 // See the following links for additional information on the RTC "status" command: 82 // RTC 2.0.0.2: 83 // http://publib.boulder.ibm.com/infocenter/rtc/v2r0m0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_status.html 84 // RTC 3.0: 85 // http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_status.html 86 // RTC 3.0.1: 87 // http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0m1/topic/com.ibm.team.scm.doc/topics/r_scm_cli_status.html 88 // 89 90 /** 91 * @author <a href="mailto:ChrisGWarp@gmail.com">Chris Graham</a> 92 */ 93 public class JazzDiffCommand 94 extends AbstractDiffCommand 95 { 96 /** 97 * {@inheritDoc} 98 */ 99 protected DiffScmResult executeDiffCommand( ScmProviderRepository repo, ScmFileSet fileSet, 100 ScmVersion startRevision, ScmVersion endRevision ) 101 throws ScmException 102 { 103 if ( getLogger().isDebugEnabled() ) 104 { 105 getLogger().debug( "Executing diff command..." ); 106 } 107 108 File baseDir = fileSet.getBasedir(); 109 File parentFolder = ( baseDir.getParentFile() != null ) ? baseDir.getParentFile() : baseDir; 110 111 // First execute the status command to get the list of changed files. 112 JazzStatusCommand statusCmd = new JazzStatusCommand(); 113 statusCmd.setLogger( getLogger() ); 114 StatusScmResult statusCmdResult = statusCmd.executeStatusCommand( repo, fileSet ); 115 List<ScmFile> statusScmFiles = statusCmdResult.getChangedFiles(); 116 117 // In this case, we also use it across multiple calls to "scm diff" so that we 118 // sum all output into on. 119 JazzScmCommand diffCmd = null; 120 StringBuilder patch = new StringBuilder(); 121 Map<String, CharSequence> differences = new HashMap<String, CharSequence>(); 122 123 // Now lets iterate through them 124 for ( ScmFile file : statusScmFiles ) 125 { 126 if ( file.getStatus() == ScmFileStatus.MODIFIED ) 127 { 128 // The "scm status" command returns files relative to the sandbox root. 129 // Whereas the "scm diff" command needs them relative to the working directory. 130 File fullPath = new File( parentFolder, file.getPath() ); 131 String relativePath = fullPath.toString().substring( baseDir.toString().length() ); 132 getLogger().debug( "Full Path : '" + fullPath + "'" ); 133 getLogger().debug( "Relative Path : '" + relativePath + "'" ); 134 135 // Now call "scm diff on it" 136 // In this case, we use the DebugLoggerConsumer's ability to store captured output 137 DebugLoggerConsumer diffConsumer = new DebugLoggerConsumer( getLogger() ); 138 ErrorConsumer errConsumer = new ErrorConsumer( getLogger() ); 139 diffCmd = createDiffCommand( repo, fileSet, relativePath ); 140 int status = diffCmd.execute( diffConsumer, errConsumer ); 141 if ( status != 0 || errConsumer.hasBeenFed() ) 142 { 143 // Return a false result (not the usual SCMResult) 144 return new DiffScmResult( diffCmd.toString(), "The scm diff command failed.", 145 errConsumer.getOutput(), false ); 146 } 147 // Append to patch (all combined) 148 patch.append( diffConsumer.getOutput() ); 149 // Set the differences map <File, <CharSequence> 150 differences.put( relativePath, diffConsumer.getOutput() ); 151 } 152 } 153 154 return new DiffScmResult( diffCmd.toString(), statusCmdResult.getChangedFiles(), differences, 155 patch.toString() ); 156 } 157 158 public JazzScmCommand createDiffCommand( ScmProviderRepository repo, ScmFileSet fileSet, String relativePath ) 159 { 160 JazzScmCommand command = new JazzScmCommand( JazzConstants.CMD_DIFF, repo, fileSet, getLogger() ); 161 command.addArgument( JazzConstants.ARG_FILE ); 162 command.addArgument( relativePath ); 163 return command; 164 } 165 }