source: CMT/v1r23/source/cmt_cvs.cxx

Last change on this file was 461, checked in by rybkin, 16 years ago

See C.L. 362

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