1 package org.apache.maven.scm.provider.hg;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.scm.ScmException;
23 import org.apache.maven.scm.ScmFileSet;
24 import org.apache.maven.scm.ScmFileStatus;
25 import org.apache.maven.scm.ScmResult;
26 import org.apache.maven.scm.provider.hg.command.HgCommandConstants;
27 import org.apache.maven.scm.provider.hg.command.HgConsumer;
28 import org.apache.maven.scm.provider.hg.command.inventory.HgChangeSet;
29 import org.apache.maven.scm.provider.hg.command.inventory.HgOutgoingConsumer;
30 import org.codehaus.plexus.util.cli.CommandLineException;
31 import org.codehaus.plexus.util.cli.CommandLineUtils;
32 import org.codehaus.plexus.util.cli.Commandline;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import java.io.File;
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.List;
40 import java.util.Map;
41
42
43
44
45
46
47
48 public final class HgUtils
49 {
50 private static final Logger LOGGER = LoggerFactory.getLogger( HgUtils.class );
51
52 public static final String DEFAULT = "default";
53
54 private HgUtils()
55 {
56
57 }
58
59
60
61
62 private static final Map<String, List<Integer>> EXIT_CODE_MAP = new HashMap<String, List<Integer>>();
63
64
65
66
67 private static final List<Integer> DEFAULT_EXIT_CODES = new ArrayList<Integer>();
68
69
70 static
71 {
72 DEFAULT_EXIT_CODES.add( Integer.valueOf( 0 ) );
73
74
75 List<Integer> diffExitCodes = new ArrayList<Integer>( 3 );
76 diffExitCodes.add( Integer.valueOf( 0 ) );
77 diffExitCodes.add( Integer.valueOf( 1 ) );
78 diffExitCodes.add( Integer.valueOf( 2 ) );
79 EXIT_CODE_MAP.put( HgCommandConstants.DIFF_CMD, diffExitCodes );
80
81 List<Integer> outgoingExitCodes = new ArrayList<Integer>( 2 );
82 outgoingExitCodes.add( Integer.valueOf( 0 ) );
83 outgoingExitCodes.add( Integer.valueOf( 1 ) );
84 EXIT_CODE_MAP.put( HgCommandConstants.OUTGOING_CMD, outgoingExitCodes );
85 }
86
87 public static ScmResult execute( HgConsumer consumer, File workingDir, String[] cmdAndArgs )
88 throws ScmException
89 {
90 try
91 {
92
93 Commandline cmd = buildCmd( workingDir, cmdAndArgs );
94 if ( LOGGER.isInfoEnabled() )
95 {
96 LOGGER.info( "EXECUTING: " + maskPassword( cmd ) );
97 }
98
99
100 int exitCode = executeCmd( consumer, cmd );
101
102
103 List<Integer> exitCodes = DEFAULT_EXIT_CODES;
104 if ( EXIT_CODE_MAP.containsKey( cmdAndArgs[0] ) )
105 {
106 exitCodes = EXIT_CODE_MAP.get( cmdAndArgs[0] );
107 }
108 boolean success = exitCodes.contains( Integer.valueOf( exitCode ) );
109
110
111 String providerMsg = "Execution of hg command succeded";
112 if ( !success )
113 {
114 HgConfig config = new HgConfig( workingDir );
115 providerMsg =
116 "\nEXECUTION FAILED" + "\n Execution of cmd : " + cmdAndArgs[0] + " failed with exit code: "
117 + exitCode + "." + "\n Working directory was: " + "\n " + workingDir.getAbsolutePath()
118 + config.toString( workingDir ) + "\n";
119 if ( LOGGER.isErrorEnabled() )
120 {
121 LOGGER.error( providerMsg );
122 }
123 }
124
125 return new ScmResult( cmd.toString(), providerMsg, consumer.getStdErr(), success );
126 }
127 catch ( ScmException se )
128 {
129 String msg =
130 "EXECUTION FAILED" + "\n Execution failed before invoking the Hg command. Last exception:" + "\n "
131 + se.getMessage();
132
133
134 if ( se.getCause() != null )
135 {
136 msg += "\n Nested exception:" + "\n " + se.getCause().getMessage();
137 }
138
139
140 if ( LOGGER.isErrorEnabled() )
141 {
142 LOGGER.error( msg );
143 }
144 throw se;
145 }
146 }
147
148 static Commandline buildCmd( File workingDir, String[] cmdAndArgs )
149 throws ScmException
150 {
151 Commandline cmd = new Commandline();
152 cmd.setExecutable( HgCommandConstants.EXEC );
153 cmd.addArguments( cmdAndArgs );
154 if ( workingDir != null )
155 {
156 cmd.setWorkingDirectory( workingDir.getAbsolutePath() );
157
158 if ( !workingDir.exists() )
159 {
160 boolean success = workingDir.mkdirs();
161 if ( !success )
162 {
163 String msg = "Working directory did not exist" + " and it couldn't be created: " + workingDir;
164 throw new ScmException( msg );
165 }
166 }
167 }
168 return cmd;
169 }
170
171 static int executeCmd( HgConsumer consumer, Commandline cmd )
172 throws ScmException
173 {
174 final int exitCode;
175 try
176 {
177 exitCode = CommandLineUtils.executeCommandLine( cmd, consumer, consumer );
178 }
179 catch ( CommandLineException ex )
180 {
181 throw new ScmException( "Command could not be executed: " + cmd, ex );
182 }
183 return exitCode;
184 }
185
186 public static ScmResult execute( File workingDir, String[] cmdAndArgs )
187 throws ScmException
188 {
189 return execute( new HgConsumer(), workingDir, cmdAndArgs );
190 }
191
192 public static String[] expandCommandLine( String[] cmdAndArgs, ScmFileSet additionalFiles )
193 {
194 List<File> filesList = additionalFiles.getFileList();
195 String[] cmd = new String[filesList.size() + cmdAndArgs.length];
196
197
198 System.arraycopy( cmdAndArgs, 0, cmd, 0, cmdAndArgs.length );
199
200
201 int i = 0;
202 for ( File scmFile : filesList )
203 {
204 String file = scmFile.getPath().replace( '\\', File.separatorChar );
205 cmd[i + cmdAndArgs.length] = file;
206 i++;
207 }
208
209 return cmd;
210 }
211
212 public static int getCurrentRevisionNumber( File workingDir )
213 throws ScmException
214 {
215
216 String[] revCmd = new String[]{ HgCommandConstants.REVNO_CMD };
217 HgRevNoConsumer consumer = new HgRevNoConsumer();
218 HgUtils.execute( consumer, workingDir, revCmd );
219
220 return consumer.getCurrentRevisionNumber();
221 }
222
223 public static String getCurrentBranchName( File workingDir )
224 throws ScmException
225 {
226 String[] branchnameCmd = new String[]{ HgCommandConstants.BRANCH_NAME_CMD };
227 HgBranchnameConsumer consumer = new HgBranchnameConsumer();
228 HgUtils.execute( consumer, workingDir, branchnameCmd );
229 return consumer.getBranchName();
230 }
231
232
233
234
235
236
237 private static class HgRevNoConsumer
238 extends HgConsumer
239 {
240
241 private int revNo;
242
243 public void doConsume( ScmFileStatus status, String line )
244 {
245 try
246 {
247 revNo = Integer.valueOf( line ).intValue();
248 }
249 catch ( NumberFormatException e )
250 {
251
252 }
253 }
254
255 int getCurrentRevisionNumber()
256 {
257 return revNo;
258 }
259 }
260
261
262
263
264 private static class HgBranchnameConsumer
265 extends HgConsumer
266 {
267
268 private String branchName;
269
270 public void doConsume( ScmFileStatus status, String trimmedLine )
271 {
272 branchName = String.valueOf( trimmedLine );
273 }
274
275 String getBranchName()
276 {
277 return branchName;
278 }
279
280
281 public void consumeLine( String line )
282 {
283 if ( logger.isDebugEnabled() )
284 {
285 logger.debug( line );
286 }
287 String trimmedLine = line.trim();
288
289 doConsume( null, trimmedLine );
290 }
291 }
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307 public static boolean differentOutgoingBranchFound( File workingDir, String workingbranchName )
308 throws ScmException
309 {
310 String[] outCmd = new String[]{ HgCommandConstants.OUTGOING_CMD };
311 HgOutgoingConsumer outConsumer = new HgOutgoingConsumer();
312 ScmResult outResult = HgUtils.execute( outConsumer, workingDir, outCmd );
313 List<HgChangeSet> changes = outConsumer.getChanges();
314 if ( outResult.isSuccess() )
315 {
316 for ( HgChangeSet set : changes )
317 {
318 if ( !getBranchName( workingbranchName ).equals( getBranchName( set.getBranch() ) ) )
319 {
320 LOGGER.warn( "A different branch than " + getBranchName( workingbranchName )
321 + " was found in outgoing changes, branch name was " + getBranchName( set.getBranch() )
322 + ". Only local branch named " + getBranchName( workingbranchName ) + " will be pushed." );
323 return true;
324 }
325 }
326 }
327 return false;
328 }
329
330 private static String getBranchName( String branch )
331 {
332 return branch == null ? DEFAULT : branch;
333 }
334
335 public static String maskPassword( Commandline cl )
336 {
337 String clString = cl.toString();
338
339 int pos = clString.indexOf( '@' );
340
341 if ( pos > 0 )
342 {
343 clString = clString.replaceAll( ":\\w+@", ":*****@" );
344 }
345
346 return clString;
347 }
348 }