001package org.apache.maven.scm.provider.synergy.util;
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 org.apache.maven.scm.ScmException;
023import org.apache.maven.scm.ScmVersion;
024import org.codehaus.plexus.util.StringUtils;
025import org.codehaus.plexus.util.cli.CommandLineUtils;
026import org.codehaus.plexus.util.cli.Commandline;
027
028import java.io.File;
029import java.io.IOException;
030import java.util.Calendar;
031import java.util.Iterator;
032import java.util.List;
033import java.util.Properties;
034
035/**
036 * This class contains methods to execute Synergy <code>ccm</code> command line.
037 *
038 * @author <a href="mailto:julien.henry@capgemini.com">Julien Henry</a>
039 *
040 */
041public class SynergyCCM
042{
043
044    private static final String CCM = "ccm";
045
046    private static final String BASELINE = "baseline";
047
048    private static final String CI = "ci";
049
050    private static final String CO = "co";
051
052    private static final String CREATE = "create";
053
054    private static final String DELETE = "delete";
055
056    private static final String DELIMITER = "delimiter";
057
058    private static final String DIR = "dir";
059
060    private static final String QUERY = "query";
061
062    private static final String RECONCILE = "rwa";
063
064    private static final String RECONFIGURE = "reconfigure";
065
066    private static final String RECONFIGURE_PROPERTIES = "reconfigure_properties";
067
068    private static final String START = "start";
069
070    private static final String STOP = "stop";
071
072    private static final String SYNC = "sync";
073
074    private static final String TASK = "task";
075
076    private static final String WA = "wa";
077
078    /**
079     * Create commandline for getting list of objects in a task.
080     *
081     * @param taskNumber Task number.
082     * @param format     Output format.
083     * @param ccmAddr
084     * @return the commandline.
085     * @throws ScmException
086     */
087    public static Commandline showTaskObjects( int taskNumber, String format, String ccmAddr )
088        throws ScmException
089    {
090        // Construct the CM Synergy command
091        Commandline cl = new Commandline();
092
093        configureEnvironment( cl, ccmAddr );
094
095        cl.setExecutable( CCM );
096
097        cl.createArg().setValue( TASK );
098        cl.createArg().setValue( "-show" );
099        cl.createArg().setValue( "objects" );
100
101        // Set up the output format
102        if ( format != null && !format.equals( "" ) )
103        {
104            cl.createArg().setValue( "-f" );
105            cl.createArg().setValue( format );
106        }
107
108        cl.createArg().setValue( Integer.toString( taskNumber ) );
109
110        return cl;
111    }
112
113    /**
114     * Create commandline for query.
115     *
116     * @param query    query.
117     * @param format   Output format
118     * @param ccmAddr
119     * @return the command line.
120     * @throws ScmException
121     */
122    public static Commandline query( String query, String format, String ccmAddr )
123        throws ScmException
124    {
125
126        // Construct the CM Synergy command
127        Commandline cl = new Commandline();
128
129        configureEnvironment( cl, ccmAddr );
130
131        cl.setExecutable( CCM );
132        cl.createArg().setValue( QUERY );
133
134        cl.createArg().setValue( "-u" );
135
136        // Set up the output format
137        if ( format != null && !format.equals( "" ) )
138        {
139            cl.createArg().setValue( "-f" );
140            cl.createArg().setValue( format );
141        }
142
143        cl.createArg().setValue( query );
144
145        return cl;
146    }
147
148    /**
149     * Create command line for creating a baseline.
150     *
151     * @param projectSpec project_name~project_version
152     * @param name        Name of the baseline
153     * @param release     the release.
154     * @param purpose     the purpose.
155     * @param ccmAddr
156     * @return the command line.
157     * @throws ScmException
158     */
159    public static Commandline createBaseline( String projectSpec, String name, String release, String purpose,
160                                              String ccmAddr )
161        throws ScmException
162    {
163        Commandline cl = new Commandline();
164
165        configureEnvironment( cl, ccmAddr );
166
167        cl.setExecutable( CCM );
168        cl.createArg().setValue( BASELINE );
169
170        cl.createArg().setValue( "-create" );
171        cl.createArg().setValue( name );
172
173        cl.createArg().setValue( "-p" );
174        cl.createArg().setValue( projectSpec );
175
176        cl.createArg().setValue( "-release" );
177        cl.createArg().setValue( release );
178
179        cl.createArg().setValue( "-purpose" );
180        cl.createArg().setValue( purpose );
181
182        return cl;
183
184    }
185
186    /**
187     * Create command line for adding a fileset to a project
188     *
189     * @param files    fileset.
190     * @param message  message log, or null if none.
191     * @param ccmAddr
192     * @return the command line.
193     * @throws ScmException
194     */
195    public static Commandline create( List<File> files, String message, String ccmAddr )
196        throws ScmException
197    {
198        Commandline cl = new Commandline();
199
200        configureEnvironment( cl, ccmAddr );
201
202        cl.setExecutable( CCM );
203        cl.createArg().setValue( CREATE );
204
205        if ( message != null && !message.equals( "" ) )
206        {
207
208            cl.createArg().setValue( "-c" );
209
210            cl.createArg().setValue( message );
211
212        }
213
214        for ( File f : files )
215        {
216            try
217            {
218                cl.createArg().setValue( f.getCanonicalPath() );
219            }
220            catch ( IOException e )
221            {
222                throw new ScmException( "Invalid file path " + f.toString(), e );
223            }
224        }
225
226        return cl;
227
228    }
229
230    /**
231     * Create command line for creating a task
232     *
233     * @param synopsis    synopsis.
234     * @param release     release.
235     * @param defaultTask default.
236     * @param ccmAddr
237     * @return the command line.
238     * @throws ScmException
239     */
240    public static Commandline createTask( String synopsis, String release, boolean defaultTask, String ccmAddr )
241        throws ScmException
242    {
243        Commandline cl = new Commandline();
244
245        configureEnvironment( cl, ccmAddr );
246
247        cl.setExecutable( CCM );
248        cl.createArg().setValue( TASK );
249
250        cl.createArg().setValue( "-create" );
251
252        cl.createArg().setValue( "-synopsis" );
253        cl.createArg().setValue( synopsis );
254
255        if ( release != null && !release.equals( "" ) )
256        {
257            cl.createArg().setValue( "-release" );
258            cl.createArg().setValue( release );
259        }
260
261        if ( defaultTask )
262        {
263            cl.createArg().setValue( "-default" );
264        }
265
266        cl.createArg().setValue( "-description" );
267        cl.createArg().setValue(
268            "This task was created by Maven SCM Synergy provider on " + Calendar.getInstance().getTime() );
269
270        return cl;
271
272    }
273
274    /**
275     * Create command line for checkin a task
276     *
277     * @param taskSpecs task_specs or default
278     * @param comment    comment.
279     * @param ccmAddr
280     * @return
281     * @throws ScmException
282     */
283    public static Commandline checkinTask( String taskSpecs, String comment, String ccmAddr )
284        throws ScmException
285    {
286        Commandline cl = new Commandline();
287
288        configureEnvironment( cl, ccmAddr );
289
290        cl.setExecutable( CCM );
291        cl.createArg().setValue( TASK );
292
293        cl.createArg().setValue( "-checkin" );
294
295        cl.createArg().setValue( taskSpecs );
296
297        cl.createArg().setValue( "-comment" );
298        cl.createArg().setValue( comment );
299
300        return cl;
301
302    }
303
304    /**
305     * Create command line for deleting file(s).
306     *
307     * @param files    fileset.
308     * @param ccmAddr
309     * @param replace  replace with previous version of file ?
310     * @return
311     * @throws ScmException
312     */
313    public static Commandline delete( List<File> files, String ccmAddr, boolean replace )
314        throws ScmException
315    {
316        Commandline cl = new Commandline();
317
318        configureEnvironment( cl, ccmAddr );
319
320        cl.setExecutable( CCM );
321        cl.createArg().setValue( DELETE );
322
323        if ( replace )
324        {
325            cl.createArg().setValue( "-replace" );
326        }
327
328        for ( File f : files )
329        {
330            try
331            {
332                cl.createArg().setValue( f.getCanonicalPath() );
333            }
334            catch ( IOException e )
335            {
336                throw new ScmException( "Invalid file path " + f.toString(), e );
337            }
338        }
339
340        return cl;
341
342    }
343
344    /**
345     * Create commandline to reconfigure a project.
346     *
347     * @param projectSpec
348     * @param ccmAddr
349     * @return the command line.
350     * @throws ScmException
351     */
352    public static Commandline reconfigure( String projectSpec, String ccmAddr )
353        throws ScmException
354    {
355        Commandline cl = new Commandline();
356
357        configureEnvironment( cl, ccmAddr );
358
359        cl.setExecutable( CCM );
360        cl.createArg().setValue( RECONFIGURE );
361
362        cl.createArg().setValue( "-recurse" );
363
364        if ( projectSpec != null )
365        {
366            cl.createArg().setValue( "-p" );
367            cl.createArg().setValue( projectSpec );
368        }
369
370        return cl;
371
372    }
373
374    /**
375     * Create commandline to reconfigure properties of a project.
376     *
377     * @param projectSpec
378     * @param ccmAddr
379     * @return
380     * @throws ScmException
381     */
382    public static Commandline reconfigureProperties( String projectSpec, String ccmAddr )
383        throws ScmException
384    {
385        Commandline cl = new Commandline();
386
387        configureEnvironment( cl, ccmAddr );
388
389        cl.setExecutable( CCM );
390        cl.createArg().setValue( RECONFIGURE_PROPERTIES );
391
392        cl.createArg().setValue( "-refresh" );
393        cl.createArg().setValue( projectSpec );
394
395        return cl;
396
397    }
398
399    /**
400     * Create command line to reconcile a project with uwa option.
401     *
402     * @param projectSpec
403     * @param ccmAddr
404     * @return
405     * @throws ScmException
406     */
407    public static Commandline reconcileUwa( String projectSpec, String ccmAddr )
408        throws ScmException
409    {
410        Commandline cl = new Commandline();
411
412        configureEnvironment( cl, ccmAddr );
413
414        cl.setExecutable( CCM );
415        cl.createArg().setValue( RECONCILE );
416
417        cl.createArg().setValue( "-r" );
418        cl.createArg().setValue( "-uwa" ); // Update wa from database
419
420        if ( projectSpec != null )
421        {
422            cl.createArg().setValue( "-p" );
423            cl.createArg().setValue( projectSpec );
424        }
425
426        return cl;
427
428    }
429
430    /**
431     * Create command line to reconcile a project with udb option.
432     *
433     * @param projectSpec
434     * @param ccmAddr
435     * @return
436     * @throws ScmException
437     */
438    public static Commandline reconcileUdb( String projectSpec, String ccmAddr )
439        throws ScmException
440    {
441        Commandline cl = new Commandline();
442
443        configureEnvironment( cl, ccmAddr );
444
445        cl.setExecutable( CCM );
446        cl.createArg().setValue( RECONCILE );
447
448        cl.createArg().setValue( "-r" );
449        cl.createArg().setValue( "-udb" ); // Update database from wa
450
451        if ( projectSpec != null )
452        {
453            cl.createArg().setValue( "-p" );
454            cl.createArg().setValue( projectSpec );
455        }
456
457        return cl;
458
459    }
460
461    /**
462     * Create command line to perform a dir on the directory.
463     *
464     * @param directory
465     * @param format    Output format.
466     * @param ccmAddr
467     * @return
468     * @throws ScmException
469     */
470    public static Commandline dir( File directory, String format, String ccmAddr )
471        throws ScmException
472    {
473        Commandline cl = new Commandline();
474
475        configureEnvironment( cl, ccmAddr );
476
477        try
478        {
479            cl.setWorkingDirectory( directory.getCanonicalPath() );
480        }
481        catch ( IOException e )
482        {
483            throw new ScmException( "Invalid directory", e );
484        }
485
486        cl.setExecutable( CCM );
487        cl.createArg().setValue( DIR );
488        cl.createArg().setValue( "-m" );
489
490        // Set up the output format
491        if ( format != null && !format.equals( "" ) )
492        {
493            cl.createArg().setValue( "-f" );
494            cl.createArg().setValue( format );
495        }
496
497        return cl;
498
499    }
500
501    /**
502     * Create commandline to checkout a fileset.
503     *
504     * @param files    fileset.
505     * @param ccmAddr
506     * @return the command line.
507     * @throws ScmException
508     */
509    public static Commandline checkoutFiles( List<File> files, String ccmAddr )
510        throws ScmException
511    {
512        Commandline cl = new Commandline();
513
514        configureEnvironment( cl, ccmAddr );
515
516        cl.setExecutable( CCM );
517        cl.createArg().setValue( CO );
518
519        for ( File f : files )
520        {
521            try
522            {
523                cl.createArg().setValue( f.getCanonicalPath() );
524            }
525            catch ( IOException e )
526            {
527                throw new ScmException( "Invalid file path " + f.toString(), e );
528            }
529        }
530
531        return cl;
532    }
533
534    /**
535     * Create commandline to checkout a project
536     *
537     * @param directory    target WA, or null if using default directory
538     * @param projectSpec
539     * @param version      new version of the project, or null if using default Synergy
540     *                     mecanism
541     * @param ccmAddr
542     * @return
543     * @throws ScmException
544     */
545    public static Commandline checkoutProject( File directory, String projectSpec, ScmVersion version, String purpose,
546                                               String release, String ccmAddr )
547        throws ScmException
548    {
549        Commandline cl = new Commandline();
550
551        configureEnvironment( cl, ccmAddr );
552
553        cl.setExecutable( CCM );
554        cl.createArg().setValue( CO );
555        cl.createArg().setValue( "-subprojects" ); // Checkout sub-projects
556        cl.createArg().setValue( "-rel" ); // Relative
557
558        if ( version != null && StringUtils.isNotEmpty( version.getName() ) )
559        {
560            cl.createArg().setValue( "-t" ); // Version
561            cl.createArg().setValue( version.getName() );
562        }
563
564        if ( purpose != null && !purpose.equals( "" ) )
565        {
566            cl.createArg().setValue( "-purpose" );
567            cl.createArg().setValue( purpose );
568        }
569
570        if ( release != null && !release.equals( "" ) )
571        {
572            cl.createArg().setValue( "-release" );
573            cl.createArg().setValue( release );
574        }
575
576        if ( directory != null )
577        {
578            cl.createArg().setValue( "-path" );
579            try
580            {
581                cl.createArg().setValue( directory.getCanonicalPath() );
582            }
583            catch ( IOException e )
584            {
585                throw new ScmException( "Invalid directory", e );
586            }
587        }
588        cl.createArg().setValue( "-p" );
589        cl.createArg().setValue( projectSpec );
590
591        return cl;
592    }
593
594    /**
595     * Create commandline to checkin a project
596     *
597     * @param projectSpec
598     * @param comment
599     * @param ccmAddr
600     * @return
601     * @throws ScmException
602     */
603    public static Commandline checkinProject( String projectSpec, String comment, String ccmAddr )
604        throws ScmException
605    {
606        Commandline cl = new Commandline();
607
608        configureEnvironment( cl, ccmAddr );
609
610        cl.setExecutable( CCM );
611        cl.createArg().setValue( CI );
612        if ( comment != null && !comment.equals( "" ) )
613        {
614            cl.createArg().setValue( "-c" );
615            cl.createArg().setValue( comment );
616        }
617        cl.createArg().setValue( "-p" );
618        cl.createArg().setValue( projectSpec );
619
620        return cl;
621    }
622
623    /**
624     * Create commandline to checkin a fileset
625     *
626     * @param files    fileset.
627     * @param comment
628     * @param ccmAddr
629     * @return
630     * @throws ScmException
631     */
632    public static Commandline checkinFiles( List<File> files, String comment, String ccmAddr )
633        throws ScmException
634    {
635        Commandline cl = new Commandline();
636
637        configureEnvironment( cl, ccmAddr );
638
639        cl.setExecutable( CCM );
640        cl.createArg().setValue( CI );
641        if ( comment != null && !comment.equals( "" ) )
642        {
643            cl.createArg().setValue( "-c" );
644            cl.createArg().setValue( comment );
645        }
646
647        if ( files.size() > 0 )
648        {
649            for ( File f : files )
650            {
651                try
652                {
653                    cl.createArg().setValue( f.getCanonicalPath() );
654                }
655                catch ( IOException e )
656                {
657                    throw new ScmException( "Invalid file path " + f.toString(), e );
658                }
659            }
660        }
661        return cl;
662    }
663
664    /**
665     * Create commandline to synchronize a project
666     *
667     * @param projectSpec
668     * @param ccmAddr
669     * @return
670     * @throws ScmException
671     */
672    public static Commandline synchronize( String projectSpec, String ccmAddr )
673        throws ScmException
674    {
675        Commandline cl = new Commandline();
676
677        configureEnvironment( cl, ccmAddr );
678
679        cl.setExecutable( CCM );
680        cl.createArg().setValue( SYNC );
681        cl.createArg().setValue( "-r" ); // Recursive
682        cl.createArg().setValue( "-p" );
683        cl.createArg().setValue( projectSpec );
684
685        return cl;
686    }
687
688    /**
689     * Create commandline to get workarea informations for a given project.
690     *
691     * @param projectSpec
692     * @param ccmAddr
693     * @return
694     * @throws ScmException
695     */
696    public static Commandline showWorkArea( String projectSpec, String ccmAddr )
697        throws ScmException
698    {
699        Commandline cl = new Commandline();
700
701        configureEnvironment( cl, ccmAddr );
702
703        cl.setExecutable( CCM );
704        cl.createArg().setValue( WA );
705        cl.createArg().setValue( "-show" );
706        cl.createArg().setValue( projectSpec );
707
708        return cl;
709    }
710
711    /**
712     * Create commandline to stop a Synergy session
713     *
714     * @param ccmAddr
715     * @return
716     * @throws ScmException
717     */
718    public static Commandline stop( String ccmAddr )
719        throws ScmException
720    {
721        Commandline cl = new Commandline();
722
723        configureEnvironment( cl, ccmAddr );
724
725        cl.setExecutable( CCM );
726        cl.createArg().setValue( STOP );
727
728        return cl;
729    }
730
731    /**
732     * Configure a commandline to use environment variables ($PATH)
733     *
734     * @param cl
735     * @param ccmAddr
736     * @throws ScmException
737     */
738    private static void configureEnvironment( Commandline cl, String ccmAddr )
739        throws ScmException
740    {
741        // We need PATH to be set for using CCM
742        try
743        {
744            Properties envVars = CommandLineUtils.getSystemEnvVars();
745
746            for ( @SuppressWarnings( "rawtypes" )
747            Iterator i = envVars.keySet().iterator(); i.hasNext(); )
748            {
749                String key = (String) i.next();
750
751                if ( !key.equalsIgnoreCase( "CCM_ADDR" ) )
752                {
753
754                    cl.addEnvironment( key, envVars.getProperty( key ) );
755
756                }
757            }
758        }
759        catch ( Exception e1 )
760        {
761            throw new ScmException( "Fail to add PATH environment variable.", e1 );
762
763        }
764        cl.addEnvironment( "CCM_ADDR", ccmAddr );
765
766    }
767
768    /**
769     * Create commandline to start a Synergy session
770     *
771     * @param username
772     * @param password
773     * @param role
774     * @return
775     * @throws ScmException
776     */
777    public static Commandline start( String username, String password, SynergyRole role )
778        throws ScmException
779    {
780        Commandline cl = new Commandline();
781
782        cl.setExecutable( CCM );
783        cl.createArg().setValue( START );
784        cl.createArg().setValue( "-nogui" );
785        cl.createArg().setValue( "-m" ); // Multissesion
786        cl.createArg().setValue( "-q" ); // Quiet (return only CCM_ADDR)
787        cl.createArg().setValue( "-n" );
788        cl.createArg().setValue( username );
789        cl.createArg().setValue( "-pw" );
790        cl.createArg().setValue( password );
791        if ( role != null )
792        {
793            cl.createArg().setValue( "-r" );
794            cl.createArg().setValue( role.toString() );
795        }
796
797        return cl;
798    }
799
800    /**
801     * Create commandline to start a  remote Synergy session
802     *
803     * @param username
804     * @param password
805     * @param role
806     * @return
807     * @throws ScmException
808     */
809    public static Commandline startRemote( String username, String password, SynergyRole role )
810        throws ScmException
811    {
812        Commandline cl = new Commandline();
813
814        cl.setExecutable( CCM );
815        cl.createArg().setValue( START );
816        cl.createArg().setValue( "-nogui" );
817        cl.createArg().setValue( "-m" ); // Multissesion
818        cl.createArg().setValue( "-q" ); // Quiet (return only CCM_ADDR)
819        cl.createArg().setValue( "-rc" ); //Remote client
820        cl.createArg().setValue( "-n" );
821        cl.createArg().setValue( username );
822        cl.createArg().setValue( "-pw" );
823        cl.createArg().setValue( password );
824        if ( role != null )
825        {
826            cl.createArg().setValue( "-r" );
827            cl.createArg().setValue( role.toString() );
828        }
829
830        return cl;
831    }
832    
833    /**
834     * Create commandline to get Synergy database delimiter
835     *
836     * @return
837     * @throws ScmException
838     */
839    public static Commandline delimiter( String ccmAddr )
840        throws ScmException
841    {
842        Commandline cl = new Commandline();
843
844        configureEnvironment( cl, ccmAddr );
845
846        cl.setExecutable( CCM );
847        cl.createArg().setValue( DELIMITER );
848
849        return cl;
850    }
851    
852    /**
853     * Create commandline to get current (i.e. default) task
854     * 
855     * @param ccmAddr current Synergy session ID
856     * @return 
857     * @throws ScmException
858     */
859    public static Commandline showDefaultTask( String ccmAddr ) 
860        throws ScmException
861    {
862        Commandline cl = new Commandline();
863
864        configureEnvironment( cl, ccmAddr );
865        cl.setExecutable( CCM );
866        cl.createArg().setValue( TASK );
867        cl.createArg().setValue( "-default" );
868        
869        return cl;
870    }
871    
872    /**
873     * Create commandline to set current (i.e. default) task
874     * 
875     * @param task      the number of the task to set as current task
876     * @param ccmAddr current Synergy session ID
877     * @return 
878     * @throws ScmException
879     */
880    public static Commandline setDefaultTask( int task, String ccmAddr ) 
881        throws ScmException
882    {
883        Commandline cl = new Commandline();
884
885        configureEnvironment( cl, ccmAddr );
886        cl.setExecutable( CCM );
887        cl.createArg().setValue( TASK );
888        cl.createArg().setValue( "-default" );
889        cl.createArg().setValue( String.valueOf( task ) );
890        return cl;
891    }
892}