source: CMT/v1r21/source/cmt_project.cxx

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

See C.L. 428

  • Property svn:eol-style set to native
File size: 78.5 KB
Line 
1
2//-----------------------------------------------------------
3// Copyright Christian Arnault LAL-Orsay CNRS
4// arnault@lal.in2p3.fr
5// Modified by garonne@lal.in2p3.fr
6// See the complete license in cmt_license.txt "http://www.cecill.info".
7//-----------------------------------------------------------
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <ctype.h>
13
14#include "cmt_project.h"
15#include "cmt_database.h"
16#include "cmt_system.h"
17#include "cmt_awk.h"
18#include "cmt_syntax.h"
19#include "cmt_tag.h"
20#include "cmt_error.h"
21#include "cmt_log.h"
22
23class ProjectReader : public Awk
24{
25public:
26
27  ProjectReader ()
28  {
29  }
30 
31  const cmt_string& get_project_name () const
32  {
33    return (m_project);
34  }
35 
36  void filter (const cmt_string& line)
37  {
38    CmtSystem::cmt_string_vector words;
39    CmtSystem::split (line, " \t", words);
40    if (words[0] == "project")
41      {
42        m_project = words[1];
43      }
44  }
45 
46private:
47  cmt_string m_project;
48};
49
50class ProjectPatcher : public Awk
51{
52public:
53
54  ProjectPatcher (const cmt_string& p) : m_project (p)
55  {
56  }
57
58  void commit ()
59  {
60    m_output.write (Project::get_project_file_name ());
61  }
62
63  void filter (const cmt_string& line)
64  {
65    CmtSystem::cmt_string_vector words;
66    CmtSystem::split (line, " \t", words);
67    if (words[0] == "project")
68      {
69        m_output += "project ";
70        m_output += m_project;
71      }
72    else
73      {
74        m_output += line;
75      }
76
77    m_output += "\n";
78  }
79 
80private:
81  cmt_string m_output;
82  const cmt_string& m_project;
83};
84
85IProjectFactory& ProjectFactory::instance ()
86{
87  static ProjectFactory me;
88 
89  return (me);
90}
91
92void ProjectFactory::reset ()
93{
94  Project::clear_all ();
95}
96
97static bool get_release_from_path (const CmtSystem::cmt_string_vector& items, 
98                                   const cmt_string& path, 
99                                   const cmt_string& name, 
100                                   cmt_string& real_name, 
101                                   cmt_string& release)
102{
103  bool result = false;
104
105  release = "";
106  real_name = "";
107
108  cmt_string p = path;
109
110  if ((items.size () == 0) && (name == ""))
111    {
112      // There is no CMTPROJECTPATH and no expected project name.
113      // We have no way to find a project structure
114      // So we only expect a 2-level structure.
115
116      CmtSystem::basename (p, release);
117      CmtSystem::dirname (p, p);
118      CmtSystem::basename (p, real_name);
119     
120      return (false);
121    }
122
123  for (;;)
124    {
125      if (p == "")
126        {
127          // Protection: we found no matching project name
128          // and path was outside any CMTPROJECTPATH
129
130          p = path;
131
132          CmtSystem::basename (p, release);
133          CmtSystem::dirname (p, p);
134          CmtSystem::basename (p, real_name);
135
136          return (false);
137        }
138
139      cmt_string n;
140
141      CmtSystem::basename (p, n);
142      CmtSystem::dirname (p, p);
143
144      if (n == name)
145        {
146          real_name = name;
147          result = true;
148          break;
149        }
150
151      CmtSystem::basename (p, real_name);
152
153      for (int i = 0; i < items.size (); i++)
154        {
155          const cmt_string& item = items[i];
156          if (p == item)
157            {
158              // We have reached an item of CMTPROJECTPATH, no need to continue
159              return (false);
160            }
161        }
162
163      if (release == "")
164        {
165          release = n;
166        }
167      else
168        {
169          cmt_string r;
170
171          r = n;
172          r += CmtSystem::file_separator ();
173          r += release;
174          release = r;
175        }
176    }
177
178  //cerr << "$CMT> GRFP> path=" << path << " name=" << name << " rel=" << release << endl;
179
180  return (result);
181}
182 
183
184/*
185  Every new CMTPATH entry becomes associated with a dedicated PROJECT
186  This function will understand this new entry to CMTPATH and understand it:
187  - it can correspond to an existing project (ie already declared)
188  - it's a new project
189  - then it tries to read and parse its project file
190*/
191Project* ProjectFactory::create_project (const cmt_string& specified_name,
192                                         const cmt_string& path,
193                                         const cmt_string& source,
194                                         Project* parent)
195{
196  cmt_string compressed_path = path;
197  CmtSystem::compress_path (compressed_path);
198  bool specify_name = (specified_name != "");
199
200  if (Cmt::get_debug ())
201    {
202      cout << "Creating project " << path << " with parent " << ((parent==0)? "0" : parent->get_name ()) << endl;
203      Project::show_all ();
204    }
205
206  cmt_string sep;
207  sep = CmtSystem::path_separator ();
208
209  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH"); 
210  CmtSystem::cmt_string_vector items;
211  CmtSystem::split (cmtprojectpath, sep, items);
212
213  cmt_string here = CmtSystem::pwd ();
214  if (!CmtSystem::cd (compressed_path)) return (0);
215  cmt_string pwd = CmtSystem::pwd ();
216
217  static Project::ProjectVector& Projects = Project::projects ();
218
219  int i;
220 
221  for (i = 0; i < Projects.size (); i++)
222    {
223      Project& p = Projects[i];
224     
225      if ((p.get_cmtpath () == compressed_path) ||
226          (p.get_cmtpath_pwd () == pwd) ||
227          (specify_name && (p.get_name () == specified_name)))
228        {
229          cmt_string r;
230          cmt_string n;
231
232          get_release_from_path (items, compressed_path, p.get_name (), n, r);
233
234          if (r != p.get_release ())
235            {
236              CmtMessage::error ("Project " + p.get_name ()
237                                   + " requested with conflicting releases "
238                                   + p.get_release () + " and " + r);
239              /*
240              if (!Cmt::get_quiet ())
241                {
242                  cerr << "#CMT> Project " << p.get_name ()
243                       << " requested with conflicting releases " << p.get_release () << " and " << r << endl;
244                }
245              */
246              CmtError::set (CmtError::project_release_conflict, p.get_name ());
247            }
248 
249          bool updated (false);
250          if (parent != 0)
251            {
252              if (!p.has_parent (parent) || !parent->has_child (&p))
253                {
254              p.add_parent (parent);
255              parent->add_child (&p);
256
257              // Since p is a new parent, we should propagate the settings UP.
258
259              parent->update_strategies_from_children ();
260              updated = true;
261                }
262
263            }
264
265          CmtSystem::cd (here);
266          if (updated) Project::order_all ();
267          return (&p);
268        }
269    }
270
271
272  Project* project = 0;
273  Project* cmt = 0;
274 
275  bool is_current = false;
276 
277  cmt_string name = specified_name;
278  cmt_string project_name;
279  cmt_string release;
280
281  //
282  // Figure out if this is the current project
283  //
284  //  if (here.find (pwd) == 0) is_current = true;
285
286  // In case there are symlinks
287
288  //  cmt_string here_real, pwd_real;
289  //cerr << "realpath_: create_project" << endl;
290  /*
291  if (CmtSystem::realpath_ (here, here_real) && CmtSystem::realpath_ (pwd, pwd_real))
292    {
293      if (here_real.find (pwd_real) == 0) is_current = true;
294    }
295  */
296  cmt_string pwd_real;
297  if (!CmtSystem::realpath_ (pwd, pwd_real))
298    {
299      CmtError::set (CmtError::file_access_error, "Cannot compute real path `" +
300                     pwd + "'");
301      CmtError::print ();
302      return 0;
303      //      if (Cmt::get_current_dir_real ().find (pwd_real) == 0) is_current = true;
304    }
305
306  cmt_string text;
307
308  /*
309    Now Figure out the project name from the project file
310    or does not specify the project name
311  */
312  bool has_project_file = false;
313
314  if (CmtSystem::cd ("cmt") && CmtSystem::test_file (Project::get_project_file_name ()))
315    {
316      has_project_file = true;
317      text.read (Project::get_project_file_name ());
318
319      ProjectReader reader;
320
321      reader.run (text);
322
323      project_name = reader.get_project_name ();
324    }
325
326  enum
327    {
328      without_project_file   = 0x01,
329      with_project_file      = 0x02,
330      without_project_name   = 0x04,
331      with_project_name      = 0x08,
332      without_specified_name = 0x10,
333      with_specified_name    = 0x20,
334      names_mismatch         = 0x40,
335      names_match            = 0x80
336    };
337
338  int status = ((has_project_file) ? with_project_file : without_project_file) |
339    ((has_project_file && (project_name != "")) ? with_project_name : without_project_name) |
340    ((specify_name) ? with_specified_name : without_specified_name) |
341    ((specify_name && has_project_file && (project_name == specified_name)) ? names_match : names_mismatch);
342
343  if (source == "default path")
344    {
345      name = "CMT";
346    }
347  else
348    {
349      cmt_string n;
350         
351      switch (status)
352        {
353        case with_project_file | without_project_name | without_specified_name | names_mismatch:
354
355          // The project is neither specified from the caller nor from the project file
356
357          /*
358            if (!Cmt::get_quiet ())
359            {
360            cerr << "#CMT> Warning: project name unspecified in project file." << endl;
361            }
362          */
363     
364          get_release_from_path (items, compressed_path, "", name, release);
365
366          break;
367         
368        case with_project_file | without_project_name | with_specified_name | names_mismatch:
369         
370          // The name is only specified from the caller
371          // find this specified name in the path
372         
373          if (get_release_from_path (items, compressed_path, specified_name, name, release))
374            {
375              // The specified name has been found from the path.
376              // We believe in the release spec.
377            }
378          else
379            {
380              // The specified name is not in the path.
381              /*
382                if (!Cmt::get_quiet ())
383                {
384                cerr << "#CMT> Warning: specified project name "
385                << specified_name
386                << " from the caller does not match path." << endl;
387                }
388              */
389              name = specified_name;
390            }
391         
392          break;
393         
394        case with_project_file | with_project_name | with_specified_name | names_match:
395         
396          // We have a double specification: from the caller and from the project file.
397          // And both specifications are consistent. 
398         
399          if (get_release_from_path (items, compressed_path, specified_name, name, release))
400            {
401              // The specified name has been found from the path.
402              // We believe in the release spec.
403            }
404          else
405            {
406              // The specified name is not in the path.
407              /*
408                if (!Cmt::get_quiet ())
409                {
410                cerr << "#CMT> Warning: specified project name "
411                << specified_name
412                << " from project file and from caller does not match path." << endl;
413                }
414              */
415              name = specified_name;
416            }
417         
418          break;
419         
420        case with_project_file | with_project_name | with_specified_name | names_mismatch:
421         
422          // We have a double specification: from the caller and from the project file.
423          // Specifications are inconsistent!!
424         
425          /*
426            if (!Cmt::get_quiet ())
427            {
428            cerr << "#CMT> Warning: specified project name "
429            << specified_name
430            << " inconsistent with name "
431            << project_name
432            << " from project file." << endl;
433            }
434          */
435         
436          if (get_release_from_path (items, compressed_path, specified_name, n, release))
437            {
438              // name from caller wins.
439            }
440          else if (get_release_from_path (items, compressed_path, project_name, name, release))
441            {
442              // name from project file wins.
443            }
444          else
445            {
446              // The specified name is not in the path.
447             
448              CmtMessage::warning ("none of specified project names "
449                                   + specified_name + " from graph and "
450                                   + project_name + " from project file match path.");
451              /*
452              if (!Cmt::get_quiet ())
453                {
454                  cerr << "#CMT> Warning: none of specified project names "
455                       << specified_name
456                       << " from graph and "
457                       << project_name
458                       << " from project file match path." << endl;
459                }
460              */
461
462              name = specified_name;
463            }
464         
465          break;
466         
467        case with_project_file | with_project_name | without_specified_name | names_mismatch:
468         
469          // Project name is specified in the project file but not from the caller.
470         
471          if (get_release_from_path (items, compressed_path, project_name, name, release))
472            {
473              // The specified name has been found from the path.
474              // We believe in the release spec.
475
476            }
477          else
478            {
479              // The specified name is not in the path.
480
481              /*
482                if (!Cmt::get_quiet ())
483                {
484                cerr << "#CMT> Warning: specified project name "
485                << project_name
486                << " from project file does not match path." << endl;
487                }
488              */
489
490              name = project_name;
491            }
492         
493          break;
494         
495        case without_project_file | without_project_name | without_specified_name | names_mismatch:
496         
497          // The project is not specified from the caller and there is no project file
498          // This corresponds to the backward compatibility
499          // For the moment, assume /name/release/ structure where release is one level only
500         
501          /*
502            if (!Cmt::get_quiet ())
503            {
504            cerr << "#CMT> Warning: project name is not specified "
505            << " (no project file)." << endl;
506            }
507          */
508         
509          CmtSystem::basename (compressed_path, release);
510          CmtSystem::dirname (compressed_path, name);
511          CmtSystem::basename (name, name);
512
513          if (name == "")
514            {
515              name = release;
516              release = "";
517            }
518         
519          break;
520         
521        case without_project_file | without_project_name | with_specified_name | names_mismatch:
522         
523          // The name is only specified from the caller
524          // find this specified name in the path
525         
526          if (get_release_from_path (items, compressed_path, specified_name, name, release))
527            {
528              // The specified name has been found from the path.
529              // We believe in the release spec.
530            }
531          else
532            {
533              // The specified name is not in the path.
534              /*
535                if (!Cmt::get_quiet ())
536                {
537                cerr << "#CMT> Warning: specified project name "
538                << specified_name
539                << " from project graph does not match path." << endl;
540                }
541              */
542              name = specified_name;
543            }
544         
545          break;
546        }
547    }
548
549  if (name == "")
550    {
551      name = "Project";
552    }
553
554  project = Project::add (name, release);
555     
556  if (parent != 0)
557    {
558      project->add_parent (parent);
559      parent->add_child (project);
560
561      // Since project is a new child, we should propagate the settings UP.
562
563      parent->update_strategies_from_children ();
564    }
565  /*
566  else if ((name != "CMTUSERCONTEXT") && (name != "CMTHOME"))
567    //  else
568    {
569      // this project has no parent thus it should become the top project.
570      // Let's look for all projects without parent.
571      // they will become children of this project.
572
573      for (i = 0; i < Projects.size (); i++)
574        {
575          Project* p = &(Projects[i]);
576          const cmt_string& n = p->get_name ();
577          if (n == name) continue;
578          //      if (p->get_name () == name) continue;
579          if ((n == "CMTUSERCONTEXT") || (n == "CMTHOME")) continue;
580          if (!p->has_parents ())
581            {
582              project->add_child (p);
583              p->add_parent (project);
584            }
585        }
586
587      // Since project is a new parent, we should upgrade its settings
588
589      project->update_strategies_from_children ();
590    }
591  */
592  if (source == "default path")
593    {
594      cmt = project;
595      is_current = false;
596    }
597
598  project->set_cmtpath (compressed_path);
599  project->set_cmtpath_real (pwd_real);
600  project->set_cmtpath_pwd (pwd);
601  project->set_cmtpath_source (source);
602
603  //  project->set_is_current (is_current);
604  /*
605  if (is_current)
606    {
607      //      cerr << "current: " << project->get_name () << endl;
608      //
609      // The current project defines a tag with its name
610      //
611
612      Tag* tag;
613     
614      tag = Tag::add (project->get_name (), PriorityConfig, "PROJECT", 0);
615      tag->mark ();
616    }
617  */
618
619  //  Project::order_all ();
620
621  if (text != "")
622    {
623      // Last step is to parse the project file
624
625      if (Cmt::get_debug ())
626        {
627          cout << "About to parse project file [" << text << "]" << endl;
628        }
629
630      // First create the Project.m_use for the policy
631
632      Use* project_use = Use::create (project->get_cmtpath(), 
633                                      "package_policy_for_project_" + project->get_name(),                                       
634                                      project->get_release (), "", "");                                                         
635
636      project_use->done      = true;
637      project_use->discarded = false;
638      project_use->m_hidden  = true;
639      project_use->selected  = true;
640      project_use->m_located = true;
641      project_use->set_auto_imports(Off);
642      project_use->initial_scope = ScopePublic;     
643      project->set_use(project_use);
644     
645     
646      // add at the uses level ?????
647      /*static Use::UsePtrVector& uses = Use::get_ordered_uses ();
648        bool found = false;
649        int  size  = uses.size ();
650        cerr << "\n size:"<<size<< ":" << endl;     
651        for (int n = 0; n < size; n++)
652        {
653        Use* tuse = uses[n];
654        cerr << "\tpackage file [" << tuse->get_package_name() << "]" <<project_use->get_package_name()<< endl;                   
655        if (tuse->get_package_name()==project_use->get_package_name())
656        found=true;
657
658        }
659   
660        if (not found)
661        {
662        uses.push_back (project_use);
663        project_use->m_index = uses.size () - 1;
664        }
665      */
666
667      SyntaxParser::parse_project_file_text (text, 
668                                             Project::get_project_file_name (),
669                                             project);
670    }
671
672
673
674  CmtSystem::cd (here);
675  Project::order_all ();
676
677  return (project);
678}
679
680/*----------------------------------------------------------*/
681/*                                                          */
682/*  Operations on Projects                                  */
683/*                                                          */
684/*----------------------------------------------------------*/
685
686//----------------------------------------------------------
687bool Project::create (const cmt_string& name, 
688                      const cmt_string& release, 
689                      const cmt_string& path)
690{
691  cmt_string pwd = CmtSystem::pwd ();
692
693  if (CmtMessage::active (Error))
694    {
695  cerr << "------------------------------------------" << endl;
696  cerr << "Configuring environment for project " << name << " " << release << " (from " << pwd << ") ";
697
698  if (path != "")
699    {
700      cout << " in " << path;
701    }
702
703  cerr << endl;
704  cerr << "CMT version " << Cmt::get_cmt_version () << "." << endl;
705  cerr << "------------------------------------------" << endl;
706    }
707
708  if (path != "")
709    {
710      if (!CmtSystem::mkdir (path))
711        {
712          CmtMessage::error ("Cannot create the " + path + " directory");
713          //          cerr << "Cannot create the " << path << " directory" << endl;
714          return (false);
715        }
716
717      if (!CmtSystem::cd (path))
718        {
719          CmtMessage::error ("Cannot access the " + path + " directory");
720          //          cerr << "Cannot access the " << path << " directory" << endl;
721          return (false);
722        }
723    }
724
725  if (!CmtSystem::mkdir (name))
726    {
727      CmtMessage::error ("Cannot create the " + name + " directory");
728      //      cerr << "Cannot create the " << name << " directory" << endl;
729      return (false);
730    }
731
732  if (!CmtSystem::cd (name))
733    {
734      CmtMessage::error ("Cannot access the " + name + " directory");
735      //      cerr << "Cannot access the " << name << " directory" << endl;
736      return (false);
737    }
738
739  if (release != "")
740    {
741      if (!CmtSystem::mkdir (release))
742        {
743          CmtMessage::error ("Cannot create the " + release + " directory");
744          //      cerr << "Cannot create the " << release << " directory" << endl;
745          return (false);
746        }
747     
748      if (!CmtSystem::cd (release))
749        {
750          CmtMessage::error ("Cannot access the " + release + " directory");
751          //      cerr << "Cannot access the " << release << " directory" << endl;
752          return (false);
753        }
754    }
755
756  if (!CmtSystem::test_directory ("cmt"))
757    {
758      if (!CmtSystem::mkdir ("cmt"))
759        {
760          CmtMessage::error ("Cannot create the cmt directory");
761          //          cerr << "Cannot create the cmt directory" << endl;
762          return (false);
763        }
764      else
765        {
766          if (CmtMessage::active (Info))
767            cerr << "Installing the cmt directory" << endl;
768        }
769    }
770
771  CmtSystem::cd ("cmt");
772
773  if (!CmtSystem::test_file (get_project_file_name ()))
774    {
775      if (CmtMessage::active (Info))
776        cerr << "Creating a new project file" << endl;
777
778      ofstream f (get_project_file_name ());
779      if (f)
780        {
781          f << "project " << name << endl;
782          f << endl;
783          f.close ();
784        }
785      else
786        {
787          CmtMessage::error ("Cannot create the project file");
788          //          cerr << "Cannot create the project file" << endl;
789          return (false);
790        }
791    }
792  else
793    {
794      cmt_string text;
795      text.read (get_project_file_name ());
796
797      ProjectPatcher p (name);
798
799      p.run (text);
800      p.commit ();
801
802      if (CmtMessage::active (Info))
803        cerr << "project file already there" << endl;
804    }
805
806  return (true);
807}
808
809//----------------------------------------------------------
810Project* Project::find_by_name (const cmt_string& name)
811{
812  static ProjectVector& Projects = projects ();
813
814  for (int i = 0; i < Projects.size (); i++)
815    {
816      Project& p = Projects[i];
817      if (p.m_name == name) return (&p);
818     
819    }
820
821  return (0);
822}
823
824//----------------------------------------------------------
825Project* Project::find_by_cmtpath (const cmt_string& cmtpath)
826{
827  cmt_string compressed_path = cmtpath;
828  CmtSystem::compress_path (compressed_path);
829
830  static ProjectVector& Projects = projects ();
831
832  for (int i = 0; i < Projects.size (); i++)
833    {
834      Project& p = Projects[i];
835
836      if (p.m_cmtpath == compressed_path) return (&p);
837      if (p.m_cmtpath_real == compressed_path) return (&p);
838      if (p.m_cmtpath_pwd == compressed_path) return (&p);
839    }
840
841  return (0);
842}
843
844//----------------------------------------------------------
845Project* Project::get_current ()
846{
847  /*
848  cmt_string here = CmtSystem::pwd ();
849
850  // In case there are symlinks
851  cmt_string here_real;
852  CmtSystem::realpath_ (here, here_real);
853  */
854  static ProjectVector& Projects = projects ();
855
856  Project* result = 0;
857
858  for (int i = (Projects.size () - 1); i >= 0; i--)
859    {
860      Project& p = Projects[i];
861
862//       if (here.find (p.m_cmtpath_pwd) == 0)
863//      {
864//        result = &p;
865//      }
866
867//      if (here.find (p.m_cmtpath) == 0)
868      if (p.is_current ()) 
869        //      if (here_real.find (p.m_cmtpath_real) == 0)
870        {
871          result = &p;
872        }
873    }
874
875  return (result);
876}
877
878//----------------------------------------------------------
879Project* Project::add (const cmt_string& name,
880                       const cmt_string& release)
881{
882  static ProjectVector& Projects = projects ();
883
884  {
885    Project* project;
886
887    project = find_by_name (name);
888    if (project != 0) 
889      {
890        //      if (!Cmt::get_quiet ())
891        //        {
892            if (release != project->get_release ())
893              {
894                if (CmtMessage::active (Verbose))
895                  CmtMessage::error ("Project " + name
896                                     + " requested with conflicting releases "
897                                     + project->get_release () + " and " + release);
898                //              cerr << "#CMT> Project " << name << " requested with conflicting releases " << project->get_release () << " and " << release << endl;
899                CmtError::set (CmtError::project_release_conflict, name);
900              }
901            //    }
902
903        // Project objects are recreated here to follow the hierarchy
904        // This duplication is needed for properly applying the strategies
905        Project& p = Projects.add ();
906
907        p.set_name (name);
908        p.set_release (release);
909        p.configure ();
910
911        return (&p);
912
913        //return (project);
914      }
915  }
916
917  Project& project = Projects.add ();
918  project.clear ();
919  project.set_name (name);
920  project.set_release (release);
921  project.configure ();
922
923  return (&project);
924}
925
926//----------------------------------------------------------
927Project::ProjectVector& Project::projects ()
928{
929  static Database& db = Database::instance ();
930  static ProjectVector& Projects = db.projects ();
931
932  return (Projects);
933}
934
935//----------------------------------------------------------
936Project::ProjectPtrVector& Project::ordered_projects ()
937{
938  static Database& db = Database::instance ();
939  static ProjectPtrVector& Projects = db.ordered_projects ();
940
941  return (Projects);
942}
943
944//----------------------------------------------------------
945void Project::order_all ()
946//Project::ProjectPtrVector Project::ordered_projects ()
947{
948  ProjectPtrVector OrderedProjects;
949  //  static ProjectPtrVector OrderedProjects;
950  static Project::ProjectPtrVector& orderedProjects = Project::ordered_projects ();
951
952  static Project::ProjectVector& Projects = Project::projects ();
953  const int size = Projects.size ();
954 
955  int offset (0);
956  int iuser (-1);
957  int ihome (-1);
958  for (int i = 0; i < 2; i++)
959    {
960      if (offset < size)
961        {
962          const cmt_string& name = Projects[offset].get_name ();
963          if (name == "CMTUSERCONTEXT")
964            {
965              iuser = offset;
966              ++offset;
967            }
968          else if (name == "CMTHOME")
969            {
970              ihome = offset;
971              ++offset;
972            }
973          else
974            break;
975        }
976    }
977
978  OrderedProjects.resize (size);
979
980  Use& use = Use::current();
981  cmt_string current_path (Cmt::get_current_dir ());
982  if (use.located ())
983    {
984      current_path = use.real_path;
985      CmtMessage::verbose ("Using current use real_path `" + current_path + "'");
986    }
987
988  cmt_string current_path_real;
989  if (!CmtSystem::realpath_ (current_path, current_path_real))
990    {
991      CmtError::set (CmtError::file_access_error, "Cannot compute real path `" +
992                     current_path + "'");
993      CmtError::print ();
994      return;
995      //CmtMessage::error ("Cannot compute real path `" + Use::current().real_path + "'");
996    }
997
998  Project* p_cur (0);
999  for (int i = 0; i < size; i++)
1000    {
1001      Project& p = Projects[i];
1002      if (i >= offset)
1003        p.m_order = -1;
1004      else
1005        p.m_order = -2;
1006      p.m_visits = 0;
1007      //
1008      // The current project specification
1009      //
1010      if (current_path_real.find (p.get_cmtpath_real ()) == 0)
1011        {
1012          p_cur = &p;
1013          if (p.is_current ()) continue;
1014
1015          p.set_is_current (true);
1016          //
1017          // The current project defines a tag with its name
1018          //
1019         
1020          Tag* tag;
1021         
1022          tag = Tag::add (p.get_name (), PriorityConfig, "PROJECT", 0);
1023          tag->mark ();
1024        }
1025      else if (p.is_current ())
1026        {
1027          //
1028          // Unset the tag with its name - TODO
1029          //
1030          p.set_is_current (false);
1031        }
1032    }
1033
1034  if (size == offset)
1035    {
1036      for (int i = 0; i < offset; i++)
1037        {
1038          Project* p = &(Projects[i]);
1039          OrderedProjects[i] = p;
1040        }
1041      /*
1042      if (2 == offset)
1043        {
1044          OrderedProjects[0]->add_child (OrderedProjects[1]);
1045          OrderedProjects[1]->add_parent (OrderedProjects[0]);
1046          OrderedProjects[0]->update_strategies_from_children ();
1047        }
1048      */
1049      for (int i = OrderedProjects.size () - 2; i >= 0; i--)
1050        {
1051          if (!OrderedProjects[i]->has_parents () &&
1052              OrderedProjects[i]->get_children_size () == 0)
1053            {
1054              OrderedProjects[i]->add_child (OrderedProjects[i + 1]);
1055              OrderedProjects[i]->update_strategies_from_children ();
1056              OrderedProjects[i]->erase_child (OrderedProjects[i + 1]);
1057            }
1058        }
1059
1060      orderedProjects = OrderedProjects;
1061      //      return OrderedProjects;
1062      return;
1063    }
1064
1065  Project* p (p_cur);
1066  //  Project* p = get_current ();
1067
1068  //  cerr << "get_current: " << p << " offset: " << offset << endl;
1069  /*
1070  if (p == 0)
1071    {
1072      p = &(Projects[offset]);
1073      //      p = &(Projects[0]);
1074    }
1075  */
1076  //  cerr << "p: " << p << " offset: " << offset << " name: " << p->get_name () << endl;
1077
1078  int order (-1);
1079  /*
1080  if ((p->get_name () != "CMTUSERCONTEXT") && (p->get_name () != "CMTHOME"))
1081    {
1082      ProjectPtrVector projs;
1083      p->m_order = ++order;
1084      //      p->m_visits++;
1085      projs.push_back (p);
1086     
1087      visit (offset, order, projs);
1088      //  visit (order, projs);
1089    }
1090  //  cerr << "order: " << order << endl;
1091  //  int unordered = size - offset - (order + 1);
1092  */
1093  ProjectPtrVector projs;
1094
1095  if (p != 0 && (p->get_name () != "CMTUSERCONTEXT") && (p->get_name () != "CMTHOME"))
1096    {
1097      p->m_order = ++order;
1098      projs.push_back (p);
1099    }
1100
1101  if (p == 0 ||
1102      (!p->has_parents () && p->get_children_size () == 0)
1103      // comes from CMTPATH entry
1104      )
1105    {
1106      for (int i = offset; i < size; i++)
1107        {
1108          Project* q = &(Projects[i]);
1109          if (q != p && !q->has_parents ())
1110            {
1111              q->m_order = ++order;
1112              projs.push_back (q);
1113            }
1114        }
1115    }
1116
1117  visit (offset, order, projs);
1118
1119  int beg (0);
1120  if  (-1 != iuser)
1121    {
1122      OrderedProjects[0] = &(Projects[iuser]);
1123      //      cerr << "OrderedProjects[0]: " << (OrderedProjects[0])->get_name () << endl;
1124      ++beg;
1125    }
1126
1127  int noorder (0);
1128  for (int i = offset; i < size; i++)
1129    //  for (int i = 0; i < size; i++)
1130    {
1131      Project* p = &(Projects[i]);
1132      int j = p->m_order;
1133      if (-1 == j)
1134        {
1135          OrderedProjects[beg + order + 1 + noorder++] = p;
1136          //      cerr << "no: OrderedProjects[" << beg + order + noorder << "]: " << (OrderedProjects[beg + order + noorder])->get_name () << endl;
1137          //      OrderedProjects[order + 1 + noorder++] = p;
1138          /*
1139          if (CmtMessage::active (Verbose))
1140            CmtMessage::warning ("Not ordered project " + p->get_name () +
1141                                 " in path " + p->get_cmtpath_pwd () +
1142                                 " from " + p->get_cmtpath_source ());
1143          continue;
1144          */
1145        }
1146      else if (-2 != j)
1147        {
1148          OrderedProjects[beg + j] = p;
1149        }
1150      /*
1151      else if  (-2 == j)
1152        {
1153        }
1154      else
1155        {
1156          OrderedProjects[beg + j] = p;
1157      //      OrderedProjects[j] = p;
1158          //      cerr << "OrderedProjects[" << beg + j << "]: " << (OrderedProjects[beg + j])->get_name () << endl;
1159        }
1160      */
1161    }
1162
1163  if (p != 0)
1164    {
1165      for (int i = 0; i < noorder; i++)
1166        OrderedProjects.pop_back ();
1167    }
1168  if  (-1 != ihome)
1169    {
1170      OrderedProjects[OrderedProjects.size () - 1] = &(Projects[ihome]);
1171    }
1172  /*
1173  if (p)
1174    {
1175      if  (-1 != ihome)
1176        {
1177          OrderedProjects[beg + order + 1] = &(Projects[ihome]);
1178        }
1179      for (int i = 0; i < noorder; i++)
1180        OrderedProjects.pop_back ();
1181    }
1182  else
1183    {
1184      if  (-1 != ihome)
1185        {
1186          OrderedProjects[size - 1] = &(Projects[ihome]);
1187        }
1188    }
1189  */
1190      /*
1191  if  (-1 != iuser)
1192    {
1193      OrderedProjects[0]->add_child (OrderedProjects[1]);
1194      OrderedProjects[1]->add_parent (OrderedProjects[0]);
1195      OrderedProjects[0]->update_strategies_from_children ();
1196    }
1197      */
1198
1199//   if  (-1 != ihome)
1200//     {
1201      /*
1202      cerr << "beg: " << beg << " order: " << order << endl;
1203      cerr << "noorder: " << noorder << " size - offset: " << size - offset << endl;
1204      */
1205      /*
1206      if (noorder != size - offset)
1207        {  // the last ordered project
1208          OrderedProjects[beg + order]->add_child (OrderedProjects[size - 1]);
1209          OrderedProjects[size - 1]->add_parent (OrderedProjects[beg + order]);
1210          OrderedProjects[beg + order]->update_strategies_from_children ();
1211        }
1212      else
1213        {
1214          OrderedProjects[size - 2]->add_child (OrderedProjects[size - 1]);
1215          OrderedProjects[size - 1]->add_parent (OrderedProjects[size - 2]);
1216          OrderedProjects[size - 2]->update_strategies_from_children ();
1217        }
1218      */
1219//     }
1220
1221  for (int i = OrderedProjects.size () - 2; i >= 0; i--)
1222    {
1223      if (!OrderedProjects[i]->has_parents () &&
1224          OrderedProjects[i]->get_children_size () == 0)
1225        {
1226          OrderedProjects[i]->add_child (OrderedProjects[i + 1]);
1227          OrderedProjects[i]->update_strategies_from_children ();
1228          OrderedProjects[i]->erase_child (OrderedProjects[i + 1]);
1229        }
1230    }
1231
1232  orderedProjects = OrderedProjects;
1233  //  return OrderedProjects;
1234  return;
1235}
1236
1237/*----------------------------------------------------------*/
1238void Project::clear_all ()
1239{
1240  static ProjectVector& Projects = projects ();
1241
1242  for (int i = 0; i < Projects.size (); i++)
1243    {
1244      Project& project = Projects[i];
1245      project.clear ();
1246    }
1247
1248  Projects.clear ();
1249}
1250
1251/*----------------------------------------------------------*/
1252void Project::show_all ()
1253{
1254  static const Project::ProjectPtrVector& Ordered = Project::ordered_projects ();
1255  static Project::ProjectVector& Projects = Project::projects ();
1256 
1257  for (int i = 0; i < Projects.size (); i++)
1258    {
1259      Project& p = Projects[i];
1260      p.m_visited = false;
1261    }
1262
1263  for (int i = 0; i < Ordered.size (); i++)
1264    Ordered[i]->show ();
1265
1266  for (int i = 0; i < Projects.size (); i++)
1267    Projects[i].show ();
1268
1269  /*
1270  Project* p = get_current ();
1271
1272  if (p == 0)
1273    {
1274      if (Ordered.size () == 0) return;
1275
1276      p = Ordered[0];
1277    }
1278  */
1279  //  p->show ();
1280}
1281
1282/*----------------------------------------------------------*/
1283void Project::show_container (const cmt_string& path)
1284//void Project::show_container ()
1285{
1286  Project* p (0);
1287  if (path == "")
1288    {
1289      p = get_current ();
1290    }
1291  else
1292    {
1293      p = find_by_cmtpath (find_in_cmt_paths (path));
1294    } 
1295
1296  if (p == 0)
1297    {
1298      cmt_string msg ("No project found for path "
1299                      + (path != "" ? path : (Use::current()).real_path)
1300                      );
1301      CmtMessage::warning (msg);
1302      CmtError::set (CmtError::warning, msg);
1303      return;
1304    }
1305  Use* use = &(p->m_container);
1306  if (use->get_package_name () == "")
1307    {
1308      cmt_string msg ("No container specified for project " + p->get_name ()
1309                      + " (" + p->get_cmtpath () + ")");
1310      CmtMessage::warning (msg);
1311      CmtError::set (CmtError::warning, msg);
1312      return;
1313    }
1314 
1315  if (!use->located ())
1316    {
1317      CmtMessage::warning ("container " + use->get_info ()
1318                           + " not found");
1319      CmtError::set (CmtError::package_not_found, use->get_package_name ());
1320    }
1321  else
1322    {
1323      static const cmt_string empty;
1324      cmt_string p = use->real_path;
1325      if (use->path != "")
1326        {
1327          int pos = p.find_last_of (use->path);
1328          if (pos != cmt_string::npos)
1329            {
1330              p.erase (pos);
1331            }
1332        }
1333     
1334      cout << "container " << use->get_package_name ()
1335           << " " << use->version;
1336     
1337      if (CmtSystem::absolute_path (use->path))
1338        {
1339          if (!Cmt::get_quiet ()) 
1340            {
1341              cout << " (" << use->path << ")";
1342            }
1343        }
1344      else
1345        {
1346          cout << " " << use->path;
1347        }
1348     
1349      if (!Cmt::get_quiet ()) 
1350        {
1351          if (p != "") cout << " (" << p << ")";
1352          if (use->auto_imports == Off) cout << " (no_auto_imports)";
1353        }
1354     
1355      cout << endl;
1356    }
1357}
1358
1359/*----------------------------------------------------------*/
1360void Project::show_specified_strategies_for_all ()
1361{
1362  static ProjectVector& Projects = projects ();
1363
1364  for (int i = 0; i < Projects.size (); i++)
1365    {
1366      const Project& project = Projects[i];
1367      project.show_specified_strategies ();
1368    }
1369}
1370
1371/*----------------------------------------------------------*/
1372class VisitorForShowPaths : public IProjectVisitor
1373{
1374public:
1375  VisitorForShowPaths ()
1376  {
1377  }
1378
1379  void pre (Project* p)
1380  {
1381    const cmt_string& w = p->get_cmtpath_pwd ();
1382    const cmt_string& s = p->get_cmtpath_source ();
1383
1384    if (s == "default path") return;
1385
1386    if (CmtSystem::test_directory (w))
1387      {
1388        cout << "# Add path " << w << " from " << s << endl;
1389      }
1390  }
1391
1392  void in (Project* p)
1393  {
1394    const cmt_string& w = p->get_cmtpath_pwd ();
1395    const cmt_string& s = p->get_cmtpath_source ();
1396
1397    if (s == "default path") return;
1398
1399    if (CmtSystem::test_directory (w))
1400      {
1401        cout << "# Add path " << w << " from " << s << endl;
1402      }
1403  }
1404
1405  void in_again (Project* p)
1406  {
1407    const cmt_string& w = p->get_cmtpath_pwd ();
1408    const cmt_string& s = p->get_cmtpath_source ();
1409
1410    if (s == "default path") return;
1411
1412    if (CmtSystem::test_directory (w))
1413      {
1414        cout << "# Remove path " << w << " from " << s << endl;
1415        cout << "# Add path " << w << " from " << s << endl;
1416      }
1417  }
1418
1419  void post (Project* p)
1420  {
1421  }
1422};
1423
1424/*----------------------------------------------------------*/
1425void Project::show_paths (const CmtSystem::cmt_string_vector& arguments)
1426//void Project::show_paths ()
1427{
1428  if (arguments.size () == 0)
1429    {
1430      const ProjectPtrVector& Ordered = Project::ordered_projects ();
1431      for (int i = 0; i < Ordered.size (); i++)
1432        {
1433          const Project* p = Ordered[i];
1434          const cmt_string& w = p->get_cmtpath_pwd ();
1435          const cmt_string& s = p->get_cmtpath_source ();
1436         
1437          if (s == "default path") continue;
1438         
1439          if (CmtSystem::test_directory (w))
1440            {
1441              cout << "# Add path " << w << " from " << s << endl;
1442            }
1443        }
1444    }
1445  else if (arguments.size () == 1 && cmt_string (arguments[0]) == "-d")
1446    {
1447      const ProjectVector& Projects = projects ();
1448      for (int i = 0; i < Projects.size (); i++)
1449        {
1450          Project& p = Projects[i];
1451          const cmt_string& w = p.get_cmtpath_pwd ();
1452          const cmt_string& s = p.get_cmtpath_source ();
1453         
1454          if (s == "default path") continue;
1455         
1456          if (CmtSystem::test_directory (w))
1457            {
1458              cout << "# Create path " << w << " from " << s << endl;
1459            }
1460        }
1461      /*
1462      VisitorForShowPaths visitor;
1463      start_visit (visitor);
1464      */
1465    }
1466  else
1467    CmtMessage::error ("show_paths: unexpected argument(s)");
1468}
1469
1470//----------------------------------------------------------
1471const cmt_string& Project::get_project_file_name ()
1472{
1473  static const cmt_string name = "project.cmt";
1474
1475  return (name);
1476}
1477
1478//----------------------------------------------------------
1479void Project::fill_selection (int depth, CmtSystem::cmt_string_vector& path_selections)
1480{
1481  static ProjectPtrVector& Ordered = Project::ordered_projects ();
1482  for (int i = 0; i < Ordered.size (); i++)
1483    {
1484      const Project* project = Ordered[i];
1485
1486      const cmt_string& p = project->get_cmtpath ();
1487      const cmt_string& pwd = project->get_cmtpath_pwd ();
1488      const cmt_string& p_real = project->get_cmtpath_real ();
1489      const cmt_string& src = project->get_cmtpath_source ();
1490      /*
1491  static ProjectVector& Projects = projects ();
1492
1493  for (int i = 0; i < Projects.size (); i++)
1494    {
1495      Project& project = Projects[i];
1496
1497      const cmt_string& p = project.get_cmtpath ();
1498      const cmt_string& pwd = project.get_cmtpath_pwd ();
1499      const cmt_string& p_real = project.get_cmtpath_real ();
1500      const cmt_string& src = project.get_cmtpath_source ();
1501      */
1502      if (src != "default path")
1503        {
1504          if (depth > 0)
1505            {
1506              cmt_string& s1 = path_selections.add ();
1507              s1 = p;
1508              if (pwd != p)
1509                {
1510                  cmt_string& s2 = path_selections.add ();
1511                  s2 = pwd;
1512                }
1513              if (p_real != p && p_real != pwd)
1514                {
1515                  cmt_string& s3 = path_selections.add ();
1516                  s3 = p_real;
1517                }
1518              if (src != "CMTHOME" && src != "CMTUSERCONTEXT")
1519                depth--;
1520
1521              if (depth == 0) break;
1522            }
1523        }
1524    }
1525}
1526
1527//----------------------------------------------------------
1528void Project::broadcast (IProjectAction& action)
1529{
1530  //  const ProjectPtrVector Projects = Project::ordered_projects ();
1531  static ProjectPtrVector& Projects = Project::ordered_projects ();
1532
1533  for (int i = 0; i < Projects.size (); i++)
1534    {
1535      const Project* project = Projects[i];
1536
1537      if (!action.run (*project)) break;
1538    }
1539  /*
1540  static ProjectVector& Projects = projects ();
1541
1542  for (int i = 0; i < Projects.size (); i++)
1543    {
1544      const Project& project = Projects[i];
1545
1546      if (!action.run (project)) break;
1547    }
1548  */
1549}
1550
1551//----------------------------------------------------------
1552void Project::reverse_broadcast (IProjectAction& action)
1553{
1554  //  const ProjectPtrVector Projects = Project::ordered_projects ();
1555  static ProjectPtrVector& Projects = Project::ordered_projects ();
1556
1557  for (int i = (Projects.size () - 1); i >= 0; i--)
1558    {
1559      const Project* project = Projects[i];
1560
1561      if (!action.run (*project)) break;
1562    }
1563  /*
1564  static ProjectVector& Projects = projects ();
1565
1566  for (int i = (Projects.size () - 1); i >= 0; i--)
1567    {
1568      const Project& project = Projects[i];
1569
1570      if (!action.run (project)) break;
1571    }
1572  */
1573}
1574
1575//----------------------------------------------------------
1576void Project::scan_paths (PathScanner& scanner, PathScanner::actor& a)
1577{
1578  static ProjectVector& Projects = projects ();
1579
1580  int i;
1581
1582  for (i = 0; i < Projects.size (); i++)
1583    {
1584      Project& p  = Projects[i];
1585      p.m_visited = false;
1586    }
1587
1588  for (i = 0; i < Projects.size (); i++)
1589    {
1590      const Project& project = Projects[i];
1591       
1592      const cmt_string& p = project.m_cmtpath;
1593      scanner.scan_path (p, a);
1594    }
1595}
1596
1597//----------------------------------------------------------
1598void Project::scan_paths_for_package (PathScanner& scanner, const cmt_string& name)
1599{
1600  static ProjectVector& Projects = projects ();
1601
1602  bool found (false);
1603  for (int i = 0; i < Projects.size (); i++)
1604    {
1605      const Project& project = Projects[i];
1606
1607      const cmt_string& p = project.m_cmtpath;
1608      if (scanner.scan_package (p, name))
1609        found = true;
1610    }
1611
1612  if (!found)
1613    CmtError::set (CmtError::package_not_found, name);
1614}
1615
1616//----------------------------------------------------------
1617cmt_string Project::find_in_cmt_paths (const cmt_string& path)
1618{
1619  const cmt_string pwd = CmtSystem::pwd ();
1620
1621  // In case there are symlinks
1622  cmt_string path_real;
1623  //cerr << "realpath_: find_in_cmt_paths" << endl;
1624  CmtSystem::realpath_ (path, path_real);
1625
1626  static ProjectVector& Projects = projects ();
1627
1628  for (int i = 0; i < Projects.size (); i++)
1629    {
1630      const Project& project = Projects[i];
1631
1632      const cmt_string& p = project.m_cmtpath;
1633      const cmt_string& p_real = project.m_cmtpath_real;
1634      const cmt_string& w = project.m_cmtpath_pwd;
1635      const cmt_string& s = project.m_cmtpath_source;
1636
1637      if (s == "default path") continue;
1638
1639      if (CmtSystem::test_directory (p))
1640        {
1641//        if (path.find (p) != cmt_string::npos)
1642//          {
1643//            return (p);
1644//          }
1645
1646          if (path_real.find (p_real) != cmt_string::npos)
1647            {
1648              return (p);
1649            }
1650
1651          // To become the current area, a path must correspond to the current package
1652          if (path.find (w) != cmt_string::npos)
1653            {
1654              return (p);
1655            }
1656        }
1657
1658      if (p == w) continue;
1659
1660      if (CmtSystem::test_directory (w))
1661        {
1662          if (path.find (w) != cmt_string::npos)
1663            {
1664              return (w);
1665            }
1666        }
1667    }
1668
1669  return ("");
1670}
1671
1672//----------------------------------------------------------
1673void Project::visit (IProjectVisitor& visitor)
1674{
1675  if (m_visited) return;
1676  m_visited = true;
1677
1678  int i;
1679
1680  for (i = 0; i < get_children_size (); i++)
1681    {
1682      Project* child = get_child (i);
1683
1684      if (child->visited ()) continue;
1685
1686      visitor.in (child);
1687    }
1688
1689  for (i = 0; i < m_children.size (); i++)
1690    {
1691      Project* child = m_children[i];
1692      child->visit (visitor);
1693    }
1694}
1695
1696//----------------------------------------------------------
1697void Project::visit (IProjectVisitor& visitor, ProjectPtrVector& projects)
1698{
1699  int size = projects.size ();
1700  if (0 == size) return;
1701
1702  ProjectPtrVector children;
1703  for (int j = 0; j < size; j++)
1704    {
1705      Project* p = projects[j];
1706      if (20 == p->m_visits)
1707        continue;
1708      for (int i = 0; i < p->get_children_size (); i++)
1709        {
1710          Project* child = p->get_child (i);
1711          if (0 == child->m_visits)       
1712            visitor.in (child);
1713          else
1714            visitor.in_again (child);
1715          child->m_visits++;
1716          children.push_back (child);
1717        }
1718    }
1719
1720  visit (visitor, children);
1721}
1722
1723//----------------------------------------------------------
1724/**
1725 *  Visit the projects tree and order the projects.
1726 *  Order is the projects upon which the project depends directly,
1727 *  then the direct dependencies of the of the first dependency, of the second
1728 *  dependency and so on. That is first left to right, then downwards.
1729 *  @param offset the offset from which to use all the projects
1730 *  @param order the order of the last project visited
1731 *  @param projs vector of projects to visit and order
1732 */
1733void Project::visit (const int offset, int& order, ProjectPtrVector& projs)
1734{
1735  int size = projs.size ();
1736  //  cerr << "visit: " << offset << " " << order << " " << size << endl;
1737  if (0 == size) return;
1738  static ProjectVector& all = Project::projects ();
1739  /*
1740  cerr << "@ visit: " << order;
1741  for (int j = 0; j < size; j++)
1742    {
1743      Project* p = projs[j];
1744      cerr << " " << p->get_name ();
1745    }
1746  cerr << " @" << endl;
1747  */
1748  ProjectPtrVector children;
1749  for (int j = 0; j < size; j++)
1750    {
1751      Project* p = projs[j];
1752      p->m_visits++;
1753      // Avoid looping in case of circular project dependencies
1754      if (500 <= p->m_visits)
1755        //      if (100 <= p->m_visits)
1756        continue;
1757      for (int i = 0; i < p->get_children_size (); i++)
1758        {
1759          Project* child = p->get_child (i);
1760          const int chorder = child->m_order;
1761          const int porder = p->m_order;
1762          /*
1763          cerr << ">>> " << p->get_name () << " child: " << i << endl;
1764          cerr << child->get_name () << " in: " << chorder << endl;
1765          */
1766          if (-2 == chorder)
1767            continue;
1768          else if (-1 == chorder)
1769            { // not ordered yet, i.e. visited for the first time
1770              child->m_order = ++order;
1771            }
1772          else if (child->is_current ())
1773            //    else if (0 == chorder)
1774            { // the project we started with, i. e. the current project:
1775              //     o circular dependency
1776              //     o do want to keep it first no matter what
1777              if (CmtMessage::active (Verbose))
1778                CmtMessage::warning ("Circular dependency on project: "
1779                                     + child->get_name ()
1780                                     + " " + child->get_release ()
1781                                     + " " + child->get_cmtpath ());
1782            }
1783          else if ((0 <= chorder) && (chorder < porder))
1784            //    else if ((0 < chorder) && (chorder < porder))
1785            { // ordered already, want to put it after the parent in the order
1786              for (int k = offset; k < all.size (); k++)
1787                {
1788                  Project& q = all[k];
1789                  if (&q == child)
1790                    {// the child we are putting after the parent in the order
1791                      q.m_order = porder;
1792                      //              cerr << "Moved back: " << q.get_name () << " order: " << q.m_order << endl;
1793                    }
1794                  else if ((chorder < q.m_order) && (q.m_order <= porder))
1795                    q.m_order--;
1796                }
1797            }
1798          //  cerr << child->get_name () << " out: " << child->m_order << endl;
1799          //      child->m_visits++;
1800          bool unknown (true);
1801          for (int j = 0; j < children.size (); j++)
1802            {
1803              if (children[j] == child)
1804                {
1805                  unknown = false;
1806                  break;
1807                }
1808            }
1809          if (unknown)
1810            {
1811              children.push_back (child);
1812            }
1813        }
1814    }
1815
1816  visit (offset, order, children);
1817}
1818
1819//----------------------------------------------------------
1820void Project::start_visit (IProjectVisitor& visitor)
1821{
1822  static Project::ProjectVector& Projects = Project::projects ();
1823 
1824  for (int i = 0; i < Projects.size (); i++)
1825    {
1826      Project& p = Projects[i];
1827      p.m_visited = false;
1828      p.m_visits = 0;
1829    }
1830
1831  Project* p = get_current ();
1832
1833  if (p == 0)
1834    {
1835      if (Projects.size () == 0) return;
1836
1837      p = &(Projects[0]);
1838    }
1839
1840  //  visitor.pre (p);
1841  //p->visit (visitor);
1842  //  visitor.post (p);
1843  visitor.in (p);
1844  p->m_visits++;
1845  ProjectPtrVector projs;
1846  projs.push_back (p);
1847  visit (visitor, projs);
1848}
1849
1850//----------------------------------------------------------
1851class VisitorForFillCMTPATH : public IProjectVisitor
1852{
1853public:
1854  VisitorForFillCMTPATH (cmt_string& buffer) : m_buffer (buffer)
1855  {
1856    buffer = "path CMTPATH \"\" \n";
1857  }
1858
1859  void pre (Project* p)
1860  {
1861    const cmt_string& w = p->get_cmtpath_pwd ();
1862    const cmt_string& s = p->get_cmtpath_source ();
1863
1864    if (s == "default path") return;
1865
1866    if (CmtSystem::test_directory (w))
1867      {
1868        m_buffer += "path_append CMTPATH \"";
1869        m_buffer += w;
1870        m_buffer += "\" \n";
1871      }
1872  }
1873
1874  void in (Project* p)
1875  {
1876    const cmt_string& w = p->get_cmtpath_pwd ();
1877    const cmt_string& s = p->get_cmtpath_source ();
1878
1879    if (s == "default path") return;
1880
1881    if (CmtSystem::test_directory (w))
1882      {
1883        m_buffer += "path_append CMTPATH \"";
1884        m_buffer += w;
1885        m_buffer += "\" \n";
1886      }
1887  }
1888
1889  void in_again (Project* p)
1890  {
1891    const cmt_string& w = p->get_cmtpath_pwd ();
1892    const cmt_string& s = p->get_cmtpath_source ();
1893
1894    if (s == "default path") return;
1895
1896    if (CmtSystem::test_directory (w))
1897      {
1898        m_buffer += "path_remove CMTPATH \"";
1899        m_buffer += w;
1900        m_buffer += "\" \n";
1901        m_buffer += "path_append CMTPATH \"";
1902        m_buffer += w;
1903        m_buffer += "\" \n";
1904      }
1905  }
1906
1907  void post (Project* p)
1908  {
1909    //cerr << "Buffer = " << m_buffer << endl;
1910  }
1911
1912private:
1913  cmt_string& m_buffer;
1914
1915};
1916
1917//----------------------------------------------------------
1918void Project::fill_cmtpaths (cmt_string& buffer)
1919{
1920  /*
1921    Try to re-create all CMTPATH items from project definitions.
1922    The goal is to generate CMTPATH even if this EV was not pre-set
1923    which is the case when CMTPROJECTPATH is only used
1924  */
1925
1926  /*
1927  VisitorForFillCMTPATH visitor (buffer);
1928
1929  start_visit (visitor);
1930  */
1931  const ProjectPtrVector& Ordered = Project::ordered_projects ();
1932
1933  buffer = "path CMTPATH \"\" \n";
1934  for (int i = 0; i < Ordered.size (); i++)
1935    {
1936      const Project* p = Ordered[i];
1937      const cmt_string& w = p->get_cmtpath_pwd ();
1938      const cmt_string& s = p->get_cmtpath_source ();
1939     
1940      if (s == "default path") continue;
1941     
1942      if (CmtSystem::test_directory (w))
1943        {
1944          buffer += "path_append CMTPATH \"";
1945          buffer += w;
1946          buffer += "\" \n";
1947        }
1948    }
1949}
1950
1951//----------------------------------------------------------
1952Project::Project () : m_name (""), m_author("")
1953{
1954  clear ();
1955}
1956
1957//----------------------------------------------------------
1958const cmt_string& Project::get_name () const
1959{
1960  return (m_name);
1961}
1962
1963//----------------------------------------------------------
1964const cmt_string& Project::get_release () const
1965{
1966  return (m_release);
1967}
1968
1969//----------------------------------------------------------
1970const cmt_string& Project::get_container_name () const
1971{
1972  return (m_container_name);
1973}
1974
1975//----------------------------------------------------------
1976const cmt_string& Project::get_container_version () const
1977{
1978  return (m_container_version);
1979}
1980
1981//----------------------------------------------------------
1982const cmt_string& Project::get_container_path () const
1983{
1984  return (m_container_path);
1985}
1986
1987//----------------------------------------------------------
1988const Use& Project::get_container () const
1989{
1990  return (m_container);
1991}
1992
1993//----------------------------------------------------------
1994const cmt_string& Project::get_cmtpath () const
1995{
1996  return (m_cmtpath);
1997}
1998
1999//----------------------------------------------------------
2000const cmt_string& Project::get_cmtpath_real () const
2001{
2002  return (m_cmtpath_real);
2003}
2004
2005//----------------------------------------------------------
2006const cmt_string& Project::get_cmtpath_pwd () const
2007{
2008  return (m_cmtpath_pwd);
2009}
2010
2011//----------------------------------------------------------
2012const cmt_string& Project::get_cmtpath_source () const
2013{
2014  return (m_cmtpath_source);
2015}
2016
2017//----------------------------------------------------------
2018int Project::get_children_size () const
2019{
2020  return (m_children.size ());
2021}
2022
2023//----------------------------------------------------------
2024Project* Project::get_child (int index) const
2025{
2026  if (index < 0) return (0);
2027  if (index >= m_children.size ()) return (0);
2028  return (m_children[index]);
2029}
2030
2031//----------------------------------------------------------
2032bool Project::visited () const
2033{
2034  return (m_visited);
2035}
2036
2037//----------------------------------------------------------
2038void Project::set_name (const cmt_string& name)
2039{
2040  m_name = name;
2041}
2042
2043//----------------------------------------------------------
2044void Project::set_release (const cmt_string& release)
2045{
2046  m_release = release;
2047}
2048
2049//----------------------------------------------------------
2050void Project::set_container_name (const cmt_string& name)
2051{
2052  m_container_name = name;
2053}
2054
2055//----------------------------------------------------------
2056void Project::set_container_version (const cmt_string& container_version)
2057{
2058  m_container_version = container_version;
2059}
2060
2061//----------------------------------------------------------
2062void Project::set_container_path (const cmt_string& container_path)
2063{
2064  m_container_path = container_path;
2065}
2066
2067//----------------------------------------------------------
2068void Project::set_cmtpath (const cmt_string& path)
2069{
2070  m_cmtpath = path;
2071}
2072
2073//----------------------------------------------------------
2074void Project::set_cmtpath_real (const cmt_string& path)
2075{
2076  m_cmtpath_real = path;
2077}
2078
2079//----------------------------------------------------------
2080void Project::set_cmtpath_pwd (const cmt_string& path)
2081{
2082  m_cmtpath_pwd = path;
2083}
2084
2085//----------------------------------------------------------
2086void Project::set_cmtpath_source (const cmt_string& source)
2087{
2088  m_cmtpath_source = source;
2089}
2090
2091//----------------------------------------------------------
2092void Project::set_is_current (bool is_current)
2093{
2094  m_is_current = is_current;
2095}
2096
2097//----------------------------------------------------------
2098bool Project::is_current () const
2099{
2100  return m_is_current;
2101}
2102
2103//----------------------------------------------------------
2104void Project::clear ()
2105{
2106  m_name    = "";
2107  m_release = "";
2108  m_cmtpath = "";
2109  m_cmtpath_real = "";
2110  m_cmtpath_pwd    = "";
2111  m_cmtpath_source = "";
2112  m_use            = 0;
2113
2114  m_parents.clear ();
2115  m_children.clear ();
2116
2117  m_configured = false;
2118
2119  m_strategies.clear ();
2120  m_is_current = false;
2121}
2122
2123//----------------------------------------------------------
2124bool Project::has_parents () const
2125{
2126  return ((m_parents.size () > 0));
2127}
2128
2129//----------------------------------------------------------
2130bool Project::has_parent (Project* p) const
2131{
2132  if (p == 0) return (false);
2133  if (p == this) return (false);
2134
2135  const cmt_string& name = p->get_name ();
2136
2137  int i;
2138
2139  for (i = 0; i < m_parents.size (); i++)
2140    {
2141      const Project* parent = m_parents[i];
2142      if (parent == 0) continue;
2143
2144      if (parent->get_name () == name)
2145        {
2146          // registered as a parent
2147          return (true);
2148        }
2149
2150      if (parent->has_parent (p))
2151        {
2152          // recurse
2153          return (true);
2154        }
2155    }
2156
2157  return (false);
2158}
2159
2160//----------------------------------------------------------
2161bool Project::has_child (Project* p) const
2162{
2163  if (p == 0) return (false);
2164  if (p == this) return (false);
2165
2166  const cmt_string& name = p->get_name ();
2167
2168  int i;
2169
2170  for (i = 0; i < m_children.size (); i++)
2171    {
2172      const Project* child = m_children[i];
2173      if (child == 0) continue;
2174
2175      if (child->get_name () == name)
2176        {
2177          // registered as a child
2178          return (true);
2179        }
2180
2181      if (child->has_child (p))
2182        {
2183          // recurse
2184          return (true);
2185        }
2186    }
2187
2188  return (false);
2189}
2190
2191//----------------------------------------------------------
2192void Project::add_parent (Project* p)
2193{
2194  if (p == 0) return;
2195  if (p == this) return;
2196
2197  //cerr << "Adding parent " << p->get_name () << " to " << m_name << endl;
2198
2199  if (has_child (p)) return;
2200  if (has_parent (p)) return;
2201
2202  m_parents.push_back (p);
2203}
2204
2205//----------------------------------------------------------
2206void Project::add_child (Project* p)
2207{
2208  if (p == 0) return;
2209  if (p == this) return;
2210
2211  if (has_child (p)) return;
2212  if (has_parent (p)) return;
2213
2214  m_children.push_back (p);
2215}
2216
2217//----------------------------------------------------------
2218void Project::erase_child (Project* p)
2219{
2220  if (p == 0) return;
2221  if (p == this) return;
2222
2223  if (!has_child (p)) return;
2224
2225  const cmt_string& name = p->get_name ();
2226
2227  for (int i = 0; i < m_children.size (); i++)
2228    {
2229      const Project* child = m_children[i];
2230      if (child == 0) continue;
2231
2232      if (child->get_name () == name)
2233        {
2234          // registered as a child
2235          m_children.erase (i);
2236          break;
2237        }
2238    }
2239}
2240
2241//----------------------------------------------------------
2242void Project::configure ()
2243{
2244  if (m_configured) return;
2245  m_configured = true;
2246
2247  set_default_strategy ("SetupConfig");
2248  set_default_strategy ("SetupRoot");
2249  set_default_strategy ("SetupCleanup");
2250  set_default_strategy ("SetupScripts");
2251  set_default_strategy ("BuildPrototypes");
2252  set_default_strategy ("InstallArea");
2253  set_default_strategy ("VersionDirectory");
2254}
2255
2256/**---------------------------------------------------------
2257   A container statement is met in the project file
2258*/
2259void Project::container_action (const CmtSystem::cmt_string_vector& words)
2260//void Project::container_action (const cmt_string& name, const cmt_string& version)
2261{
2262  //
2263  // complete syntax : "container <package> <version> <path>" 
2264  // minimal syntax  : "container <package>"
2265  //
2266  //  o if <version> is omitted then take any version available
2267  //  o <version> can be specified using "v*" or "v<n>r*" or "v<n>r<m>p*"
2268  //
2269  //  o the notation "v*" is preferred to omission (particularly since
2270  //    omission does not permit <path>)
2271  //
2272  Use* use = &m_container;
2273  use->~Use ();
2274  if (words.size () < 2) return;
2275
2276  CmtSystem::cmt_string_vector ewords;
2277  for (int i = 1; i < words.size (); i++)
2278    {
2279      const cmt_string& w = words[i];
2280      cmt_string ew = w;
2281
2282      Symbol::expand (ew);
2283      if (ew != w)
2284        {
2285          CmtSystem::cmt_string_vector ws;
2286          CmtSystem::split (ew, " ", ws);
2287
2288          for (int j = 0; j < ws.size (); ++j)
2289            {
2290              ewords.push_back (ws[j]);
2291            }
2292        }
2293      else
2294        {
2295          ewords.push_back (w);
2296        }
2297    }
2298
2299  cmt_string name, version, path;
2300  if (ewords.size () > 0) name = ewords[0];
2301  if (ewords.size () > 1) version = ewords[1];
2302  if (ewords.size () > 2) path = ewords[2];
2303
2304  if (name != "")
2305    {
2306      use->set (name, version, path);
2307      use->get_package ()->remove_use (use);
2308      CmtSystem::cd (m_cmtpath_pwd);
2309      if (use->move_to ("", true) &&
2310          !CmtSystem::absolute_path (use->real_path))
2311        {
2312          use->change_path (m_cmtpath_pwd);
2313        }
2314      CmtSystem::cd (m_cmtpath_pwd + CmtSystem::file_separator () + "cmt");
2315    }
2316
2317  set_container_name (name);
2318  set_container_version (version);
2319  set_container_path (path);
2320}
2321
2322/**---------------------------------------------------------
2323   A use statement is met in the project file
2324*/
2325void Project::use_action (const cmt_string& name, const cmt_string& release)
2326{
2327  if (Cmt::get_debug ())
2328    {
2329      cout << "Use action " << name << " " << release << endl;
2330    }
2331
2332  // A project with its release is specified
2333  //
2334  // Is this project already visible?
2335  // If not: look for it
2336  //   + get CMTPROJECTPATH
2337  //   + search from all entries of CMTPROJECTPATH : p(i)/<name>/<release>
2338  //   + when found, this should become a new CMTPATH entry
2339  //   +             the new project is then parsed ... etc...
2340
2341  // First test it wilcard is used
2342  int v = -1;
2343  int r = -1;
2344  int p = -1;
2345  cmt_string new_release = release;
2346  CmtSystem::is_version_directory (new_release, v, r, p); 
2347  bool use_has_wild_card = (v == -1) || (r == -1) || (p == -1);
2348  if (use_has_wild_card)
2349    {
2350      cmt_string selected_release = "";
2351
2352      if (select_release(name, new_release,selected_release))
2353        {
2354          // cerr <<"selected_release: "<<selected_release<<endl;   
2355          new_release = selected_release;
2356        }         
2357    }
2358
2359  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2360  cmt_string sep;
2361  sep = CmtSystem::path_separator ();
2362
2363  CmtSystem::cmt_string_vector items;
2364  CmtSystem::split (cmtprojectpath, sep, items);
2365
2366  bool found = false;
2367
2368  for (int i = 0; i < items.size (); i++)
2369    {
2370      const cmt_string& item = items[i];
2371      cmt_string p = item;
2372      p += CmtSystem::file_separator ();
2373      p += name;
2374      if (new_release != "")
2375        {
2376          p += CmtSystem::file_separator ();
2377          p += new_release;
2378        }
2379
2380      if (CmtSystem::test_directory (p))
2381        {
2382          //cerr << "Project directory " << p << " exists " << endl;
2383
2384          found = true;
2385
2386          IProjectFactory& factory = ProjectFactory::instance ();
2387
2388          factory.create_project (name, p, "ProjectPath", this);
2389
2390          break;
2391        }
2392    }
2393
2394  if (!found)
2395    {
2396      Project* p = Project::find_by_name (name);
2397
2398      if (p != 0)
2399        {
2400          found = true;
2401          p->add_parent (this);
2402          add_child (p);
2403
2404          update_strategies_from_children ();
2405        }
2406    }
2407   
2408  if (!found && (cmtprojectpath != ""))
2409    {
2410      CmtMessage::warning ("Project " + name + " " + release + " requested by " + m_name + " not found in CMTPROJECTPATH");
2411      //      cerr << "#CMT> Project " << name << " " << release << " requested by " << m_name << " not found in CMTPROJECTPATH" << endl;
2412    }
2413}
2414
2415//---------------------------------------------------------
2416bool Project::select_release(const cmt_string& name, const cmt_string& release, cmt_string& result)
2417{
2418  cmt_string selected_release = "";
2419
2420  int v = -1;
2421  int r = -1;
2422  int p = -1;
2423  CmtSystem::is_version_directory (release, v, r, p); 
2424
2425  int selected_v = -1;
2426  int selected_r = -1;
2427  int selected_p = -1;
2428  CmtSystem::cmt_string_vector releases = get_project_releases(name);
2429  for (int j = 0; j < releases.size (); j++)
2430    {
2431      int new_v = -1;
2432      int new_r = -1;
2433      int new_p = -1;
2434      CmtSystem::is_version_directory (releases[j], new_v, new_r, new_p);
2435      if (v == -1)
2436        {
2437          if (selected_v < new_v)
2438            {
2439              selected_v = new_v;
2440              selected_r = -1;
2441              selected_p = -1;
2442              selected_release = releases[j];
2443            }
2444          else if (selected_v == new_v)
2445            {
2446              // We compare the r
2447              if (selected_r < new_r)
2448                {
2449                  selected_r = new_r;
2450                  selected_p = -1;
2451                  selected_release = releases[j];                               
2452                }
2453              else if (selected_r == new_r)
2454                {
2455                  // We compare the p
2456                  if (selected_p < new_p)
2457                    {
2458                      selected_p = new_p;
2459                      selected_release = releases[j];                               
2460                    }
2461                  // else if ? not possible                                                           
2462                }                               
2463            }
2464        }
2465      else if (r == -1)
2466        {
2467          if (v == new_v)
2468            {
2469              // We compare the r                                                     
2470              if (selected_r < new_r)
2471                {
2472                  selected_r = new_r;
2473                  selected_p = -1;
2474                  selected_release = releases[j];                               
2475                }
2476              else if (selected_r == new_r)
2477                { 
2478                  // We compare the p
2479                  if (selected_p < new_p)
2480                    {
2481                      selected_p = new_p;
2482                      selected_release = releases[j];                               
2483                    }
2484                  // else if ? not possible
2485                }
2486            }
2487        }
2488      else if (p == -1)
2489        {
2490          if ((v == new_v) && (r == new_r))
2491            { 
2492              // We compare the p
2493              if (selected_p < new_p)
2494                {
2495                  selected_p = new_p;
2496                  selected_release = releases[j];                               
2497                }
2498              // else if ? not possible
2499            }       
2500        }       
2501
2502      //cerr << "v:" << new_v << ", r:" << new_r << ", p:" << new_p << endl;             
2503      //cerr << "req v:" << v << ", req r:" << r << ", req p:" << p << endl;       
2504
2505    }
2506
2507  // cerr << "selected release: " << selected_release << endl; 
2508
2509  if (selected_release == "") return false;
2510
2511  result = selected_release;   
2512
2513  return (true);
2514}
2515
2516//---------------------------------------------------------
2517const CmtSystem::cmt_string_vector Project::get_project_releases (const cmt_string& name) const
2518{
2519  CmtSystem::cmt_string_vector releases;
2520  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2521
2522  static cmt_string sep = CmtSystem::path_separator ();
2523
2524  CmtSystem::cmt_string_vector items;
2525  CmtSystem::split (cmtprojectpath, sep, items);   
2526
2527  for (int i = 0; i < items.size (); i++)
2528    {
2529      const cmt_string& item = items[i];
2530      cmt_string p = item;
2531      p += CmtSystem::file_separator ();
2532      p += name;
2533
2534      if (CmtSystem::test_directory (p))
2535        { 
2536          CmtSystem::cmt_string_vector directories;
2537          CmtSystem::scan_dir (p, directories);
2538
2539          for (int j = 0; j < directories.size (); j++)
2540            {
2541              if  (CmtSystem::test_directory(directories[j]))
2542                {
2543                  cmt_string release;
2544                  CmtSystem:: basename(directories[j], release);
2545
2546                  if (CmtSystem::is_version_directory(release))
2547                    {                             
2548                      cmt_string& name_entry = releases.add ();
2549                      name_entry = release; 
2550                    }             
2551                }                           
2552            }                           
2553        }
2554    }
2555  return (releases);
2556}
2557
2558//----------------------------------------------------------
2559Project& Project::operator = (const Project& other)
2560{
2561  m_name = other.m_name;
2562  m_cmtpath = other.m_cmtpath;
2563  m_cmtpath_real = other.m_cmtpath_real;
2564  m_cmtpath_pwd = other.m_cmtpath_pwd;
2565  m_cmtpath_source = other.m_cmtpath_source;
2566
2567  return (*this);
2568}
2569
2570//----------------------------------------------------------
2571bool Project::operator == (const cmt_string& name) const
2572{
2573  return ((m_name == name));
2574}
2575
2576//----------------------------------------------------------
2577bool Project::operator != (const cmt_string& name) const
2578{
2579  return ((m_name != name));
2580}
2581
2582//----------------------------------------------------------
2583void Project::show ()
2584{
2585  if (m_visited) return;
2586  m_visited = true;
2587
2588  static int level = 0;
2589
2590  //  bool is_current = false;
2591
2592  //  cmt_string here = CmtSystem::pwd ();
2593  // In case there are symlinks
2594  /*
2595  cmt_string here_real;
2596  CmtSystem::realpath_ (CmtSystem::pwd (), here_real);
2597
2598  //  if (here.find (m_cmtpath) == 0)
2599  if (here_real.find (m_cmtpath_real) == 0)
2600    {
2601      if (m_cmtpath_source != "default path")
2602        {
2603          is_current = true;
2604        }
2605    }
2606  */
2607  for (int tab = 0; tab < level; tab++) cout << "  ";
2608  cout << m_name << " " << (m_name != "CMTUSERCONTEXT" && m_name != "CMTHOME" ? m_release : "v0") << " (in " << m_cmtpath << ")";
2609  //  cout << m_name << " " << m_release << " (in " << m_cmtpath << ")";
2610
2611  if (m_is_current) cout << " (current)";
2612  //  if (is_current) cout << " (current)";
2613
2614  int i;
2615
2616  for (i = 0; i < m_parents.size (); i++)
2617    {
2618      Project* p = m_parents[i];
2619      if (p == 0) continue;
2620      cout << " P=" << p->get_name ();
2621    }
2622
2623  for (i = 0; i < m_children.size (); i++)
2624    {
2625      Project* p = m_children[i];
2626      if (p == 0) continue;
2627      cout << " C=" << p->get_name ();
2628    }
2629
2630  cout << endl;
2631
2632/*
2633  if (m_visited) return;
2634
2635  m_visited = true;
2636*/
2637
2638  for (i = 0; i < m_children.size (); i++)
2639    {
2640      Project* p = m_children[i];
2641      if (p == 0) continue;
2642      level++;
2643      p->show ();
2644      level--;
2645    }
2646}
2647
2648
2649//----------------------------------------------------------
2650void Project::show_specified_strategies () const
2651{
2652  int i;
2653
2654  for (i = 0; i < m_strategies.size (); i++)
2655    {
2656      const Strategy& s = m_strategies[i];
2657      if (s.m_specified)
2658        {
2659          const StrategyDef* def = s.m_definition;
2660 
2661          cout << "# Project " << m_name
2662               << " sets " << def->m_keyword
2663               << " strategy to " << ((s.m_value) ? def->m_on_value : def->m_off_value);
2664
2665          if (s.m_context != "")
2666            {
2667              cout << " (from package " << s.m_context << ")";
2668            }
2669
2670          cout << endl;
2671        }
2672    }
2673}
2674
2675//----------------------------------------------------------
2676bool Project::has_strategy (const StrategyDef* definition) const
2677{
2678  int i;
2679
2680  for (i = 0; i < m_strategies.size (); i++)
2681    {
2682      const Strategy& s = m_strategies[i];
2683      if (s.m_definition == definition)
2684        {
2685          return (true);
2686        }
2687    }
2688
2689  return (false);
2690}
2691
2692//----------------------------------------------------------
2693bool Project::get_strategy (const cmt_string& name) const
2694{
2695  static StrategyMgr& mgr = StrategyMgr::instance ();
2696
2697  StrategyDef* def = mgr.find_strategy (name);
2698  if (def == 0)
2699    {
2700      CmtMessage::warning ("strategy " + name + " undefined");
2701      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2702      return (false);
2703    }
2704
2705  return (get_strategy (def));
2706}
2707
2708//----------------------------------------------------------
2709bool Project::is_specified (const StrategyDef* definition) const
2710{
2711  int i;
2712
2713  for (i = 0; i < m_strategies.size (); i++)
2714    {
2715      Strategy& s = m_strategies[i];
2716      if (s.m_definition == definition)
2717        {
2718          // This strategy is applied in this project
2719          return (s.m_specified);
2720        }
2721    }
2722
2723  // This strategy is not applied in this project
2724  return (false);
2725}
2726
2727//----------------------------------------------------------
2728bool Project::get_strategy (const StrategyDef* def) const
2729{
2730  int i;
2731
2732  for (i = 0; i < m_strategies.size (); i++)
2733    {
2734      Strategy& s = m_strategies[i];
2735      if (s.m_definition == def)
2736        {
2737          // This strategy is applied in this project
2738          if (s.m_specified)
2739            {
2740              return (s.m_specified_value);
2741            }
2742          return (s.m_value);
2743        }
2744    }
2745
2746  // This strategy is not applied in this project
2747  return (def->m_default_value);
2748}
2749
2750//----------------------------------------------------------
2751void Project::set_default_strategy (const cmt_string& name)
2752{
2753  static StrategyMgr& mgr = StrategyMgr::instance ();
2754
2755  StrategyDef* def = mgr.find_strategy (name);
2756  if (def == 0)
2757    {
2758      CmtMessage::warning ("strategy " + name + " undefined");
2759      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2760      return;
2761    }
2762
2763  update_strategy (def, def->m_default_value);
2764}
2765
2766
2767//----------------------------------------------------------
2768void Project::set_strategy (const cmt_string& name, const cmt_string& value, const cmt_string& context)
2769{
2770  static StrategyMgr& mgr = StrategyMgr::instance ();
2771
2772  StrategyDef* def = mgr.find_strategy (name);
2773  if (def == 0)
2774    {
2775      CmtMessage::warning ("strategy " + name + " undefined");
2776      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2777      return;
2778    }
2779
2780  bool b_value = false;
2781
2782  if (value == def->m_on_value)
2783    {
2784      b_value = true;
2785    }
2786  else if (value == def->m_off_value)
2787    {
2788      b_value = false;
2789    }
2790  else
2791    {
2792      CmtMessage::warning ("requested strategy value " + value + " undefined in strategy " + name);
2793      //      cerr << "#CMT> requested strategy value " << value << " undefined in strategy " << name << endl;
2794      return;
2795    }
2796
2797  set_strategy (def, b_value, context);
2798}
2799
2800//----------------------------------------------------------
2801void Project::set_strategy (StrategyDef* definition, bool b_value, const cmt_string& context)
2802{
2803  bool need_strategy = true;
2804
2805  int i;
2806
2807  for (i = 0; i < m_strategies.size (); i++)
2808    {
2809      Strategy& s = m_strategies[i];
2810      if (s.m_definition == definition)
2811        {
2812          // This strategy is already applied in this project. Let's change it's value
2813          s.set (definition, b_value, get_name ());
2814          if (context != "")
2815            {
2816              if (s.m_context != "") s.m_context += " ";
2817              s.m_context += context;
2818            }
2819          need_strategy = false;
2820          break;
2821        }
2822    }
2823
2824  if (need_strategy)
2825    {
2826      // This strategy is not yet applied in this project.
2827
2828      Strategy& s = m_strategies.add ();
2829      s.clear ();
2830      s.set (definition, b_value, get_name ());
2831      s.m_context = context;
2832    }
2833 
2834  for (i = 0; i < m_parents.size (); i++)
2835    {
2836      Project* project = m_parents[i];
2837
2838      project->update_strategy (definition, b_value);
2839    }
2840}
2841
2842/**----------------------------------------------------------
2843   The strategy value is changed because of indirect influences
2844   - default strategy at initialization time
2845   - change in the children
2846   - change in the children list
2847
2848   (This is not a specification : see the set_strategy method)
2849*/
2850void Project::update_strategy (StrategyDef* definition, bool b_value)
2851{
2852  bool need_strategy = true;
2853  bool specified = false;
2854
2855  int i;
2856
2857  for (i = 0; i < m_strategies.size (); i++)
2858    {
2859      Strategy& s = m_strategies[i];
2860      if (s.m_definition == definition)
2861        {
2862          need_strategy = false;
2863
2864          if (!s.m_specified)
2865            {
2866              // This strategy is already applied in this project. Let's change it's value
2867              s.update (definition, b_value, get_name ());
2868            }
2869          else
2870            {
2871              specified = true;
2872            }
2873          break;
2874        }
2875    }
2876
2877  if (need_strategy)
2878    {
2879      // This strategy is not yet applied in this project.
2880
2881      Strategy& s = m_strategies.add ();
2882      s.clear ();
2883      s.update (definition, b_value, get_name ());
2884    }
2885
2886  if (!specified)
2887    {
2888      for (i = 0; i < m_parents.size (); i++)
2889        {
2890          Project* project = m_parents[i];
2891
2892          project->update_strategy (definition, b_value);
2893        }
2894    }
2895}
2896
2897/**----------------------------------------------------------
2898   At least one of the children has changed this strategy
2899   Or the list of children has changed.
2900   We need to update the strategy value accordingly
2901   This will not change the specified value for this strategy
2902*/
2903void Project::update_strategy_from_children (StrategyDef* definition)
2904{
2905  // If this strategy is specified we don't care what happens from the children
2906
2907  //cerr << "Updating strategy " << definition->m_name << " from children for project " << m_name << endl;
2908
2909  int i;
2910
2911  for (i = 0; i < m_strategies.size (); i++)
2912    {
2913      Strategy& s = m_strategies[i];
2914      if (s.m_definition == definition)
2915        {
2916          // This strategy is applied in this project.
2917
2918          if (s.m_specified)
2919            {
2920              // There will be no impact since the strategy is specified
2921
2922              //cerr << "This strategy is specified in this project" << endl;
2923              return;
2924            }
2925
2926          break;
2927        }
2928    }
2929
2930  // The strategy is not specified locally so we will now figure out
2931  // which strategy has to be considered from the mixture of specifications
2932  // from all children.
2933
2934  // Algorithm:
2935  // - We consider children by pairs
2936  // - a child that specifies its strategy wins over a child that does not
2937  // - when the two children have the same level of priority we consider the priority value
2938
2939  Project* selected = 0;
2940  bool selected_is_specified = false;
2941  bool selected_value = definition->m_default_value;
2942
2943  for (i = 0; i < m_children.size (); i++)
2944    {
2945      Project* p = m_children[i];
2946
2947      //cerr << "Checking strategy for child " << p->get_name () << endl;
2948
2949      bool is_specified = p->is_specified (definition);
2950      bool value = p->get_strategy (definition);
2951
2952      if (selected == 0)
2953        {
2954          selected = p;
2955          selected_is_specified = is_specified;
2956          selected_value = value;
2957          continue;
2958        }
2959
2960      if (is_specified == selected_is_specified)
2961        {
2962          if (selected_value != value)
2963            {
2964              // same level of priority but different values -> we must decide
2965              bool priority_value = definition->m_priority_value;
2966              if (value == priority_value)
2967                {
2968                  selected = p;
2969                  selected_is_specified = is_specified;
2970                  selected_value = value;
2971                }
2972            }
2973        }
2974      else
2975        {
2976          if (is_specified)
2977            {
2978              selected = p;
2979              selected_is_specified = is_specified;
2980              selected_value = value;
2981            }
2982        }
2983    }
2984
2985  update_strategy (definition, selected_value); 
2986}
2987
2988/**----------------------------------------------------------
2989   At least one of the children has changed its strategies
2990   Or the list of children has changed.
2991   We need to update the strategy values accordingly
2992   This will not change the specified values
2993*/
2994void Project::update_strategies_from_children ()
2995{
2996  StrategyDef::StrategyDefs& defs = StrategyMgr::get_definitions ();
2997
2998  //cerr << "Updating strategies from children for project " << m_name << endl;
2999
3000  int i;
3001
3002  for (i = 0; i < defs.size (); i++)
3003    {
3004      StrategyDef* def = defs[i];
3005     
3006      update_strategy_from_children (def);
3007    }
3008
3009  for (i = 0; i < m_parents.size (); i++)
3010    {
3011      Project* p = m_parents[i];
3012      p->update_strategies_from_children ();
3013    }
3014}
3015
3016/**----------------------------------------------------------
3017   The StrategyMgr singleton
3018*/
3019StrategyMgr& StrategyMgr::instance ()
3020{
3021  static StrategyMgr me;
3022  return (me);
3023}
3024
3025/**----------------------------------------------------------
3026   The StrategyMgr constructor
3027   Here are primarily constructed all strategy definitions
3028*/
3029StrategyMgr::StrategyMgr ()
3030{
3031  m_defs.clear ();
3032
3033  StrategyDef* s;
3034
3035  s = new StrategyDef;
3036  s->m_keyword = "build";
3037  s->m_name = "BuildPrototypes";
3038  s->m_on_value = "prototypes";
3039  s->m_off_value = "no_prototypes";
3040  s->m_default_value = true;
3041  s->m_priority_value = false;
3042
3043  m_defs.push_back (s);
3044
3045  s = new StrategyDef;
3046  s->m_keyword = "build";
3047  s->m_name = "InstallArea";
3048  s->m_on_value = "with_installarea";
3049  s->m_off_value = "without_installarea";
3050  s->m_default_value = false;
3051  s->m_priority_value = true;
3052
3053  m_defs.push_back (s);
3054
3055  s = new StrategyDef;
3056  s->m_keyword = "setup";
3057  s->m_name = "SetupConfig";
3058  s->m_on_value = "config";
3059  s->m_off_value = "no_config";
3060  s->m_default_value = true;
3061  s->m_priority_value = false;
3062
3063  m_defs.push_back (s);
3064
3065  s = new StrategyDef;
3066  s->m_keyword = "setup";
3067  s->m_name = "SetupRoot";
3068  s->m_on_value = "root";
3069  s->m_off_value = "no_root";
3070  s->m_default_value = true;
3071  s->m_priority_value = false;
3072
3073  m_defs.push_back (s);
3074
3075  s = new StrategyDef;
3076  s->m_keyword = "setup";
3077  s->m_name = "SetupCleanup";
3078  s->m_on_value = "cleanup";
3079  s->m_off_value = "no_cleanup";
3080  s->m_default_value = true;
3081  s->m_priority_value = false;
3082
3083  m_defs.push_back (s);
3084
3085  s = new StrategyDef;
3086  s->m_keyword = "setup";
3087  s->m_name = "SetupScripts";
3088  s->m_on_value = "scripts";
3089  s->m_off_value = "no_scripts";
3090  s->m_default_value = true;
3091  s->m_priority_value = false;
3092
3093  m_defs.push_back (s);
3094
3095  s = new StrategyDef;
3096  s->m_keyword = "structure";
3097  s->m_name = "VersionDirectory";
3098  s->m_on_value = "with_version_directory";
3099  s->m_off_value = "without_version_directory";
3100  if (Cmt::get_current_structuring_style () != without_version_directory)
3101    {
3102      s->m_default_value = true;
3103      s->m_priority_value = false;
3104    }
3105  else
3106    {
3107      s->m_default_value = false;
3108      s->m_priority_value = true;
3109    }
3110
3111  m_defs.push_back (s);
3112}
3113
3114/**----------------------------------------------------------
3115   Find a strategy definition by its name
3116*/
3117StrategyDef* StrategyMgr::find_strategy (const cmt_string& name)
3118{
3119  static StrategyMgr& me = instance ();
3120
3121  int i;
3122
3123  for (i = 0; i < me.m_defs.size (); i++)
3124    {
3125      StrategyDef* def = me.m_defs[i];
3126      if (def->m_name == name)
3127        {
3128          return (def);
3129        }
3130    }
3131
3132  return (0);
3133}
3134
3135/**----------------------------------------------------------
3136   Retreive the default value defined for a given strategy
3137*/
3138bool StrategyMgr::get_default_strategy (const cmt_string& name)
3139{
3140  StrategyDef* def = find_strategy (name);
3141  if (def == 0) return (false);
3142  return (def->m_default_value);
3143}
3144
3145/**----------------------------------------------------------
3146   Retreive the priority value defined for a given strategy
3147   This value is used when two children of a project request two conflicting strategy values
3148*/
3149bool StrategyMgr::get_priority_strategy (const cmt_string& name)
3150{
3151  StrategyDef* def = find_strategy (name);
3152  if (def == 0) return (false);
3153  return (def->m_priority_value);
3154}
3155
3156/**----------------------------------------------------------
3157   Return the vector of all existing strategy definitions
3158*/
3159StrategyDef::StrategyDefs& StrategyMgr::get_definitions ()
3160{
3161  static StrategyMgr& me = instance ();
3162
3163  return (me.m_defs);
3164}
3165
3166//-----------------------------------------------------------
3167Strategy::Strategy ()
3168{
3169  clear ();
3170}
3171
3172//-----------------------------------------------------------
3173void Strategy::clear ()
3174{
3175  m_definition = 0;
3176  m_specified = false;
3177  m_specified_value = false;
3178  m_value = false;
3179  m_on_tag = 0;
3180  m_off_tag = 0;
3181}
3182
3183/**----------------------------------------------------------
3184   Specify a new value for this strategy.
3185   This only happens when a strategy statement is met in a project file or in a requirements file.
3186*/
3187void Strategy::set (StrategyDef* definition, bool value, const cmt_string& project_name)
3188{
3189  //cerr << "Setting strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
3190
3191  m_definition = definition;
3192  m_specified = true;
3193  m_specified_value = value;
3194
3195  update (definition, value, project_name);
3196}
3197
3198/**----------------------------------------------------------
3199   Change the effective value for this strategy.
3200   This has no impact on to the specified value.
3201   This will adapt the tag settings
3202*/
3203void Strategy::update (StrategyDef* definition, bool value, const cmt_string& project_name)
3204{
3205  //cerr << "Updating strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
3206
3207  m_value = value;
3208  m_definition = definition;
3209
3210  cmt_string to_tag_name = project_name;
3211  cmt_string to_untag_name = project_name;
3212
3213  to_tag_name += "_";
3214  to_untag_name += "_";
3215
3216  if (m_value)
3217    {
3218      to_tag_name += m_definition->m_on_value;
3219      to_untag_name += m_definition->m_off_value;
3220    }
3221  else
3222    {
3223      to_tag_name += m_definition->m_off_value;
3224      to_untag_name += m_definition->m_on_value;
3225    }
3226
3227  m_on_tag = Tag::find (to_tag_name);
3228  m_off_tag = Tag::find (to_untag_name);
3229
3230  if (m_on_tag == 0 || m_off_tag == 0)
3231    {
3232      m_on_tag = Tag::add (to_tag_name, PriorityConfig, "PROJECT", 0);
3233      m_off_tag = Tag::add (to_untag_name, PriorityConfig, "PROJECT", 0);
3234
3235      m_on_tag->add_tag_exclude (m_off_tag);
3236      m_off_tag->add_tag_exclude (m_on_tag);
3237    }
3238
3239  m_off_tag->unmark ();
3240  m_on_tag->mark ();
3241}
3242
3243//-----------------------------------------------------------
3244const cmt_string& StrategyDef::get_default_value () const
3245{
3246  if (m_default_value)
3247    {
3248      return (m_on_value);
3249    }
3250  else
3251    {
3252      return (m_off_value);
3253    }
3254}
3255
3256//-----------------------------------------------------------
3257void Project::set_author (const cmt_string& name)
3258{
3259  // cerr << "set_author" << name << endl;     
3260  this->m_author = name;
3261}
3262
3263//-----------------------------------------------------------
3264const cmt_string& Project::get_author () const
3265{
3266  return (m_author);
3267}
3268
3269//-----------------------------------------------------------
3270void Project::project_author_action (const CmtSystem::cmt_string_vector& words)
3271{
3272  if (m_author != "") m_author += "\n";
3273
3274  for (int i = 1; i < words.size (); i++)
3275    {
3276      const cmt_string& w = words[i];
3277     
3278      if (i > 1) m_author += " ";
3279      m_author += w; 
3280    }
3281}
3282
3283//-----------------------------------------------------------
3284Use*  Project::get_use () const
3285{
3286  return m_use;   
3287} 
3288
3289//-----------------------------------------------------------
3290void  Project::set_use (Use* use)
3291{ 
3292  this->m_use = use;
3293}
3294
3295//-----------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.