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

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

See C.L. 426

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