source: CMT/v1r25-branch/source/cmt_cvs.cxx

Last change on this file was 664, checked in by rybkin, 10 years ago

merge -r 646:663 HEAD

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