source: CMT/v1r20p20070517/source/cmt_cvs.cxx

Last change on this file was 412, checked in by arnault, 17 years ago

Fix: Forgot to consider the minimal case where only one tag exists for the package, the tag related with the original import. CL 330

  • Property svn:eol-style set to native
File size: 63.1 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                  execute ("cmt -quiet broadcast cmt -quiet config");
1890             
1891              }
1892            else
1893              {
1894                if (no_config==false)
1895                  execute ("cmt -quiet config");
1896              }
1897          }
1898        else
1899          {
1900            if (no_config==false)
1901              execute ("cmt -quiet config");
1902          }
1903      }
1904    else if (structure_info == "project")
1905      {
1906       
1907        if (m_verbose)
1908          {
1909            cerr << "#CMT> dir=" << dir << endl;
1910          }
1911       
1912        if (!CmtSystem::cd (dir))
1913          {
1914            cerr << "#CMT> Project directory not created " << dir << endl;
1915            return;
1916          }
1917       
1918        cmt_string file_name;
1919       
1920        file_name = "cmt";
1921        file_name += CmtSystem::file_separator ();
1922        file_name += "project.cmt";
1923       
1924        if (!CmtSystem::test_file (file_name))
1925          {
1926            cerr << "# " << product << " not a CMT project" << endl;
1927            return;
1928          }
1929       
1930        if (recursive)
1931          {
1932            checkout_from_project_file (file_name);
1933          }
1934
1935        cerr << "# ================= Project " << product << " completed" << endl;
1936
1937      }
1938  }
1939 
1940  /**
1941     Top level of the checkout operation, initiated from the command line arguments
1942
1943     Construct an history of the checkouts to avoid duplicating the
1944     checkouts during the recursivity
1945
1946     Eventually
1947     o perform the cmt config for packages.
1948
1949  */
1950  void do_checkout_phase1 (const cmt_string& module, 
1951                           const cmt_string& version_dir, 
1952                           const cmt_string& version_tag)
1953  {
1954    if (m_verbose)
1955      {
1956        cerr << "#CMT> checkout phase1 module=" << module
1957             << " version_dir=" << version_dir << " version_tag=" << version_tag << endl;
1958      }
1959
1960    add_cmtpath (m_home_dir);
1961
1962    History& h = History::instance ();
1963
1964    h.clear ();
1965
1966    if (module == "")
1967      {
1968        if (m_verbose)
1969          {
1970            cerr << "#CMT> Missing module name" << endl;
1971          }
1972        return;
1973      }
1974
1975    cmt_string offset;
1976    cmt_string product;
1977    cmt_string version;
1978    cmt_string tag;
1979   
1980    {
1981      cmt_string m;
1982      m = m_cvs_offset;
1983      m += module;
1984       
1985      get_cvs_infos_with_offset (m);
1986       
1987      if (error_info != "")
1988        {
1989          cerr << error_info << endl;
1990          return;
1991        }
1992    }
1993
1994    if (version_tag == "")
1995      {
1996        // No version tag is specified
1997        // we need to discard all CVS branches
1998        //
1999        cmt_string versions = "";
2000
2001        if (cvsversions_top_info != "")
2002          {
2003            versions = cvsversions_top_info;
2004            versions += " ";
2005          }
2006
2007        versions += cvsversions_info;
2008
2009        if (m_verbose)
2010          {
2011            cerr << "#CMT> cumulated versions " << versions << endl;
2012          }
2013
2014        static CmtSystem::cmt_string_vector words;
2015
2016        // Get all <tag>:<version> items
2017
2018        CmtSystem::split (versions, " \t", words);
2019
2020        for (int i = 0; i < words.size (); i++)
2021          {
2022            // split to get <tag> and <version> separately
2023
2024            static CmtSystem::cmt_string_vector vts;
2025            CmtSystem::split (words[i], ":", vts);
2026
2027            cmt_string t = vts[0];
2028            cmt_string v = vts[1];
2029
2030            // Split to count the number of items for the CVS version
2031
2032            static CmtSystem::cmt_string_vector ds;
2033            CmtSystem::split (v, ".", ds);
2034
2035            if ((ds.size () == 2) || (v == "1.1.1.1"))
2036              {
2037                tag = t;
2038                break;
2039              }
2040          }
2041      }
2042    else
2043      {
2044        tag = version_tag;
2045      }
2046
2047    version = (version_dir == "") ? tag : version_dir;
2048
2049    CmtSystem::dirname (module, offset);
2050    CmtSystem::basename (module, product);
2051   
2052    cmt_string top_dir;
2053       
2054    top_dir = m_home_dir;
2055    top_dir += CmtSystem::file_separator ();
2056    top_dir += m_checkout_dir;
2057    top_dir += CmtSystem::file_separator ();
2058    top_dir += offset;
2059    top_dir += CmtSystem::file_separator ();
2060    top_dir += product;
2061    top_dir += CmtSystem::file_separator ();
2062    top_dir += version;
2063
2064    CmtSystem::reduce_file_separators (top_dir);
2065
2066    if (m_verbose)
2067      {
2068        cerr << "#CMT> about to checkout " << structure_info
2069             << " " << product << " version " << version << " into " << top_dir << endl;
2070      }
2071
2072    static const cmt_string empty;
2073    do_checkout_phase2 (offset, product, version, tag);
2074
2075    if (m_simulation) return;
2076
2077    if (!CmtSystem::cd (top_dir)) return;
2078
2079    if (structure_info == "project")
2080      {
2081        cmt_string file_name;
2082   
2083        file_name = "cmt";
2084        file_name += CmtSystem::file_separator ();
2085        file_name += "project.cmt";
2086       
2087        if (!CmtSystem::test_file (file_name))
2088          {
2089            cerr << "# " << product << " was not properly checked out and is missing its cmt/project.cmt file" << endl;
2090            return;
2091          }
2092      }
2093    else
2094      {
2095        cmt_string file_name;
2096   
2097        file_name = "cmt";
2098        file_name += CmtSystem::file_separator ();
2099        file_name += "requirements";
2100       
2101        if (CmtSystem::test_file (file_name))
2102          {
2103            top_dir += CmtSystem::file_separator ();
2104            top_dir += "cmt";
2105            CmtSystem::cd ("cmt");
2106          }
2107        else
2108          {
2109            file_name = "mgr";
2110            file_name += CmtSystem::file_separator ();
2111            file_name += "requirements";
2112           
2113            if (CmtSystem::test_file (file_name))
2114              {
2115                top_dir += CmtSystem::file_separator ();
2116                top_dir += "mgr";
2117                CmtSystem::cd ("mgr");
2118              }
2119            else
2120              {
2121                cerr << "# " << product << " was not properly checked out and is missing its cmt/requirements file" << endl;
2122                return;
2123              }
2124          }
2125       
2126        if (m_verbose)
2127          {
2128            cerr << "#CMT> product " << product << " has been checked out" << endl;
2129          }
2130       
2131        if (!m_recursive)
2132          {
2133            if (no_config==false)
2134              execute ("cmt -quiet config");
2135          }
2136      }
2137  }
2138
2139  void help ()
2140  {
2141    cerr << "> cd <some work area>" << endl;
2142    cerr << "> cmt checkout [modifier ...] <package|project>" << endl;
2143    cerr << "" << endl;
2144    cerr << "   modifier :" << endl;
2145    cerr << "   -l        Do not process used packages (default)." << endl;
2146    cerr << "   -R        Process used products recursively." << endl;
2147    cerr << "   -r rev    Check out version tag. (is sticky)" << endl;
2148    cerr << "   -vd dir   Use this version directory instead of CVS tag." << endl;
2149    cerr << "   -d dir    Check out into dir instead of module name." << endl;
2150    cerr << "   -o offset Offset in the CVS repository" << endl;
2151    cerr << "   -requirements <requirements file path>  Check out packages referenced in this requirements file" << endl;
2152    cerr << "   -t  Change file timestamps to the date of checkout" << endl;
2153    cerr << "   -n        simulation mode on" << endl;
2154    cerr << "   -no_config  Disable config step after checkout" << endl;   
2155    cerr << "   -v        verbose mode on" << endl;
2156    cerr << "   --help    print this help" << endl;
2157    cerr << "" << endl;
2158    cerr << "> cmt cvstags <package|project>" << endl;
2159    cerr << "> cmt cvssubpackages <directory>" << endl;
2160    cerr << "> cmt cvssubprojects <directory>" << endl;
2161    cerr << "" << endl;
2162  }
2163
2164  /**
2165     Implementation of the cmt cvstags
2166     Get the CVS tags of a module
2167  */
2168  void tags (const CmtSystem::cmt_string_vector& arguments)
2169  {
2170    if (arguments.size () < 1)
2171      {
2172        help ();
2173        return;
2174      }
2175   
2176    if (CmtSystem::getenv ("CVSROOT") == "")
2177      {
2178        cerr << "# Please set CVSROOT first !" << endl;
2179        return;
2180      }
2181   
2182    m_cvs_offset = CmtSystem::getenv ("CMTCVSOFFSET");
2183    if (m_cvs_offset != "") 
2184      {
2185        m_cvs_offset += "/";
2186        m_cvs_offset.replace_all ("//", "/");
2187      }
2188   
2189    bool all = false;
2190   
2191    for (int arg = 0; arg < arguments.size (); arg++)
2192      {
2193        const cmt_string& option = arguments[arg];
2194       
2195        if (option == "-all")
2196          {
2197            all = true;
2198          }
2199        else
2200          {
2201            get_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), option);
2202           
2203            if (error_info != "")
2204              {
2205                cerr << error_info << endl;
2206              }
2207            else
2208              {
2209                cmt_string tags;
2210               
2211                if (all)
2212                  {
2213                    tags = cvsversions_top_info;
2214                    tags += " ";
2215                    tags += cvsversions_info;
2216                  }
2217                else
2218                  {
2219                    tags = tags_top_info;
2220                    tags += " ";
2221                    tags += tags_info;
2222                  }
2223               
2224                CmtSystem::cmt_string_vector v;
2225               
2226                CmtSystem::split (tags, " \t", v);
2227                for (int i = 0; i < v.size (); i++)
2228                  {
2229                    const cmt_string& s = v[i];
2230                    cerr << s << endl;
2231                  }
2232              }
2233          }
2234      }
2235  }
2236
2237  /**
2238     Implementation of the cmt cvsbranches
2239     Get the subdirs of a module that are not subackages
2240  */
2241  void branches (const cmt_string& module)
2242  {
2243    cmt_string out;
2244   
2245    get_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), module);
2246   
2247    if (error_info != "")
2248      {
2249        cerr << error_info << endl;
2250      }
2251    else
2252      {
2253        cerr << branches_info << endl;
2254      }
2255  }
2256
2257  /**
2258     Implementation of the cmt cvssubpackages
2259     Get the subdirs of a module that ARE CMT subpackages
2260  */
2261  void subpackages (const cmt_string& module)
2262  {
2263    cmt_string out;
2264   
2265    get_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), (module == "") ? "." : module);
2266   
2267    if (error_info != "")
2268      {
2269        cerr << error_info << endl;
2270      }
2271    else
2272      {
2273        cerr << subpackages_info << endl;
2274      }
2275  }
2276 
2277  /**
2278     Implementation of the cmt cvssubrojects
2279     Get the subdirs of a module that ARE CMT projects
2280  */
2281  void subprojects (const cmt_string& module)
2282  {
2283    cmt_string out;
2284   
2285    get_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), (module == "") ? "." : module);
2286   
2287    if (error_info != "")
2288      {
2289        cerr << error_info << endl;
2290      }
2291    else
2292      {
2293        cerr << subprojects_info << endl;
2294      }
2295  }
2296
2297  /**
2298     Implementation of the cmt checkout
2299     Parse the arguments
2300     Then call do_checkout for each argument
2301  */
2302  void checkout (const CmtSystem::cmt_string_vector& arguments)
2303  {
2304    if (arguments.size () < 1)
2305      {
2306        help ();
2307        return;
2308      }
2309   
2310    if (CmtSystem::getenv ("CVSROOT") == "")
2311      {
2312        cerr << "# Please set CVSROOT first !" << endl;
2313        return;
2314      }
2315   
2316    m_home_dir = CmtSystem::pwd ();
2317    m_checkout_dir = "";
2318    m_version_dir = "";
2319    m_cvs_offset = "";
2320
2321    cmt_string module;
2322   
2323    m_recursive      = false;
2324    need_touch_files = false;
2325    no_config        = false;
2326   
2327    bool need_version_tag = false;
2328    cmt_string version_tag;
2329   
2330   
2331    bool need_checkout_dir = false;
2332    bool need_cvs_offset = false;
2333    bool need_requirements_file = false;
2334    bool need_version_dir = false;
2335   
2336    m_simulation = false;
2337    //m_verbose = true;
2338    m_verbose = false;
2339   
2340    m_head = true;
2341   
2342    m_cvs_offset = CmtSystem::getenv ("CMTCVSOFFSET");
2343    if (m_cvs_offset != "") 
2344      {
2345        m_cvs_offset += "/";
2346        m_cvs_offset.replace_all ("//", "/");
2347      }
2348   
2349    for (int arg = 0; arg < arguments.size (); arg++)
2350      {
2351        const cmt_string& option = arguments[arg];
2352       
2353        if (need_version_tag)
2354          {
2355            need_version_tag = false;
2356           
2357            if (option == "HEAD")
2358              {
2359                m_head = true;
2360              }
2361            else
2362              {
2363                version_tag = option;
2364              }
2365          }
2366        else if (need_checkout_dir)
2367          {
2368            need_checkout_dir = false;
2369            m_checkout_dir = option;
2370          }
2371        else if (need_version_dir)
2372          {
2373            need_version_dir = false;
2374            m_version_dir = option;
2375          }
2376        else if (need_cvs_offset)
2377          {
2378            need_cvs_offset = false;
2379            m_cvs_offset = option;
2380            m_cvs_offset += '/';
2381            m_cvs_offset.replace_all ("//", "/");
2382          }
2383        else if (need_requirements_file)
2384          {
2385            need_requirements_file = false;
2386            m_head = false;
2387            checkout_from_requirements (option);
2388          }
2389        else
2390          {
2391            if (option == "-R")
2392              {
2393                m_recursive = true;
2394              }
2395            else if (option == "-t")
2396              {   
2397                need_touch_files = true;
2398              } 
2399            else if (option == "-l")
2400              {
2401                m_recursive = false;
2402              }
2403            else if (option == "-r")
2404              {
2405                need_version_tag = true;
2406                m_head = false;
2407              }
2408            else if (option == "-d")
2409              {
2410                need_checkout_dir = true;
2411              }
2412            else if (option == "-o")
2413              {
2414                need_cvs_offset = true;
2415              }
2416            else if (option == "-n")
2417              {
2418                m_simulation = true;
2419              }
2420            else if (option == "-no_config")
2421              {
2422                no_config = true;
2423              }       
2424            else if (option == "-v")
2425              {
2426                m_verbose = true;
2427              }
2428            else if (option == "-vd")
2429              {
2430                need_version_dir = true;
2431              }
2432            else if (option == "-requirements")
2433              {
2434                need_requirements_file = true;
2435              }
2436            else if (option == "--help")
2437              {
2438                help ();
2439                return;
2440              }
2441            else if (option[0] == '-')
2442              {
2443                help ();
2444                return;
2445              }
2446            else
2447              {
2448                do_checkout_phase1 (option, m_version_dir, version_tag);
2449              }
2450          }
2451      }
2452  }
2453
2454private:
2455
2456  bool m_recursive;
2457  bool need_touch_files;
2458  bool m_head;
2459  bool m_verbose;
2460  bool m_simulation;
2461  bool no_config;
2462
2463  cmt_string m_home_dir;
2464  cmt_string m_checkout_dir;
2465  cmt_string m_version_dir;
2466  cmt_string m_cvs_offset;
2467
2468  cmt_string m_protocol_level;
2469  cmt_string m_last_module;
2470  cmt_string m_last_cvs_infos;
2471  cmt_string structure_info;
2472  cmt_string error_info;
2473  cmt_string tags_top_info;
2474  cmt_string tags_info;
2475  cmt_string cvsversions_top_info;
2476  cmt_string cvsversions_info;
2477  cmt_string branches_info;
2478  cmt_string subpackages_info;
2479  cmt_string subprojects_info;
2480};
2481
2482//--------------------------------------------------------------------
2483
2484void Grep::begin ()
2485{
2486  m_result = "";
2487}
2488
2489void Grep::filter (const cmt_string& line)
2490{
2491  //if (CmtSystem::testenv ("CMTTESTAWK")) cerr << "Grep::filter" << endl;
2492
2493  if (m_result != "") m_result += " ";
2494  m_result += line;
2495}
2496
2497const cmt_string& Grep::result () const
2498{
2499  return (m_result);
2500}
2501
2502//--------------------------------------------------------------------
2503
2504Cut::Cut (int field)
2505{
2506  m_field = field;
2507}
2508
2509void Cut::begin ()
2510{
2511  //if (CmtSystem::testenv ("CMTTESTAWK")) cerr << "Cut::begin" << endl;
2512  m_result = "";
2513}
2514
2515void Cut::filter (const cmt_string& line)
2516{
2517  //if (CmtSystem::testenv ("CMTTESTAWK")) cerr << "Cut::filter" << endl;
2518
2519  static CmtSystem::cmt_string_vector words;
2520 
2521  CmtSystem::split (line, " \t", words);
2522 
2523  if (words.size () <= m_field) return;
2524 
2525  if (m_result != "") m_result += " ";
2526  m_result += words[m_field];
2527}
2528
2529const cmt_string& Cut::result () const
2530{
2531  return (m_result);
2532}
2533
2534//--------------------------------------------------------------------
2535//--------------------------------------------------------------------
2536
2537History& History::instance ()
2538{
2539  static History h;
2540  return (h);
2541}
2542
2543void History::clear ()
2544{
2545  m_installed = "";
2546}
2547
2548void History::install (const cmt_string& line)
2549{
2550  m_installed += "|";
2551  m_installed += line;
2552  m_installed += "|";
2553}
2554
2555bool History::is_installed (const cmt_string& line)
2556{
2557  if (m_installed.find (line) != cmt_string::npos)
2558    {
2559      return (true);
2560    }
2561 
2562  return (false);
2563}
2564
2565History::History ()
2566{
2567}
2568
2569
2570//--------------------------------------------------------------------
2571
2572void RecursivePass1::begin ()
2573{
2574  m_first = true;
2575  m_result = "";
2576}
2577
2578void RecursivePass1::filter (const cmt_string& line)
2579{
2580  //if (CmtSystem::testenv ("CMTTESTAWK")) cerr << "RecursivePass1::filter> "
2581  //                                          << "line=[" << line << "]" << endl;
2582
2583  if (line.find ("use CMT") != cmt_string::npos) return;
2584  if (line.find ("use cmt") != cmt_string::npos) return;
2585 
2586  History& h = History::instance ();
2587 
2588  if (h.is_installed (line)) return;
2589 
2590  CmtSystem::cmt_string_vector words;
2591 
2592  CmtSystem::split (line, " \t", words);
2593
2594  enum
2595    {
2596      need_package,
2597      need_version,
2598      need_path,
2599      no_need
2600    } state = need_package;
2601
2602  cmt_string package;
2603  cmt_string version;
2604  cmt_string path;
2605
2606  for (int i = 1; i < words.size (); i++)
2607    {
2608      const cmt_string& s = words[i];
2609
2610      if (s[0] == '-') continue;
2611
2612      switch (state)
2613        {
2614        case need_package:
2615          package = s;
2616          state = need_version;
2617          break;
2618        case need_version:
2619          version = s;
2620          state = need_path;
2621          break;
2622        case need_path:
2623          path = s;
2624          state = no_need;
2625          break;
2626        }
2627    }
2628 
2629  if (version.find ("*") != cmt_string::npos)
2630    {
2631      /*
2632        cerr << "# ================= Package " << package
2633        << " version " << version << " " << path
2634        << " has wild cards and will not be considered." << endl;
2635      */
2636      return;
2637    }
2638
2639  /**
2640   *  At the first pass, we simply accumulate the not-yet handled
2641   *  use statements.
2642   */
2643 
2644  m_result += line;
2645  m_result += "\n";
2646 
2647  if (m_first)
2648    {
2649      m_first = false;
2650      cerr << "  # --> now propagate cmt checkout to :" << endl;
2651    }
2652 
2653  cerr << "  #     " << package << " " << version << " " << path << endl;
2654}
2655
2656const cmt_string& RecursivePass1::result () const
2657{
2658  return (m_result);
2659}
2660
2661//--------------------------------------------------------------------
2662
2663RecursivePass2::RecursivePass2 (CvsImplementation& cvs) : m_cvs (cvs)
2664{
2665}
2666
2667void RecursivePass2::begin ()
2668{
2669}
2670
2671void RecursivePass2::filter (const cmt_string& line)
2672{
2673  //if (CmtSystem::testenv ("CMTTESTAWK")) cerr << "RecursivePass2::filter> "
2674  //                                          << "line=[" << line << "]" << endl;
2675
2676  /**
2677   *   At the second pass, the lines are really handled. Thus
2678   *   the lines are stored into m_installed so as to avoid
2679   *   later on re-installation.
2680   */
2681 
2682  History& h = History::instance ();
2683 
2684  if (h.is_installed (line)) return;
2685 
2686  h.install (line);
2687 
2688  CmtSystem::cmt_string_vector words;
2689 
2690  CmtSystem::split (line, " \t", words);
2691
2692  enum
2693    {
2694      need_package,
2695      need_version,
2696      need_path,
2697      no_need
2698    } state = need_package;
2699
2700  cmt_string package;
2701  cmt_string version;
2702  cmt_string path;
2703
2704  for (int i = 1; i < words.size (); i++)
2705    {
2706      const cmt_string& s = words[i];
2707
2708      if (s[0] == '-') continue;
2709
2710      switch (state)
2711        {
2712        case need_package:
2713          package = s;
2714          state = need_version;
2715          break;
2716        case need_version:
2717          version = s;
2718          state = need_path;
2719          break;
2720        case need_path:
2721          path = s;
2722          state = no_need;
2723          break;
2724        }
2725    }
2726
2727  if (version.find ("*") != cmt_string::npos)
2728    {
2729      /*
2730        cerr << "# ================= Package " << package
2731        << " version " << version << " " << path
2732        << " has wild cards and will not be considered." << endl;
2733      */
2734    }
2735  else
2736    {
2737      static const cmt_string empty;
2738      m_cvs.do_checkout_phase2 (path, package, version, empty);
2739    }
2740}
2741
2742//--------------------------------------------------------------------
2743
2744void RecursivePass3::begin ()
2745{
2746  m_first = true;
2747  m_result = "";
2748}
2749
2750void RecursivePass3::filter (const cmt_string& line)
2751{
2752  History& h = History::instance ();
2753 
2754  if (h.is_installed (line)) return;
2755 
2756  CmtSystem::cmt_string_vector words;
2757 
2758  CmtSystem::split (line, " \t", words);
2759
2760  enum
2761    {
2762      need_project,
2763      need_version,
2764      need_tag,
2765      no_need
2766    } state = need_project;
2767
2768  cmt_string project;
2769  cmt_string version;
2770  cmt_string tag;
2771
2772  for (int i = 1; i < words.size (); i++)
2773    {
2774      const cmt_string& s = words[i];
2775
2776      switch (state)
2777        {
2778        case need_project:
2779          project = s;
2780          state = need_version;
2781          break;
2782        case need_version:
2783          version = s;
2784          state = need_tag;
2785          break;
2786        case need_tag:
2787          tag = s;
2788          state = no_need;
2789          break;
2790        }
2791    }
2792 
2793  if (version.find ("*") != cmt_string::npos)
2794    {
2795      /*
2796        cerr << "# ================= Project " << project
2797        << " version " << version << " " << path
2798        << " has wild cards and will not be considered." << endl;
2799      */
2800      return;
2801    }
2802
2803  /**
2804   *  At the first pass, we simply accumulate the not-yet handled
2805   *  use statements.
2806   */
2807 
2808  m_result += line;
2809  m_result += "\n";
2810 
2811  if (m_first)
2812    {
2813      m_first = false;
2814      cerr << "  # --> now propagate cmt checkout to :" << endl;
2815    }
2816 
2817  cerr << "  #     " << project << " " << version << " " << tag << endl;
2818}
2819
2820const cmt_string& RecursivePass3::result () const
2821{
2822  return (m_result);
2823}
2824
2825//--------------------------------------------------------------------
2826
2827RecursivePass4::RecursivePass4 (CvsImplementation& cvs) : m_cvs (cvs)
2828{
2829}
2830
2831void RecursivePass4::begin ()
2832{
2833}
2834
2835void RecursivePass4::filter (const cmt_string& line)
2836{
2837  //if (CmtSystem::testenv ("CMTTESTAWK")) cerr << "RecursivePass4::filter> "
2838  //                                          << "line=[" << line << "]" << endl;
2839
2840  /**
2841   *   At the second pass, the lines are really handled. Thus
2842   *   the lines are stored into m_installed so as to avoid
2843   *   later on re-installation.
2844   */
2845 
2846  History& h = History::instance ();
2847 
2848  if (h.is_installed (line)) return;
2849 
2850  h.install (line);
2851 
2852  CmtSystem::cmt_string_vector words;
2853 
2854  CmtSystem::split (line, " \t", words);
2855
2856  enum
2857    {
2858      need_project,
2859      need_version,
2860      need_tag,
2861      no_need
2862    } state = need_project;
2863
2864  cmt_string project;
2865  cmt_string version;
2866  cmt_string tag;
2867
2868  for (int i = 1; i < words.size (); i++)
2869    {
2870      const cmt_string& s = words[i];
2871
2872      switch (state)
2873        {
2874        case need_project:
2875          project = s;
2876          state = need_version;
2877          break;
2878        case need_version:
2879          version = s;
2880          state = need_tag;
2881          break;
2882        case need_tag:
2883          tag = s;
2884          state = no_need;
2885          break;
2886        }
2887    }
2888
2889  if (version.find ("*") != cmt_string::npos)
2890    {
2891      /*
2892        cerr << "# ================= Project " << project
2893        << " version " << version
2894        << " has wild cards and will not be considered." << endl;
2895      */
2896    }
2897  else
2898    {
2899      static const cmt_string empty;
2900      m_cvs.do_checkout_phase2 (empty, project, version, tag);
2901    }
2902}
2903
2904//--------------------------------------------------------------------
2905
2906void Cvs::tags (const CmtSystem::cmt_string_vector& arguments)
2907{
2908  CvsImplementation cvs;
2909
2910  cvs.tags (arguments);
2911}
2912
2913void Cvs::branches (const cmt_string& module)
2914{
2915  CvsImplementation cvs;
2916
2917  cvs.branches (module);
2918}
2919
2920void Cvs::subpackages (const cmt_string& module)
2921{
2922  CvsImplementation cvs;
2923
2924  cvs.subpackages (module);
2925}
2926
2927void Cvs::subprojects (const cmt_string& module)
2928{
2929  CvsImplementation cvs;
2930
2931  cvs.subprojects (module);
2932}
2933
2934void Cvs::checkout (const CmtSystem::cmt_string_vector& arguments)
2935{
2936  CvsImplementation cvs;
2937
2938  cvs.checkout (arguments);
2939}
2940
Note: See TracBrowser for help on using the repository browser.