source: CMT/HEAD/source/cmt_vcs.cxx @ 534

Last change on this file since 534 was 534, checked in by rybkin, 15 years ago

See C.L. 421

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