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