001package org.apache.maven.scm.provider.jazz.command.diff; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026 027import org.apache.maven.scm.ScmException; 028import org.apache.maven.scm.ScmFile; 029import org.apache.maven.scm.ScmFileSet; 030import org.apache.maven.scm.ScmFileStatus; 031import org.apache.maven.scm.ScmVersion; 032import org.apache.maven.scm.command.diff.AbstractDiffCommand; 033import org.apache.maven.scm.command.diff.DiffScmResult; 034import org.apache.maven.scm.command.status.StatusScmResult; 035import org.apache.maven.scm.provider.ScmProviderRepository; 036import org.apache.maven.scm.provider.jazz.command.JazzConstants; 037import org.apache.maven.scm.provider.jazz.command.JazzScmCommand; 038import org.apache.maven.scm.provider.jazz.command.consumer.DebugLoggerConsumer; 039import org.apache.maven.scm.provider.jazz.command.consumer.ErrorConsumer; 040import org.apache.maven.scm.provider.jazz.command.status.JazzStatusCommand; 041 042// The Maven SCM plugin "diff" goal may have different interpretations in RTC depending on how 043// the user is using RTC. In one instance, the user may expect the diff to report back on the differences between 044// the local 'sandbox' and their connected repository workspace (ie. What files are 'unresolved'). 045// Other users may want the diff the report back the differences between their connected repository workspace 046// and the stream that it flows with (ie. What files are 'outgoing' / 'incoming'). 047// As a first step, we would have to figure out how to distinguish between these two use cases when using this goal. 048 049// Whilst, the above is true, based upon the SVN implementation, its diff does a difference 050// between the local working copy (sandbox) vs's repository (workspace repository). 051// 052// So this implementation will compare the sandbox with the workspace repository (even if there is 053// a valid flow target). As the "scm diff" command does not support this direct comparison (I have 054// had an Enhancement Work Item opened to do so), we will call the "scm status" command to get all 055// of the change files, and then iterate through all of them to get a diff of all of them. The combined 056// output of all of the various diffs will then be returned as a single output operation. 057// -Chris 24/02/12 058 059// The following RTC commands may be useful however it retrieving the required information. 060// 061// 1. RTC "compare" command: Compare two workspaces/streams/baselines/snapshots, showing differing baselines and change sets. 062// See the following links for additional information on the RTC "compare" command: 063// RTC 2.0.0.2: 064// http://publib.boulder.ibm.com/infocenter/rtc/v2r0m0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_compare.html 065// RTC 3.0: 066// http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_compare.html 067// RTC 3.0.1: 068// http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0m1/topic/com.ibm.team.scm.doc/topics/r_scm_cli_compare.html 069// 070// 2. RTC "diff" command: Compare two states of a file. 071// See the following links for additional information on the RTC "diff" command: 072// RTC 2.0.0.2: 073// http://publib.boulder.ibm.com/infocenter/rtc/v2r0m0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_diff.html 074// RTC 3.0: 075// http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_diff.html 076// RTC 3.0.1: 077// http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0m1/topic/com.ibm.team.scm.doc/topics/r_scm_cli_diff.html 078// 079// 3. RTC "status" command: Show modification status of items in a workspace. 080// See the following links for additional information on the RTC "status" command: 081// RTC 2.0.0.2: 082// http://publib.boulder.ibm.com/infocenter/rtc/v2r0m0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_status.html 083// RTC 3.0: 084// http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0/topic/com.ibm.team.scm.doc/topics/r_scm_cli_status.html 085// RTC 3.0.1: 086// http://publib.boulder.ibm.com/infocenter/clmhelp/v3r0m1/topic/com.ibm.team.scm.doc/topics/r_scm_cli_status.html 087// 088 089/** 090 * @author <a href="mailto:ChrisGWarp@gmail.com">Chris Graham</a> 091 */ 092public class JazzDiffCommand 093 extends AbstractDiffCommand 094{ 095 /** 096 * {@inheritDoc} 097 */ 098 protected DiffScmResult executeDiffCommand( ScmProviderRepository repo, ScmFileSet fileSet, 099 ScmVersion startRevision, ScmVersion endRevision ) 100 throws ScmException 101 { 102 if ( getLogger().isDebugEnabled() ) 103 { 104 getLogger().debug( "Executing diff command..." ); 105 } 106 107 File baseDir = fileSet.getBasedir(); 108 File parentFolder = ( baseDir.getParentFile() != null ) ? baseDir.getParentFile() : baseDir; 109 110 // First execute the status command to get the list of changed files. 111 JazzStatusCommand statusCmd = new JazzStatusCommand(); 112 statusCmd.setLogger( getLogger() ); 113 StatusScmResult statusCmdResult = statusCmd.executeStatusCommand( repo, fileSet ); 114 List<ScmFile> statusScmFiles = statusCmdResult.getChangedFiles(); 115 116 // In this case, we also use it across multiple calls to "scm diff" so that we 117 // sum all output into on. 118 JazzScmCommand diffCmd = null; 119 StringBuilder patch = new StringBuilder(); 120 Map<String, CharSequence> differences = new HashMap<String, CharSequence>(); 121 122 // Now lets iterate through them 123 for ( ScmFile file : statusScmFiles ) 124 { 125 if ( file.getStatus() == ScmFileStatus.MODIFIED ) 126 { 127 // The "scm status" command returns files relative to the sandbox root. 128 // Whereas the "scm diff" command needs them relative to the working directory. 129 File fullPath = new File( parentFolder, file.getPath() ); 130 String relativePath = fullPath.toString().substring( baseDir.toString().length() ); 131 getLogger().debug( "Full Path : '" + fullPath + "'" ); 132 getLogger().debug( "Relative Path : '" + relativePath + "'" ); 133 134 // Now call "scm diff on it" 135 // In this case, we use the DebugLoggerConsumer's ability to store captured output 136 DebugLoggerConsumer diffConsumer = new DebugLoggerConsumer( getLogger() ); 137 ErrorConsumer errConsumer = new ErrorConsumer( getLogger() ); 138 diffCmd = createDiffCommand( repo, fileSet, relativePath ); 139 int status = diffCmd.execute( diffConsumer, errConsumer ); 140 if ( status != 0 || errConsumer.hasBeenFed() ) 141 { 142 // Return a false result (not the usual SCMResult) 143 return new DiffScmResult( diffCmd.toString(), "The scm diff command failed.", 144 errConsumer.getOutput(), false ); 145 } 146 // Append to patch (all combined) 147 patch.append( diffConsumer.getOutput() ); 148 // Set the differences map <File, <CharSequence> 149 differences.put( relativePath, diffConsumer.getOutput() ); 150 } 151 } 152 153 return new DiffScmResult( diffCmd.toString(), statusCmdResult.getChangedFiles(), differences, 154 patch.toString() ); 155 } 156 157 public JazzScmCommand createDiffCommand( ScmProviderRepository repo, ScmFileSet fileSet, String relativePath ) 158 { 159 JazzScmCommand command = new JazzScmCommand( JazzConstants.CMD_DIFF, repo, fileSet, getLogger() ); 160 command.addArgument( JazzConstants.ARG_FILE ); 161 command.addArgument( relativePath ); 162 return command; 163 } 164}