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

Last change on this file since 590 was 590, checked in by rybkin, 13 years ago

See C.L. 467

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