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

Last change on this file since 44 was 44, checked in by arnault, 19 years ago

Clean up cmt checkout - prepare project checkout

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