source: CMT/v1r20p20070208/source/cmt_project.cxx

Last change on this file was 334, checked in by garonne, 18 years ago

fixed bug with the hidden type package

  • Property svn:eol-style set to native
File size: 56.2 KB
Line 
1//-----------------------------------------------------------
2// Copyright Christian Arnault LAL-Orsay CNRS
3// arnault@lal.in2p3.fr
4// Modified by garonne@lal.in2p3.fr
5// See the complete license in cmt_license.txt "http://www.cecill.info".
6//-----------------------------------------------------------
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <ctype.h>
12
13#include "cmt_project.h"
14#include "cmt_database.h"
15#include "cmt_system.h"
16#include "cmt_awk.h"
17#include "cmt_syntax.h"
18#include "cmt_tag.h"
19#include "cmt_error.h"
20
21class ProjectReader : public Awk
22{
23public:
24
25  ProjectReader ()
26  {
27  }
28 
29  const cmt_string& get_project_name () const
30  {
31    return (m_project);
32  }
33 
34  void filter (const cmt_string& line)
35  {
36    CmtSystem::cmt_string_vector words;
37    CmtSystem::split (line, " \t", words);
38    if (words[0] == "project")
39      {
40        m_project = words[1];
41      }
42  }
43 
44private:
45  cmt_string m_project;
46};
47
48class ProjectPatcher : public Awk
49{
50public:
51
52  ProjectPatcher (const cmt_string& p) : m_project (p)
53  {
54  }
55
56  void commit ()
57  {
58    m_output.write (Project::get_project_file_name ());
59  }
60
61  void filter (const cmt_string& line)
62  {
63    CmtSystem::cmt_string_vector words;
64    CmtSystem::split (line, " \t", words);
65    if (words[0] == "project")
66      {
67        m_output += "project ";
68        m_output += m_project;
69      }
70    else
71      {
72        m_output += line;
73      }
74
75    m_output += "\n";
76  }
77 
78private:
79  cmt_string m_output;
80  const cmt_string& m_project;
81};
82
83IProjectFactory& ProjectFactory::instance ()
84{
85  static ProjectFactory me;
86 
87  return (me);
88}
89
90void ProjectFactory::reset ()
91{
92  Project::clear_all ();
93}
94
95static bool get_release_from_path (const CmtSystem::cmt_string_vector& items, 
96                                   const cmt_string& path, 
97                                   const cmt_string& name, 
98                                   cmt_string& real_name, 
99                                   cmt_string& release)
100{
101  bool result = false;
102
103  release = "";
104  real_name = "";
105
106  cmt_string p = path;
107
108  if ((items.size () == 0) && (name == ""))
109    {
110      // There is no CMTPROJECTPATH and no expected project name.
111      // We have no way to find a project structure
112      // So we only expect a 2-level structure.
113
114      CmtSystem::basename (p, release);
115      CmtSystem::dirname (p, p);
116      CmtSystem::basename (p, real_name);
117     
118      return (false);
119    }
120
121  for (;;)
122    {
123      if (p == "")
124        {
125          // Protection: we found no matching project name
126          // and path was outside any CMTPROJECTPATH
127
128          p = path;
129
130          CmtSystem::basename (p, release);
131          CmtSystem::dirname (p, p);
132          CmtSystem::basename (p, real_name);
133
134          return (false);
135        }
136
137      cmt_string n;
138
139      CmtSystem::basename (p, n);
140      CmtSystem::dirname (p, p);
141
142      if (n == name)
143        {
144          real_name = name;
145          result = true;
146          break;
147        }
148
149      CmtSystem::basename (p, real_name);
150
151      for (int i = 0; i < items.size (); i++)
152        {
153          const cmt_string& item = items[i];
154          if (p == item)
155            {
156              // We have reached an item of CMTPROJECTPATH, no need to continue
157              return (false);
158            }
159        }
160
161      if (release == "")
162        {
163          release = n;
164        }
165      else
166        {
167          cmt_string r;
168
169          r = n;
170          r += CmtSystem::file_separator ();
171          r += release;
172          release = r;
173        }
174    }
175
176  //cerr << "$CMT> GRFP> path=" << path << " name=" << name << " rel=" << release << endl;
177
178  return (result);
179}
180 
181
182/*
183  Every new CMTPATH entry becomes associated with a dedicated PROJECT
184  This function will understand this new entry to CMTPATH and understand it:
185  - it can correspond to an existing project (ie already declared)
186  - it's a new project
187     - then it tries to read and parse its project file
188 */
189Project* ProjectFactory::create_project (const cmt_string& specified_name,
190                                         const cmt_string& path,
191                                         const cmt_string& source,
192                                         Project* parent)
193{
194  cmt_string compressed_path = path;
195  CmtSystem::compress_path (compressed_path);
196  bool specify_name = (specified_name != "");
197
198  if (Cmt::get_debug ())
199    {
200      cout << "Creating project " << path << " with parent " << ((parent==0)? "0" : parent->get_name ()) << endl;
201      Project::show_all ();
202    }
203
204  cmt_string sep;
205  sep = CmtSystem::path_separator ();
206
207  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH"); 
208  CmtSystem::cmt_string_vector items;
209  CmtSystem::split (cmtprojectpath, sep, items);
210
211  cmt_string here = CmtSystem::pwd ();
212  if (!CmtSystem::cd (compressed_path)) return (0);
213  cmt_string pwd = CmtSystem::pwd ();
214
215  static Project::ProjectVector& Projects = Project::projects ();
216
217  int i;
218 
219  for (i = 0; i < Projects.size (); i++)
220    {
221      Project& p = Projects[i];
222     
223      if ((p.get_cmtpath () == compressed_path) ||
224          (p.get_cmtpath_pwd () == pwd) ||
225          (specify_name && (p.get_name () == specified_name)))
226        {
227          cmt_string r;
228          cmt_string n;
229
230          get_release_from_path (items, compressed_path, p.get_name (), n, r);
231
232          if (r != p.get_release ())
233            {
234              cerr << "#CMT> Project " << p.get_name ()
235                   << " requested with conflicting releases " << p.get_release () << " and " << r << endl;
236              CmtError::set (CmtError::project_release_conflict, p.get_name ());
237            }
238 
239          if (parent != 0)
240            {
241              p.add_parent (parent);
242              parent->add_child (&p);
243
244              // Since p is a new parent, we should propagate the settings UP.
245
246              parent->update_strategies_from_children ();
247            }
248
249          CmtSystem::cd (here);
250          return (&p);
251        }
252    }
253
254
255  Project* project = 0;
256  Project* cmt = 0;
257 
258  bool is_current = false;
259 
260  cmt_string name = specified_name;
261  cmt_string project_name;
262  cmt_string release;
263
264  //
265  // Figure out if this is the current project
266  //
267  if (here.find (pwd) == 0) is_current = true;
268
269  cmt_string text;
270
271  /*
272    Now Figure out the project name from the project file
273       or does not specify the project name
274   */
275  bool has_project_file = false;
276
277  if (CmtSystem::cd ("cmt") && CmtSystem::test_file (Project::get_project_file_name ()))
278    {
279      has_project_file = true;
280      text.read (Project::get_project_file_name ());
281
282      ProjectReader reader;
283
284      reader.run (text);
285
286      project_name = reader.get_project_name ();
287    }
288
289  enum
290    {
291      without_project_file   = 0x01,
292      with_project_file      = 0x02,
293      without_project_name   = 0x04,
294      with_project_name      = 0x08,
295      without_specified_name = 0x10,
296      with_specified_name    = 0x20,
297      names_mismatch         = 0x40,
298      names_match            = 0x80
299    };
300
301  int status = ((has_project_file) ? with_project_file : without_project_file) |
302    ((has_project_file && (project_name != "")) ? with_project_name : without_project_name) |
303    ((specify_name) ? with_specified_name : without_specified_name) |
304    ((specify_name && has_project_file && (project_name == specified_name)) ? names_match : names_mismatch);
305
306  if (source == "default path")
307    {
308      name = "CMT";
309    }
310  else
311    {
312      cmt_string n;
313         
314      switch (status)
315        {
316        case with_project_file | without_project_name | without_specified_name | names_mismatch:
317
318          // The project is neither specified from the caller nor from the project file
319
320          /*
321            if (!Cmt::get_quiet ())
322            {
323            cerr << "#CMT> Warning: project name unspecified in project file." << endl;
324            }
325          */
326     
327          get_release_from_path (items, compressed_path, "", name, release);
328
329          break;
330         
331        case with_project_file | without_project_name | with_specified_name | names_mismatch:
332         
333          // The name is only specified from the caller
334          // find this specified name in the path
335         
336          if (get_release_from_path (items, compressed_path, specified_name, name, release))
337            {
338              // The specified name has been found from the path.
339              // We believe in the release spec.
340            }
341          else
342            {
343              // The specified name is not in the path.
344              /*
345              if (!Cmt::get_quiet ())
346                {
347                  cerr << "#CMT> Warning: specified project name "
348                       << specified_name
349                       << " from the caller does not match path." << endl;
350                }
351              */
352              name = specified_name;
353            }
354         
355          break;
356         
357        case with_project_file | with_project_name | with_specified_name | names_match:
358         
359          // We have a double specification: from the caller and from the project file.
360          // And both specifications are consistent. 
361         
362          if (get_release_from_path (items, compressed_path, specified_name, name, release))
363            {
364              // The specified name has been found from the path.
365              // We believe in the release spec.
366            }
367          else
368            {
369              // The specified name is not in the path.
370              /*
371              if (!Cmt::get_quiet ())
372                {
373                  cerr << "#CMT> Warning: specified project name "
374                       << specified_name
375                       << " from project file and from caller does not match path." << endl;
376                }
377              */
378              name = specified_name;
379            }
380         
381          break;
382         
383        case with_project_file | with_project_name | with_specified_name | names_mismatch:
384         
385          // We have a double specification: from the caller and from the project file.
386          // Specifications are inconsistent!!
387         
388          /*
389          if (!Cmt::get_quiet ())
390            {
391              cerr << "#CMT> Warning: specified project name "
392                   << specified_name
393                   << " inconsistent with name "
394                   << project_name
395                   << " from project file." << endl;
396            }
397          */
398         
399          if (get_release_from_path (items, compressed_path, specified_name, n, release))
400            {
401              // name from caller wins.
402            }
403          else if (get_release_from_path (items, compressed_path, project_name, name, release))
404            {
405              // name from project file wins.
406            }
407          else
408            {
409              // The specified name is not in the path.
410             
411              if (!Cmt::get_quiet ())
412                {
413                  cerr << "#CMT> Warning: none of specified project names "
414                       << specified_name
415                       << " from graph and "
416                       << project_name
417                       << " from project file match path." << endl;
418                }
419
420              name = specified_name;
421            }
422         
423          break;
424         
425        case with_project_file | with_project_name | without_specified_name | names_mismatch:
426         
427          // Project name is specified in the project file but not from the caller.
428         
429          if (get_release_from_path (items, compressed_path, project_name, name, release))
430            {
431              // The specified name has been found from the path.
432              // We believe in the release spec.
433
434            }
435          else
436            {
437              // The specified name is not in the path.
438
439              /*
440              if (!Cmt::get_quiet ())
441                {
442                  cerr << "#CMT> Warning: specified project name "
443                       << project_name
444                       << " from project file does not match path." << endl;
445                }
446              */
447
448              name = project_name;
449            }
450         
451          break;
452         
453        case without_project_file | without_project_name | without_specified_name | names_mismatch:
454         
455          // The project is not specified from the caller and there is no project file
456          // This corresponds to the backward compatibility
457          // For the moment, assume /name/release/ structure where release is one level only
458         
459          /*
460            if (!Cmt::get_quiet ())
461            {
462            cerr << "#CMT> Warning: project name is not specified "
463            << " (no project file)." << endl;
464            }
465          */
466         
467          CmtSystem::basename (compressed_path, release);
468          CmtSystem::dirname (compressed_path, name);
469          CmtSystem::basename (name, name);
470
471          if (name == "")
472            {
473              name = release;
474              release = "";
475            }
476         
477          break;
478         
479        case without_project_file | without_project_name | with_specified_name | names_mismatch:
480         
481          // The name is only specified from the caller
482          // find this specified name in the path
483         
484          if (get_release_from_path (items, compressed_path, specified_name, name, release))
485            {
486              // The specified name has been found from the path.
487              // We believe in the release spec.
488            }
489          else
490            {
491              // The specified name is not in the path.
492              /*
493              if (!Cmt::get_quiet ())
494                {
495                  cerr << "#CMT> Warning: specified project name "
496                       << specified_name
497                       << " from project graph does not match path." << endl;
498                }
499              */
500              name = specified_name;
501            }
502         
503          break;
504        }
505    }
506
507  if (name == "")
508    {
509      name = "Project";
510    }
511
512  project = Project::add (name, release);
513     
514  if (parent != 0)
515    {
516      project->add_parent (parent);
517      parent->add_child (project);
518
519      // Since project is a new child, we should propagate the settings UP.
520
521      parent->update_strategies_from_children ();
522    }
523  else
524    {
525      // this project has no parent thus it should become the top project.
526      // Let's look for all projects without parent.
527      // they will become children of this project.
528
529      for (i = 0; i < Projects.size (); i++)
530        {
531          Project* p = &(Projects[i]);
532          if (p->get_name () == name) continue;
533          if (!p->has_parents ())
534            {
535              project->add_child (p);
536              p->add_parent (project);
537            }
538        }
539
540      // Since project is a new parent, we should upgrade its settings
541
542      project->update_strategies_from_children ();
543    }
544
545  if (source == "default path")
546    {
547      cmt = project;
548      is_current = false;
549    }
550
551  project->set_cmtpath (compressed_path);
552  project->set_cmtpath_pwd (pwd);
553  project->set_cmtpath_source (source);
554
555  if (is_current)
556    {
557      //
558      // The current project defines a tag with its name
559      //
560
561      Tag* tag;
562     
563      tag = Tag::add (project->get_name (), PriorityConfig, "PROJECT", 0);
564      tag->mark ();
565    }
566
567
568
569  if (text != "")
570    {
571      // Last step is to parse the project file
572
573      if (Cmt::get_debug ())
574        {
575          cout << "About to parse project file [" << text << "]" << endl;
576        }
577
578      // First create the Project.m_use for the policy
579          // cout << "About to add project policy package file [" <<  project->get_name()+"_project_policy" << "]" << endl;     
580      Use* project_use = Use::create (project->get_cmtpath(), 
581                                      "package_policy_for_project_"+project->get_name(),                                       
582                                      project->get_release (), "", "");                                                         
583      project_use->done      = true; //false;
584      project_use->discarded = false;//true; //false;
585      project_use->m_hidden  = true;
586      project_use->selected  = true;
587      project_use->m_located = true;
588      project_use->set_auto_imports(Off);
589      project_use->initial_scope = ScopePublic;     
590      project->set_use(project_use);
591     
592     
593     // add at the uses level ?????
594    /*static Use::UsePtrVector& uses = Use::get_ordered_uses ();
595     bool found = false;
596     int  size  = uses.size ();
597     cerr << "\n size:"<<size<< ":" << endl;     
598     for (int n = 0; n < size; n++)
599     {
600         Use* tuse = uses[n];
601         cerr << "\tpackage file [" << tuse->get_package_name() << "]" <<project_use->get_package_name()<< endl;                   
602         if (tuse->get_package_name()==project_use->get_package_name())
603                   found=true;
604
605     }
606   
607     if (not found)
608    {
609        uses.push_back (project_use);
610        project_use->m_index = uses.size () - 1;
611    }
612      */
613
614      SyntaxParser::parse_project_file_text (text, 
615                                             Project::get_project_file_name (),
616                                             project);
617    }
618
619
620
621  CmtSystem::cd (here);
622
623  return (project);
624}
625
626/*----------------------------------------------------------*/
627/*                                                          */
628/*  Operations on Projects                                  */
629/*                                                          */
630/*----------------------------------------------------------*/
631
632//----------------------------------------------------------
633bool Project::create (const cmt_string& name, 
634                      const cmt_string& release, 
635                      const cmt_string& path)
636{
637  cout << "------------------------------------------" << endl;
638  cout << "Configuring environment for project " << name << " " << release;
639
640  if (path != "")
641    {
642      cout << " in " << path;
643    }
644
645  cout << endl;
646  cout << "CMT version " << Cmt::get_cmt_version () << "." << endl;
647  cout << "------------------------------------------" << endl;
648
649  if (path != "")
650    {
651      if (!CmtSystem::mkdir (path))
652        {
653          cout << "Cannot create the " << path << " directory" << endl;
654          return (false);
655        }
656
657      if (!CmtSystem::cd (path))
658        {
659          cout << "Cannot access the " << path << " directory" << endl;
660          return (false);
661        }
662    }
663
664  if (!CmtSystem::mkdir (name))
665    {
666      cout << "Cannot create the " << name << " directory" << endl;
667      return (false);
668    }
669
670  if (!CmtSystem::cd (name))
671    {
672      cout << "Cannot access the " << name << " directory" << endl;
673      return (false);
674    }
675
676  if (release != "")
677    {
678      if (!CmtSystem::mkdir (release))
679        {
680          cout << "Cannot create the " << release << " directory" << endl;
681          return (false);
682        }
683     
684      if (!CmtSystem::cd (release))
685        {
686          cout << "Cannot access the " << release << " directory" << endl;
687          return (false);
688        }
689    }
690
691  if (!CmtSystem::test_directory ("cmt"))
692    {
693      if (!CmtSystem::mkdir ("cmt"))
694        {
695          cout << "Cannot create the cmt directory" << endl;
696          return (false);
697        }
698      else
699        {
700          cout << "Installing the cmt directory" << endl;
701        }
702    }
703
704  CmtSystem::cd ("cmt");
705
706  if (!CmtSystem::test_file (get_project_file_name ()))
707    {
708      cout << "Creating a new project file" << endl;
709
710      ofstream f (get_project_file_name ());
711      if (f)
712        {
713          f << "project " << name << endl;
714          f << endl;
715          f.close ();
716        }
717      else
718        {
719          cout << "Cannot create the project file" << endl;
720          return (false);
721        }
722    }
723  else
724    {
725      cmt_string text;
726      text.read (get_project_file_name ());
727
728      ProjectPatcher p (name);
729
730      p.run (text);
731      p.commit ();
732
733      cout << "project file already there" << endl;
734    }
735
736  return (true);
737}
738
739//----------------------------------------------------------
740Project* Project::find_by_name (const cmt_string& name)
741{
742  static ProjectVector& Projects = projects ();
743
744  for (int i = 0; i < Projects.size (); i++)
745    {
746      Project& p = Projects[i];
747      if (p.m_name == name) return (&p);
748     
749    }
750
751  return (0);
752}
753
754//----------------------------------------------------------
755Project* Project::find_by_cmtpath (const cmt_string& cmtpath)
756{
757  cmt_string compressed_path = cmtpath;
758  CmtSystem::compress_path (compressed_path);
759
760  static ProjectVector& Projects = projects ();
761
762  for (int i = 0; i < Projects.size (); i++)
763    {
764      Project& p = Projects[i];
765
766      if (p.m_cmtpath == compressed_path) return (&p);
767      if (p.m_cmtpath_pwd == compressed_path) return (&p);
768    }
769
770  return (0);
771}
772
773//----------------------------------------------------------
774Project* Project::get_current ()
775{
776  cmt_string here = CmtSystem::pwd ();
777
778  static ProjectVector& Projects = projects ();
779
780  Project* result = 0;
781
782  for (int i = (Projects.size () - 1); i >= 0; i--)
783    {
784      Project& p = Projects[i];
785
786      if (here.find (p.m_cmtpath_pwd) == 0) 
787        {
788          result = &p;
789        }
790
791      if (here.find (p.m_cmtpath) == 0) 
792        {
793          result = &p;
794        }
795    }
796
797  return (result);
798}
799
800//----------------------------------------------------------
801Project* Project::add (const cmt_string& name,
802                       const cmt_string& release)
803{
804  static ProjectVector& Projects = projects ();
805
806  //cout << "Project::add> name=" << name << endl;
807
808  {
809    Project* project;
810
811    project = find_by_name (name);
812    if (project != 0) 
813      {
814        if (!Cmt::get_quiet ())
815          {
816            if (release != project->get_release ())
817              {
818                cerr << "#CMT> Project " << name << " requested with conflicting releases " << project->get_release () << " and " << release << endl;
819                CmtError::set (CmtError::project_release_conflict, name);
820              }
821          }
822
823        // Project objects are recreated here to follow the hierarchy
824        // This duplication is needed for properly applying the strategies
825        Project& p = Projects.add ();
826
827        p.set_name (name);
828        p.set_release (release);
829        p.configure ();
830
831        return (&p);
832
833        //return (project);
834      }
835  }
836
837  Project& project = Projects.add ();
838  project.clear ();
839  project.set_name (name);
840  project.set_release (release);
841  project.configure ();
842
843  return (&project);
844}
845
846//----------------------------------------------------------
847Project::ProjectVector& Project::projects ()
848{
849  static Database& db = Database::instance ();
850  static ProjectVector& Projects = db.projects ();
851
852  return (Projects);
853}
854
855/*----------------------------------------------------------*/
856void Project::clear_all ()
857{
858  static ProjectVector& Projects = projects ();
859
860  for (int i = 0; i < Projects.size (); i++)
861    {
862      Project& project = Projects[i];
863      project.clear ();
864    }
865
866  Projects.clear ();
867}
868
869/*----------------------------------------------------------*/
870void Project::show_all ()
871{
872  static Project::ProjectVector& Projects = Project::projects ();
873 
874  for (int i = 0; i < Projects.size (); i++)
875    {
876      Project& p = Projects[i];
877      p.m_visited = false;
878    }
879
880  Project* p = get_current ();
881
882  if (p == 0)
883    {
884      if (Projects.size () == 0) return;
885
886      p = &(Projects[0]);
887    }
888
889  p->show ();
890}
891
892/*----------------------------------------------------------*/
893void Project::show_specified_strategies_for_all ()
894{
895  static ProjectVector& Projects = projects ();
896
897  for (int i = 0; i < Projects.size (); i++)
898    {
899      const Project& project = Projects[i];
900      project.show_specified_strategies ();
901    }
902}
903
904/*----------------------------------------------------------*/
905class VisitorForShowPaths : public IProjectVisitor
906{
907public:
908  VisitorForShowPaths ()
909  {
910  }
911
912  void pre (Project* p)
913  {
914    const cmt_string& w = p->get_cmtpath_pwd ();
915    const cmt_string& s = p->get_cmtpath_source ();
916
917    if (s == "default path") return;
918
919    if (CmtSystem::test_directory (w))
920      {
921        cout << "# Add path " << w << " from " << s << endl;
922      }
923  }
924
925  void in (Project* p)
926  {
927    const cmt_string& w = p->get_cmtpath_pwd ();
928    const cmt_string& s = p->get_cmtpath_source ();
929
930    if (s == "default path") return;
931
932    if (CmtSystem::test_directory (w))
933      {
934        cout << "# Add path " << w << " from " << s << endl;
935      }
936  }
937
938  void post (Project* p)
939  {
940  }
941};
942
943/*----------------------------------------------------------*/
944void Project::show_paths ()
945{
946  VisitorForShowPaths visitor;
947
948  start_visit (visitor);
949}
950
951//----------------------------------------------------------
952const cmt_string& Project::get_project_file_name ()
953{
954  static const cmt_string name = "project.cmt";
955
956  return (name);
957}
958
959//----------------------------------------------------------
960void Project::fill_selection (int depth, CmtSystem::cmt_string_vector& path_selections)
961{
962  static ProjectVector& Projects = projects ();
963
964  for (int i = 0; i < Projects.size (); i++)
965    {
966      Project& project = Projects[i];
967
968      const cmt_string& p = project.get_cmtpath ();
969      const cmt_string& pwd = project.get_cmtpath_pwd ();
970      const cmt_string& src = project.get_cmtpath_source ();
971
972      if (src != "default path")
973        {
974          if (depth > 0)
975            {
976              cmt_string& s1 = path_selections.add ();
977              s1 = p;
978              cmt_string& s2 = path_selections.add ();
979              s2 = pwd;
980              depth--;
981
982              if (depth == 0) break;
983            }
984        }
985    }
986}
987
988//----------------------------------------------------------
989void Project::broadcast (IProjectAction& action)
990{
991  static ProjectVector& Projects = projects ();
992
993  for (int i = 0; i < Projects.size (); i++)
994    {
995      const Project& project = Projects[i];
996
997      if (!action.run (project)) break;
998    }
999}
1000
1001//----------------------------------------------------------
1002void Project::reverse_broadcast (IProjectAction& action)
1003{
1004  static ProjectVector& Projects = projects ();
1005
1006  for (int i = (Projects.size () - 1); i >= 0; i--)
1007    {
1008      const Project& project = Projects[i];
1009
1010      if (!action.run (project)) break;
1011    }
1012}
1013
1014//----------------------------------------------------------
1015void Project::scan_paths (PathScanner& scanner, PathScanner::actor& a)
1016{
1017  static ProjectVector& Projects = projects ();
1018
1019  int i;
1020
1021  for (i = 0; i < Projects.size (); i++)
1022    {
1023      Project& p  = Projects[i];
1024      p.m_visited = false;
1025    }
1026
1027  for (i = 0; i < Projects.size (); i++)
1028    {
1029      const Project& project = Projects[i];
1030       
1031      const cmt_string& p = project.m_cmtpath;
1032      scanner.scan_path (p, a);
1033    }
1034}
1035
1036//----------------------------------------------------------
1037void Project::scan_paths_for_package (PathScanner& scanner, const cmt_string& name)
1038{
1039  static ProjectVector& Projects = projects ();
1040
1041  for (int i = 0; i < Projects.size (); i++)
1042    {
1043      const Project& project = Projects[i];
1044
1045      const cmt_string& p = project.m_cmtpath;
1046      scanner.scan_package (p, name);
1047    }
1048}
1049
1050//----------------------------------------------------------
1051cmt_string Project::find_in_cmt_paths (const cmt_string& path)
1052{
1053  const cmt_string pwd = CmtSystem::pwd ();
1054
1055  static ProjectVector& Projects = projects ();
1056
1057  for (int i = 0; i < Projects.size (); i++)
1058    {
1059      const Project& project = Projects[i];
1060
1061      const cmt_string& p = project.m_cmtpath;
1062      const cmt_string& w = project.m_cmtpath_pwd;
1063      const cmt_string& s = project.m_cmtpath_source;
1064
1065      if (s == "default path") continue;
1066
1067      if (CmtSystem::test_directory (p))
1068        {
1069          if (path.find (p) != cmt_string::npos)
1070            {
1071              return (p);
1072            }
1073
1074          // To become the current area, a path must correspond to the current package
1075          if (path.find (w) != cmt_string::npos)
1076            {
1077              return (p);
1078            }
1079        }
1080
1081      if (p == w) continue;
1082
1083      if (CmtSystem::test_directory (w))
1084        {
1085          if (path.find (w) != cmt_string::npos)
1086            {
1087              return (w);
1088            }
1089        }
1090    }
1091
1092  return ("");
1093}
1094
1095//----------------------------------------------------------
1096void Project::visit (IProjectVisitor& visitor)
1097{
1098  if (m_visited) return;
1099  m_visited = true;
1100
1101  int i;
1102
1103  for (i = 0; i < get_children_size (); i++)
1104    {
1105      Project* child = get_child (i);
1106
1107      if (child->visited ()) continue;
1108
1109      visitor.in (child);
1110    }
1111
1112  for (i = 0; i < m_children.size (); i++)
1113    {
1114      Project* child = m_children[i];
1115      child->visit (visitor);
1116    }
1117}
1118
1119//----------------------------------------------------------
1120void Project::start_visit (IProjectVisitor& visitor)
1121{
1122  static Project::ProjectVector& Projects = Project::projects ();
1123 
1124  for (int i = 0; i < Projects.size (); i++)
1125    {
1126      Project& p = Projects[i];
1127      p.m_visited = false;
1128    }
1129
1130  Project* p = get_current ();
1131
1132  if (p == 0)
1133    {
1134      if (Projects.size () == 0) return;
1135
1136      p = &(Projects[0]);
1137    }
1138
1139  visitor.pre (p);
1140  p->visit (visitor);
1141  visitor.post (p);
1142}
1143
1144//----------------------------------------------------------
1145class VisitorForFillCMTPATH : public IProjectVisitor
1146{
1147public:
1148  VisitorForFillCMTPATH (cmt_string& buffer) : m_buffer (buffer)
1149  {
1150    buffer = "path CMTPATH \"\" \n";
1151  }
1152
1153  void pre (Project* p)
1154  {
1155    const cmt_string& w = p->get_cmtpath_pwd ();
1156    const cmt_string& s = p->get_cmtpath_source ();
1157
1158    if (s == "default path") return;
1159
1160    if (CmtSystem::test_directory (w))
1161      {
1162        m_buffer += "path_append CMTPATH \"";
1163        m_buffer += w;
1164        m_buffer += "\" \n";
1165      }
1166  }
1167
1168  void in (Project* p)
1169  {
1170    const cmt_string& w = p->get_cmtpath_pwd ();
1171    const cmt_string& s = p->get_cmtpath_source ();
1172
1173    if (s == "default path") return;
1174
1175    if (CmtSystem::test_directory (w))
1176      {
1177        m_buffer += "path_append CMTPATH \"";
1178        m_buffer += w;
1179        m_buffer += "\" \n";
1180      }
1181  }
1182
1183  void post (Project* p)
1184  {
1185    //cerr << "Buffer = " << m_buffer << endl;
1186  }
1187
1188private:
1189  cmt_string& m_buffer;
1190
1191};
1192
1193//----------------------------------------------------------
1194void Project::fill_cmtpaths (cmt_string& buffer)
1195{
1196  /*
1197    Try to re-create all CMTPATH items from project definitions.
1198    The goal is to generate CMTPATH even if this EV was not pre-set
1199    which is the case when CMTPROJECTPATH is only used
1200   */
1201
1202  VisitorForFillCMTPATH visitor (buffer);
1203
1204  start_visit (visitor);
1205}
1206
1207//----------------------------------------------------------
1208Project::Project () : m_name (""), m_author("")
1209{
1210  clear ();
1211}
1212
1213//----------------------------------------------------------
1214const cmt_string& Project::get_name () const
1215{
1216  return (m_name);
1217}
1218
1219//----------------------------------------------------------
1220const cmt_string& Project::get_release () const
1221{
1222  return (m_release);
1223}
1224
1225//----------------------------------------------------------
1226const cmt_string& Project::get_container () const
1227{
1228  return (m_container);
1229}
1230
1231//----------------------------------------------------------
1232const cmt_string& Project::get_container_version () const
1233{
1234  return (m_container_version);
1235}
1236
1237//----------------------------------------------------------
1238const cmt_string& Project::get_cmtpath () const
1239{
1240  return (m_cmtpath);
1241}
1242
1243//----------------------------------------------------------
1244const cmt_string& Project::get_cmtpath_pwd () const
1245{
1246  return (m_cmtpath_pwd);
1247}
1248
1249//----------------------------------------------------------
1250const cmt_string& Project::get_cmtpath_source () const
1251{
1252  return (m_cmtpath_source);
1253}
1254
1255//----------------------------------------------------------
1256int Project::get_children_size () const
1257{
1258  return (m_children.size ());
1259}
1260
1261//----------------------------------------------------------
1262Project* Project::get_child (int index) const
1263{
1264  if (index < 0) return (0);
1265  if (index >= m_children.size ()) return (0);
1266  return (m_children[index]);
1267}
1268
1269//----------------------------------------------------------
1270bool Project::visited () const
1271{
1272  return (m_visited);
1273}
1274
1275//----------------------------------------------------------
1276void Project::set_name (const cmt_string& name)
1277{
1278  m_name = name;
1279}
1280
1281//----------------------------------------------------------
1282void Project::set_release (const cmt_string& release)
1283{
1284  m_release = release;
1285}
1286
1287//----------------------------------------------------------
1288void Project::set_container (const cmt_string& container)
1289{
1290  m_container = container;
1291}
1292
1293//----------------------------------------------------------
1294void Project::set_container_version (const cmt_string& container_version)
1295{
1296  m_container_version = container_version;
1297}
1298
1299//----------------------------------------------------------
1300void Project::set_cmtpath (const cmt_string& path)
1301{
1302  m_cmtpath = path;
1303}
1304
1305//----------------------------------------------------------
1306void Project::set_cmtpath_pwd (const cmt_string& path)
1307{
1308  m_cmtpath_pwd = path;
1309}
1310
1311//----------------------------------------------------------
1312void Project::set_cmtpath_source (const cmt_string& source)
1313{
1314  m_cmtpath_source = source;
1315}
1316
1317//----------------------------------------------------------
1318void Project::clear ()
1319{
1320  m_name    = "";
1321  m_release = "";
1322  m_cmtpath = "";
1323  m_cmtpath_pwd    = "";
1324  m_cmtpath_source = "";
1325  m_use            = 0;
1326
1327  m_parents.clear ();
1328  m_children.clear ();
1329
1330  m_configured = false;
1331
1332  m_strategies.clear ();
1333}
1334
1335//----------------------------------------------------------
1336bool Project::has_parents () const
1337{
1338  return ((m_parents.size () > 0));
1339}
1340
1341//----------------------------------------------------------
1342bool Project::has_parent (Project* p) const
1343{
1344  if (p == 0) return (false);
1345  if (p == this) return (false);
1346
1347  const cmt_string& name = p->get_name ();
1348
1349  int i;
1350
1351  for (i = 0; i < m_parents.size (); i++)
1352    {
1353      const Project* parent = m_parents[i];
1354      if (parent == 0) continue;
1355
1356      if (parent->get_name () == name)
1357        {
1358          // registered as a parent
1359          return (true);
1360        }
1361
1362      if (parent->has_parent (p))
1363        {
1364          // recurse
1365          return (true);
1366        }
1367    }
1368
1369  return (false);
1370}
1371
1372//----------------------------------------------------------
1373bool Project::has_child (Project* p) const
1374{
1375  if (p == 0) return (false);
1376  if (p == this) return (false);
1377
1378  const cmt_string& name = p->get_name ();
1379
1380  int i;
1381
1382  for (i = 0; i < m_children.size (); i++)
1383    {
1384      const Project* child = m_children[i];
1385      if (child == 0) continue;
1386
1387      if (child->get_name () == name)
1388        {
1389          // registered as a child
1390          return (true);
1391        }
1392
1393      if (child->has_child (p))
1394        {
1395          // recurse
1396          return (true);
1397        }
1398    }
1399
1400  return (false);
1401}
1402
1403//----------------------------------------------------------
1404void Project::add_parent (Project* p)
1405{
1406  if (p == 0) return;
1407  if (p == this) return;
1408
1409  //cerr << "Adding parent " << p->get_name () << " to " << m_name << endl;
1410
1411  if (has_child (p)) return;
1412  if (has_parent (p)) return;
1413
1414  m_parents.push_back (p);
1415}
1416
1417//----------------------------------------------------------
1418void Project::add_child (Project* p)
1419{
1420  if (p == 0) return;
1421  if (p == this) return;
1422
1423  if (has_child (p)) return;
1424  if (has_parent (p)) return;
1425
1426  m_children.push_back (p);
1427}
1428
1429//----------------------------------------------------------
1430void Project::configure ()
1431{
1432  if (m_configured) return;
1433  m_configured = true;
1434
1435  set_default_strategy ("SetupConfig");
1436  set_default_strategy ("SetupRoot");
1437  set_default_strategy ("SetupCleanup");
1438  set_default_strategy ("BuildPrototypes");
1439  set_default_strategy ("InstallArea");
1440  set_default_strategy ("VersionDirectory");
1441}
1442
1443/**---------------------------------------------------------
1444 A container statement is met in the project file
1445*/
1446void Project::container_action (const cmt_string& name, const cmt_string& version)
1447{
1448  //cerr << "Container action " << name << " " << version << endl;
1449
1450  set_container (name);
1451  set_container_version (version);
1452}
1453
1454/**---------------------------------------------------------
1455 A use statement is met in the project file
1456*/
1457void Project::use_action (const cmt_string& name, const cmt_string& release)
1458{
1459  if (Cmt::get_debug ())
1460    {
1461      cout << "Use action " << name << " " << release << endl;
1462    }
1463
1464  // A project with its release is specified
1465  //
1466  // Is this project already visible?
1467  // If not: look for it
1468  //   + get CMTPROJECTPATH
1469  //   + search from all entries of CMTPROJECTPATH : p(i)/<name>/<release>
1470  //   + when found, this should become a new CMTPATH entry
1471  //   +             the new project is then parsed ... etc...
1472
1473  // First test it wilcard is used
1474  int v = -1;
1475  int r = -1;
1476  int p = -1;
1477  cmt_string new_release = release;
1478  CmtSystem::is_version_directory (new_release, v, r, p); 
1479  bool use_has_wild_card = (v == -1) || (r == -1) || (p == -1);
1480  if (use_has_wild_card)
1481  {
1482      cmt_string selected_release = "";
1483      if (select_release(name, new_release,selected_release))
1484      { // yes
1485          // cout <<"selected_release: "<<selected_release<<endl;   
1486          new_release = selected_release;
1487      }         
1488   }
1489
1490  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
1491  cmt_string sep;
1492  sep = CmtSystem::path_separator ();
1493
1494  //cerr << "cmtprojectpath = " << cmtprojectpath << endl;
1495  CmtSystem::cmt_string_vector items;
1496  CmtSystem::split (cmtprojectpath, sep, items);
1497
1498  bool found = false;
1499
1500  for (int i = 0; i < items.size (); i++)
1501    {
1502      const cmt_string& item = items[i];
1503      cmt_string p = item;
1504      p += CmtSystem::file_separator ();
1505      p += name;
1506      if (new_release != "")
1507        {
1508          p += CmtSystem::file_separator ();
1509          p += new_release;
1510        }
1511
1512    if (CmtSystem::test_directory (p))
1513        {
1514          //cerr << "Project directory " << p << " exists " << endl;
1515
1516          found = true;
1517
1518          IProjectFactory& factory = ProjectFactory::instance ();
1519
1520          factory.create_project (name, p, "ProjectPath", this);
1521
1522          break;
1523        }
1524    }
1525
1526  if (!found)
1527    {
1528      Project* p = Project::find_by_name (name);
1529
1530      if (p != 0)
1531          {
1532              found = true;
1533              p->add_parent (this);
1534              add_child (p);
1535
1536              update_strategies_from_children ();
1537            }
1538    }
1539   
1540  if (!found && (cmtprojectpath != ""))
1541    {
1542      cerr << "#CMT> Project " << name << " " << release << " requested by " << m_name << " not found in CMTPROJECTPATH" << endl;
1543    }
1544}
1545
1546//---------------------------------------------------------
1547bool Project::select_release(const cmt_string& name, const cmt_string& release, cmt_string& result)
1548{
1549    cmt_string selected_release = "";
1550
1551    int v = -1;
1552    int r = -1;
1553    int p = -1;
1554    CmtSystem::is_version_directory (release, v, r, p); 
1555
1556    int selected_v = -1;
1557    int selected_r = -1;
1558    int selected_p = -1;
1559    CmtSystem::cmt_string_vector releases = get_project_releases(name);
1560    for (int j = 0; j < releases.size (); j++)
1561    {
1562         //cout <<releases[j]<<endl; 
1563         int new_v = -1;
1564         int new_r = -1;
1565         int new_p = -1;
1566         CmtSystem::is_version_directory (releases[j], new_v, new_r, new_p);
1567         if (v == -1)
1568         {
1569             if (selected_v<new_v)
1570             {
1571                 selected_v       = new_v;
1572                 selected_r = -1;
1573                 selected_p = -1;
1574                 selected_release = releases[j];
1575             }
1576             else if (selected_v==new_v)
1577             { // We compare the r
1578                 if (selected_r<new_r)
1579                 {
1580                     selected_r = new_r;
1581                     selected_p = -1;
1582                     selected_release = releases[j];                               
1583                 }
1584                 else if (selected_r==new_r)
1585                 { // We compare the p
1586                     if (selected_p<new_p)
1587                     {
1588                         selected_p = new_p;
1589                         selected_release = releases[j];                               
1590                     }
1591                     // else if ? not possible                                                           
1592                 }                               
1593             }
1594         }
1595         else if (r == -1)
1596         {
1597             if (v==new_v)
1598             { // We compare the r                                                     
1599                 if (selected_r<new_r)
1600                 {
1601                     selected_r = new_r;
1602                     selected_p = -1;
1603                     selected_release = releases[j];                               
1604                 }
1605                 else if (selected_r==new_r)
1606                 { // We compare the p
1607                     if (selected_p<new_p)
1608                     {
1609                         selected_p = new_p;
1610                         selected_release = releases[j];                               
1611                     }
1612                     // else if ? not possible
1613                 }
1614             }
1615         }
1616         else if (p == -1)
1617         {
1618             if (v==new_v && r==new_r)
1619                 { // We compare the p
1620                     if (selected_p<new_p)
1621                     {
1622                         selected_p = new_p;
1623                         selected_release = releases[j];                               
1624                     }
1625                     // else if ? not possible
1626                 }       
1627         }       
1628         //cerr<<"v:"<<new_v<<", r:"<<new_r<<", p:"<<new_p<<endl;             
1629         //cerr<<"req v:"<<v<<", req r:"<<r<<", req p:"<<p<<endl;       
1630    }
1631    //cerr <<"selected release: "<<selected_release<<endl; 
1632    if (selected_release == "")
1633        return false;
1634    result = selected_release;   
1635    return true;
1636}
1637
1638//---------------------------------------------------------
1639const CmtSystem::cmt_string_vector Project::get_project_releases(const cmt_string& name) const
1640{
1641        CmtSystem::cmt_string_vector releases;
1642    cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
1643    cmt_string sep;
1644    sep = CmtSystem::path_separator ();
1645
1646    CmtSystem::cmt_string_vector items;
1647    CmtSystem::split (cmtprojectpath, sep, items);   
1648    for (int i = 0; i < items.size (); i++)
1649    {
1650        const cmt_string& item = items[i];
1651        cmt_string p = item;
1652        p += CmtSystem::file_separator ();
1653        p += name;
1654        if (CmtSystem::test_directory (p))
1655            { 
1656                CmtSystem::cmt_string_vector directories;
1657            CmtSystem::scan_dir (p, directories);
1658                for (int j = 0; j < directories.size (); j++)
1659                {
1660                    if  (CmtSystem::test_directory(directories[j]))
1661                    {
1662                        cmt_string release;
1663                        CmtSystem:: basename(directories[j], release);
1664                        if (CmtSystem::is_version_directory(release))
1665                        {                                 
1666                             cmt_string& name_entry = releases.add ();
1667                             name_entry = release; 
1668                             //cout << release <<endl; 
1669                        }             
1670                    }                       
1671                }                               
1672            }
1673    }
1674    return (releases);
1675}
1676
1677//----------------------------------------------------------
1678Project& Project::operator = (const Project& other)
1679{
1680  m_name = other.m_name;
1681  m_cmtpath = other.m_cmtpath;
1682  m_cmtpath_pwd = other.m_cmtpath_pwd;
1683  m_cmtpath_source = other.m_cmtpath_source;
1684
1685  return (*this);
1686}
1687
1688//----------------------------------------------------------
1689bool Project::operator == (const cmt_string& name) const
1690{
1691  return ((m_name == name));
1692}
1693
1694//----------------------------------------------------------
1695bool Project::operator != (const cmt_string& name) const
1696{
1697  return ((m_name != name));
1698}
1699
1700//----------------------------------------------------------
1701void Project::show ()
1702{
1703  static int level = 0;
1704
1705  bool is_current = false;
1706
1707  cmt_string here = CmtSystem::pwd ();
1708
1709  if (here.find (m_cmtpath) == 0) 
1710    {
1711      if (m_cmtpath_source != "default path")
1712        {
1713          is_current = true;
1714        }
1715    }
1716
1717  for (int tab = 0; tab < level; tab++) cout << "  ";
1718  cout << m_name << " " << m_release << " (in " << m_cmtpath << ")";
1719
1720  if (is_current) cout << " (current)";
1721
1722  int i;
1723
1724  for (i = 0; i < m_parents.size (); i++)
1725    {
1726      Project* p = m_parents[i];
1727      if (p == 0) continue;
1728      cout << " P=" << p->get_name ();
1729    }
1730
1731  for (i = 0; i < m_children.size (); i++)
1732    {
1733      Project* p = m_children[i];
1734      if (p == 0) continue;
1735      cout << " C=" << p->get_name ();
1736    }
1737
1738  cout << endl;
1739
1740  if (m_visited) return;
1741
1742  m_visited = true;
1743
1744  for (i = 0; i < m_children.size (); i++)
1745    {
1746      Project* p = m_children[i];
1747      if (p == 0) continue;
1748      level++;
1749      p->show ();
1750      level--;
1751    }
1752}
1753
1754
1755//----------------------------------------------------------
1756void Project::show_specified_strategies () const
1757{
1758  int i;
1759
1760  for (i = 0; i < m_strategies.size (); i++)
1761    {
1762      const Strategy& s = m_strategies[i];
1763      if (s.m_specified)
1764        {
1765          const StrategyDef* def = s.m_definition;
1766 
1767          cout << "# Project " << m_name
1768               << " sets " << def->m_keyword
1769               << " strategy to " << ((s.m_value) ? def->m_on_value : def->m_off_value);
1770
1771          if (s.m_context != "")
1772            {
1773              cout << " (from package " << s.m_context << ")";
1774            }
1775
1776          cout << endl;
1777        }
1778    }
1779}
1780
1781//----------------------------------------------------------
1782bool Project::has_strategy (const StrategyDef* definition) const
1783{
1784  int i;
1785
1786  for (i = 0; i < m_strategies.size (); i++)
1787    {
1788      const Strategy& s = m_strategies[i];
1789      if (s.m_definition == definition)
1790        {
1791          return (true);
1792        }
1793    }
1794
1795  return (false);
1796}
1797
1798//----------------------------------------------------------
1799bool Project::get_strategy (const cmt_string& name) const
1800{
1801  static StrategyMgr& mgr = StrategyMgr::instance ();
1802
1803  StrategyDef* def = mgr.find_strategy (name);
1804  if (def == 0)
1805    {
1806      cerr << "#CMT> strategy " << name << " undefined" << endl;
1807      return (false);
1808    }
1809
1810  return (get_strategy (def));
1811}
1812
1813//----------------------------------------------------------
1814bool Project::is_specified (const StrategyDef* definition) const
1815{
1816  int i;
1817
1818  for (i = 0; i < m_strategies.size (); i++)
1819    {
1820      Strategy& s = m_strategies[i];
1821      if (s.m_definition == definition)
1822        {
1823          // This strategy is applied in this project
1824          return (s.m_specified);
1825        }
1826    }
1827
1828  // This strategy is not applied in this project
1829  return (false);
1830}
1831
1832//----------------------------------------------------------
1833bool Project::get_strategy (const StrategyDef* def) const
1834{
1835  int i;
1836
1837  for (i = 0; i < m_strategies.size (); i++)
1838    {
1839      Strategy& s = m_strategies[i];
1840      if (s.m_definition == def)
1841        {
1842          // This strategy is applied in this project
1843          if (s.m_specified)
1844            {
1845              return (s.m_specified_value);
1846            }
1847          return (s.m_value);
1848        }
1849    }
1850
1851  // This strategy is not applied in this project
1852  return (def->m_default_value);
1853}
1854
1855//----------------------------------------------------------
1856void Project::set_default_strategy (const cmt_string& name)
1857{
1858  static StrategyMgr& mgr = StrategyMgr::instance ();
1859
1860  StrategyDef* def = mgr.find_strategy (name);
1861  if (def == 0)
1862    {
1863      cerr << "#CMT> strategy " << name << " undefined" << endl;
1864      return;
1865    }
1866
1867  update_strategy (def, def->m_default_value);
1868}
1869
1870
1871//----------------------------------------------------------
1872void Project::set_strategy (const cmt_string& name, const cmt_string& value, const cmt_string& context)
1873{
1874  static StrategyMgr& mgr = StrategyMgr::instance ();
1875
1876  StrategyDef* def = mgr.find_strategy (name);
1877  if (def == 0)
1878    {
1879      cerr << "#CMT> strategy " << name << " undefined" << endl;
1880      return;
1881    }
1882
1883  bool b_value = false;
1884
1885  if (value == def->m_on_value)
1886    {
1887      b_value = true;
1888    }
1889  else if (value == def->m_off_value)
1890    {
1891      b_value = false;
1892    }
1893  else
1894    {
1895      cerr << "#CMT> requested strategy value " << value << " undefined in strategy " << name << endl;
1896      return;
1897    }
1898
1899  set_strategy (def, b_value, context);
1900}
1901
1902//----------------------------------------------------------
1903void Project::set_strategy (StrategyDef* definition, bool b_value, const cmt_string& context)
1904{
1905  bool need_strategy = true;
1906
1907  int i;
1908
1909  for (i = 0; i < m_strategies.size (); i++)
1910    {
1911      Strategy& s = m_strategies[i];
1912      if (s.m_definition == definition)
1913        {
1914          // This strategy is already applied in this project. Let's change it's value
1915          s.set (definition, b_value, get_name ());
1916          if (context != "")
1917            {
1918              if (s.m_context != "") s.m_context += " ";
1919              s.m_context += context;
1920            }
1921          need_strategy = false;
1922          break;
1923        }
1924    }
1925
1926  if (need_strategy)
1927    {
1928      // This strategy is not yet applied in this project.
1929
1930      Strategy& s = m_strategies.add ();
1931      s.clear ();
1932      s.set (definition, b_value, get_name ());
1933      s.m_context = context;
1934    }
1935 
1936  for (i = 0; i < m_parents.size (); i++)
1937    {
1938      Project* project = m_parents[i];
1939
1940      project->update_strategy (definition, b_value);
1941    }
1942}
1943
1944/**----------------------------------------------------------
1945   The strategy value is changed because of indirect influences
1946   - default strategy at initialization time
1947   - change in the children
1948   - change in the children list
1949
1950   (This is not a specification : see the set_strategy method)
1951 */
1952void Project::update_strategy (StrategyDef* definition, bool b_value)
1953{
1954  bool need_strategy = true;
1955  bool specified = false;
1956
1957  int i;
1958
1959  for (i = 0; i < m_strategies.size (); i++)
1960    {
1961      Strategy& s = m_strategies[i];
1962      if (s.m_definition == definition)
1963        {
1964          need_strategy = false;
1965
1966          if (!s.m_specified)
1967            {
1968              // This strategy is already applied in this project. Let's change it's value
1969              s.update (definition, b_value, get_name ());
1970            }
1971          else
1972            {
1973              specified = true;
1974            }
1975          break;
1976        }
1977    }
1978
1979  if (need_strategy)
1980    {
1981      // This strategy is not yet applied in this project.
1982
1983      Strategy& s = m_strategies.add ();
1984      s.clear ();
1985      s.update (definition, b_value, get_name ());
1986    }
1987
1988  if (!specified)
1989    {
1990      for (i = 0; i < m_parents.size (); i++)
1991        {
1992          Project* project = m_parents[i];
1993
1994          project->update_strategy (definition, b_value);
1995        }
1996    }
1997}
1998
1999/**----------------------------------------------------------
2000   At least one of the children has changed this strategy
2001   Or the list of children has changed.
2002   We need to update the strategy value accordingly
2003   This will not change the specified value for this strategy
2004 */
2005void Project::update_strategy_from_children (StrategyDef* definition)
2006{
2007  // If this strategy is specified we don't care what happens from the children
2008
2009  //cerr << "Updating strategy " << definition->m_name << " from children for project " << m_name << endl;
2010
2011  int i;
2012
2013  for (i = 0; i < m_strategies.size (); i++)
2014    {
2015      Strategy& s = m_strategies[i];
2016      if (s.m_definition == definition)
2017        {
2018          // This strategy is applied in this project.
2019
2020          if (s.m_specified)
2021            {
2022              // There will be no impact since the strategy is specified
2023
2024              //cerr << "This strategy is specified in this project" << endl;
2025              return;
2026            }
2027
2028          break;
2029        }
2030    }
2031
2032  // The strategy is not specified locally so we will now figure out
2033  // which strategy has to be considered from the mixture of specifications
2034  // from all children.
2035
2036  // Algorithm:
2037  // - We consider children by pairs
2038  // - a child that specifies its strategy wins over a child that does not
2039  // - when the two children have the same level of priority we consider the priority value
2040
2041  Project* selected = 0;
2042  bool selected_is_specified = false;
2043  bool selected_value = definition->m_default_value;
2044
2045  for (i = 0; i < m_children.size (); i++)
2046    {
2047      Project* p = m_children[i];
2048
2049      //cerr << "Checking strategy for child " << p->get_name () << endl;
2050
2051      bool is_specified = p->is_specified (definition);
2052      bool value = p->get_strategy (definition);
2053
2054      if (selected == 0)
2055        {
2056          selected = p;
2057          selected_is_specified = is_specified;
2058          selected_value = value;
2059          continue;
2060        }
2061
2062      if (is_specified == selected_is_specified)
2063        {
2064          if (selected_value != value)
2065            {
2066              // same level of priority but different values -> we must decide
2067              bool priority_value = definition->m_priority_value;
2068              if (value == priority_value)
2069                {
2070                  selected = p;
2071                  selected_is_specified = is_specified;
2072                  selected_value = value;
2073                }
2074            }
2075        }
2076      else
2077        {
2078          if (is_specified)
2079            {
2080              selected = p;
2081              selected_is_specified = is_specified;
2082              selected_value = value;
2083            }
2084        }
2085    }
2086
2087  update_strategy (definition, selected_value); 
2088}
2089
2090/**----------------------------------------------------------
2091   At least one of the children has changed its strategies
2092   Or the list of children has changed.
2093   We need to update the strategy values accordingly
2094   This will not change the specified values
2095 */
2096void Project::update_strategies_from_children ()
2097{
2098  StrategyDef::StrategyDefs& defs = StrategyMgr::get_definitions ();
2099
2100  //cerr << "Updating strategies from children for project " << m_name << endl;
2101
2102  int i;
2103
2104  for (i = 0; i < defs.size (); i++)
2105    {
2106      StrategyDef* def = defs[i];
2107     
2108      update_strategy_from_children (def);
2109    }
2110
2111  for (i = 0; i < m_parents.size (); i++)
2112    {
2113      Project* p = m_parents[i];
2114      p->update_strategies_from_children ();
2115    }
2116}
2117
2118/**----------------------------------------------------------
2119   The StrategyMgr singleton
2120 */
2121StrategyMgr& StrategyMgr::instance ()
2122{
2123  static StrategyMgr me;
2124  return (me);
2125}
2126
2127/**----------------------------------------------------------
2128   The StrategyMgr constructor
2129   Here are primarily constructed all strategy definitions
2130 */
2131StrategyMgr::StrategyMgr ()
2132{
2133  m_defs.clear ();
2134
2135  StrategyDef* s;
2136
2137  s = new StrategyDef;
2138  s->m_keyword = "build";
2139  s->m_name = "BuildPrototypes";
2140  s->m_on_value = "prototypes";
2141  s->m_off_value = "no_prototypes";
2142  s->m_default_value = true;
2143  s->m_priority_value = false;
2144
2145  m_defs.push_back (s);
2146
2147  s = new StrategyDef;
2148  s->m_keyword = "build";
2149  s->m_name = "InstallArea";
2150  s->m_on_value = "with_installarea";
2151  s->m_off_value = "without_installarea";
2152  s->m_default_value = false;
2153  s->m_priority_value = true;
2154
2155  m_defs.push_back (s);
2156
2157  s = new StrategyDef;
2158  s->m_keyword = "setup";
2159  s->m_name = "SetupConfig";
2160  s->m_on_value = "config";
2161  s->m_off_value = "no_config";
2162  s->m_default_value = true;
2163  s->m_priority_value = false;
2164
2165  m_defs.push_back (s);
2166
2167  s = new StrategyDef;
2168  s->m_keyword = "setup";
2169  s->m_name = "SetupRoot";
2170  s->m_on_value = "root";
2171  s->m_off_value = "no_root";
2172  s->m_default_value = true;
2173  s->m_priority_value = false;
2174
2175  m_defs.push_back (s);
2176
2177  s = new StrategyDef;
2178  s->m_keyword = "setup";
2179  s->m_name = "SetupCleanup";
2180  s->m_on_value = "cleanup";
2181  s->m_off_value = "no_cleanup";
2182  s->m_default_value = true;
2183  s->m_priority_value = false;
2184
2185  m_defs.push_back (s);
2186
2187  s = new StrategyDef;
2188  s->m_keyword = "structure";
2189  s->m_name = "VersionDirectory";
2190  s->m_on_value = "with_version_directory";
2191  s->m_off_value = "without_version_directory";
2192  if (Cmt::get_current_structuring_style () != without_version_directory)
2193    {
2194      s->m_default_value = true;
2195      s->m_priority_value = false;
2196    }
2197  else
2198    {
2199      s->m_default_value = false;
2200      s->m_priority_value = true;
2201    }
2202
2203  m_defs.push_back (s);
2204}
2205
2206/**----------------------------------------------------------
2207   Find a strategy definition by its name
2208 */
2209StrategyDef* StrategyMgr::find_strategy (const cmt_string& name)
2210{
2211  static StrategyMgr& me = instance ();
2212
2213  int i;
2214
2215  for (i = 0; i < me.m_defs.size (); i++)
2216    {
2217      StrategyDef* def = me.m_defs[i];
2218      if (def->m_name == name)
2219        {
2220          return (def);
2221        }
2222    }
2223
2224  return (0);
2225}
2226
2227/**----------------------------------------------------------
2228   Retreive the default value defined for a given strategy
2229 */
2230bool StrategyMgr::get_default_strategy (const cmt_string& name)
2231{
2232  StrategyDef* def = find_strategy (name);
2233  if (def == 0) return (false);
2234  return (def->m_default_value);
2235}
2236
2237/**----------------------------------------------------------
2238   Retreive the priority value defined for a given strategy
2239   This value is used when two children of a project request two conflicting strategy values
2240 */
2241bool StrategyMgr::get_priority_strategy (const cmt_string& name)
2242{
2243  StrategyDef* def = find_strategy (name);
2244  if (def == 0) return (false);
2245  return (def->m_priority_value);
2246}
2247
2248/**----------------------------------------------------------
2249   Return the vector of all existing strategy definitions
2250 */
2251StrategyDef::StrategyDefs& StrategyMgr::get_definitions ()
2252{
2253  static StrategyMgr& me = instance ();
2254
2255  return (me.m_defs);
2256}
2257
2258//-----------------------------------------------------------
2259Strategy::Strategy ()
2260{
2261  clear ();
2262}
2263
2264//-----------------------------------------------------------
2265void Strategy::clear ()
2266{
2267  m_definition = 0;
2268  m_specified = false;
2269  m_specified_value = false;
2270  m_value = false;
2271  m_on_tag = 0;
2272  m_off_tag = 0;
2273}
2274
2275/**----------------------------------------------------------
2276   Specify a new value for this strategy.
2277   This only happens when a strategy statement is met in a project file or in a requirements file.
2278 */
2279void Strategy::set (StrategyDef* definition, bool value, const cmt_string& project_name)
2280{
2281  //cerr << "Setting strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
2282
2283  m_definition = definition;
2284  m_specified = true;
2285  m_specified_value = value;
2286
2287  update (definition, value, project_name);
2288}
2289
2290/**----------------------------------------------------------
2291   Change the effective value for this strategy.
2292   This has no impact on to the specified value.
2293   This will adapt the tag settings
2294 */
2295void Strategy::update (StrategyDef* definition, bool value, const cmt_string& project_name)
2296{
2297  //cerr << "Updating strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
2298
2299  m_value = value;
2300  m_definition = definition;
2301
2302  cmt_string to_tag_name = project_name;
2303  cmt_string to_untag_name = project_name;
2304
2305  to_tag_name += "_";
2306  to_untag_name += "_";
2307
2308  if (m_value)
2309    {
2310      to_tag_name += m_definition->m_on_value;
2311      to_untag_name += m_definition->m_off_value;
2312    }
2313  else
2314    {
2315      to_tag_name += m_definition->m_off_value;
2316      to_untag_name += m_definition->m_on_value;
2317    }
2318
2319  m_on_tag = Tag::find (to_tag_name);
2320  m_off_tag = Tag::find (to_untag_name);
2321
2322  if (m_on_tag == 0) 
2323    {
2324      m_on_tag = Tag::add (to_tag_name, PriorityConfig, "PROJECT", 0);
2325      m_off_tag = Tag::add (to_untag_name, PriorityConfig, "PROJECT", 0);
2326
2327      m_on_tag->add_tag_exclude (m_off_tag);
2328      m_off_tag->add_tag_exclude (m_on_tag);
2329    }
2330
2331  m_off_tag->unmark ();
2332  m_on_tag->mark ();
2333}
2334//-----------------------------------------------------------
2335const cmt_string& StrategyDef::get_default_value () const
2336{
2337  if (m_default_value)
2338    {
2339      return (m_on_value);
2340    }
2341  else
2342    {
2343      return (m_off_value);
2344    }
2345}
2346//-----------------------------------------------------------
2347void Project::set_author (const cmt_string& name)
2348{
2349  cout<<"set_author"<<name<<endl;     
2350  this->m_author = name;
2351}
2352//-----------------------------------------------------------
2353const cmt_string& Project::get_author () const
2354{
2355  return (m_author);
2356}
2357//-----------------------------------------------------------
2358void Project::project_author_action (const CmtSystem::cmt_string_vector& words)
2359{
2360  if (m_author != "") m_author += "\n";
2361  for (int i = 1; i < words.size (); i++)
2362    {
2363      const cmt_string& w = words[i];
2364     
2365      if (i > 1) m_author += " ";
2366      m_author += w; 
2367    }
2368}
2369//-----------------------------------------------------------
2370Use*  Project::get_use () const
2371{
2372    return m_use;   
2373} 
2374//-----------------------------------------------------------
2375void  Project::set_use (Use* use)
2376{ 
2377    this->m_use = use;
2378}
2379//-----------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.