source: CMT/v1r20p20070208/source/cmt_cvs.cxx

Last change on this file was 295, checked in by garonne, 18 years ago

beta development 1

  • Property svn:eol-style set to native
File size: 63.7 KB
Line 
1//-----------------------------------------------------------
2// Copyright Christian Arnault LAL-Orsay CNRS
3// arnault@lal.in2p3.fr
4// Modified by: garonne@lal.in2p3.fr
5// See the complete license in cmt_license.txt "http://www.cecill.info".
6//-----------------------------------------------------------
7
8#include <stdlib.h>
9#include <stdio.h>
10
11#include "cmt.h"
12#include "cmt_cvs.h"
13#include "cmt_awk.h"
14#include "cmt_symbol.h"
15#include "cmt_project.h"
16
17/**
18
19    Grep : perform a grep like operation onto a cmt_string
20
21    o All lines of the input string are collected when they contain
22      the specified pattern.
23    o The input string and the selector pattern are specified in
24      the constructor:
25
26         Grep (input_string, pattern)
27
28    o All selected lines are accumulated (appended) into the internal
29      variable m_result . 'space' is the separator.
30
31    o The accumulator is retrieved by the result () method.
32
33 */
34class Grep : public Awk
35{
36public:
37
38  void begin ();
39  void filter (const cmt_string& line);
40  const cmt_string& result () const;
41
42private:
43  cmt_string m_result;
44};
45
46/**
47
48     Cut : perform a cut-like operation :
49
50     o collect the <field>'th field of every line into the m_result
51       internal variable
52
53     o the field number is given in the constructor and starts at zero.
54
55     o selected fields are accumulated with a space as separator.
56
57 */
58class Cut : public Awk
59{
60public:
61  Cut (int field);
62  void begin ();
63  void filter (const cmt_string& line);
64  const cmt_string& result () const;
65
66private:
67  cmt_string m_result;
68  int m_field;
69};
70
71/**
72
73      History : maintains the history of checkouts during a
74                recursive checkout, so as to avoid double checkouts.
75
76 */
77class History
78{
79public:
80  static History& instance ();
81  void clear ();
82  void install (const cmt_string& line);
83  bool is_installed (const cmt_string& line);
84
85private:
86  History ();
87
88  cmt_string m_installed;
89};
90
91/**
92
93     RecursivePass1 : simply validate use statements in a requirements file
94                      and echo those that really need to be handled.
95
96 */
97class RecursivePass1 : public Awk
98{
99public:
100
101  void begin ();
102  void filter (const cmt_string& line);
103  const cmt_string& result () const;
104
105private:
106  cmt_string m_result;
107  bool m_first;
108};
109
110/**
111
112     RecursivePass2 : after filtering the use statements really perform the
113                      checkouts.
114
115 */
116class CvsImplementation;
117class RecursivePass2 : public Awk
118{
119public:
120  RecursivePass2 (CvsImplementation& cvs);
121  void begin ();
122  void filter (const cmt_string& line);
123
124private:
125  CvsImplementation& m_cvs;
126};
127
128/**
129
130     RecursivePass3 : simply validate use statements in a project file
131                      and echo those that really need to be handled.
132
133 */
134class RecursivePass3 : public Awk
135{
136public:
137
138  void begin ();
139  void filter (const cmt_string& line);
140  const cmt_string& result () const;
141
142private:
143  cmt_string m_result;
144  bool m_first;
145};
146
147/**
148
149     RecursivePass4 : after filtering the use statements really perform the
150                      project checkouts.
151
152 */
153class CvsImplementation;
154class RecursivePass4 : public Awk
155{
156public:
157  RecursivePass4 (CvsImplementation& cvs);
158  void begin ();
159  void filter (const cmt_string& line);
160
161private:
162  CvsImplementation& m_cvs;
163};
164
165/**
166
167   Internal implementation of CVS to CMT operations.
168   The Cvs class only provides abstract interface.
169
170 */
171class CvsImplementation
172{
173public:
174
175  CvsImplementation ()
176  {
177    clear ();
178  }
179
180  void clear ()
181  {
182    m_recursive  = false;
183    m_head       = false;
184    m_verbose    = false;
185    m_simulation = false;
186    no_config    = false;
187
188    m_home_dir     = "";
189    m_checkout_dir = "";
190    m_version_dir  = "";
191    m_cvs_offset   = "";
192
193    m_last_module        = "";
194    m_last_cvs_infos     = "";
195    structure_info       = "";
196    error_info           = "";
197    tags_top_info        = "";
198    tags_info            = "";
199    cvsversions_top_info = "";
200    cvsversions_info     = "";
201    branches_info        = "";
202    subpackages_info     = "";
203    subprojects_info     = "";
204
205    m_protocol_level     = "";
206
207    Symbol* symbol = Symbol::find ("cmt_cvs_protocol_level");
208    if (symbol != 0)
209      {
210        m_protocol_level = symbol->build_macro_value ();
211        Symbol::expand (m_protocol_level);
212      }
213  }
214
215  CvsImplementation& operator = (const CvsImplementation& other)
216  {
217    m_recursive  = other.m_recursive;
218    m_head       = other.m_head;
219    m_verbose    = other.m_verbose;
220    m_simulation = other.m_simulation;
221    no_config    = other.no_config;
222
223    m_home_dir       = other.m_home_dir;
224    m_checkout_dir   = other.m_checkout_dir;
225    m_version_dir    = other.m_version_dir;
226    m_cvs_offset     = other.m_cvs_offset;
227    m_protocol_level = other.m_protocol_level;
228    m_last_module    = other.m_last_module;
229    m_last_cvs_infos = other.m_last_cvs_infos;
230
231    structure_info       = other.structure_info;
232    error_info           = other.error_info;
233    tags_top_info        = other.tags_top_info;
234    tags_info            = other.tags_info;
235    cvsversions_top_info = other.cvsversions_top_info;
236    cvsversions_info     = other.cvsversions_info;
237    branches_info        = other.branches_info;
238    subpackages_info     = other.subpackages_info;
239    subprojects_info     = other.subprojects_info;
240
241    return (*this);
242  }
243
244  /**
245     Filter out the space-separated words of a text that don't match a regexp.
246   */
247  void filter_list (cmt_string& text, const cmt_regexp& exp)
248  {
249    CmtSystem::cmt_string_vector list;
250
251    CmtSystem::split (text, " ", list);
252
253    int i;
254
255    text = "";
256
257    for (i = 0; i < list.size (); i++)
258      {
259        const cmt_string& s = list[i];
260        if (exp.match (s))
261          {
262            if (i > 0) text += " ";
263            text += s;
264          }
265      }
266  }
267
268  int execute (const cmt_string& command)
269  {
270    int status = 0;
271
272    if (m_verbose || m_simulation)
273      {
274        cout << "#CMT> Executing [" << command << "]" << endl;
275      }
276   
277    if (!m_simulation)
278      {
279        status = CmtSystem::execute (command);
280      }
281
282    return (status);
283  }
284
285  void execute_and_retry (const cmt_string& command, const cmt_string& message)
286  {
287    int status;
288    int retry = 0;
289
290    for (;;)
291      {
292        status = execute (command);
293       
294        if (status != 0)
295          {
296            retry++;
297           
298            cout << "# " << message << ": status=" << status << endl;
299            cout << "#---------------------------------------------------------" << endl;
300           
301            if (retry > 5) exit(0);
302          }
303        else
304          {
305            break;
306          }
307      }
308  }
309
310  int execute (const cmt_string& command, cmt_string& out)
311  {
312    int status = 0;
313
314    if (m_verbose || m_simulation)
315      {
316        cout << "#CMT> Executing [" << command << "]" << endl;
317      }
318   
319    if (!m_simulation)
320      {
321        status = CmtSystem::execute (command, out);
322       
323      }
324     
325    //if (m_verbose || m_simulation)
326    //  {
327    //       cout << out << endl;
328    //  }
329    return (status);
330  }
331
332
333  /**
334     This function will check the protocol level with the CVS pluggin.
335     The expected level is defined in a macro (in the requirements file of CMT)
336     The protocol level characterizes the structure of the message received from the CVS pluggin
337     and depends on its version.
338
339     In order to know if the pluggin is installed AND if the support for this version is
340     installed, we checkout CVSROOT/loginfo which should contain entries with selection patterns
341
342     .cmtcvsinfos/<protocol_level>
343
344     However old versions only offer as pattern:
345
346     .cmtcvsinfos
347
348     In this function we'll detect if the effective protocol level satisifies the
349     level expected for this release of CMT
350
351     In simulation mode we suppose the expected protocol has been found.
352   */
353  bool check_protocol ()
354  {
355    static bool done = false;
356    static bool found = true;
357
358    if (done) return (found);
359    done = true;
360
361    cmt_string cvsroot;
362       
363    CmtSystem::get_cvsroot (cvsroot);
364       
365    cmt_string command;
366       
367    command = "cvs";
368    if (cvsroot != "") 
369      {
370        command += " -d ";
371        command += cvsroot;
372      }
373    command += " -Q co -p CVSROOT/loginfo ";
374
375    found = false;
376
377    cmt_string pattern = ".cmtcvsinfos";
378
379    if (m_protocol_level != "")
380      {
381        pattern += "/";
382        pattern += m_protocol_level;
383      }
384
385    cmt_string loginfo;
386
387    if (m_simulation)
388      {
389        loginfo = pattern;
390      }
391
392    execute (command, loginfo);
393
394    int pos = loginfo.find (pattern);
395
396    if (pos != cmt_string::npos)
397      {
398        found = true;
399      }
400
401    if (m_verbose)
402      {
403        if (found)
404          {
405            cout << "#CMT> Protocol level " << m_protocol_level << endl;
406          }
407        else
408          {
409            cout << "#CMT> The CVS pluggin is not installed or is not at protocol level " << m_protocol_level << endl;
410          }
411      }
412   
413    return (found);
414  }
415
416  /**
417     Execute the CVS command that activates the CVS pluggin, ie this is a cvs import
418     using the conventional module .cmtcvsinfos/<protocol-level>/<module>
419
420     We create a temporary directory just to lauch the command. However nothing
421     should change in this temporary directory since the pluggin returns an error status.
422   */
423  void retreive_cvs_infos (const cmt_string& module)
424  {
425    static const cmt_string cmtcvsinfos = ".cmtcvsinfos";
426
427    cmt_string home_dir = CmtSystem::pwd ();
428       
429    //
430    // Activities related with .cmtcvsinfos will occur in a temporary directory
431    //
432    cmt_string tmp_dir = CmtSystem::getenv ("TMPDIR");
433    if (tmp_dir == "")
434      {
435        tmp_dir = CmtSystem::file_separator ();
436        tmp_dir += "tmp";
437      }
438   
439    if (!CmtSystem::cd (tmp_dir))
440      {
441        tmp_dir = home_dir;
442      }
443   
444    tmp_dir += CmtSystem::file_separator ();
445    tmp_dir += "cmtcvs";
446    {
447      cmt_string temp = CmtSystem::get_temporary_name ();
448      CmtSystem::basename (temp, temp);
449      // Suppress dots for Windows
450      temp.replace_all (".", "");
451      tmp_dir += temp;
452    }
453   
454    if (!CmtSystem::test_directory (tmp_dir))
455      {
456        if (!CmtSystem::mkdir (tmp_dir))
457          {
458            cout << "#CMT> Cannot create the temporary directory [" << tmp_dir << "]" << endl;
459            return;
460          }
461      }
462   
463    //trap "rm -rf ${tmp_dir}" 0 1 2 15
464   
465    if (!CmtSystem::cd (tmp_dir))
466      {
467        cout << "#CMT> Cannot move to the temporary directory " << tmp_dir << endl;
468       
469        if (m_verbose)
470          {
471            cout << "#CMT> now removing tmp_dir " << tmp_dir << " home=" << home_dir << endl;
472          }
473       
474        CmtSystem::remove_directory (tmp_dir);
475       
476        return;
477      }
478   
479    if (m_verbose)
480      {
481        cout << "#CMT> cvs infos are now obtained from the temporary directory " << CmtSystem::pwd () << endl; 
482      }
483   
484    /**
485       The script associated to such entries is supposed to :
486        1) extract the set of <infos> from ${module}/cmt/requirements
487                                        or ${module}/cmt/project.cmt
488        2) build an output of the form :
489            <infos>=info1 info2 info3 ...
490     
491       Currently this script can be found in
492     
493       ${CMTROOT}/cmt/cmt_buildcvsinfos2.sh
494       %CMTROOT%/cmt/cmt_buildcvsinfos.py
495       There is a C++ implementation as cmtcvs.exe
496     
497    */
498   
499    if (!CmtSystem::test_directory (cmtcvsinfos))
500      {
501        CmtSystem::mkdir (cmtcvsinfos);
502      }
503   
504    CmtSystem::cd (cmtcvsinfos);
505   
506    cmt_string cvsroot;
507   
508    CmtSystem::get_cvsroot (cvsroot);
509   
510    cmt_string command;
511   
512    command = "cvs";
513    if (cvsroot != "") 
514      {
515        command += " -d ";
516        command += cvsroot;
517      }
518    command += " -Q import -m cmt ";
519   
520    command += cmtcvsinfos;
521   
522    if (m_protocol_level != "")
523      {
524        command += "/";
525        command += m_protocol_level;
526      }
527    command += "/";
528    command += module;
529    command += " CMT v1";
530   
531    m_last_cvs_infos = "";
532
533    execute (command, m_last_cvs_infos);
534   
535    if (m_verbose)
536      {
537        cout << "#CMT> now removing tmp_dir " << tmp_dir << " home=" << home_dir << endl;
538      }
539   
540    CmtSystem::cd (home_dir);
541    CmtSystem::remove_directory (tmp_dir);     
542  }
543
544  /**
545     This method exploits the hook installed into the loginfo script.
546     A communication is setup with a dummy CVS module named .cmtcvsinfos/<module>
547   
548     At import time, the contents of the file will be used to parameterize
549     the script named cmt_buildcvsinfos2.sh (referenced in the loginfo script)
550   
551      This script performs a scan in the CVS repository for the following types of
552     information :
553   
554       the recognized structure below this module (none, project, package)
555       all top symbolic tags installed for the module
556       all symbolic tags installed for the module
557       all branches available below this module
558       all subpackages installed below the module.
559       all subprojects installed below the module.
560   
561        In principle, only modules corresponding to true CMT products (packages or projects) are considered.
562          o tags are obtained from the requirements or the project file
563          o branches are sub-directories which are not themselves packages
564          o subpackages are sub-directories which are CMT packages
565            (a subdirectory is always either a branch or a subpackage)
566  */
567  void get_cvs_infos_with_offset (const cmt_string& module)
568  {
569    if (!check_protocol ())
570      {
571        cout << "#CMT> The CVS pluggin is not installed or is not at protocol level " << m_protocol_level << endl;
572        return;
573      }
574
575    if (module == "")
576      {
577        cout << "#CMT> cmt cvs needs a module name" << endl;
578        return;
579      }
580
581    if (module == m_last_module)
582      {
583        if (m_verbose)
584          {
585            cout << "#CMT> cvs infos for module " << module << " already there" << endl;
586          }
587      }
588    else
589      {
590        m_last_module = module;
591       
592        retreive_cvs_infos (module);
593      }
594   
595    /**
596       Now retrieve all info fields :
597    */
598
599    Grep grep;
600
601    grep.run (m_last_cvs_infos, "structure=");
602   
603    if (grep.result () != "")
604      {
605        structure_info = grep.result ();
606        structure_info.replace ("structure=", "");
607      }
608    else
609      {
610        // This may happen for old protocol level < v1r1
611        structure_info = "package";
612      }
613   
614    grep.run (m_last_cvs_infos, "error=");
615   
616    if (grep.result () != "")
617      {
618        error_info = grep.result ();
619        error_info.replace ("error=", "");
620      }
621    else
622      {
623        error_info = "";
624      }
625   
626    grep.run (m_last_cvs_infos, "tags_top=");
627   
628    if (grep.result () != "")
629      {
630        tags_top_info = grep.result ();
631        tags_top_info.replace ("tags_top=", "");
632      }
633    else
634      {
635        tags_top_info = "";
636      }
637   
638    grep.run (m_last_cvs_infos, "tags=");
639   
640    if (grep.result () != "")
641      {
642        tags_info = grep.result ();
643        tags_info.replace ("tags=", "");
644      }
645    else
646      {
647        tags_info = "";
648      }
649   
650    grep.run (m_last_cvs_infos, "cvsversions_top=");
651   
652    if (grep.result () != "")
653      {
654        cvsversions_top_info = grep.result ();
655        cvsversions_top_info.replace ("cvsversions_top=", "");
656      }
657    else
658      {
659        cvsversions_top_info = "";
660      }
661   
662    grep.run (m_last_cvs_infos, "cvsversions=");
663   
664    if (grep.result () != "")
665      {
666        cvsversions_info = grep.result ();
667        cvsversions_info.replace ("cvsversions=", "");
668      }
669    else
670      {
671        cvsversions_info = "";
672      }
673   
674    grep.run (m_last_cvs_infos, "branches=");
675   
676    if (grep.result () != "")
677      {
678        branches_info = grep.result ();
679        branches_info.replace ("branches=", "");
680      }
681    else
682      {
683        branches_info = "";
684      }
685   
686    grep.run (m_last_cvs_infos, "subpackages=");
687   
688    if (grep.result () != "")
689      {
690        subpackages_info = grep.result ();
691        subpackages_info.replace ("subpackages=", "");
692      }
693    else
694      {
695        subpackages_info = "";
696      }
697   
698    grep.run (m_last_cvs_infos, "subprojects=");
699
700    if (grep.result () != "")
701      {
702        subprojects_info = grep.result ();
703        subprojects_info.replace ("subprojects=", "");
704      }
705    else
706      {
707        subprojects_info = "";
708      }
709
710    /**
711       The CMTCVSTAGFILTER env. var. may contain a regexp that will exclude some tags
712       from the answr of the CVS pluggin.
713       The pattern is a regexp but it may also contain the <package> template
714     */
715    cmt_string tag_filter = CmtSystem::getenv ("CMTCVSTAGFILTER");
716   
717    if (tag_filter != "")
718      {
719        cmt_string package;
720        CmtSystem::basename (module, package);
721       
722        cmt_string pattern = "<package>";
723       
724        tag_filter.replace_all (pattern, package);
725       
726        cmt_regexp exp (tag_filter);
727       
728        cmt_string text;
729       
730        filter_list (tags_top_info, exp);
731        filter_list (tags_info, exp);
732        filter_list (cvsversions_top_info, exp);
733        filter_list (cvsversions_info, exp);
734      }
735  }
736 
737  void get_cvs_infos (const cmt_string& cvs_offset, const cmt_string& module)
738  {
739    cmt_string full_name;
740
741    if (cvs_offset != "") 
742      {
743        full_name = cvs_offset;
744        full_name += "/";
745        while (full_name.find ("//") != cmt_string::npos)
746          {
747            full_name.replace_all ("//", "/");
748          }
749      }
750
751    full_name += module;
752
753    get_cvs_infos_with_offset (full_name);
754  }
755
756  /**
757     From a space-separated list of version tags, try to find one tag
758     matching a given regular expression.
759
760       o The first matching tag is returned into 'version'
761       o Success is returned as function value.
762
763   */
764  bool match_version_request (const cmt_string& text, 
765                              const cmt_regexp& version_exp,
766                              cmt_string& version)
767  {
768    CmtSystem::cmt_string_vector vs;
769     
770    CmtSystem::split (text, " \t", vs);
771
772    version = "";
773
774    for (int i = 0; i < vs.size (); i++)
775      {
776        const cmt_string& vv = "^"+ vs[i] + "$";
777       
778        if (version_exp.match (vv))
779          {
780            version = vv;
781            return (true);
782          }
783      }
784
785    return (false);
786  }
787
788  void get_module (const cmt_string& offset,
789                   const cmt_string& product,
790                   cmt_string& module)
791  {
792    module = "";
793
794    if (offset != "")
795      {
796        module = offset;
797        module += "/"; // This is for CVS only thus we don't use the real separator.
798        while (module.find ("//") != cmt_string::npos)
799          {
800            module.replace_all ("//", "/");
801          }
802      }
803
804    module += product;
805  }
806
807  bool get_version (const cmt_string& offset,
808                    const cmt_string& product,
809                    const cmt_string& version_request,
810                    const cmt_string& module,
811                    cmt_string& version,
812                    bool& at_head)
813  {
814    Grep grep;
815    cmt_string topversions;
816    cmt_string versions;
817    cmt_string requested_version = version_request;
818   
819    at_head = false;
820           
821    /**
822     *   Try to figure out what is the effective version tag available
823     *   for the requested version expressions (which may contain
824     *   wild card)
825     *
826     *     the requested version may either be in the top tags (ie those
827     *     corresponding to the same most recent CVS version number before
828     *     the HEAD) or not. The returned at_head flag will show this.
829     *
830     *     then the requested product may either be located in the CVS repository
831     *     under the offset or not, the returned module will contain the effective
832     *     location where the requested version has been found.
833     */
834   
835    if (m_verbose)
836      {
837             cout << "#CMT> requesting cvs infos onto module " << module << endl;
838      }
839   
840    get_cvs_infos_with_offset (module);
841   
842    if (error_info != "")
843      {
844        versions = "";
845        cout << "#CMT> Product " << product << " not found in ${CVSROOT}" << endl;
846        return (false);
847      }
848
849    versions = tags_top_info;
850
851    cmt_string v = version_request;
852   
853    if (version_request.find ("*") != cmt_string::npos)
854      {
855        v.replace_all ("*", ".*");
856      }
857    else
858      {
859        // this is an exact match to the end of the word since there is no wild card
860        v += "$";
861      }
862   
863    cmt_regexp version_exp (v);
864   
865    if (!match_version_request (versions, version_exp, version))
866      {
867        // We try on non-top versions
868
869        versions = tags_info;
870
871        if (!match_version_request (versions, version_exp, version))
872          {
873            version = requested_version;
874            int pos = 0;
875            if ((pos = version.find ("*")) != cmt_string::npos)
876              {
877                //
878                //  There was a wild card but the expression does not match
879                // any of the existing tags in CVS.
880                //  Things will be retreived from HEAD but we have to build
881                // a reasonable version tag from the wild card expression.
882                //  If the letter before the * was a digit, then simply remove
883                // the * (v5* -> v5) otherwise add a zero (v5r* -> v5r0)
884                //
885                if (pos > 0)
886                  {
887                    char letter = version[pos-1];
888                   
889                    static const cmt_string digits = "0123456789";
890                   
891                    if (digits.find (letter) == cmt_string::npos)
892                      {
893                        // "v5r*" -> "v5r0"
894                        version.replace ("*", "0");
895                      }
896                    else
897                      {
898                        // "v5*" -> "v5"
899                        version.replace ("*", "");
900                      }
901                  }
902                else
903                  {
904                    // The expression was simply "*" !!!
905                    version = "v0";
906                  }
907              }
908            at_head = true;
909          }
910        else
911          {
912            at_head = false;
913          }
914      }
915    else
916      {
917        at_head = true;
918      }
919   
920    /**
921     *   Here we have at least one version matching the requested expression.
922     */
923   
924    return (true);
925  }
926
927  bool do_need_version ()
928  {
929     bool need_version = false;
930
931    if (structure_info == "project")
932    {
933             need_version = true;
934             //CmtStructuringStyle style = Cmt::get_current_structuring_style ();
935         //if (style == default_structuring_style)
936             //{
937             //   Use& current_use = Use::current ();
938             //   if (current_use.get_strategy ("VersionDirectory"))
939             //      need_version = true;
940             //}
941             //else if (style == with_version_directory)
942             //    need_version = true;               
943             // cout<<"need version"<<need_version<<endl;
944        }
945    else
946      {
947             CmtStructuringStyle style = Cmt::get_current_structuring_style ();
948         if (style == default_structuring_style)
949             {
950                Use& current_use = Use::current ();
951                if (current_use.get_strategy ("VersionDirectory"))
952                   need_version = true;
953             }
954             else if (style == with_version_directory)
955                 need_version = true;           
956      }
957
958    return (need_version);
959  }
960
961  /**
962     Take care of structuring style for packages and of project vs package conventions
963   */
964  cmt_string build_version_directory (const cmt_string& offset,
965                                      const cmt_string& product,
966                                      const cmt_string& version)
967  {
968    cmt_string dir = m_home_dir;
969   
970    if (m_checkout_dir != "")
971      {
972        // consider the usual -d option
973 
974        dir += CmtSystem::file_separator ();
975        dir += m_checkout_dir;
976      }
977   
978    dir += CmtSystem::file_separator ();
979    dir += offset;
980    dir += CmtSystem::file_separator ();
981    dir += product;
982
983    if (do_need_version ())
984      {
985        dir += CmtSystem::file_separator ();
986        dir += version;
987      }
988   
989    CmtSystem::reduce_file_separators (dir);
990   
991    return (dir);
992  }
993
994  /**
995     Wrapper to mkdir handling simulation and verbose options.
996   */
997  bool mkdir (const cmt_string& dir)
998  {
999    if (m_simulation)
1000      {
1001        cout << "#CMT> Would create the " << dir << " directory" << endl;
1002      }
1003    else
1004      {
1005        if (!CmtSystem::cd (dir))
1006          {
1007            if (m_verbose)
1008              {
1009                cout << "#CMT> About to mkdir " << dir << endl;
1010              }
1011
1012            CmtSystem::mkdir (dir);
1013            if (!CmtSystem::cd (dir))
1014              {
1015                cout << "# Error creating the directory :" << dir << endl;
1016                cout << "#---------------------------------------------------------" << endl;
1017                return (false);
1018              }
1019          }
1020      }
1021    return (true);
1022  }
1023
1024  /**
1025     When running cmt cvs commands, we stand by definition outside of any existing
1026     package context. Thus it's likely that CMTPATH are not completely defined.
1027     This function manually prepends CMTPATH entries to the environment variable.
1028   */
1029  void add_cmtpath (const cmt_string& dir)
1030  {
1031    static cmt_string CMTPATH;
1032
1033    cmt_string cmtpath = Symbol::get_env_value ("CMTPATH");
1034
1035    if (cmtpath.find (dir) == cmt_string::npos)
1036      {
1037        CMTPATH = dir;
1038        CMTPATH += ":";
1039        CMTPATH += cmtpath;
1040
1041        CmtSystem::putenv ("CMTPATH", CMTPATH);
1042      }
1043
1044    if (m_verbose)
1045      {
1046        cout << "#CMT> CMTPATH=" << CmtSystem::getenv ("CMTPATH") << endl;
1047      }
1048  }
1049
1050  /**
1051     Specific checkout of one project
1052   */
1053  bool really_checkout_project_contents (const cmt_string& offset,
1054                                         const cmt_string& project,
1055                                         const cmt_string& version,
1056                                         const cmt_string& tag,
1057                                         const cmt_string& module,
1058                                         const cmt_string& basedir,
1059                                         bool at_head,
1060                                         const cmt_string& currentdir)
1061  {
1062    cmt_string dir = currentdir;
1063
1064    cout << "  # get project files into " << dir << endl;
1065
1066
1067    cmt_string version_dir = version;
1068    if (!mkdir (version_dir)) return (false);
1069
1070    dir += CmtSystem::file_separator ();
1071    dir += version_dir;
1072   
1073    cmt_string command = "cvs -f -Q co -P ";
1074    if (!at_head)
1075      {
1076        command += "-r ";
1077        command += (tag != "") ? tag : version;
1078      }
1079
1080    command += " -d cmt ";
1081
1082    command += " ";
1083    command += module;
1084    command += "/cmt";
1085
1086    command += CmtSystem::command_separator ();
1087
1088    command += " cvs -f update -l .";
1089
1090    execute_and_retry (command, "Error getting project CMT contents");
1091
1092    return (true);
1093  }
1094  /**
1095     Construct CVS management files in the top directory. This is needed
1096     if the top directory of a product is empty. (In this case the
1097     co -l results in nothing)
1098   */
1099  void make_management_files (const cmt_string& module,
1100                              const cmt_string& entries_text)
1101  {
1102    if (!CmtSystem::test_directory ("CVS"))
1103      {
1104        /**
1105         * The CVS repository had not been created (this is generally
1106         * due to the lack of top files)
1107         */
1108
1109        if (!mkdir ("CVS")) return;
1110
1111        CmtSystem::cd ("..");
1112
1113        cmt_string s;
1114       
1115        // Let's create first the CVS/Root file.
1116       
1117        CmtSystem::get_cvsroot (s);
1118        s += "\n";
1119       
1120        cmt_string f;
1121       
1122        f = "CVS";
1123        f += CmtSystem::file_separator ();
1124        f += "Root";
1125       
1126        if (m_simulation)
1127          {
1128            cout << "#CMT> Would fill in the CVS/Root file with " << endl;
1129            cout << s << endl;
1130          }
1131        else
1132          {
1133            if (m_verbose)
1134              {
1135                cout << "#CMT> Fill in the CVS/Root file with " << endl;
1136                cout << s << endl;
1137              }
1138            s.write (f);
1139          }
1140       
1141        // Now we create the CVS/Repository file
1142       
1143        f = "CVS";
1144        f += CmtSystem::file_separator ();
1145        f += "Repository";
1146       
1147        CmtSystem::get_cvsroot (s);
1148        if (s[0] == ':')
1149          {
1150            int pos = s.find (1, ":");
1151            s.erase (0, pos+1);
1152            pos = s.find (0, ":");
1153            s.erase (0, pos+1);
1154          }
1155        s += "/";
1156        s += module;
1157        s += "\n";
1158       
1159        if (m_simulation)
1160          {
1161            cout << "#CMT> Would fill in the CVS/Repository file with " << endl;
1162            cout << s << endl;
1163          }
1164        else
1165          {
1166            if (m_verbose)
1167              {
1168                cout << "#CMT> Fill in the CVS/Repository file with " << endl;
1169                cout << s << endl;
1170              }
1171            s.write (f);
1172          }
1173      }
1174   
1175    if (m_simulation)
1176      {
1177        cout << "#CMT> Would write the top CVS/Entries file with " << endl;
1178        cout << entries_text << endl;
1179      }
1180    else
1181      {
1182        cmt_string entries_file_name;
1183
1184        entries_file_name = "CVS";
1185        entries_file_name += CmtSystem::file_separator ();
1186        entries_file_name += "Entries";
1187   
1188        cmt_string text;
1189
1190        if (!text.read (entries_file_name))
1191          {
1192            // This happens when there were no top files
1193          }
1194
1195        text += entries_text;
1196
1197        // Now the CVS/Entries is ready to be created.
1198        if (m_verbose)
1199          {
1200            cout << "#CMT> Fill in the top CVS/Entries file with " << endl;
1201            cout << text << endl;
1202          }
1203
1204        text.write (entries_file_name);
1205      }
1206  }
1207
1208
1209  /**
1210     Specific checkout of one package
1211
1212     1) get top files (no directories)
1213     2) construct the directory structure (with or without version directory)
1214     3) build the CVS/Entries file for subdirs and co individual subdirs
1215     4) write the CVS management files if CVS did not do it.
1216   */
1217  bool really_checkout_package_contents (const cmt_string& offset,
1218                                         const cmt_string& package,
1219                                         const cmt_string& version,
1220                                         const cmt_string& module,
1221                                         const cmt_string& basedir,
1222                                         bool at_head,
1223                                         const cmt_string& currentdir)
1224  {
1225    cmt_string dir = currentdir;
1226
1227    cout << "  # get top files " << endl;
1228           
1229    cmt_string command = "cvs -f -Q co -l ";
1230    if (!at_head)
1231      {
1232        command += "-r ";
1233        command += version;
1234      }
1235
1236    bool need_version = do_need_version ();
1237
1238    if (need_version)
1239      {
1240        command += " -d ";
1241        command += version;
1242      }
1243    else
1244      {
1245        command += " -d ";
1246        command += package;
1247
1248        // Must stand just above the package directory
1249        CmtSystem::cd ("..");
1250        CmtSystem::dirname (dir, dir);
1251      }
1252   
1253    command += " ";
1254    command += module;
1255   
1256    execute_and_retry (command, "Error getting package CMT contents");
1257
1258    if (need_version)
1259      {
1260               if (!mkdir (version)) return (false);   
1261               dir += CmtSystem::file_separator ();
1262               dir += version;
1263      }
1264    else
1265      {
1266        if (!mkdir (package)) return (false);
1267       
1268        dir += CmtSystem::file_separator ();
1269        dir += package;
1270      }
1271   
1272    if (m_verbose)
1273      {
1274        cout << "#CMT> Now getting subdirectories pwd=" << CmtSystem::pwd () << " dir=" << dir << endl;
1275      }
1276   
1277    cmt_string branches = CmtSystem::getenv ("CMTCVSBRANCHES");
1278   
1279    if (branches == "")
1280      {
1281            branches = branches_info;
1282      }
1283   
1284    CmtSystem::cmt_string_vector branch_vector;
1285   
1286    CmtSystem::split (branches, " \t", branch_vector);
1287     
1288    cmt_string text = "";
1289   
1290    command = "";
1291
1292    if (!CmtSystem::test_directory ("CVS"))
1293      {
1294          int i;
1295          for (i = 0; i < branch_vector.size (); i++)
1296            {
1297               cmt_string& branch = branch_vector[i];   
1298               if (i > 0)
1299                   {
1300                      command += CmtSystem::command_separator ();
1301                   }
1302       
1303               command += "cvs -f -Q co ";
1304       
1305               if (!at_head)
1306                  {
1307                     command += "-r ";
1308                     command += version;
1309                  }
1310       
1311               command += " -d ";
1312               command += branch;
1313               command += " ";
1314               command += module;
1315               command += "/";    // CVS uses the '/' notation on all platforms!!
1316               command += branch;
1317       
1318               text += "D/";
1319               text += branch;
1320               text += "////\n";
1321            } 
1322        execute_and_retry (command, "Error getting package contents");
1323
1324        make_management_files (module, text);
1325
1326        if (need_touch_files)
1327        { 
1328   
1329            cout << "# --> udapte the file timestamps" << endl;                 
1330            for (i = 0; i < branch_vector.size (); i++)
1331            {   
1332                    cmt_string& branch = branch_vector[i];   
1333                CmtSystem::cmt_string_vector& list = CmtSystem::scan_dir (branch);
1334                int j;
1335                for (j = 0; j < list.size (); j++)
1336                    if (CmtSystem::test_file(list[j]))               
1337                        CmtSystem::touch_file (list[j]);
1338            }
1339        }       
1340        return (true);   
1341      }
1342 
1343    command += "cvs -Q update -d ";
1344
1345    if (!at_head)
1346      {
1347        command += "-r ";
1348        command += version;
1349      }
1350
1351    int i;
1352   
1353    for (i = 0; i < branch_vector.size (); i++)
1354      {
1355            cmt_string& branch = branch_vector[i];
1356            if (branch != "CVS")
1357            {   
1358                command += " ";
1359                command += branch;
1360             }
1361      }
1362
1363    command += CmtSystem::command_separator ();
1364
1365    command += "cvs update -l .";
1366   
1367    execute_and_retry (command, "Error getting package contents");
1368
1369    if (need_touch_files)
1370    { 
1371   
1372        cout << "# --> udapte the file timestamps" << endl;                 
1373        for (i = 0; i < branch_vector.size (); i++)
1374        {       
1375                cmt_string& branch = branch_vector[i];   
1376            CmtSystem::cmt_string_vector& list = CmtSystem::scan_dir (branch);
1377            int j;
1378            for (j = 0; j < list.size (); j++)
1379                if (CmtSystem::test_file(list[j]))               
1380                    CmtSystem::touch_file (list[j]);
1381        }
1382    }       
1383    return (true);
1384  }
1385
1386  /**
1387     Effective checkout of a package or a project
1388   */
1389  bool really_checkout (const cmt_string& offset,
1390                        const cmt_string& product,
1391                        const cmt_string& version,
1392                        const cmt_string& tag,
1393                        const cmt_string& module,
1394                        const cmt_string& basedir,
1395                        bool at_head)
1396  {
1397    cmt_string dir = basedir;
1398    cmt_string out;
1399   
1400    cout << "# ================= working on " << structure_info << " " << product
1401         << " version " << version;
1402
1403    if (at_head) cout << " (At head) ";
1404
1405    cmt_string full_offset;
1406
1407    full_offset = m_cvs_offset;
1408    full_offset += offset;
1409
1410    cmt_string echo_ppath;
1411       
1412    if (offset != "")
1413      {
1414        echo_ppath = " path ";
1415        echo_ppath += offset;
1416      }
1417   
1418    cout << echo_ppath << " in " << dir << endl;
1419
1420    if (do_need_version ())
1421      {
1422        // Move back to the product name.
1423        CmtSystem::dirname (dir, dir);
1424      }
1425
1426    if (!mkdir (dir)) return (false);
1427       
1428    if (structure_info == "package")
1429      {
1430        really_checkout_package_contents (offset,
1431                                          product,
1432                                          version,
1433                                          module,
1434                                          basedir,
1435                                          at_head,
1436                                          dir);
1437      }
1438    else if (structure_info == "project")
1439      {
1440        really_checkout_project_contents (offset,
1441                                          product,
1442                                          version,
1443                                          tag,
1444                                          module,
1445                                          basedir,
1446                                          at_head,
1447                                          dir);
1448      }
1449
1450    return (true);
1451  }
1452
1453  /**
1454     Find the most appropriate effective version directory corresponding to the
1455     specified version expression.
1456     The specified expression may contain wildcards (in the file manager sense). This
1457     FME is first converted into a RE then a directory search is performed.
1458     An empty string is returned if no match is found.
1459   */
1460  cmt_string find_matching_version (const cmt_string& expression)
1461  {
1462     
1463    cmt_string result;     
1464   
1465    //
1466    // Here expression takes the form
1467    //   <some path>/<expression with wild-card>
1468    //
1469
1470    cmt_string dir;
1471    CmtSystem::dirname (expression, dir);
1472    dir += CmtSystem::file_separator ();
1473   
1474    cmt_string version;
1475    CmtSystem::basename (expression, version);
1476
1477    if (version.find ("*") == cmt_string::npos)
1478      {
1479        // there is no wildcarding here. A simple test is enough.
1480        if (CmtSystem::test_directory (expression))
1481          {
1482            result = version;
1483          }
1484      }
1485    else
1486      {
1487        version.replace ("*", ".*");
1488       
1489        cmt_regexp exp (version);
1490       
1491        CmtSystem::cmt_string_vector list;
1492       
1493        CmtSystem::scan_dir (dir, exp, list);
1494       
1495        if (list.size () > 0)
1496          {
1497            result = list[0];
1498           
1499            CmtSystem::basename (result, result);
1500          }
1501      }
1502   
1503    return (result);
1504  }
1505 
1506  /**
1507   *   We provide a path to a requirements file. From it we read the use
1508   *  statements, and we try to checkout the corresponding packages.
1509   *
1510   *   A boolean return tells if any recursion occurred.
1511   */
1512  bool checkout_from_requirements (const cmt_string& requirements_path)
1513  {
1514    static cmt_regexp expression ("^[ \t]*use[ \t]");
1515
1516    cmt_string text;
1517
1518    text.read (requirements_path);
1519
1520    RecursivePass1 p1;
1521    p1.run (text, expression);
1522
1523    bool result = (p1.result () != "");
1524    RecursivePass2 p2 (*this);
1525    p2.run (p1.result ());
1526
1527    return (result);
1528  }
1529
1530  /**
1531   *   We provide a path to a project file. From it we read the use
1532   *  statements, and we try to checkout the corresponding projects.
1533   */
1534  void checkout_from_project_file (const cmt_string& file_name)
1535  {
1536    static cmt_regexp expression ("^[ \t]*use[ \t]");
1537
1538    cmt_string text;
1539
1540    text.read (file_name);
1541
1542    CvsImplementation& me = *this;
1543    CvsImplementation saved;
1544    saved = me;
1545    cmt_string here = CmtSystem::pwd ();
1546
1547    RecursivePass3 p3;
1548    p3.run (text, expression);
1549
1550    RecursivePass4 p4 (*this);
1551    p4.run (p3.result ());
1552
1553    Grep grep;
1554
1555    grep.run (text, "container");
1556    cmt_string container = grep.result ();
1557
1558    if (container != "")
1559      {
1560        static cmt_regexp container_expression ("^[ \t]*container[ \t]");
1561
1562        add_cmtpath (here);
1563
1564        cout << "  # --> now getting project packages from the " << container << " " << here << endl;
1565
1566        CmtSystem::cd (here);
1567
1568        RecursivePass1 p1;
1569        p1.run (text, container_expression);
1570
1571        RecursivePass2 p2 (*this);
1572
1573        m_home_dir = CmtSystem::pwd ();
1574        p2.run (p1.result ());
1575      }
1576
1577    CmtSystem::cd (here);
1578    me = saved;
1579  }
1580
1581  /**
1582     Check whether a given directory structure matches an expected product structure
1583     given by the structure info obtained from the most recent request to the CVS pluggin
1584   */
1585  bool check_structure (const cmt_string& dir, const cmt_string& version)
1586  {
1587    bool result = false;
1588    if (!CmtSystem::test_directory (dir))
1589      {
1590               return (false);
1591      }
1592
1593    if (structure_info == "package")
1594      {
1595        // Check if it is a true CMT package.   
1596        cmt_string file_name;
1597       
1598        file_name = dir;
1599        file_name += CmtSystem::file_separator ();
1600        file_name += "cmt";
1601        file_name += CmtSystem::file_separator ();
1602        file_name += "requirements";
1603       
1604        if (CmtSystem::test_file (file_name))
1605          {       
1606               if (!do_need_version ())
1607               {
1608                   // open the version.cmt file and compare the version
1609                 cmt_string current_version;
1610                 cmt_string version_file = dir;
1611                 version_file += CmtSystem::file_separator ();
1612                 version_file += "CVS";
1613                 version_file += CmtSystem::file_separator ();
1614                 version_file += "Tag"; 
1615                 current_version.read (version_file);               
1616                 //cout <<version_file<<", "<<current_version<<", "<<"N"+version+"\n"<<endl;
1617                 return current_version=="N"+version+"\n";                 
1618                }   
1619                else
1620                       result = true;
1621          }
1622        else
1623          {
1624
1625            file_name = dir;
1626            file_name += CmtSystem::file_separator ();
1627            file_name += "mgr";
1628            file_name += CmtSystem::file_separator ();
1629            file_name += "requirements";
1630           
1631            if (CmtSystem::test_file (file_name))
1632              {
1633               if (!do_need_version ())
1634               {
1635                   // open the version.cmt file and compare the version
1636                 cmt_string current_version;
1637                 cmt_string version_file = dir;
1638                 version_file += CmtSystem::file_separator ();
1639                 version_file += "CVS";
1640                 version_file += CmtSystem::file_separator ();
1641                 version_file += "Tag"; 
1642                 current_version.read (version_file);               
1643                 //cout <<version_file<<", "<<current_version<<", "<<"N"+version+"\n"<<endl;
1644                 return current_version=="N"+version+"\n";                 
1645                }   
1646                else
1647                       result = true;
1648              }
1649          }
1650      }
1651    else if (structure_info == "project")
1652      {
1653        cmt_string file_name;
1654       
1655        file_name = dir;
1656        file_name += CmtSystem::file_separator ();
1657        file_name += "cmt";
1658        file_name += CmtSystem::file_separator ();
1659        file_name += "project.cmt";
1660       
1661        if (CmtSystem::test_file (file_name))
1662          {
1663            result = true;
1664          }
1665    }
1666
1667    return (result);
1668  }
1669
1670  /**
1671     Internal call from the initial do_checkout or from recursive passes
1672     Prepare the directory structure for the checkout
1673     Do the checkout
1674     Check if everything was done properly, if a package or a project has been created
1675     If needed recurse from the requirements or project file
1676
1677     For projects there may be two different specifications for
1678     - the version directory
1679     - the CVS tag
1680   */
1681  void do_checkout_phase2 (const cmt_string& offset,
1682                           const cmt_string& product,
1683                           const cmt_string& specified_version,
1684                           const cmt_string& tag)
1685  {
1686    if (m_verbose)
1687      {
1688        cout << "#CMT> do_checkout_phase2> offset=" << offset
1689             << " " << structure_info << "=" << product
1690             << " specified_version=" << specified_version
1691             << " tag=" << tag
1692             << " pwd=" << CmtSystem::pwd ()
1693             << endl;
1694      }
1695   
1696    cmt_string version = specified_version;
1697    cmt_string empty;
1698    cmt_string full_offset;
1699
1700    full_offset = m_cvs_offset;
1701    full_offset += offset;
1702   
1703    cmt_string echo_ppath;
1704   
1705    if (offset != "")
1706      {
1707        echo_ppath = " path ";
1708        echo_ppath += offset;
1709      }
1710   
1711    if (version == "")
1712      {
1713        cout << "# ================= No version specified for " << structure_info << " " << product << endl;
1714        return;
1715      }
1716   
1717    //
1718    //  First make an attempt to locate the specified version of
1719    //  this product "as-it-is" in the work area.
1720    //   Since 'version' may contain wild-card, it's likely that
1721    //  we should not simply use CmtSystem::test_directory but
1722    //  use the wild-card search.
1723    //
1724   
1725    cmt_string dir;
1726   
1727    dir = build_version_directory (offset, product, version);
1728   
1729    bool recursive = m_recursive;
1730   
1731    cmt_string effective_version = "";
1732    if (do_need_version ())
1733    {
1734    /* Important this part should be enhanced ASAP
1735       and deal with many other cases.... arghhhh !!
1736    */   
1737        effective_version = find_matching_version (dir);         
1738    }
1739
1740
1741         
1742    cmt_string module;
1743    get_module (full_offset, product, module);
1744
1745    cmt_string cvs_tag = (tag != "") ? tag : version;
1746    bool at_head = false;
1747
1748    if (effective_version != "")
1749      {
1750        version = effective_version;
1751      }
1752    else
1753      {
1754        //
1755        // get_version attempts to find the most appropriate version
1756        // tag matching the specification FROM the repository. However,
1757        // we should take into account situations where some versions have
1758        // already been checked out, in which case they might be sufficient
1759        // (or preferred?)
1760        //
1761       
1762        if (cvs_tag.find ("*") != cmt_string::npos)
1763          {
1764            cout << "# ================= " << structure_info << " " << product
1765                 << " version " << cvs_tag << echo_ppath
1766                 << " has wild cards and will not be considered." << endl;
1767            return;
1768          }
1769       
1770        if (!get_version (full_offset, product, cvs_tag, module,
1771                          cvs_tag, at_head))
1772          {
1773            return;
1774          }
1775       
1776        if (m_head)
1777          {
1778            m_head = false;
1779           
1780            at_head = true;
1781          }
1782        else
1783          {
1784            at_head = false;
1785          }
1786       
1787        //
1788        // Make a second try after having selected a CVS tag from all the
1789        // available tags compatible with the specified version
1790        //
1791
1792        if (tag == "")
1793          {
1794            // If tag was not specified, then the version directory has to match the CVS tag
1795            // Otherwise the original version specification is kept for the directory.
1796            version = cvs_tag;
1797            dir = build_version_directory (offset, product, version);
1798          }
1799      }
1800   
1801    if (check_structure (dir, version))
1802      {
1803             cout << "# ================= " << structure_info << " " << product
1804                  << " version "            << version        << echo_ppath
1805                  << " already installed."  << endl;   
1806             recursive = false;
1807      }
1808    else
1809      {
1810        //
1811        // Now we can say that we have to perform the real checkout.
1812        //
1813       
1814        if (!really_checkout (offset, product, version, cvs_tag, module, dir, at_head))
1815          {
1816            cout << "# bad return from really_checkout_product" << endl;
1817            return;
1818          }
1819      }
1820
1821    //
1822    //  Now reach the newly checked out product.
1823    //
1824   
1825    if (m_simulation)
1826      {
1827        cout << "#CMT> " << structure_info << " directory not really created " << dir << endl;
1828      }
1829    else if (structure_info == "package")
1830      {
1831        if (!CmtSystem::cd (dir))
1832          {
1833            cout << "#CMT> Package directory not created " << dir << endl;
1834            return;
1835          }
1836       
1837        // Check if it is a true CMT package.
1838       
1839        cmt_string file_name;
1840       
1841        file_name = "cmt";
1842        file_name += CmtSystem::file_separator ();
1843        file_name += "requirements";
1844       
1845        if (CmtSystem::test_file (file_name))
1846          {
1847            dir += CmtSystem::file_separator ();
1848            dir += "cmt";
1849            CmtSystem::cd ("cmt");
1850           
1851            if (!do_need_version ())
1852              {
1853                cmt_string text = version;
1854                text += "\n";
1855                text.write ("version.cmt");
1856              }
1857          }
1858        else
1859          {
1860            file_name = "mgr";
1861            file_name += CmtSystem::file_separator ();
1862            file_name += "requirements";
1863           
1864            if (CmtSystem::test_file (file_name))
1865              {
1866                dir += CmtSystem::file_separator ();
1867                dir += "mgr";
1868                CmtSystem::cd ("mgr");
1869              }
1870            else
1871              {
1872                cout << "# " << product << " not a CMT package" << endl;
1873                return;
1874              }
1875          }
1876       
1877        if (recursive)
1878          {
1879            cmt_string here = CmtSystem::pwd ();
1880
1881            bool did_recurse = checkout_from_requirements ("requirements");
1882
1883            CmtSystem::cd (here);
1884
1885            if (did_recurse) 
1886              {
1887                  if (no_config==false)           
1888                        execute ("cmt -quiet broadcast cmt -quiet config");
1889             
1890              }
1891            else
1892              {
1893                  if (no_config==false)
1894                        execute ("cmt -quiet config");
1895              }
1896          }
1897        else
1898          {
1899            if (no_config==false)
1900            execute ("cmt -quiet config");
1901          }
1902      }
1903    else if (structure_info == "project")
1904      {
1905       
1906        if (m_verbose)
1907          {
1908            cout << "#CMT> dir=" << dir << endl;
1909          }
1910       
1911        if (!CmtSystem::cd (dir))
1912          {
1913            cout << "#CMT> Project directory not created " << dir << endl;
1914            return;
1915          }
1916       
1917        cmt_string file_name;
1918       
1919        file_name = "cmt";
1920        file_name += CmtSystem::file_separator ();
1921        file_name += "project.cmt";
1922       
1923        if (!CmtSystem::test_file (file_name))
1924          {
1925            cout << "# " << product << " not a CMT project" << endl;
1926            return;
1927          }
1928       
1929        if (recursive)
1930          {
1931            checkout_from_project_file (file_name);
1932          }
1933
1934        cout << "# ================= Project " << product << " completed" << endl;
1935
1936      }
1937  }
1938 
1939  /**
1940     Top level of the checkout operation, initiated from the command line arguments
1941
1942     Construct an history of the checkouts to avoid duplicating the
1943     checkouts during the recursivity
1944
1945     Eventually
1946     o perform the cmt config for packages.
1947
1948   */
1949  void do_checkout_phase1 (const cmt_string& module, 
1950                           const cmt_string& version_dir, 
1951                           const cmt_string& version_tag)
1952  {
1953    add_cmtpath (m_home_dir);
1954
1955    History& h = History::instance ();
1956
1957    h.clear ();
1958
1959    if (module == "")
1960      {
1961        if (m_verbose)
1962          {
1963            cout << "#CMT> Missing module name" << endl;
1964          }
1965        return;
1966      }
1967
1968    cmt_string offset;
1969    cmt_string product;
1970    cmt_string version;
1971    cmt_string tag;
1972   
1973    {
1974      cmt_string m;
1975      m = m_cvs_offset;
1976      m += module;
1977       
1978      get_cvs_infos_with_offset (m);
1979       
1980      if (error_info != "")
1981        {
1982          cout << error_info << endl;
1983          return;
1984        }
1985    }
1986
1987    if (version_tag == "")
1988      {
1989        Cut cut (0);
1990       
1991        if (tags_top_info != "") tag = tags_top_info;
1992        else tag = tags_info;
1993       
1994        cut.run (tag);
1995       
1996        tag = cut.result ();
1997      }
1998    else
1999      {
2000        tag = version_tag;
2001      }
2002
2003    version = (version_dir == "") ? tag : version_dir;
2004
2005    CmtSystem::dirname (module, offset);
2006    CmtSystem::basename (module, product);
2007   
2008    cmt_string top_dir;
2009       
2010    top_dir = m_home_dir;
2011    top_dir += CmtSystem::file_separator ();
2012    top_dir += m_checkout_dir;
2013    top_dir += CmtSystem::file_separator ();
2014    top_dir += offset;
2015    top_dir += CmtSystem::file_separator ();
2016    top_dir += product;
2017    top_dir += CmtSystem::file_separator ();
2018    top_dir += version;
2019
2020    CmtSystem::reduce_file_separators (top_dir);
2021
2022    if (m_verbose)
2023      {
2024        cout << "#CMT> about to checkout " << structure_info
2025             << " " << product << " version " << version << " into " << top_dir << endl;
2026      }
2027
2028    static const cmt_string empty;
2029    do_checkout_phase2 (offset, product, version, tag);
2030
2031    if (m_simulation) return;
2032
2033    if (!CmtSystem::cd (top_dir)) return;
2034
2035    if (structure_info == "project")
2036      {
2037        cmt_string file_name;
2038   
2039        file_name = "cmt";
2040        file_name += CmtSystem::file_separator ();
2041        file_name += "project.cmt";
2042       
2043        if (!CmtSystem::test_file (file_name))
2044          {
2045            cout << "# " << product << " was not properly checked out and is missing its cmt/project.cmt file" << endl;
2046            return;
2047          }
2048      }
2049    else
2050      {
2051        cmt_string file_name;
2052   
2053        file_name = "cmt";
2054        file_name += CmtSystem::file_separator ();
2055        file_name += "requirements";
2056       
2057        if (CmtSystem::test_file (file_name))
2058          {
2059            top_dir += CmtSystem::file_separator ();
2060            top_dir += "cmt";
2061            CmtSystem::cd ("cmt");
2062          }
2063        else
2064          {
2065            file_name = "mgr";
2066            file_name += CmtSystem::file_separator ();
2067            file_name += "requirements";
2068           
2069            if (CmtSystem::test_file (file_name))
2070              {
2071                top_dir += CmtSystem::file_separator ();
2072                top_dir += "mgr";
2073                CmtSystem::cd ("mgr");
2074              }
2075            else
2076              {
2077                cout << "# " << product << " was not properly checked out and is missing its cmt/requirements file" << endl;
2078                return;
2079              }
2080          }
2081       
2082        if (m_verbose)
2083          {
2084            cout << "#CMT> product " << product << " has been checked out" << endl;
2085          }
2086       
2087        if (!m_recursive)
2088          {
2089              if (no_config==false)
2090                execute ("cmt -quiet config");
2091          }
2092      }
2093  }
2094
2095  void help ()
2096  {
2097    cout << "> cd <some work area>" << endl;
2098    cout << "> cmt checkout [modifier ...] <package|project>" << endl;
2099    cout << "" << endl;
2100    cout << "   modifier :" << endl;
2101    cout << "   -l        Do not process used packages (default)." << endl;
2102    cout << "   -R        Process used products recursively." << endl;
2103    cout << "   -r rev    Check out version tag. (is sticky)" << endl;
2104    cout << "   -vd dir   Use this version directory instead of CVS tag." << endl;
2105    cout << "   -d dir    Check out into dir instead of module name." << endl;
2106    cout << "   -o offset Offset in the CVS repository" << endl;
2107    cout << "   -requirements <requirements file path>  Check out packages referenced in this requirements file" << endl;
2108    cout << "   -t  Change file timestamps to the date of checkout" << endl;
2109    cout << "   -n        simulation mode on" << endl;
2110    cout << "   -no_config  Disable config step after checkout" << endl;   
2111    cout << "   -v        verbose mode on" << endl;
2112    cout << "   --help    print this help" << endl;
2113    cout << "" << endl;
2114    cout << "> cmt cvstags <package|project>" << endl;
2115    cout << "> cmt cvssubpackages <directory>" << endl;
2116    cout << "> cmt cvssubprojects <directory>" << endl;
2117    cout << "" << endl;
2118  }
2119
2120  /**
2121     Implementation of the cmt cvstags
2122     Get the CVS tags of a module
2123   */
2124  void tags (const CmtSystem::cmt_string_vector& arguments)
2125  {
2126    if (arguments.size () < 1)
2127      {
2128        help ();
2129        return;
2130      }
2131   
2132    if (CmtSystem::getenv ("CVSROOT") == "")
2133      {
2134        cout << "# Please set CVSROOT first !" << endl;
2135        return;
2136      }
2137   
2138    m_cvs_offset = CmtSystem::getenv ("CMTCVSOFFSET");
2139    if (m_cvs_offset != "") 
2140      {
2141        m_cvs_offset += "/";
2142        m_cvs_offset.replace_all ("//", "/");
2143      }
2144   
2145    bool all = false;
2146   
2147    for (int arg = 0; arg < arguments.size (); arg++)
2148      {
2149        const cmt_string& option = arguments[arg];
2150       
2151        if (option == "-all")
2152          {
2153            all = true;
2154          }
2155        else
2156          {
2157            get_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), option);
2158           
2159            if (error_info != "")
2160              {
2161                cout << error_info << endl;
2162              }
2163            else
2164              {
2165                cmt_string tags;
2166               
2167                if (all)
2168                  {
2169                    tags = cvsversions_top_info;
2170                    tags += " ";
2171                    tags += cvsversions_info;
2172                  }
2173                else
2174                  {
2175                    tags = tags_top_info;
2176                    tags += " ";
2177                    tags += tags_info;
2178                  }
2179               
2180                CmtSystem::cmt_string_vector v;
2181               
2182                CmtSystem::split (tags, " \t", v);
2183                for (int i = 0; i < v.size (); i++)
2184                  {
2185                    const cmt_string& s = v[i];
2186                    cout << s << endl;
2187                  }
2188              }
2189          }
2190      }
2191  }
2192
2193  /**
2194     Implementation of the cmt cvsbranches
2195     Get the subdirs of a module that are not subackages
2196   */
2197  void branches (const cmt_string& module)
2198  {
2199    cmt_string out;
2200   
2201    get_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), module);
2202   
2203    if (error_info != "")
2204      {
2205        cout << error_info << endl;
2206      }
2207    else
2208      {
2209        cout << branches_info << endl;
2210      }
2211  }
2212
2213  /**
2214     Implementation of the cmt cvssubpackages
2215     Get the subdirs of a module that ARE CMT subpackages
2216   */
2217  void subpackages (const cmt_string& module)
2218  {
2219    cmt_string out;
2220   
2221    get_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), (module == "") ? "." : module);
2222   
2223    if (error_info != "")
2224      {
2225        cout << error_info << endl;
2226      }
2227    else
2228      {
2229        cout << subpackages_info << endl;
2230      }
2231  }
2232 
2233  /**
2234     Implementation of the cmt cvssubrojects
2235     Get the subdirs of a module that ARE CMT projects
2236   */
2237  void subprojects (const cmt_string& module)
2238  {
2239    cmt_string out;
2240   
2241    get_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), (module == "") ? "." : module);
2242   
2243    if (error_info != "")
2244      {
2245        cout << error_info << endl;
2246      }
2247    else
2248      {
2249        cout << subprojects_info << endl;
2250      }
2251  }
2252
2253  /**
2254     Implementation of the cmt checkout
2255     Parse the arguments
2256     Then call do_checkout for each argument
2257   */
2258  void checkout (const CmtSystem::cmt_string_vector& arguments)
2259  {
2260    if (arguments.size () < 1)
2261      {
2262        help ();
2263        return;
2264      }
2265   
2266    if (CmtSystem::getenv ("CVSROOT") == "")
2267      {
2268        cout << "# Please set CVSROOT first !" << endl;
2269        return;
2270      }
2271   
2272    m_home_dir = CmtSystem::pwd ();
2273    m_checkout_dir = "";
2274    m_version_dir = "";
2275    m_cvs_offset = "";
2276
2277    cmt_string module;
2278   
2279    m_recursive      = false;
2280    need_touch_files = false;
2281    no_config        = false;
2282   
2283    bool need_version_tag = false;
2284    cmt_string version_tag;
2285   
2286   
2287    bool need_checkout_dir = false;
2288    bool need_cvs_offset = false;
2289    bool need_requirements_file = false;
2290    bool need_version_dir = false;
2291   
2292    m_simulation = false;
2293    //m_verbose = true;
2294    m_verbose = false;
2295   
2296    m_head = true;
2297   
2298    m_cvs_offset = CmtSystem::getenv ("CMTCVSOFFSET");
2299    if (m_cvs_offset != "") 
2300      {
2301        m_cvs_offset += "/";
2302        m_cvs_offset.replace_all ("//", "/");
2303      }
2304   
2305    for (int arg = 0; arg < arguments.size (); arg++)
2306      {
2307        const cmt_string& option = arguments[arg];
2308       
2309        if (need_version_tag)
2310          {
2311            need_version_tag = false;
2312           
2313            if (option == "HEAD")
2314              {
2315                m_head = true;
2316              }
2317            else
2318              {
2319                version_tag = option;
2320              }
2321          }
2322        else if (need_checkout_dir)
2323          {
2324            need_checkout_dir = false;
2325            m_checkout_dir = option;
2326          }
2327        else if (need_version_dir)
2328          {
2329            need_version_dir = false;
2330            m_version_dir = option;
2331          }
2332        else if (need_cvs_offset)
2333          {
2334            need_cvs_offset = false;
2335            m_cvs_offset = option;
2336            m_cvs_offset += '/';
2337            m_cvs_offset.replace_all ("//", "/");
2338          }
2339        else if (need_requirements_file)
2340          {
2341            need_requirements_file = false;
2342            m_head = false;
2343            checkout_from_requirements (option);
2344          }
2345        else
2346          {
2347            if (option == "-R")
2348              {
2349                m_recursive = true;
2350              }
2351            else if (option == "-t")
2352            {   
2353               need_touch_files = true;
2354            } 
2355            else if (option == "-l")
2356              {
2357                m_recursive = false;
2358              }
2359            else if (option == "-r")
2360              {
2361                need_version_tag = true;
2362                m_head = false;
2363              }
2364            else if (option == "-d")
2365              {
2366                need_checkout_dir = true;
2367              }
2368            else if (option == "-o")
2369              {
2370                need_cvs_offset = true;
2371              }
2372            else if (option == "-n")
2373              {
2374                m_simulation = true;
2375              }
2376            else if (option == "-no_config")
2377              {
2378                    no_config = true;
2379              }       
2380            else if (option == "-v")
2381              {
2382                m_verbose = true;
2383              }
2384            else if (option == "-vd")
2385              {
2386                need_version_dir = true;
2387              }
2388            else if (option == "-requirements")
2389              {
2390                need_requirements_file = true;
2391              }
2392            else if (option == "--help")
2393              {
2394                help ();
2395                return;
2396              }
2397            else if (option[0] == '-')
2398              {
2399                help ();
2400                return;
2401              }
2402            else
2403              {
2404                do_checkout_phase1 (option, m_version_dir, version_tag);
2405              }
2406          }
2407      }
2408  }
2409
2410private:
2411
2412  bool m_recursive;
2413  bool need_touch_files;
2414  bool m_head;
2415  bool m_verbose;
2416  bool m_simulation;
2417  bool no_config;
2418
2419  cmt_string m_home_dir;
2420  cmt_string m_checkout_dir;
2421  cmt_string m_version_dir;
2422  cmt_string m_cvs_offset;
2423
2424  cmt_string m_protocol_level;
2425  cmt_string m_last_module;
2426  cmt_string m_last_cvs_infos;
2427  cmt_string structure_info;
2428  cmt_string error_info;
2429  cmt_string tags_top_info;
2430  cmt_string tags_info;
2431  cmt_string cvsversions_top_info;
2432  cmt_string cvsversions_info;
2433  cmt_string branches_info;
2434  cmt_string subpackages_info;
2435  cmt_string subprojects_info;
2436};
2437
2438//--------------------------------------------------------------------
2439
2440void Grep::begin ()
2441{
2442  m_result = "";
2443}
2444
2445void Grep::filter (const cmt_string& line)
2446{
2447    //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "Grep::filter" << endl;
2448
2449  if (m_result != "") m_result += " ";
2450  m_result += line;
2451}
2452
2453const cmt_string& Grep::result () const
2454{
2455  return (m_result);
2456}
2457
2458//--------------------------------------------------------------------
2459
2460Cut::Cut (int field)
2461{
2462  m_field = field;
2463}
2464
2465void Cut::begin ()
2466{
2467    //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "Cut::begin" << endl;
2468  m_result = "";
2469}
2470
2471void Cut::filter (const cmt_string& line)
2472{
2473    //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "Cut::filter" << endl;
2474
2475  static CmtSystem::cmt_string_vector words;
2476 
2477  CmtSystem::split (line, " \t", words);
2478 
2479  if (words.size () <= m_field) return;
2480 
2481  if (m_result != "") m_result += " ";
2482  m_result += words[m_field];
2483}
2484
2485const cmt_string& Cut::result () const
2486{
2487  return (m_result);
2488}
2489
2490//--------------------------------------------------------------------
2491//--------------------------------------------------------------------
2492
2493History& History::instance ()
2494{
2495  static History h;
2496  return (h);
2497}
2498
2499void History::clear ()
2500{
2501  m_installed = "";
2502}
2503
2504void History::install (const cmt_string& line)
2505{
2506  m_installed += "|";
2507  m_installed += line;
2508  m_installed += "|";
2509}
2510
2511bool History::is_installed (const cmt_string& line)
2512{
2513  if (m_installed.find (line) != cmt_string::npos)
2514    {
2515      return (true);
2516    }
2517 
2518  return (false);
2519}
2520
2521History::History ()
2522{
2523}
2524
2525
2526//--------------------------------------------------------------------
2527
2528void RecursivePass1::begin ()
2529{
2530  m_first = true;
2531  m_result = "";
2532}
2533
2534void RecursivePass1::filter (const cmt_string& line)
2535{
2536    //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "RecursivePass1::filter> "
2537    //                                          << "line=[" << line << "]" << endl;
2538
2539  if (line.find ("use CMT") != cmt_string::npos) return;
2540  if (line.find ("use cmt") != cmt_string::npos) return;
2541 
2542  History& h = History::instance ();
2543 
2544  if (h.is_installed (line)) return;
2545 
2546  CmtSystem::cmt_string_vector words;
2547 
2548  CmtSystem::split (line, " \t", words);
2549
2550  enum
2551  {
2552    need_package,
2553    need_version,
2554    need_path,
2555    no_need
2556  } state = need_package;
2557
2558  cmt_string package;
2559  cmt_string version;
2560  cmt_string path;
2561
2562  for (int i = 1; i < words.size (); i++)
2563    {
2564      const cmt_string& s = words[i];
2565
2566      if (s[0] == '-') continue;
2567
2568      switch (state)
2569        {
2570          case need_package:
2571            package = s;
2572            state = need_version;
2573            break;
2574          case need_version:
2575            version = s;
2576            state = need_path;
2577            break;
2578          case need_path:
2579            path = s;
2580            state = no_need;
2581            break;
2582        }
2583    }
2584 
2585  if (version.find ("*") != cmt_string::npos)
2586    {
2587        /*
2588      cout << "# ================= Package " << package
2589           << " version " << version << " " << path
2590           << " has wild cards and will not be considered." << endl;
2591        */
2592      return;
2593    }
2594
2595  /**
2596   *  At the first pass, we simply accumulate the not-yet handled
2597   *  use statements.
2598   */
2599 
2600  m_result += line;
2601  m_result += "\n";
2602 
2603  if (m_first)
2604    {
2605      m_first = false;
2606      cout << "  # --> now propagate cmt checkout to :" << endl;
2607    }
2608 
2609  cout << "  #     " << package << " " << version << " " << path << endl;
2610}
2611
2612const cmt_string& RecursivePass1::result () const
2613{
2614  return (m_result);
2615}
2616
2617//--------------------------------------------------------------------
2618
2619RecursivePass2::RecursivePass2 (CvsImplementation& cvs) : m_cvs (cvs)
2620{
2621}
2622
2623void RecursivePass2::begin ()
2624{
2625}
2626
2627void RecursivePass2::filter (const cmt_string& line)
2628{
2629    //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "RecursivePass2::filter> "
2630    //                                          << "line=[" << line << "]" << endl;
2631
2632  /**
2633   *   At the second pass, the lines are really handled. Thus
2634   *   the lines are stored into m_installed so as to avoid
2635   *   later on re-installation.
2636   */
2637 
2638  History& h = History::instance ();
2639 
2640  if (h.is_installed (line)) return;
2641 
2642  h.install (line);
2643 
2644  CmtSystem::cmt_string_vector words;
2645 
2646  CmtSystem::split (line, " \t", words);
2647
2648  enum
2649  {
2650    need_package,
2651    need_version,
2652    need_path,
2653    no_need
2654  } state = need_package;
2655
2656  cmt_string package;
2657  cmt_string version;
2658  cmt_string path;
2659
2660  for (int i = 1; i < words.size (); i++)
2661    {
2662      const cmt_string& s = words[i];
2663
2664      if (s[0] == '-') continue;
2665
2666      switch (state)
2667        {
2668          case need_package:
2669            package = s;
2670            state = need_version;
2671            break;
2672          case need_version:
2673            version = s;
2674            state = need_path;
2675            break;
2676          case need_path:
2677            path = s;
2678            state = no_need;
2679            break;
2680        }
2681    }
2682
2683  if (version.find ("*") != cmt_string::npos)
2684    {
2685        /*
2686      cout << "# ================= Package " << package
2687           << " version " << version << " " << path
2688           << " has wild cards and will not be considered." << endl;
2689        */
2690    }
2691  else
2692    {
2693      static const cmt_string empty;
2694      m_cvs.do_checkout_phase2 (path, package, version, empty);
2695    }
2696}
2697
2698//--------------------------------------------------------------------
2699
2700void RecursivePass3::begin ()
2701{
2702  m_first = true;
2703  m_result = "";
2704}
2705
2706void RecursivePass3::filter (const cmt_string& line)
2707{
2708  History& h = History::instance ();
2709 
2710  if (h.is_installed (line)) return;
2711 
2712  CmtSystem::cmt_string_vector words;
2713 
2714  CmtSystem::split (line, " \t", words);
2715
2716  enum
2717  {
2718    need_project,
2719    need_version,
2720    need_tag,
2721    no_need
2722  } state = need_project;
2723
2724  cmt_string project;
2725  cmt_string version;
2726  cmt_string tag;
2727
2728  for (int i = 1; i < words.size (); i++)
2729    {
2730      const cmt_string& s = words[i];
2731
2732      switch (state)
2733        {
2734          case need_project:
2735            project = s;
2736            state = need_version;
2737            break;
2738          case need_version:
2739            version = s;
2740            state = need_tag;
2741            break;
2742          case need_tag:
2743            tag = s;
2744            state = no_need;
2745            break;
2746        }
2747    }
2748 
2749  if (version.find ("*") != cmt_string::npos)
2750    {
2751        /*
2752      cout << "# ================= Project " << project
2753           << " version " << version << " " << path
2754           << " has wild cards and will not be considered." << endl;
2755        */
2756      return;
2757    }
2758
2759  /**
2760   *  At the first pass, we simply accumulate the not-yet handled
2761   *  use statements.
2762   */
2763 
2764  m_result += line;
2765  m_result += "\n";
2766 
2767  if (m_first)
2768    {
2769      m_first = false;
2770      cout << "  # --> now propagate cmt checkout to :" << endl;
2771    }
2772 
2773  cout << "  #     " << project << " " << version << " " << tag << endl;
2774}
2775
2776const cmt_string& RecursivePass3::result () const
2777{
2778  return (m_result);
2779}
2780
2781//--------------------------------------------------------------------
2782
2783RecursivePass4::RecursivePass4 (CvsImplementation& cvs) : m_cvs (cvs)
2784{
2785}
2786
2787void RecursivePass4::begin ()
2788{
2789}
2790
2791void RecursivePass4::filter (const cmt_string& line)
2792{
2793    //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "RecursivePass4::filter> "
2794    //                                          << "line=[" << line << "]" << endl;
2795
2796  /**
2797   *   At the second pass, the lines are really handled. Thus
2798   *   the lines are stored into m_installed so as to avoid
2799   *   later on re-installation.
2800   */
2801 
2802  History& h = History::instance ();
2803 
2804  if (h.is_installed (line)) return;
2805 
2806  h.install (line);
2807 
2808  CmtSystem::cmt_string_vector words;
2809 
2810  CmtSystem::split (line, " \t", words);
2811
2812  enum
2813  {
2814    need_project,
2815    need_version,
2816    need_tag,
2817    no_need
2818  } state = need_project;
2819
2820  cmt_string project;
2821  cmt_string version;
2822  cmt_string tag;
2823
2824  for (int i = 1; i < words.size (); i++)
2825    {
2826      const cmt_string& s = words[i];
2827
2828      switch (state)
2829        {
2830          case need_project:
2831            project = s;
2832            state = need_version;
2833            break;
2834          case need_version:
2835            version = s;
2836            state = need_tag;
2837            break;
2838          case need_tag:
2839            tag = s;
2840            state = no_need;
2841            break;
2842        }
2843    }
2844
2845  if (version.find ("*") != cmt_string::npos)
2846    {
2847        /*
2848      cout << "# ================= Project " << project
2849           << " version " << version
2850           << " has wild cards and will not be considered." << endl;
2851        */
2852    }
2853  else
2854    {
2855      static const cmt_string empty;
2856      m_cvs.do_checkout_phase2 (empty, project, version, tag);
2857    }
2858}
2859
2860//--------------------------------------------------------------------
2861
2862void Cvs::tags (const CmtSystem::cmt_string_vector& arguments)
2863{
2864  CvsImplementation cvs;
2865
2866  cvs.tags (arguments);
2867}
2868
2869void Cvs::branches (const cmt_string& module)
2870{
2871  CvsImplementation cvs;
2872
2873  cvs.branches (module);
2874}
2875
2876void Cvs::subpackages (const cmt_string& module)
2877{
2878  CvsImplementation cvs;
2879
2880  cvs.subpackages (module);
2881}
2882
2883void Cvs::subprojects (const cmt_string& module)
2884{
2885  CvsImplementation cvs;
2886
2887  cvs.subprojects (module);
2888}
2889
2890void Cvs::checkout (const CmtSystem::cmt_string_vector& arguments)
2891{
2892  CvsImplementation cvs;
2893
2894  cvs.checkout (arguments);
2895}
2896
Note: See TracBrowser for help on using the repository browser.