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

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

See C.L. 522

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