1 package org.apache.maven.scm.provider.cvslib.cvsjava.util;
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.log.ScmLogger;
23 import org.codehaus.plexus.util.StringUtils;
24 import org.codehaus.plexus.util.cli.CommandLineUtils;
25 import org.netbeans.lib.cvsclient.CVSRoot;
26 import org.netbeans.lib.cvsclient.Client;
27 import org.netbeans.lib.cvsclient.admin.StandardAdminHandler;
28 import org.netbeans.lib.cvsclient.command.Command;
29 import org.netbeans.lib.cvsclient.command.CommandAbortedException;
30 import org.netbeans.lib.cvsclient.command.CommandException;
31 import org.netbeans.lib.cvsclient.command.GlobalOptions;
32 import org.netbeans.lib.cvsclient.commandLine.CommandFactory;
33 import org.netbeans.lib.cvsclient.commandLine.GetOpt;
34 import org.netbeans.lib.cvsclient.connection.AbstractConnection;
35 import org.netbeans.lib.cvsclient.connection.AuthenticationException;
36 import org.netbeans.lib.cvsclient.connection.Connection;
37 import org.netbeans.lib.cvsclient.connection.ConnectionFactory;
38 import org.netbeans.lib.cvsclient.connection.PServerConnection;
39 import org.netbeans.lib.cvsclient.connection.StandardScrambler;
40 import org.netbeans.lib.cvsclient.event.CVSListener;
41
42 import java.io.BufferedReader;
43 import java.io.File;
44 import java.io.FileReader;
45 import java.io.IOException;
46
47
48
49
50
51
52
53 public class CvsConnection
54 {
55
56
57
58
59 @SuppressWarnings( "unused" )
60 private String repository;
61
62
63
64
65 private String localPath;
66
67
68
69
70 private Connection connection;
71
72
73
74
75 private Client client;
76
77
78
79
80
81 private GlobalOptions globalOptions;
82
83 private CvsConnection()
84 {
85 }
86
87
88
89
90
91
92
93 public boolean executeCommand( Command command )
94 throws CommandException, AuthenticationException
95 {
96 return client.executeCommand( command, globalOptions );
97 }
98
99 public void setRepository( String repository )
100 {
101 this.repository = repository;
102 }
103
104 public void setLocalPath( String localPath )
105 {
106 this.localPath = localPath;
107 }
108
109 public void setGlobalOptions( GlobalOptions globalOptions )
110 {
111 this.globalOptions = globalOptions;
112 }
113
114
115
116
117 private void connect( CVSRoot root, String password )
118 throws AuthenticationException, CommandAbortedException
119 {
120 if ( CVSRoot.METHOD_EXT.equals( root.getMethod() ) )
121 {
122 String cvsRsh = System.getProperty( "maven.scm.cvs.java.cvs_rsh" );
123 if ( cvsRsh == null )
124 {
125 try
126 {
127 cvsRsh = CommandLineUtils.getSystemEnvVars().getProperty( "CVS_RSH" );
128 }
129 catch ( IOException e )
130 {
131
132 }
133 }
134
135 if ( cvsRsh != null )
136 {
137 if ( cvsRsh.indexOf( ' ' ) < 0 )
138 {
139
140
141 String username = root.getUserName();
142 if ( username == null )
143 {
144 username = System.getProperty( "user.name" );
145 }
146
147 cvsRsh += " " + username + "@" + root.getHostName() + " cvs server";
148 }
149
150 AbstractConnection conn = new org.netbeans.lib.cvsclient.connection.ExtConnection( cvsRsh );
151 conn.setRepository( root.getRepository() );
152 connection = conn;
153 }
154 else
155 {
156 connection = new ExtConnection( root );
157 }
158 }
159 else
160 {
161 connection = ConnectionFactory.getConnection( root );
162 if ( CVSRoot.METHOD_PSERVER.equals( root.getMethod() ) )
163 {
164 ( (PServerConnection) connection ).setEncodedPassword( password );
165 }
166 }
167 connection.open();
168
169 client = new Client( connection, new StandardAdminHandler() );
170 client.setLocalPath( localPath );
171 }
172
173 private void disconnect()
174 {
175 if ( connection != null && connection.isOpen() )
176 {
177 try
178 {
179 connection.close();
180 }
181 catch ( IOException e )
182 {
183
184 }
185 }
186 }
187
188 private void addListener( CVSListener listener )
189 {
190 if ( client != null )
191 {
192
193 client.getEventManager().addCVSListener( listener );
194 }
195 }
196
197
198
199
200
201
202
203 private static String getCVSRoot( String workingDir )
204 {
205 String root = null;
206 BufferedReader r = null;
207 if ( workingDir == null )
208 {
209 workingDir = System.getProperty( "user.dir" );
210 }
211 try
212 {
213 File f = new File( workingDir );
214 File rootFile = new File( f, "CVS/Root" );
215 if ( rootFile.exists() )
216 {
217 r = new BufferedReader( new FileReader( rootFile ) );
218 root = r.readLine();
219 }
220 }
221 catch ( IOException e )
222 {
223
224 }
225 finally
226 {
227 try
228 {
229 if ( r != null )
230 {
231 r.close();
232 }
233 }
234 catch ( IOException e )
235 {
236 System.err.println( "Warning: could not close CVS/Root file!" );
237 }
238 }
239 if ( root == null )
240 {
241 root = System.getProperty( "cvs.root" );
242 }
243 return root;
244 }
245
246
247
248
249
250
251
252
253 private static int processGlobalOptions( String[] args, GlobalOptions globalOptions )
254 {
255 final String getOptString = globalOptions.getOptString();
256 GetOpt go = new GetOpt( args, getOptString );
257 int ch;
258 while ( ( ch = go.getopt() ) != GetOpt.optEOF )
259 {
260
261
262 String arg = go.optArgGet();
263 boolean success = globalOptions.setCVSCommand( (char) ch, arg );
264 if ( !success )
265 {
266 throw new IllegalArgumentException( "Failed to set CVS Command: -" + ch + " = " + arg );
267 }
268 }
269
270 return go.optIndexGet();
271 }
272
273
274
275
276
277
278
279
280 private static String lookupPassword( String cvsRoot, ScmLogger logger )
281 {
282 File passFile = new File( System.getProperty( "cygwin.user.home", System.getProperty( "user.home" ) ) + File
283 .separatorChar + ".cvspass" );
284
285 BufferedReader reader = null;
286 String password = null;
287
288 try
289 {
290 reader = new BufferedReader( new FileReader( passFile ) );
291 password = processCvspass( cvsRoot, reader );
292 }
293 catch ( IOException e )
294 {
295 if ( logger.isWarnEnabled() )
296 {
297 logger.warn( "Could not read password for '" + cvsRoot + "' from '" + passFile + "'", e );
298 }
299 return null;
300 }
301 finally
302 {
303 if ( reader != null )
304 {
305 try
306 {
307 reader.close();
308 }
309 catch ( IOException e )
310 {
311 if ( logger.isErrorEnabled() )
312 {
313 logger.error( "Warning: could not close password file." );
314 }
315 }
316 }
317 }
318 if ( password == null )
319 {
320 if ( logger.isErrorEnabled() )
321 {
322 logger.error( "Didn't find password for CVSROOT '" + cvsRoot + "'." );
323 }
324 }
325 return password;
326 }
327
328
329
330
331
332
333
334
335
336
337 static String processCvspass( String cvsRoot, BufferedReader reader )
338 throws IOException
339 {
340 String line;
341 String password = null;
342 while ( ( line = reader.readLine() ) != null )
343 {
344 if ( line.startsWith( "/" ) )
345 {
346 String[] cvspass = StringUtils.split( line, " " );
347 String cvspassRoot = cvspass[1];
348 if ( compareCvsRoot( cvsRoot, cvspassRoot ) )
349 {
350 int index = line.indexOf( cvspassRoot ) + cvspassRoot.length() + 1;
351 password = line.substring( index );
352 break;
353 }
354 }
355 else if ( line.startsWith( cvsRoot ) )
356 {
357 password = line.substring( cvsRoot.length() + 1 );
358 break;
359 }
360 }
361 return password;
362 }
363
364 static boolean compareCvsRoot( String cvsRoot, String target )
365 {
366 String s1 = completeCvsRootPort( cvsRoot );
367 String s2 = completeCvsRootPort( target );
368 return s1 != null && s1.equals( s2 );
369
370 }
371
372 private static String completeCvsRootPort( String cvsRoot )
373 {
374 String result = cvsRoot;
375 int idx = cvsRoot.indexOf( ':' );
376 for ( int i = 0; i < 2 && idx != -1; i++ )
377 {
378 idx = cvsRoot.indexOf( ':', idx + 1 );
379 }
380 if ( idx != -1 && cvsRoot.charAt( idx + 1 ) == '/' )
381 {
382 StringBuilder sb = new StringBuilder();
383 sb.append( cvsRoot.substring( 0, idx + 1 ) );
384 sb.append( "2401" );
385 sb.append( cvsRoot.substring( idx + 1 ) );
386 result = sb.toString();
387 }
388 return result;
389
390 }
391
392
393
394
395
396
397
398
399 public static boolean processCommand( String[] args, String localPath, CVSListener listener, ScmLogger logger )
400 throws Exception
401 {
402
403
404
405 GlobalOptions globalOptions = new GlobalOptions();
406 globalOptions.setCVSRoot( getCVSRoot( localPath ) );
407
408
409
410 int commandIndex;
411
412 try
413 {
414 commandIndex = processGlobalOptions( args, globalOptions );
415 }
416 catch ( IllegalArgumentException e )
417 {
418 if ( logger.isErrorEnabled() )
419 {
420 logger.error( "Invalid argument: " + e );
421 }
422 return false;
423 }
424
425
426 if ( globalOptions.getCVSRoot() == null )
427 {
428 if ( logger.isErrorEnabled() )
429 {
430 logger.error( "No CVS root is set. Check your <repository> information in the POM." );
431 }
432 return false;
433 }
434
435
436 CVSRoot root;
437 final String cvsRoot = globalOptions.getCVSRoot();
438 try
439 {
440 root = CVSRoot.parse( cvsRoot );
441 }
442 catch ( IllegalArgumentException e )
443 {
444 if ( logger.isErrorEnabled() )
445 {
446 logger.error( "Incorrect format for CVSRoot: " + cvsRoot + "\nThe correct format is: "
447 + "[:method:][[user][:password]@][hostname:[port]]/path/to/repository"
448 + "\nwhere \"method\" is pserver." );
449 }
450 return false;
451 }
452
453 final String command = args[commandIndex];
454
455
456
457
458 Command c;
459 try
460 {
461 c = CommandFactory.getDefault().createCommand( command, args, ++commandIndex, globalOptions, localPath );
462 }
463 catch ( IllegalArgumentException e )
464 {
465 if ( logger.isErrorEnabled() )
466 {
467 logger.error( "Illegal argument: " + e.getMessage() );
468 }
469 return false;
470 }
471
472 String password = null;
473
474 if ( CVSRoot.METHOD_PSERVER.equals( root.getMethod() ) )
475 {
476 password = root.getPassword();
477 if ( password != null )
478 {
479 password = StandardScrambler.getInstance().scramble( password );
480 }
481 else
482 {
483 password = lookupPassword( cvsRoot, logger );
484 if ( password == null )
485 {
486 password = StandardScrambler.getInstance().scramble( "" );
487
488 }
489 }
490 }
491 CvsConnection cvsCommand = new CvsConnection();
492 cvsCommand.setGlobalOptions( globalOptions );
493 cvsCommand.setRepository( root.getRepository() );
494
495
496
497 cvsCommand.setLocalPath( localPath );
498
499 cvsCommand.connect( root, password );
500 cvsCommand.addListener( listener );
501 if ( logger.isDebugEnabled() )
502 {
503 logger.debug( "Executing CVS command: " + c.getCVSCommand() );
504 }
505 boolean result = cvsCommand.executeCommand( c );
506 cvsCommand.disconnect();
507 return result;
508 }
509 }