source: CMT/v1r18p20060606/source/cmt_cvs.cxx

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

ignore CVS directory when checkouting

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