source: CMT/HEAD/source/cmt_cvs.cxx @ 453

Last change on this file since 453 was 452, checked in by rybkin, 16 years ago

See C.L. 353

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