source: CMT/v1r25p20140131/source/cmt_vcs.cxx

Last change on this file was 669, checked in by rybkin, 10 years ago

svn merge -r 666:668 HEAD

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