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

Last change on this file since 535 was 535, checked in by rybkin, 14 years ago

See C.L. 422

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