source: CMT/HEAD/source/cmt_project.cxx @ 537

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

See C.L. 424

  • Property svn:eol-style set to native
File size: 78.4 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          if (p.is_current ()) continue;
1013          p.set_is_current (true);
1014          //
1015          // The current project defines a tag with its name
1016          //
1017         
1018          Tag* tag;
1019         
1020          tag = Tag::add (p.get_name (), PriorityConfig, "PROJECT", 0);
1021          tag->mark ();
1022
1023          p_cur = &p;
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 ()
1284{
1285  Project* p = get_current ();
1286
1287  if (p == 0) return;
1288  Use* use = &(p->m_container);
1289  if (use->get_package_name () == "") return;
1290
1291          if (!use->located ())
1292            {
1293              CmtMessage::warning ("container " + use->get_package_name ()
1294                                   + " " + use->version + " " + use->path
1295                                   + " not found");
1296              /*
1297              if (!Cmt::get_quiet ())
1298                {
1299                  cout << "# package " << use->get_package_name () <<
1300                    " " << use->version << " " << use->path <<
1301                    " not found" <<
1302                    endl;
1303                }
1304              */
1305              CmtError::set (CmtError::package_not_found, use->get_package_name ());
1306            }
1307          else
1308            {
1309              static const cmt_string empty;
1310              cmt_string p = use->real_path;
1311              if (use->path != "")
1312                {
1313                  int pos = p.find_last_of (use->path);
1314                  if (pos != cmt_string::npos)
1315                    {
1316                      p.erase (pos);
1317                    }
1318                }
1319             
1320              cout << "container " << use->get_package_name ()
1321                   << " " << use->version;
1322
1323              if (CmtSystem::absolute_path (use->path))
1324                {
1325                  if (!Cmt::get_quiet ()) 
1326                    {
1327                      cout << " (" << use->path << ")";
1328                    }
1329                }
1330              else
1331                {
1332                  cout << " " << use->path;
1333                }
1334
1335              if (!Cmt::get_quiet ()) 
1336                {
1337                  if (p != "") cout << " (" << p << ")";
1338                  if (use->auto_imports == Off) cout << " (no_auto_imports)";
1339                }
1340
1341              cout << endl;
1342            }
1343}
1344/*----------------------------------------------------------*/
1345void Project::show_specified_strategies_for_all ()
1346{
1347  static ProjectVector& Projects = projects ();
1348
1349  for (int i = 0; i < Projects.size (); i++)
1350    {
1351      const Project& project = Projects[i];
1352      project.show_specified_strategies ();
1353    }
1354}
1355
1356/*----------------------------------------------------------*/
1357class VisitorForShowPaths : public IProjectVisitor
1358{
1359public:
1360  VisitorForShowPaths ()
1361  {
1362  }
1363
1364  void pre (Project* p)
1365  {
1366    const cmt_string& w = p->get_cmtpath_pwd ();
1367    const cmt_string& s = p->get_cmtpath_source ();
1368
1369    if (s == "default path") return;
1370
1371    if (CmtSystem::test_directory (w))
1372      {
1373        cout << "# Add path " << w << " from " << s << endl;
1374      }
1375  }
1376
1377  void in (Project* p)
1378  {
1379    const cmt_string& w = p->get_cmtpath_pwd ();
1380    const cmt_string& s = p->get_cmtpath_source ();
1381
1382    if (s == "default path") return;
1383
1384    if (CmtSystem::test_directory (w))
1385      {
1386        cout << "# Add path " << w << " from " << s << endl;
1387      }
1388  }
1389
1390  void in_again (Project* p)
1391  {
1392    const cmt_string& w = p->get_cmtpath_pwd ();
1393    const cmt_string& s = p->get_cmtpath_source ();
1394
1395    if (s == "default path") return;
1396
1397    if (CmtSystem::test_directory (w))
1398      {
1399        cout << "# Remove path " << w << " from " << s << endl;
1400        cout << "# Add path " << w << " from " << s << endl;
1401      }
1402  }
1403
1404  void post (Project* p)
1405  {
1406  }
1407};
1408
1409/*----------------------------------------------------------*/
1410void Project::show_paths (const CmtSystem::cmt_string_vector& arguments)
1411//void Project::show_paths ()
1412{
1413  if (arguments.size () == 0)
1414    {
1415      const ProjectPtrVector& Ordered = Project::ordered_projects ();
1416      for (int i = 0; i < Ordered.size (); i++)
1417        {
1418          const Project* p = Ordered[i];
1419          const cmt_string& w = p->get_cmtpath_pwd ();
1420          const cmt_string& s = p->get_cmtpath_source ();
1421         
1422          if (s == "default path") continue;
1423         
1424          if (CmtSystem::test_directory (w))
1425            {
1426              cout << "# Add path " << w << " from " << s << endl;
1427            }
1428        }
1429    }
1430  else if (arguments.size () == 1 && cmt_string (arguments[0]) == "-d")
1431    {
1432      const ProjectVector& Projects = projects ();
1433      for (int i = 0; i < Projects.size (); i++)
1434        {
1435          Project& p = Projects[i];
1436          const cmt_string& w = p.get_cmtpath_pwd ();
1437          const cmt_string& s = p.get_cmtpath_source ();
1438         
1439          if (s == "default path") continue;
1440         
1441          if (CmtSystem::test_directory (w))
1442            {
1443              cout << "# Create path " << w << " from " << s << endl;
1444            }
1445        }
1446      /*
1447      VisitorForShowPaths visitor;
1448      start_visit (visitor);
1449      */
1450    }
1451  else
1452    CmtMessage::error ("show_paths: unexpected argument(s)");
1453}
1454
1455//----------------------------------------------------------
1456const cmt_string& Project::get_project_file_name ()
1457{
1458  static const cmt_string name = "project.cmt";
1459
1460  return (name);
1461}
1462
1463//----------------------------------------------------------
1464void Project::fill_selection (int depth, CmtSystem::cmt_string_vector& path_selections)
1465{
1466  static ProjectPtrVector& Ordered = Project::ordered_projects ();
1467  for (int i = 0; i < Ordered.size (); i++)
1468    {
1469      const Project* project = Ordered[i];
1470
1471      const cmt_string& p = project->get_cmtpath ();
1472      const cmt_string& pwd = project->get_cmtpath_pwd ();
1473      const cmt_string& p_real = project->get_cmtpath_real ();
1474      const cmt_string& src = project->get_cmtpath_source ();
1475      /*
1476  static ProjectVector& Projects = projects ();
1477
1478  for (int i = 0; i < Projects.size (); i++)
1479    {
1480      Project& project = Projects[i];
1481
1482      const cmt_string& p = project.get_cmtpath ();
1483      const cmt_string& pwd = project.get_cmtpath_pwd ();
1484      const cmt_string& p_real = project.get_cmtpath_real ();
1485      const cmt_string& src = project.get_cmtpath_source ();
1486      */
1487      if (src != "default path")
1488        {
1489          if (depth > 0)
1490            {
1491              cmt_string& s1 = path_selections.add ();
1492              s1 = p;
1493              if (pwd != p)
1494                {
1495                  cmt_string& s2 = path_selections.add ();
1496                  s2 = pwd;
1497                }
1498              if (p_real != p && p_real != pwd)
1499                {
1500                  cmt_string& s3 = path_selections.add ();
1501                  s3 = p_real;
1502                }
1503              if (src != "CMTHOME" && src != "CMTUSERCONTEXT")
1504                depth--;
1505
1506              if (depth == 0) break;
1507            }
1508        }
1509    }
1510}
1511
1512//----------------------------------------------------------
1513void Project::broadcast (IProjectAction& action)
1514{
1515  //  const ProjectPtrVector Projects = Project::ordered_projects ();
1516  static ProjectPtrVector& Projects = Project::ordered_projects ();
1517
1518  for (int i = 0; i < Projects.size (); i++)
1519    {
1520      const Project* project = Projects[i];
1521
1522      if (!action.run (*project)) break;
1523    }
1524  /*
1525  static ProjectVector& Projects = projects ();
1526
1527  for (int i = 0; i < Projects.size (); i++)
1528    {
1529      const Project& project = Projects[i];
1530
1531      if (!action.run (project)) break;
1532    }
1533  */
1534}
1535
1536//----------------------------------------------------------
1537void Project::reverse_broadcast (IProjectAction& action)
1538{
1539  //  const ProjectPtrVector Projects = Project::ordered_projects ();
1540  static ProjectPtrVector& Projects = Project::ordered_projects ();
1541
1542  for (int i = (Projects.size () - 1); i >= 0; i--)
1543    {
1544      const Project* project = Projects[i];
1545
1546      if (!action.run (*project)) break;
1547    }
1548  /*
1549  static ProjectVector& Projects = projects ();
1550
1551  for (int i = (Projects.size () - 1); i >= 0; i--)
1552    {
1553      const Project& project = Projects[i];
1554
1555      if (!action.run (project)) break;
1556    }
1557  */
1558}
1559
1560//----------------------------------------------------------
1561void Project::scan_paths (PathScanner& scanner, PathScanner::actor& a)
1562{
1563  static ProjectVector& Projects = projects ();
1564
1565  int i;
1566
1567  for (i = 0; i < Projects.size (); i++)
1568    {
1569      Project& p  = Projects[i];
1570      p.m_visited = false;
1571    }
1572
1573  for (i = 0; i < Projects.size (); i++)
1574    {
1575      const Project& project = Projects[i];
1576       
1577      const cmt_string& p = project.m_cmtpath;
1578      scanner.scan_path (p, a);
1579    }
1580}
1581
1582//----------------------------------------------------------
1583void Project::scan_paths_for_package (PathScanner& scanner, const cmt_string& name)
1584{
1585  static ProjectVector& Projects = projects ();
1586
1587  bool found (false);
1588  for (int i = 0; i < Projects.size (); i++)
1589    {
1590      const Project& project = Projects[i];
1591
1592      const cmt_string& p = project.m_cmtpath;
1593      if (scanner.scan_package (p, name))
1594        found = true;
1595    }
1596
1597  if (!found)
1598    CmtError::set (CmtError::package_not_found, name);
1599}
1600
1601//----------------------------------------------------------
1602cmt_string Project::find_in_cmt_paths (const cmt_string& path)
1603{
1604  const cmt_string pwd = CmtSystem::pwd ();
1605
1606  // In case there are symlinks
1607  cmt_string path_real;
1608  //cerr << "realpath_: find_in_cmt_paths" << endl;
1609  CmtSystem::realpath_ (path, path_real);
1610
1611  static ProjectVector& Projects = projects ();
1612
1613  for (int i = 0; i < Projects.size (); i++)
1614    {
1615      const Project& project = Projects[i];
1616
1617      const cmt_string& p = project.m_cmtpath;
1618      const cmt_string& p_real = project.m_cmtpath_real;
1619      const cmt_string& w = project.m_cmtpath_pwd;
1620      const cmt_string& s = project.m_cmtpath_source;
1621
1622      if (s == "default path") continue;
1623
1624      if (CmtSystem::test_directory (p))
1625        {
1626//        if (path.find (p) != cmt_string::npos)
1627//          {
1628//            return (p);
1629//          }
1630
1631          if (path_real.find (p_real) != cmt_string::npos)
1632            {
1633              return (p);
1634            }
1635
1636          // To become the current area, a path must correspond to the current package
1637          if (path.find (w) != cmt_string::npos)
1638            {
1639              return (p);
1640            }
1641        }
1642
1643      if (p == w) continue;
1644
1645      if (CmtSystem::test_directory (w))
1646        {
1647          if (path.find (w) != cmt_string::npos)
1648            {
1649              return (w);
1650            }
1651        }
1652    }
1653
1654  return ("");
1655}
1656
1657//----------------------------------------------------------
1658void Project::visit (IProjectVisitor& visitor)
1659{
1660  if (m_visited) return;
1661  m_visited = true;
1662
1663  int i;
1664
1665  for (i = 0; i < get_children_size (); i++)
1666    {
1667      Project* child = get_child (i);
1668
1669      if (child->visited ()) continue;
1670
1671      visitor.in (child);
1672    }
1673
1674  for (i = 0; i < m_children.size (); i++)
1675    {
1676      Project* child = m_children[i];
1677      child->visit (visitor);
1678    }
1679}
1680
1681//----------------------------------------------------------
1682void Project::visit (IProjectVisitor& visitor, ProjectPtrVector& projects)
1683{
1684  int size = projects.size ();
1685  if (0 == size) return;
1686
1687  ProjectPtrVector children;
1688  for (int j = 0; j < size; j++)
1689    {
1690      Project* p = projects[j];
1691      if (20 == p->m_visits)
1692        continue;
1693      for (int i = 0; i < p->get_children_size (); i++)
1694        {
1695          Project* child = p->get_child (i);
1696          if (0 == child->m_visits)       
1697            visitor.in (child);
1698          else
1699            visitor.in_again (child);
1700          child->m_visits++;
1701          children.push_back (child);
1702        }
1703    }
1704
1705  visit (visitor, children);
1706}
1707
1708//----------------------------------------------------------
1709/**
1710 *  Visit the projects tree and order the projects.
1711 *  Order is the projects upon which the project depends directly,
1712 *  then the direct dependencies of the of the first dependency, of the second
1713 *  dependency and so on. That is first left to right, then downwards.
1714 *  @param offset the offset from which to use all the projects
1715 *  @param order the order of the last project visited
1716 *  @param projs vector of projects to visit and order
1717 */
1718void Project::visit (const int offset, int& order, ProjectPtrVector& projs)
1719{
1720  int size = projs.size ();
1721  //  cerr << "visit: " << offset << " " << order << " " << size << endl;
1722  if (0 == size) return;
1723  static ProjectVector& all = Project::projects ();
1724  /*
1725  cerr << "@ visit: " << order;
1726  for (int j = 0; j < size; j++)
1727    {
1728      Project* p = projs[j];
1729      cerr << " " << p->get_name ();
1730    }
1731  cerr << " @" << endl;
1732  */
1733  ProjectPtrVector children;
1734  for (int j = 0; j < size; j++)
1735    {
1736      Project* p = projs[j];
1737      p->m_visits++;
1738      // Avoid looping in case of circular project dependencies
1739      if (500 <= p->m_visits)
1740        //      if (100 <= p->m_visits)
1741        continue;
1742      for (int i = 0; i < p->get_children_size (); i++)
1743        {
1744          Project* child = p->get_child (i);
1745          const int chorder = child->m_order;
1746          const int porder = p->m_order;
1747          /*
1748          cerr << ">>> " << p->get_name () << " child: " << i << endl;
1749          cerr << child->get_name () << " in: " << chorder << endl;
1750          */
1751          if (-2 == chorder)
1752            continue;
1753          else if (-1 == chorder)
1754            { // not ordered yet, i.e. visited for the first time
1755              child->m_order = ++order;
1756            }
1757          else if (child->is_current ())
1758            //    else if (0 == chorder)
1759            { // the project we started with, i. e. the current project:
1760              //     o circular dependency
1761              //     o do want to keep it first no matter what
1762              if (CmtMessage::active (Verbose))
1763                CmtMessage::warning ("Circular dependency on project: "
1764                                     + child->get_name ()
1765                                     + " " + child->get_release ()
1766                                     + " " + child->get_cmtpath ());
1767            }
1768          else if ((0 <= chorder) && (chorder < porder))
1769            //    else if ((0 < chorder) && (chorder < porder))
1770            { // ordered already, want to put it after the parent in the order
1771              for (int k = offset; k < all.size (); k++)
1772                {
1773                  Project& q = all[k];
1774                  if (&q == child)
1775                    {// the child we are putting after the parent in the order
1776                      q.m_order = porder;
1777                      //              cerr << "Moved back: " << q.get_name () << " order: " << q.m_order << endl;
1778                    }
1779                  else if ((chorder < q.m_order) && (q.m_order <= porder))
1780                    q.m_order--;
1781                }
1782            }
1783          //  cerr << child->get_name () << " out: " << child->m_order << endl;
1784          //      child->m_visits++;
1785          bool unknown (true);
1786          for (int j = 0; j < children.size (); j++)
1787            {
1788              if (children[j] == child)
1789                {
1790                  unknown = false;
1791                  break;
1792                }
1793            }
1794          if (unknown)
1795            {
1796              children.push_back (child);
1797            }
1798        }
1799    }
1800
1801  visit (offset, order, children);
1802}
1803
1804//----------------------------------------------------------
1805void Project::start_visit (IProjectVisitor& visitor)
1806{
1807  static Project::ProjectVector& Projects = Project::projects ();
1808 
1809  for (int i = 0; i < Projects.size (); i++)
1810    {
1811      Project& p = Projects[i];
1812      p.m_visited = false;
1813      p.m_visits = 0;
1814    }
1815
1816  Project* p = get_current ();
1817
1818  if (p == 0)
1819    {
1820      if (Projects.size () == 0) return;
1821
1822      p = &(Projects[0]);
1823    }
1824
1825  //  visitor.pre (p);
1826  //p->visit (visitor);
1827  //  visitor.post (p);
1828  visitor.in (p);
1829  p->m_visits++;
1830  ProjectPtrVector projs;
1831  projs.push_back (p);
1832  visit (visitor, projs);
1833}
1834
1835//----------------------------------------------------------
1836class VisitorForFillCMTPATH : public IProjectVisitor
1837{
1838public:
1839  VisitorForFillCMTPATH (cmt_string& buffer) : m_buffer (buffer)
1840  {
1841    buffer = "path CMTPATH \"\" \n";
1842  }
1843
1844  void pre (Project* p)
1845  {
1846    const cmt_string& w = p->get_cmtpath_pwd ();
1847    const cmt_string& s = p->get_cmtpath_source ();
1848
1849    if (s == "default path") return;
1850
1851    if (CmtSystem::test_directory (w))
1852      {
1853        m_buffer += "path_append CMTPATH \"";
1854        m_buffer += w;
1855        m_buffer += "\" \n";
1856      }
1857  }
1858
1859  void in (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_again (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_remove CMTPATH \"";
1884        m_buffer += w;
1885        m_buffer += "\" \n";
1886        m_buffer += "path_append CMTPATH \"";
1887        m_buffer += w;
1888        m_buffer += "\" \n";
1889      }
1890  }
1891
1892  void post (Project* p)
1893  {
1894    //cerr << "Buffer = " << m_buffer << endl;
1895  }
1896
1897private:
1898  cmt_string& m_buffer;
1899
1900};
1901
1902//----------------------------------------------------------
1903void Project::fill_cmtpaths (cmt_string& buffer)
1904{
1905  /*
1906    Try to re-create all CMTPATH items from project definitions.
1907    The goal is to generate CMTPATH even if this EV was not pre-set
1908    which is the case when CMTPROJECTPATH is only used
1909  */
1910
1911  /*
1912  VisitorForFillCMTPATH visitor (buffer);
1913
1914  start_visit (visitor);
1915  */
1916  const ProjectPtrVector& Ordered = Project::ordered_projects ();
1917
1918  buffer = "path CMTPATH \"\" \n";
1919  for (int i = 0; i < Ordered.size (); i++)
1920    {
1921      const Project* p = Ordered[i];
1922      const cmt_string& w = p->get_cmtpath_pwd ();
1923      const cmt_string& s = p->get_cmtpath_source ();
1924     
1925      if (s == "default path") continue;
1926     
1927      if (CmtSystem::test_directory (w))
1928        {
1929          buffer += "path_append CMTPATH \"";
1930          buffer += w;
1931          buffer += "\" \n";
1932        }
1933    }
1934}
1935
1936//----------------------------------------------------------
1937Project::Project () : m_name (""), m_author("")
1938{
1939  clear ();
1940}
1941
1942//----------------------------------------------------------
1943const cmt_string& Project::get_name () const
1944{
1945  return (m_name);
1946}
1947
1948//----------------------------------------------------------
1949const cmt_string& Project::get_release () const
1950{
1951  return (m_release);
1952}
1953
1954//----------------------------------------------------------
1955const cmt_string& Project::get_container_name () const
1956{
1957  return (m_container_name);
1958}
1959
1960//----------------------------------------------------------
1961const cmt_string& Project::get_container_version () const
1962{
1963  return (m_container_version);
1964}
1965
1966//----------------------------------------------------------
1967const cmt_string& Project::get_container_path () const
1968{
1969  return (m_container_path);
1970}
1971
1972//----------------------------------------------------------
1973const Use& Project::get_container () const
1974{
1975  return (m_container);
1976}
1977
1978//----------------------------------------------------------
1979const cmt_string& Project::get_cmtpath () const
1980{
1981  return (m_cmtpath);
1982}
1983
1984//----------------------------------------------------------
1985const cmt_string& Project::get_cmtpath_real () const
1986{
1987  return (m_cmtpath_real);
1988}
1989
1990//----------------------------------------------------------
1991const cmt_string& Project::get_cmtpath_pwd () const
1992{
1993  return (m_cmtpath_pwd);
1994}
1995
1996//----------------------------------------------------------
1997const cmt_string& Project::get_cmtpath_source () const
1998{
1999  return (m_cmtpath_source);
2000}
2001
2002//----------------------------------------------------------
2003int Project::get_children_size () const
2004{
2005  return (m_children.size ());
2006}
2007
2008//----------------------------------------------------------
2009Project* Project::get_child (int index) const
2010{
2011  if (index < 0) return (0);
2012  if (index >= m_children.size ()) return (0);
2013  return (m_children[index]);
2014}
2015
2016//----------------------------------------------------------
2017bool Project::visited () const
2018{
2019  return (m_visited);
2020}
2021
2022//----------------------------------------------------------
2023void Project::set_name (const cmt_string& name)
2024{
2025  m_name = name;
2026}
2027
2028//----------------------------------------------------------
2029void Project::set_release (const cmt_string& release)
2030{
2031  m_release = release;
2032}
2033
2034//----------------------------------------------------------
2035void Project::set_container_name (const cmt_string& name)
2036{
2037  m_container_name = name;
2038}
2039
2040//----------------------------------------------------------
2041void Project::set_container_version (const cmt_string& container_version)
2042{
2043  m_container_version = container_version;
2044}
2045
2046//----------------------------------------------------------
2047void Project::set_container_path (const cmt_string& container_path)
2048{
2049  m_container_path = container_path;
2050}
2051
2052//----------------------------------------------------------
2053void Project::set_cmtpath (const cmt_string& path)
2054{
2055  m_cmtpath = path;
2056}
2057
2058//----------------------------------------------------------
2059void Project::set_cmtpath_real (const cmt_string& path)
2060{
2061  m_cmtpath_real = path;
2062}
2063
2064//----------------------------------------------------------
2065void Project::set_cmtpath_pwd (const cmt_string& path)
2066{
2067  m_cmtpath_pwd = path;
2068}
2069
2070//----------------------------------------------------------
2071void Project::set_cmtpath_source (const cmt_string& source)
2072{
2073  m_cmtpath_source = source;
2074}
2075
2076//----------------------------------------------------------
2077void Project::set_is_current (bool is_current)
2078{
2079  m_is_current = is_current;
2080}
2081
2082//----------------------------------------------------------
2083bool Project::is_current () const
2084{
2085  return m_is_current;
2086}
2087
2088//----------------------------------------------------------
2089void Project::clear ()
2090{
2091  m_name    = "";
2092  m_release = "";
2093  m_cmtpath = "";
2094  m_cmtpath_real = "";
2095  m_cmtpath_pwd    = "";
2096  m_cmtpath_source = "";
2097  m_use            = 0;
2098
2099  m_parents.clear ();
2100  m_children.clear ();
2101
2102  m_configured = false;
2103
2104  m_strategies.clear ();
2105  m_is_current = false;
2106}
2107
2108//----------------------------------------------------------
2109bool Project::has_parents () const
2110{
2111  return ((m_parents.size () > 0));
2112}
2113
2114//----------------------------------------------------------
2115bool Project::has_parent (Project* p) const
2116{
2117  if (p == 0) return (false);
2118  if (p == this) return (false);
2119
2120  const cmt_string& name = p->get_name ();
2121
2122  int i;
2123
2124  for (i = 0; i < m_parents.size (); i++)
2125    {
2126      const Project* parent = m_parents[i];
2127      if (parent == 0) continue;
2128
2129      if (parent->get_name () == name)
2130        {
2131          // registered as a parent
2132          return (true);
2133        }
2134
2135      if (parent->has_parent (p))
2136        {
2137          // recurse
2138          return (true);
2139        }
2140    }
2141
2142  return (false);
2143}
2144
2145//----------------------------------------------------------
2146bool Project::has_child (Project* p) const
2147{
2148  if (p == 0) return (false);
2149  if (p == this) return (false);
2150
2151  const cmt_string& name = p->get_name ();
2152
2153  int i;
2154
2155  for (i = 0; i < m_children.size (); i++)
2156    {
2157      const Project* child = m_children[i];
2158      if (child == 0) continue;
2159
2160      if (child->get_name () == name)
2161        {
2162          // registered as a child
2163          return (true);
2164        }
2165
2166      if (child->has_child (p))
2167        {
2168          // recurse
2169          return (true);
2170        }
2171    }
2172
2173  return (false);
2174}
2175
2176//----------------------------------------------------------
2177void Project::add_parent (Project* p)
2178{
2179  if (p == 0) return;
2180  if (p == this) return;
2181
2182  //cerr << "Adding parent " << p->get_name () << " to " << m_name << endl;
2183
2184  if (has_child (p)) return;
2185  if (has_parent (p)) return;
2186
2187  m_parents.push_back (p);
2188}
2189
2190//----------------------------------------------------------
2191void Project::add_child (Project* p)
2192{
2193  if (p == 0) return;
2194  if (p == this) return;
2195
2196  if (has_child (p)) return;
2197  if (has_parent (p)) return;
2198
2199  m_children.push_back (p);
2200}
2201
2202//----------------------------------------------------------
2203void Project::erase_child (Project* p)
2204{
2205  if (p == 0) return;
2206  if (p == this) return;
2207
2208  if (!has_child (p)) return;
2209
2210  const cmt_string& name = p->get_name ();
2211
2212  for (int i = 0; i < m_children.size (); i++)
2213    {
2214      const Project* child = m_children[i];
2215      if (child == 0) continue;
2216
2217      if (child->get_name () == name)
2218        {
2219          // registered as a child
2220          m_children.erase (i);
2221          break;
2222        }
2223    }
2224}
2225
2226//----------------------------------------------------------
2227void Project::configure ()
2228{
2229  if (m_configured) return;
2230  m_configured = true;
2231
2232  set_default_strategy ("SetupConfig");
2233  set_default_strategy ("SetupRoot");
2234  set_default_strategy ("SetupCleanup");
2235  set_default_strategy ("SetupScripts");
2236  set_default_strategy ("BuildPrototypes");
2237  set_default_strategy ("InstallArea");
2238  set_default_strategy ("VersionDirectory");
2239}
2240
2241/**---------------------------------------------------------
2242   A container statement is met in the project file
2243*/
2244void Project::container_action (const CmtSystem::cmt_string_vector& words)
2245//void Project::container_action (const cmt_string& name, const cmt_string& version)
2246{
2247  //
2248  // complete syntax : "container <package> <version> <path>" 
2249  // minimal syntax  : "container <package>"
2250  //
2251  //  o if <version> is omitted then take any version available
2252  //  o <version> can be specified using "v*" or "v<n>r*" or "v<n>r<m>p*"
2253  //
2254  //  o the notation "v*" is preferred to omission (particularly since
2255  //    omission does not permit <path>)
2256  //
2257  Use* use = &m_container;
2258  use->~Use ();
2259  if (words.size () < 2) return;
2260
2261  CmtSystem::cmt_string_vector ewords;
2262  for (int i = 1; i < words.size (); i++)
2263    {
2264      const cmt_string& w = words[i];
2265      cmt_string ew = w;
2266
2267      Symbol::expand (ew);
2268      if (ew != w)
2269        {
2270          CmtSystem::cmt_string_vector ws;
2271          CmtSystem::split (ew, " ", ws);
2272
2273          for (int j = 0; j < ws.size (); ++j)
2274            {
2275              ewords.push_back (ws[j]);
2276            }
2277        }
2278      else
2279        {
2280          ewords.push_back (w);
2281        }
2282    }
2283
2284  cmt_string name, version, path;
2285  if (ewords.size () > 0) name = ewords[0];
2286  if (ewords.size () > 1) version = ewords[1];
2287  if (ewords.size () > 2) path = ewords[2];
2288
2289  if (name != "")
2290    {
2291      use->set (name, version, path);
2292      use->get_package ()->remove_use (use);
2293      CmtSystem::cd (m_cmtpath_pwd);
2294      if (use->move_to ("", true) &&
2295          !CmtSystem::absolute_path (use->real_path))
2296        {
2297          use->change_path (m_cmtpath_pwd);
2298        }
2299      CmtSystem::cd (m_cmtpath_pwd + CmtSystem::file_separator () + "cmt");
2300    }
2301
2302  set_container_name (name);
2303  set_container_version (version);
2304  set_container_path (path);
2305}
2306
2307/**---------------------------------------------------------
2308   A use statement is met in the project file
2309*/
2310void Project::use_action (const cmt_string& name, const cmt_string& release)
2311{
2312  if (Cmt::get_debug ())
2313    {
2314      cout << "Use action " << name << " " << release << endl;
2315    }
2316
2317  // A project with its release is specified
2318  //
2319  // Is this project already visible?
2320  // If not: look for it
2321  //   + get CMTPROJECTPATH
2322  //   + search from all entries of CMTPROJECTPATH : p(i)/<name>/<release>
2323  //   + when found, this should become a new CMTPATH entry
2324  //   +             the new project is then parsed ... etc...
2325
2326  // First test it wilcard is used
2327  int v = -1;
2328  int r = -1;
2329  int p = -1;
2330  cmt_string new_release = release;
2331  CmtSystem::is_version_directory (new_release, v, r, p); 
2332  bool use_has_wild_card = (v == -1) || (r == -1) || (p == -1);
2333  if (use_has_wild_card)
2334    {
2335      cmt_string selected_release = "";
2336
2337      if (select_release(name, new_release,selected_release))
2338        {
2339          // cerr <<"selected_release: "<<selected_release<<endl;   
2340          new_release = selected_release;
2341        }         
2342    }
2343
2344  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2345  cmt_string sep;
2346  sep = CmtSystem::path_separator ();
2347
2348  CmtSystem::cmt_string_vector items;
2349  CmtSystem::split (cmtprojectpath, sep, items);
2350
2351  bool found = false;
2352
2353  for (int i = 0; i < items.size (); i++)
2354    {
2355      const cmt_string& item = items[i];
2356      cmt_string p = item;
2357      p += CmtSystem::file_separator ();
2358      p += name;
2359      if (new_release != "")
2360        {
2361          p += CmtSystem::file_separator ();
2362          p += new_release;
2363        }
2364
2365      if (CmtSystem::test_directory (p))
2366        {
2367          //cerr << "Project directory " << p << " exists " << endl;
2368
2369          found = true;
2370
2371          IProjectFactory& factory = ProjectFactory::instance ();
2372
2373          factory.create_project (name, p, "ProjectPath", this);
2374
2375          break;
2376        }
2377    }
2378
2379  if (!found)
2380    {
2381      Project* p = Project::find_by_name (name);
2382
2383      if (p != 0)
2384        {
2385          found = true;
2386          p->add_parent (this);
2387          add_child (p);
2388
2389          update_strategies_from_children ();
2390        }
2391    }
2392   
2393  if (!found && (cmtprojectpath != ""))
2394    {
2395      CmtMessage::warning ("Project " + name + " " + release + " requested by " + m_name + " not found in CMTPROJECTPATH");
2396      //      cerr << "#CMT> Project " << name << " " << release << " requested by " << m_name << " not found in CMTPROJECTPATH" << endl;
2397    }
2398}
2399
2400//---------------------------------------------------------
2401bool Project::select_release(const cmt_string& name, const cmt_string& release, cmt_string& result)
2402{
2403  cmt_string selected_release = "";
2404
2405  int v = -1;
2406  int r = -1;
2407  int p = -1;
2408  CmtSystem::is_version_directory (release, v, r, p); 
2409
2410  int selected_v = -1;
2411  int selected_r = -1;
2412  int selected_p = -1;
2413  CmtSystem::cmt_string_vector releases = get_project_releases(name);
2414  for (int j = 0; j < releases.size (); j++)
2415    {
2416      int new_v = -1;
2417      int new_r = -1;
2418      int new_p = -1;
2419      CmtSystem::is_version_directory (releases[j], new_v, new_r, new_p);
2420      if (v == -1)
2421        {
2422          if (selected_v < new_v)
2423            {
2424              selected_v = new_v;
2425              selected_r = -1;
2426              selected_p = -1;
2427              selected_release = releases[j];
2428            }
2429          else if (selected_v == new_v)
2430            {
2431              // We compare the r
2432              if (selected_r < new_r)
2433                {
2434                  selected_r = new_r;
2435                  selected_p = -1;
2436                  selected_release = releases[j];                               
2437                }
2438              else if (selected_r == new_r)
2439                {
2440                  // We compare the p
2441                  if (selected_p < new_p)
2442                    {
2443                      selected_p = new_p;
2444                      selected_release = releases[j];                               
2445                    }
2446                  // else if ? not possible                                                           
2447                }                               
2448            }
2449        }
2450      else if (r == -1)
2451        {
2452          if (v == new_v)
2453            {
2454              // We compare the r                                                     
2455              if (selected_r < new_r)
2456                {
2457                  selected_r = new_r;
2458                  selected_p = -1;
2459                  selected_release = releases[j];                               
2460                }
2461              else if (selected_r == new_r)
2462                { 
2463                  // We compare the p
2464                  if (selected_p < new_p)
2465                    {
2466                      selected_p = new_p;
2467                      selected_release = releases[j];                               
2468                    }
2469                  // else if ? not possible
2470                }
2471            }
2472        }
2473      else if (p == -1)
2474        {
2475          if ((v == new_v) && (r == new_r))
2476            { 
2477              // We compare the p
2478              if (selected_p < new_p)
2479                {
2480                  selected_p = new_p;
2481                  selected_release = releases[j];                               
2482                }
2483              // else if ? not possible
2484            }       
2485        }       
2486
2487      //cerr << "v:" << new_v << ", r:" << new_r << ", p:" << new_p << endl;             
2488      //cerr << "req v:" << v << ", req r:" << r << ", req p:" << p << endl;       
2489
2490    }
2491
2492  // cerr << "selected release: " << selected_release << endl; 
2493
2494  if (selected_release == "") return false;
2495
2496  result = selected_release;   
2497
2498  return (true);
2499}
2500
2501//---------------------------------------------------------
2502const CmtSystem::cmt_string_vector Project::get_project_releases (const cmt_string& name) const
2503{
2504  CmtSystem::cmt_string_vector releases;
2505  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2506
2507  static cmt_string sep = CmtSystem::path_separator ();
2508
2509  CmtSystem::cmt_string_vector items;
2510  CmtSystem::split (cmtprojectpath, sep, items);   
2511
2512  for (int i = 0; i < items.size (); i++)
2513    {
2514      const cmt_string& item = items[i];
2515      cmt_string p = item;
2516      p += CmtSystem::file_separator ();
2517      p += name;
2518
2519      if (CmtSystem::test_directory (p))
2520        { 
2521          CmtSystem::cmt_string_vector directories;
2522          CmtSystem::scan_dir (p, directories);
2523
2524          for (int j = 0; j < directories.size (); j++)
2525            {
2526              if  (CmtSystem::test_directory(directories[j]))
2527                {
2528                  cmt_string release;
2529                  CmtSystem:: basename(directories[j], release);
2530
2531                  if (CmtSystem::is_version_directory(release))
2532                    {                             
2533                      cmt_string& name_entry = releases.add ();
2534                      name_entry = release; 
2535                    }             
2536                }                           
2537            }                           
2538        }
2539    }
2540  return (releases);
2541}
2542
2543//----------------------------------------------------------
2544Project& Project::operator = (const Project& other)
2545{
2546  m_name = other.m_name;
2547  m_cmtpath = other.m_cmtpath;
2548  m_cmtpath_real = other.m_cmtpath_real;
2549  m_cmtpath_pwd = other.m_cmtpath_pwd;
2550  m_cmtpath_source = other.m_cmtpath_source;
2551
2552  return (*this);
2553}
2554
2555//----------------------------------------------------------
2556bool Project::operator == (const cmt_string& name) const
2557{
2558  return ((m_name == name));
2559}
2560
2561//----------------------------------------------------------
2562bool Project::operator != (const cmt_string& name) const
2563{
2564  return ((m_name != name));
2565}
2566
2567//----------------------------------------------------------
2568void Project::show ()
2569{
2570  if (m_visited) return;
2571  m_visited = true;
2572
2573  static int level = 0;
2574
2575  //  bool is_current = false;
2576
2577  //  cmt_string here = CmtSystem::pwd ();
2578  // In case there are symlinks
2579  /*
2580  cmt_string here_real;
2581  CmtSystem::realpath_ (CmtSystem::pwd (), here_real);
2582
2583  //  if (here.find (m_cmtpath) == 0)
2584  if (here_real.find (m_cmtpath_real) == 0)
2585    {
2586      if (m_cmtpath_source != "default path")
2587        {
2588          is_current = true;
2589        }
2590    }
2591  */
2592  for (int tab = 0; tab < level; tab++) cout << "  ";
2593  cout << m_name << " " << (m_name != "CMTUSERCONTEXT" && m_name != "CMTHOME" ? m_release : "v0") << " (in " << m_cmtpath << ")";
2594  //  cout << m_name << " " << m_release << " (in " << m_cmtpath << ")";
2595
2596  if (m_is_current) cout << " (current)";
2597  //  if (is_current) cout << " (current)";
2598
2599  int i;
2600
2601  for (i = 0; i < m_parents.size (); i++)
2602    {
2603      Project* p = m_parents[i];
2604      if (p == 0) continue;
2605      cout << " P=" << p->get_name ();
2606    }
2607
2608  for (i = 0; i < m_children.size (); i++)
2609    {
2610      Project* p = m_children[i];
2611      if (p == 0) continue;
2612      cout << " C=" << p->get_name ();
2613    }
2614
2615  cout << endl;
2616
2617/*
2618  if (m_visited) return;
2619
2620  m_visited = true;
2621*/
2622
2623  for (i = 0; i < m_children.size (); i++)
2624    {
2625      Project* p = m_children[i];
2626      if (p == 0) continue;
2627      level++;
2628      p->show ();
2629      level--;
2630    }
2631}
2632
2633
2634//----------------------------------------------------------
2635void Project::show_specified_strategies () const
2636{
2637  int i;
2638
2639  for (i = 0; i < m_strategies.size (); i++)
2640    {
2641      const Strategy& s = m_strategies[i];
2642      if (s.m_specified)
2643        {
2644          const StrategyDef* def = s.m_definition;
2645 
2646          cout << "# Project " << m_name
2647               << " sets " << def->m_keyword
2648               << " strategy to " << ((s.m_value) ? def->m_on_value : def->m_off_value);
2649
2650          if (s.m_context != "")
2651            {
2652              cout << " (from package " << s.m_context << ")";
2653            }
2654
2655          cout << endl;
2656        }
2657    }
2658}
2659
2660//----------------------------------------------------------
2661bool Project::has_strategy (const StrategyDef* definition) const
2662{
2663  int i;
2664
2665  for (i = 0; i < m_strategies.size (); i++)
2666    {
2667      const Strategy& s = m_strategies[i];
2668      if (s.m_definition == definition)
2669        {
2670          return (true);
2671        }
2672    }
2673
2674  return (false);
2675}
2676
2677//----------------------------------------------------------
2678bool Project::get_strategy (const cmt_string& name) const
2679{
2680  static StrategyMgr& mgr = StrategyMgr::instance ();
2681
2682  StrategyDef* def = mgr.find_strategy (name);
2683  if (def == 0)
2684    {
2685      CmtMessage::warning ("strategy " + name + " undefined");
2686      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2687      return (false);
2688    }
2689
2690  return (get_strategy (def));
2691}
2692
2693//----------------------------------------------------------
2694bool Project::is_specified (const StrategyDef* definition) const
2695{
2696  int i;
2697
2698  for (i = 0; i < m_strategies.size (); i++)
2699    {
2700      Strategy& s = m_strategies[i];
2701      if (s.m_definition == definition)
2702        {
2703          // This strategy is applied in this project
2704          return (s.m_specified);
2705        }
2706    }
2707
2708  // This strategy is not applied in this project
2709  return (false);
2710}
2711
2712//----------------------------------------------------------
2713bool Project::get_strategy (const StrategyDef* def) const
2714{
2715  int i;
2716
2717  for (i = 0; i < m_strategies.size (); i++)
2718    {
2719      Strategy& s = m_strategies[i];
2720      if (s.m_definition == def)
2721        {
2722          // This strategy is applied in this project
2723          if (s.m_specified)
2724            {
2725              return (s.m_specified_value);
2726            }
2727          return (s.m_value);
2728        }
2729    }
2730
2731  // This strategy is not applied in this project
2732  return (def->m_default_value);
2733}
2734
2735//----------------------------------------------------------
2736void Project::set_default_strategy (const cmt_string& name)
2737{
2738  static StrategyMgr& mgr = StrategyMgr::instance ();
2739
2740  StrategyDef* def = mgr.find_strategy (name);
2741  if (def == 0)
2742    {
2743      CmtMessage::warning ("strategy " + name + " undefined");
2744      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2745      return;
2746    }
2747
2748  update_strategy (def, def->m_default_value);
2749}
2750
2751
2752//----------------------------------------------------------
2753void Project::set_strategy (const cmt_string& name, const cmt_string& value, const cmt_string& context)
2754{
2755  static StrategyMgr& mgr = StrategyMgr::instance ();
2756
2757  StrategyDef* def = mgr.find_strategy (name);
2758  if (def == 0)
2759    {
2760      CmtMessage::warning ("strategy " + name + " undefined");
2761      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2762      return;
2763    }
2764
2765  bool b_value = false;
2766
2767  if (value == def->m_on_value)
2768    {
2769      b_value = true;
2770    }
2771  else if (value == def->m_off_value)
2772    {
2773      b_value = false;
2774    }
2775  else
2776    {
2777      CmtMessage::warning ("requested strategy value " + value + " undefined in strategy " + name);
2778      //      cerr << "#CMT> requested strategy value " << value << " undefined in strategy " << name << endl;
2779      return;
2780    }
2781
2782  set_strategy (def, b_value, context);
2783}
2784
2785//----------------------------------------------------------
2786void Project::set_strategy (StrategyDef* definition, bool b_value, const cmt_string& context)
2787{
2788  bool need_strategy = true;
2789
2790  int i;
2791
2792  for (i = 0; i < m_strategies.size (); i++)
2793    {
2794      Strategy& s = m_strategies[i];
2795      if (s.m_definition == definition)
2796        {
2797          // This strategy is already applied in this project. Let's change it's value
2798          s.set (definition, b_value, get_name ());
2799          if (context != "")
2800            {
2801              if (s.m_context != "") s.m_context += " ";
2802              s.m_context += context;
2803            }
2804          need_strategy = false;
2805          break;
2806        }
2807    }
2808
2809  if (need_strategy)
2810    {
2811      // This strategy is not yet applied in this project.
2812
2813      Strategy& s = m_strategies.add ();
2814      s.clear ();
2815      s.set (definition, b_value, get_name ());
2816      s.m_context = context;
2817    }
2818 
2819  for (i = 0; i < m_parents.size (); i++)
2820    {
2821      Project* project = m_parents[i];
2822
2823      project->update_strategy (definition, b_value);
2824    }
2825}
2826
2827/**----------------------------------------------------------
2828   The strategy value is changed because of indirect influences
2829   - default strategy at initialization time
2830   - change in the children
2831   - change in the children list
2832
2833   (This is not a specification : see the set_strategy method)
2834*/
2835void Project::update_strategy (StrategyDef* definition, bool b_value)
2836{
2837  bool need_strategy = true;
2838  bool specified = false;
2839
2840  int i;
2841
2842  for (i = 0; i < m_strategies.size (); i++)
2843    {
2844      Strategy& s = m_strategies[i];
2845      if (s.m_definition == definition)
2846        {
2847          need_strategy = false;
2848
2849          if (!s.m_specified)
2850            {
2851              // This strategy is already applied in this project. Let's change it's value
2852              s.update (definition, b_value, get_name ());
2853            }
2854          else
2855            {
2856              specified = true;
2857            }
2858          break;
2859        }
2860    }
2861
2862  if (need_strategy)
2863    {
2864      // This strategy is not yet applied in this project.
2865
2866      Strategy& s = m_strategies.add ();
2867      s.clear ();
2868      s.update (definition, b_value, get_name ());
2869    }
2870
2871  if (!specified)
2872    {
2873      for (i = 0; i < m_parents.size (); i++)
2874        {
2875          Project* project = m_parents[i];
2876
2877          project->update_strategy (definition, b_value);
2878        }
2879    }
2880}
2881
2882/**----------------------------------------------------------
2883   At least one of the children has changed this strategy
2884   Or the list of children has changed.
2885   We need to update the strategy value accordingly
2886   This will not change the specified value for this strategy
2887*/
2888void Project::update_strategy_from_children (StrategyDef* definition)
2889{
2890  // If this strategy is specified we don't care what happens from the children
2891
2892  //cerr << "Updating strategy " << definition->m_name << " from children for project " << m_name << endl;
2893
2894  int i;
2895
2896  for (i = 0; i < m_strategies.size (); i++)
2897    {
2898      Strategy& s = m_strategies[i];
2899      if (s.m_definition == definition)
2900        {
2901          // This strategy is applied in this project.
2902
2903          if (s.m_specified)
2904            {
2905              // There will be no impact since the strategy is specified
2906
2907              //cerr << "This strategy is specified in this project" << endl;
2908              return;
2909            }
2910
2911          break;
2912        }
2913    }
2914
2915  // The strategy is not specified locally so we will now figure out
2916  // which strategy has to be considered from the mixture of specifications
2917  // from all children.
2918
2919  // Algorithm:
2920  // - We consider children by pairs
2921  // - a child that specifies its strategy wins over a child that does not
2922  // - when the two children have the same level of priority we consider the priority value
2923
2924  Project* selected = 0;
2925  bool selected_is_specified = false;
2926  bool selected_value = definition->m_default_value;
2927
2928  for (i = 0; i < m_children.size (); i++)
2929    {
2930      Project* p = m_children[i];
2931
2932      //cerr << "Checking strategy for child " << p->get_name () << endl;
2933
2934      bool is_specified = p->is_specified (definition);
2935      bool value = p->get_strategy (definition);
2936
2937      if (selected == 0)
2938        {
2939          selected = p;
2940          selected_is_specified = is_specified;
2941          selected_value = value;
2942          continue;
2943        }
2944
2945      if (is_specified == selected_is_specified)
2946        {
2947          if (selected_value != value)
2948            {
2949              // same level of priority but different values -> we must decide
2950              bool priority_value = definition->m_priority_value;
2951              if (value == priority_value)
2952                {
2953                  selected = p;
2954                  selected_is_specified = is_specified;
2955                  selected_value = value;
2956                }
2957            }
2958        }
2959      else
2960        {
2961          if (is_specified)
2962            {
2963              selected = p;
2964              selected_is_specified = is_specified;
2965              selected_value = value;
2966            }
2967        }
2968    }
2969
2970  update_strategy (definition, selected_value); 
2971}
2972
2973/**----------------------------------------------------------
2974   At least one of the children has changed its strategies
2975   Or the list of children has changed.
2976   We need to update the strategy values accordingly
2977   This will not change the specified values
2978*/
2979void Project::update_strategies_from_children ()
2980{
2981  StrategyDef::StrategyDefs& defs = StrategyMgr::get_definitions ();
2982
2983  //cerr << "Updating strategies from children for project " << m_name << endl;
2984
2985  int i;
2986
2987  for (i = 0; i < defs.size (); i++)
2988    {
2989      StrategyDef* def = defs[i];
2990     
2991      update_strategy_from_children (def);
2992    }
2993
2994  for (i = 0; i < m_parents.size (); i++)
2995    {
2996      Project* p = m_parents[i];
2997      p->update_strategies_from_children ();
2998    }
2999}
3000
3001/**----------------------------------------------------------
3002   The StrategyMgr singleton
3003*/
3004StrategyMgr& StrategyMgr::instance ()
3005{
3006  static StrategyMgr me;
3007  return (me);
3008}
3009
3010/**----------------------------------------------------------
3011   The StrategyMgr constructor
3012   Here are primarily constructed all strategy definitions
3013*/
3014StrategyMgr::StrategyMgr ()
3015{
3016  m_defs.clear ();
3017
3018  StrategyDef* s;
3019
3020  s = new StrategyDef;
3021  s->m_keyword = "build";
3022  s->m_name = "BuildPrototypes";
3023  s->m_on_value = "prototypes";
3024  s->m_off_value = "no_prototypes";
3025  s->m_default_value = true;
3026  s->m_priority_value = false;
3027
3028  m_defs.push_back (s);
3029
3030  s = new StrategyDef;
3031  s->m_keyword = "build";
3032  s->m_name = "InstallArea";
3033  s->m_on_value = "with_installarea";
3034  s->m_off_value = "without_installarea";
3035  s->m_default_value = false;
3036  s->m_priority_value = true;
3037
3038  m_defs.push_back (s);
3039
3040  s = new StrategyDef;
3041  s->m_keyword = "setup";
3042  s->m_name = "SetupConfig";
3043  s->m_on_value = "config";
3044  s->m_off_value = "no_config";
3045  s->m_default_value = true;
3046  s->m_priority_value = false;
3047
3048  m_defs.push_back (s);
3049
3050  s = new StrategyDef;
3051  s->m_keyword = "setup";
3052  s->m_name = "SetupRoot";
3053  s->m_on_value = "root";
3054  s->m_off_value = "no_root";
3055  s->m_default_value = true;
3056  s->m_priority_value = false;
3057
3058  m_defs.push_back (s);
3059
3060  s = new StrategyDef;
3061  s->m_keyword = "setup";
3062  s->m_name = "SetupCleanup";
3063  s->m_on_value = "cleanup";
3064  s->m_off_value = "no_cleanup";
3065  s->m_default_value = true;
3066  s->m_priority_value = false;
3067
3068  m_defs.push_back (s);
3069
3070  s = new StrategyDef;
3071  s->m_keyword = "setup";
3072  s->m_name = "SetupScripts";
3073  s->m_on_value = "scripts";
3074  s->m_off_value = "no_scripts";
3075  s->m_default_value = true;
3076  s->m_priority_value = false;
3077
3078  m_defs.push_back (s);
3079
3080  s = new StrategyDef;
3081  s->m_keyword = "structure";
3082  s->m_name = "VersionDirectory";
3083  s->m_on_value = "with_version_directory";
3084  s->m_off_value = "without_version_directory";
3085  if (Cmt::get_current_structuring_style () != without_version_directory)
3086    {
3087      s->m_default_value = true;
3088      s->m_priority_value = false;
3089    }
3090  else
3091    {
3092      s->m_default_value = false;
3093      s->m_priority_value = true;
3094    }
3095
3096  m_defs.push_back (s);
3097}
3098
3099/**----------------------------------------------------------
3100   Find a strategy definition by its name
3101*/
3102StrategyDef* StrategyMgr::find_strategy (const cmt_string& name)
3103{
3104  static StrategyMgr& me = instance ();
3105
3106  int i;
3107
3108  for (i = 0; i < me.m_defs.size (); i++)
3109    {
3110      StrategyDef* def = me.m_defs[i];
3111      if (def->m_name == name)
3112        {
3113          return (def);
3114        }
3115    }
3116
3117  return (0);
3118}
3119
3120/**----------------------------------------------------------
3121   Retreive the default value defined for a given strategy
3122*/
3123bool StrategyMgr::get_default_strategy (const cmt_string& name)
3124{
3125  StrategyDef* def = find_strategy (name);
3126  if (def == 0) return (false);
3127  return (def->m_default_value);
3128}
3129
3130/**----------------------------------------------------------
3131   Retreive the priority value defined for a given strategy
3132   This value is used when two children of a project request two conflicting strategy values
3133*/
3134bool StrategyMgr::get_priority_strategy (const cmt_string& name)
3135{
3136  StrategyDef* def = find_strategy (name);
3137  if (def == 0) return (false);
3138  return (def->m_priority_value);
3139}
3140
3141/**----------------------------------------------------------
3142   Return the vector of all existing strategy definitions
3143*/
3144StrategyDef::StrategyDefs& StrategyMgr::get_definitions ()
3145{
3146  static StrategyMgr& me = instance ();
3147
3148  return (me.m_defs);
3149}
3150
3151//-----------------------------------------------------------
3152Strategy::Strategy ()
3153{
3154  clear ();
3155}
3156
3157//-----------------------------------------------------------
3158void Strategy::clear ()
3159{
3160  m_definition = 0;
3161  m_specified = false;
3162  m_specified_value = false;
3163  m_value = false;
3164  m_on_tag = 0;
3165  m_off_tag = 0;
3166}
3167
3168/**----------------------------------------------------------
3169   Specify a new value for this strategy.
3170   This only happens when a strategy statement is met in a project file or in a requirements file.
3171*/
3172void Strategy::set (StrategyDef* definition, bool value, const cmt_string& project_name)
3173{
3174  //cerr << "Setting strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
3175
3176  m_definition = definition;
3177  m_specified = true;
3178  m_specified_value = value;
3179
3180  update (definition, value, project_name);
3181}
3182
3183/**----------------------------------------------------------
3184   Change the effective value for this strategy.
3185   This has no impact on to the specified value.
3186   This will adapt the tag settings
3187*/
3188void Strategy::update (StrategyDef* definition, bool value, const cmt_string& project_name)
3189{
3190  //cerr << "Updating strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
3191
3192  m_value = value;
3193  m_definition = definition;
3194
3195  cmt_string to_tag_name = project_name;
3196  cmt_string to_untag_name = project_name;
3197
3198  to_tag_name += "_";
3199  to_untag_name += "_";
3200
3201  if (m_value)
3202    {
3203      to_tag_name += m_definition->m_on_value;
3204      to_untag_name += m_definition->m_off_value;
3205    }
3206  else
3207    {
3208      to_tag_name += m_definition->m_off_value;
3209      to_untag_name += m_definition->m_on_value;
3210    }
3211
3212  m_on_tag = Tag::find (to_tag_name);
3213  m_off_tag = Tag::find (to_untag_name);
3214
3215  if (m_on_tag == 0 || m_off_tag == 0)
3216    {
3217      m_on_tag = Tag::add (to_tag_name, PriorityConfig, "PROJECT", 0);
3218      m_off_tag = Tag::add (to_untag_name, PriorityConfig, "PROJECT", 0);
3219
3220      m_on_tag->add_tag_exclude (m_off_tag);
3221      m_off_tag->add_tag_exclude (m_on_tag);
3222    }
3223
3224  m_off_tag->unmark ();
3225  m_on_tag->mark ();
3226}
3227
3228//-----------------------------------------------------------
3229const cmt_string& StrategyDef::get_default_value () const
3230{
3231  if (m_default_value)
3232    {
3233      return (m_on_value);
3234    }
3235  else
3236    {
3237      return (m_off_value);
3238    }
3239}
3240
3241//-----------------------------------------------------------
3242void Project::set_author (const cmt_string& name)
3243{
3244  // cerr << "set_author" << name << endl;     
3245  this->m_author = name;
3246}
3247
3248//-----------------------------------------------------------
3249const cmt_string& Project::get_author () const
3250{
3251  return (m_author);
3252}
3253
3254//-----------------------------------------------------------
3255void Project::project_author_action (const CmtSystem::cmt_string_vector& words)
3256{
3257  if (m_author != "") m_author += "\n";
3258
3259  for (int i = 1; i < words.size (); i++)
3260    {
3261      const cmt_string& w = words[i];
3262     
3263      if (i > 1) m_author += " ";
3264      m_author += w; 
3265    }
3266}
3267
3268//-----------------------------------------------------------
3269Use*  Project::get_use () const
3270{
3271  return m_use;   
3272} 
3273
3274//-----------------------------------------------------------
3275void  Project::set_use (Use* use)
3276{ 
3277  this->m_use = use;
3278}
3279
3280//-----------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.