1 package org.apache.maven.scm.provider.accurev.cli;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.ByteArrayInputStream;
23 import java.io.File;
24 import java.io.InputStream;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.regex.Pattern;
32
33 import org.apache.maven.scm.command.blame.BlameLine;
34 import org.apache.maven.scm.log.ScmLogger;
35 import org.apache.maven.scm.provider.accurev.AccuRev;
36 import org.apache.maven.scm.provider.accurev.AccuRevException;
37 import org.apache.maven.scm.provider.accurev.AccuRevInfo;
38 import org.apache.maven.scm.provider.accurev.AccuRevStat;
39 import org.apache.maven.scm.provider.accurev.AccuRevVersion;
40 import org.apache.maven.scm.provider.accurev.CategorisedElements;
41 import org.apache.maven.scm.provider.accurev.FileDifference;
42 import org.apache.maven.scm.provider.accurev.Stream;
43 import org.apache.maven.scm.provider.accurev.Transaction;
44 import org.apache.maven.scm.provider.accurev.WorkSpace;
45 import org.codehaus.plexus.util.Os;
46 import org.codehaus.plexus.util.StringUtils;
47 import org.codehaus.plexus.util.cli.CommandLineException;
48 import org.codehaus.plexus.util.cli.CommandLineUtils;
49 import org.codehaus.plexus.util.cli.Commandline;
50 import org.codehaus.plexus.util.cli.StreamConsumer;
51
52
53
54
55 public class AccuRevCommandLine
56 implements AccuRev
57 {
58
59 private static final String[] EMPTY_STRING_ARRAY = new String[] {};
60
61 private static final File CURRENT_DIR = new File( "." );
62
63 private ScmLogger logger;
64
65 private Commandline cl = new Commandline();
66
67 private StringBuilder commandLines = new StringBuilder();
68
69 private StringBuilder errorOutput = new StringBuilder();
70
71 private StreamConsumer systemErr;
72
73 private String[] hostArgs = EMPTY_STRING_ARRAY;
74
75 private String[] authArgs = EMPTY_STRING_ARRAY;
76
77 private String executable = "accurev";
78
79 private long executableModTime;
80
81 private String clientVersion;
82
83 public AccuRevCommandLine()
84 {
85 super();
86 reset();
87 }
88
89 public AccuRevCommandLine( String host, int port )
90 {
91 this();
92 setServer( host, port );
93 }
94
95 public void setServer( String host, int port )
96 {
97
98 if ( host != null )
99 {
100 hostArgs = new String[] { "-H", host + ":" + port };
101 }
102 else
103 {
104 hostArgs = EMPTY_STRING_ARRAY;
105 }
106
107 }
108
109 public void setExecutable( String accuRevExe )
110 {
111
112 executable = accuRevExe;
113 reset();
114 }
115
116 private boolean executeCommandLine( File basedir, String[] args, Iterable<File> elements, Pattern matchPattern,
117 List<File> matchedFiles )
118 throws AccuRevException
119 {
120
121 FileConsumer stdoutConsumer = new FileConsumer( matchedFiles, matchPattern );
122
123 return executeCommandLine( basedir, args, elements, stdoutConsumer );
124 }
125
126 private boolean executeCommandLine( File basedir, String[] args, Iterable<File> elements,
127 StreamConsumer stdoutConsumer )
128 throws AccuRevException
129 {
130
131 setWorkingDirectory( basedir );
132 setCommandLineArgs( args );
133
134 if ( elements != null )
135 {
136 for ( File file : elements )
137 {
138 String path = file.getPath();
139
140 if ( "\\.".equals( path ) )
141 {
142 path = "\\.\\";
143 }
144 cl.createArg().setValue( path );
145 }
146 }
147 return executeCommandLine( null, stdoutConsumer ) == 0;
148 }
149
150 private void setCommandLineArgs( String[] args )
151 {
152
153 cl.clearArgs();
154
155 if ( args.length > 0 )
156 {
157
158 cl.createArg().setValue( args[0] );
159
160
161 cl.addArguments( hostArgs );
162 cl.addArguments( authArgs );
163 }
164
165 for ( int i = 1; i < args.length; i++ )
166 {
167 cl.createArg().setValue( args[i] );
168 }
169
170 }
171
172 private boolean executeCommandLine( String[] args )
173 throws AccuRevException
174 {
175
176 return executeCommandLine( args, null, null ) == 0;
177 }
178
179 private int executeCommandLine( String[] args, InputStream stdin, StreamConsumer stdout )
180 throws AccuRevException
181 {
182
183 setCommandLineArgs( args );
184
185 return executeCommandLine( stdin, stdout );
186
187 }
188
189 private int executeCommandLine( InputStream stdin, StreamConsumer stdout )
190 throws AccuRevException
191 {
192
193 commandLines.append( cl.toString() );
194 commandLines.append( ';' );
195
196 if ( getLogger().isDebugEnabled() )
197 {
198 getLogger().debug( cl.toString() );
199 }
200 try
201 {
202
203 int result = executeCommandLine( cl, stdin, new CommandOutputConsumer( getLogger(), stdout ), systemErr );
204 if ( result != 0 )
205 {
206 getLogger().debug( "Non zero result - " + result );
207 }
208 return result;
209 }
210 catch ( CommandLineException ex )
211 {
212 throw new AccuRevException( "Error executing command " + cl.toString(), ex );
213 }
214
215 }
216
217
218
219
220
221
222
223
224
225
226 protected int executeCommandLine( Commandline cl, InputStream stdin, CommandOutputConsumer stdout,
227 StreamConsumer stderr )
228 throws CommandLineException
229 {
230
231 int result = CommandLineUtils.executeCommandLine( cl, stdin, stdout, stderr );
232 stdout.waitComplete();
233
234 return result;
235 }
236
237 protected Commandline getCommandline()
238 {
239
240 return cl;
241 }
242
243 public void reset()
244 {
245
246
247
248
249
250 cl = new Commandline();
251 commandLines = new StringBuilder();
252 errorOutput = new StringBuilder();
253 systemErr = new ErrorConsumer( getLogger(), errorOutput );
254 cl.getShell().setQuotedArgumentsEnabled( true );
255 cl.setExecutable( executable );
256
257 try
258 {
259 cl.addSystemEnvironment();
260 }
261 catch ( Exception e )
262 {
263 if ( getLogger().isDebugEnabled() )
264 {
265 getLogger().debug( "Unable to obtain system environment", e );
266 }
267 else
268 {
269 getLogger().warn( "Unable to obtain system environment" );
270 }
271 }
272 }
273
274
275
276
277 public boolean mkws( String basisStream, String workspaceName, File basedir )
278 throws AccuRevException
279 {
280
281 setWorkingDirectory( basedir );
282 String[] mkws = { "mkws", "-b", basisStream, "-w", workspaceName, "-l", basedir.getAbsolutePath() };
283
284 return executeCommandLine( mkws );
285 }
286
287
288
289
290 public List<File> update( File baseDir, String transactionId )
291 throws AccuRevException
292 {
293
294 if ( transactionId == null )
295 {
296 transactionId = "highest";
297 }
298 String[] update = { "update", "-t", transactionId };
299 setWorkingDirectory( baseDir );
300
301 List<File> updatedFiles = new ArrayList<File>();
302 int ret = executeCommandLine( update, null, new FileConsumer( updatedFiles, FileConsumer.UPDATE_PATTERN ) );
303 return ret == 0 ? updatedFiles : null;
304
305 }
306
307
308
309
310 public List<File> add( File basedir, List<File> elements, String message )
311 throws AccuRevException
312 {
313
314 if ( StringUtils.isBlank( message ) )
315 {
316 message = AccuRev.DEFAULT_ADD_MESSAGE;
317 }
318
319 boolean recursive = false;
320
321 if ( elements == null || elements.isEmpty() )
322 {
323 elements = Collections.singletonList( CURRENT_DIR );
324 recursive = true;
325 }
326 else if ( elements.size() == 1 && elements.toArray()[0].equals( CURRENT_DIR ) )
327 {
328 recursive = true;
329 }
330
331 List<File> addedFiles = new ArrayList<File>();
332 return executeCommandLine( basedir, new String[] { "add", "-c", message, recursive ? "-R" : null }, elements,
333 FileConsumer.ADD_PATTERN, addedFiles ) ? addedFiles : null;
334
335 }
336
337 public List<File> defunct( File basedir, List<File> files, String message )
338 throws AccuRevException
339 {
340
341 if ( StringUtils.isBlank( message ) )
342 {
343 message = AccuRev.DEFAULT_REMOVE_MESSAGE;
344 }
345
346 if ( files == null || files.isEmpty() )
347 {
348 files = Collections.singletonList( CURRENT_DIR );
349 }
350
351 ArrayList<File> defunctFiles = new ArrayList<File>();
352 return executeCommandLine( basedir, new String[] { "defunct", "-c", message }, files,
353 FileConsumer.DEFUNCT_PATTERN, defunctFiles ) ? defunctFiles : null;
354 }
355
356 public List<File> promote( File basedir, List<File> files, String message )
357 throws AccuRevException
358 {
359
360 if ( StringUtils.isBlank( message ) )
361 {
362 message = AccuRev.DEFAULT_PROMOTE_MESSAGE;
363 }
364 List<File> promotedFiles = new ArrayList<File>();
365 return executeCommandLine( basedir, new String[] { "promote", "-K", "-c", message }, files,
366 FileConsumer.PROMOTE_PATTERN, promotedFiles ) ? promotedFiles : null;
367
368 }
369
370 public String getCommandLines()
371 {
372
373 return commandLines.toString();
374 }
375
376 public String getErrorOutput()
377 {
378
379 return errorOutput.toString();
380 }
381
382 public void setLogger( ScmLogger logger )
383 {
384 this.logger = logger;
385 }
386
387 public ScmLogger getLogger()
388 {
389
390 return logger;
391 }
392
393 public boolean mkdepot( String depotName )
394 throws AccuRevException
395 {
396
397 String[] mkdepot = { "mkdepot", "-p", depotName };
398
399 return executeCommandLine( mkdepot );
400
401 }
402
403 public boolean mkstream( String backingStream, String newStreamName )
404 throws AccuRevException
405 {
406 String[] mkstream = { "mkstream", "-b", backingStream, "-s", newStreamName };
407 return executeCommandLine( mkstream );
408
409 }
410
411 public boolean promoteStream( String subStream, String commitMessage, List<File> promotedFiles )
412 throws AccuRevException
413 {
414 String[] promote = { "promote", "-s", subStream, "-d" };
415 return executeCommandLine( promote );
416
417 }
418
419
420
421
422 public List<File> promoteAll( File baseDir, String commitMessage )
423 throws AccuRevException
424 {
425 setWorkingDirectory( baseDir );
426 String[] promote = { "promote", "-p", "-K", "-c", commitMessage };
427
428 List<File> promotedFiles = new ArrayList<File>();
429 int ret = executeCommandLine( promote, null, new FileConsumer( promotedFiles, FileConsumer.PROMOTE_PATTERN ) );
430 return ret == 0 ? promotedFiles : null;
431 }
432
433 public AccuRevInfo info( File basedir )
434 throws AccuRevException
435 {
436
437 setWorkingDirectory( basedir );
438 String[] info = { "info" };
439 AccuRevInfo result = new AccuRevInfo( basedir );
440
441 executeCommandLine( info, null, new InfoConsumer( result ) );
442 return result;
443 }
444
445 private void setWorkingDirectory( File basedir )
446 {
447
448
449
450
451
452
453 if ( basedir == null )
454 {
455 cl.setWorkingDirectory( "." );
456 }
457 cl.setWorkingDirectory( basedir );
458 }
459
460 public boolean reactivate( String workSpaceName )
461 throws AccuRevException
462 {
463
464 String[] reactivate = { "reactivate", "wspace", workSpaceName };
465
466 return executeCommandLine( reactivate, null, new CommandOutputConsumer( getLogger(), null ) ) == 0;
467
468 }
469
470 public boolean rmws( String workSpaceName )
471 throws AccuRevException
472 {
473
474 String[] rmws = { "rmws", "-s", workSpaceName };
475
476 return executeCommandLine( rmws );
477
478 }
479
480 public String stat( File element )
481 throws AccuRevException
482 {
483
484 String[] stat = { "stat", "-fx", element.getAbsolutePath() };
485
486 StatConsumer statConsumer = new StatConsumer( getLogger() );
487 executeCommandLine( stat, null, statConsumer );
488 return statConsumer.getStatus();
489
490 }
491
492 public boolean chws( File basedir, String workSpaceName, String newBasisStream )
493 throws AccuRevException
494 {
495
496 setWorkingDirectory( basedir );
497 return executeCommandLine( new String[] { "chws", "-s", workSpaceName, "-b", newBasisStream, "-l", "." } );
498
499 }
500
501 public boolean mksnap( String snapShotName, String basisStream )
502 throws AccuRevException
503 {
504 return executeCommandLine( new String[] { "mksnap", "-s", snapShotName, "-b", basisStream, "-t", "now" } );
505 }
506
507 public List<File> statTag( String streamName )
508 throws AccuRevException
509 {
510
511 List<File> taggedFiles = new ArrayList<File>();
512 String[] stat = new String[] { "stat", "-a", "-ffl", "-s", streamName };
513 return executeCommandLine( null, stat, null, FileConsumer.STAT_PATTERN, taggedFiles ) ? taggedFiles : null;
514 }
515
516 public List<File> stat( File basedir, Collection<File> elements, AccuRevStat statType )
517 throws AccuRevException
518 {
519
520 boolean recursive = false;
521
522 if ( elements == null || elements.isEmpty() )
523 {
524 elements = Collections.singletonList( CURRENT_DIR );
525 recursive = true;
526 }
527 else if ( elements.size() == 1 && elements.toArray()[0].equals( CURRENT_DIR ) )
528 {
529 recursive = true;
530 }
531
532 String[] args = { "stat", "-ffr", statType.getStatArg(), recursive ? "-R" : null };
533
534 List<File> matchingElements = new ArrayList<File>();
535 boolean ret = executeCommandLine( basedir, args, elements, statType.getMatchPattern(), matchingElements );
536 return ret ? matchingElements : null;
537 }
538
539 public List<File> pop( File basedir, Collection<File> elements )
540 throws AccuRevException
541 {
542
543 if ( elements == null || elements.isEmpty() )
544 {
545 elements = Collections.singletonList( CURRENT_DIR );
546 }
547
548 String[] popws = { "pop", "-R" };
549
550 List<File> poppedFiles = new ArrayList<File>();
551 boolean ret = executeCommandLine( basedir, popws, elements, FileConsumer.POPULATE_PATTERN, poppedFiles );
552 return ret ? poppedFiles : null;
553 }
554
555 public List<File> popExternal( File basedir, String versionSpec, String tranSpec, Collection<File> elements )
556 throws AccuRevException
557 {
558
559 if ( elements == null || elements.isEmpty() )
560 {
561 elements = Collections.singletonList( new File( "/./" ) );
562 }
563
564 if ( StringUtils.isBlank( tranSpec ) )
565 {
566 tranSpec = "now";
567 }
568
569 String[] popArgs;
570 if ( AccuRevVersion.isNow( tranSpec ) )
571 {
572 popArgs = new String[] { "pop", "-v", versionSpec, "-L", basedir.getAbsolutePath(), "-R" };
573 }
574 else
575
576 {
577 popArgs = new String[] { "pop", "-v", versionSpec, "-L", basedir.getAbsolutePath(), "-t", tranSpec, "-R" };
578 }
579
580 List<File> poppedFiles = new ArrayList<File>();
581 boolean ret = executeCommandLine( basedir, popArgs, elements, FileConsumer.POPULATE_PATTERN, poppedFiles );
582 return ret ? poppedFiles : null;
583 }
584
585 public CategorisedElements statBackingStream( File basedir, Collection<File> elements )
586 throws AccuRevException
587 {
588
589 CategorisedElements catElems = new CategorisedElements();
590
591 if ( elements.isEmpty() )
592 {
593 return catElems;
594 }
595 String[] args = { "stat", "-b", "-ffr" };
596
597 boolean ret =
598 executeCommandLine( basedir, args, elements, new StatBackingConsumer( catElems.getMemberElements(),
599 catElems.getNonMemberElements() ) );
600 return ret ? catElems : null;
601
602 }
603
604 public List<Transaction> history( String baseStream, String fromTimeSpec, String toTimeSpec, int count,
605 boolean depotHistory, boolean transactionsOnly )
606 throws AccuRevException
607 {
608
609 String timeSpec = fromTimeSpec;
610
611 if ( toTimeSpec != null )
612 {
613 timeSpec = timeSpec + "-" + toTimeSpec;
614 }
615
616 if ( count > 0 )
617 {
618 timeSpec = timeSpec + "." + count;
619 }
620
621 String[] hist =
622 { "hist", transactionsOnly ? "-ftx" : "-fx", depotHistory ? "-p" : "-s", baseStream, "-t", timeSpec };
623
624 ArrayList<Transaction> transactions = new ArrayList<Transaction>();
625 HistoryConsumer stdout = new HistoryConsumer( getLogger(), transactions );
626 return executeCommandLine( hist, null, stdout ) == 0 ? transactions : null;
627 }
628
629 public List<FileDifference> diff( String baseStream, String fromTimeSpec, String toTimeSpec )
630 throws AccuRevException
631 {
632 String timeSpec = fromTimeSpec + "-" + toTimeSpec;
633 String[] diff = { "diff", "-fx", "-a", "-i", "-v", baseStream, "-V", baseStream, "-t", timeSpec };
634
635 List<FileDifference> results = new ArrayList<FileDifference>();
636 DiffConsumer stdout = new DiffConsumer( getLogger(), results );
637 return executeCommandLine( diff, null, stdout ) < 2 ? results : null;
638 }
639
640 public boolean login( String user, String password )
641 throws AccuRevException
642 {
643
644
645
646 cl.setWorkingDirectory( "." );
647 authArgs = EMPTY_STRING_ARRAY;
648 AuthTokenConsumer stdout = new AuthTokenConsumer();
649
650 boolean result;
651 if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
652 {
653 if ( StringUtils.isBlank( password ) )
654 {
655
656 password = "\"\"";
657 }
658 String[] login = { "login", "-A", user, password };
659 result = executeCommandLine( login, null, stdout ) == 0;
660 }
661 else
662 {
663 String[] login = { "login", "-A", user };
664 password = StringUtils.clean( password ) + "\n";
665 byte[] bytes = password.getBytes();
666 ByteArrayInputStream stdin = new ByteArrayInputStream( bytes );
667 result = executeCommandLine( login, stdin, stdout ) == 0;
668
669 }
670
671 authArgs = new String[] { "-A", stdout.getAuthToken() };
672 return result;
673 }
674
675 public boolean logout()
676 throws AccuRevException
677 {
678
679 String[] logout = { "logout" };
680 return executeCommandLine( logout );
681
682 }
683
684 public List<BlameLine> annotate( File basedir, File file )
685 throws AccuRevException
686 {
687
688 String[] annotate = { "annotate", "-ftud" };
689 List<BlameLine> lines = new ArrayList<BlameLine>();
690 AnnotateConsumer stdout = new AnnotateConsumer( lines, getLogger() );
691
692 return executeCommandLine( basedir, annotate, Collections.singletonList( file ), stdout ) ? lines : null;
693 }
694
695 public Map<String, WorkSpace> showRefTrees()
696 throws AccuRevException
697 {
698
699 String[] show = { "show", "-fx", "refs" };
700 Map<String, WorkSpace> refTrees = new HashMap<String, WorkSpace>();
701 WorkSpaceConsumer stdout = new WorkSpaceConsumer( getLogger(), refTrees );
702 return executeCommandLine( show, null, stdout ) == 0 ? refTrees : null;
703 }
704
705 public Map<String, WorkSpace> showWorkSpaces()
706 throws AccuRevException
707 {
708
709 String[] show = { "show", "-a", "-fx", "wspaces" };
710 Map<String, WorkSpace> workSpaces = new HashMap<String, WorkSpace>();
711 WorkSpaceConsumer stdout = new WorkSpaceConsumer( getLogger(), workSpaces );
712 return executeCommandLine( show, null, stdout ) == 0 ? workSpaces : null;
713 }
714
715 public Stream showStream( String stream )
716 throws AccuRevException
717 {
718 String[] show = { "show", "-s", stream, "-fx", "streams" };
719 List<Stream> streams = new ArrayList<Stream>();
720 StreamsConsumer stdout = new StreamsConsumer( getLogger(), streams );
721
722 return executeCommandLine( show, null, stdout ) == 0 && streams.size() == 1 ? streams.get( 0 ) : null;
723 }
724
725 public String getExecutable()
726 {
727
728 return executable;
729 }
730
731 public String getClientVersion()
732 throws AccuRevException
733 {
734
735 long lastModified = new File( getExecutable() ).lastModified();
736 if ( clientVersion == null || executableModTime != lastModified )
737 {
738 executableModTime = lastModified;
739
740 ClientVersionConsumer stdout = new ClientVersionConsumer();
741 executeCommandLine( new String[] {}, null, stdout );
742 clientVersion = stdout.getClientVersion();
743 }
744 return clientVersion;
745
746 }
747
748 public boolean syncReplica()
749 throws AccuRevException
750 {
751 return executeCommandLine( new String[] { "replica", "sync" } );
752 }
753
754 }