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

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

See C.L. 432

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