source: CMT/v1rbeta20p20061025/source/cmt_project.cxx @ 297

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

Màj

  • Property svn:eol-style set to native
File size: 56.3 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
574      // First create the Project.m_use for the policy
575          //cout << "About to add project policy package file [" <<  project->get_name()+"_project_policy" << "]" << endl;     
576         
577          if (project->get_use() == 0)
578
579      if (Cmt::get_debug ())
580        {
581          cout << "About to parse project file [" << text << "]" << endl;
582        }
583
584
585      {
586         
587     Use* project_use = Use::create (project->get_cmtpath(), 
588                                 project->get_name()+"_project_policy", 
589                                 project->get_release (), "", "");                       
590                                 
591      project_use->done      = true;
592      project_use->discarded = false;
593      project_use->selected  = false;
594      project_use->m_located = true;
595      project_use->set_auto_imports(On);
596
597    // add at the uses level
598    static Use::UsePtrVector& uses = Use::get_ordered_uses ();
599     bool found = false;
600     int  size  = uses.size ();
601     //cerr << "\n size:"<<size<< ":" << endl; 
602     for (int n = 0; n < size; n++)
603     {
604          Use* tuse = uses[n];
605          //cerr << "\tpackage file [" << tuse->get_package_name() << "]" <<project_use->get_package_name()<< endl;           
606          if (tuse->get_package_name()==project_use->get_package_name())
607                    found=true;
608
609     }
610     
611     project->set_use(project_use);     
612     
613     if (not found)
614    {
615         uses.push_back (project_use);
616         project_use->m_index = uses.size () - 1;
617
618    }
619   
620    //             Use::UsePtrVector& uses = use->get_package()->get_uses ();
621    //             uses.push_back (p_use);
622    //             use->m_index = uses.size () - 1;
623
624
625
626      SyntaxParser::parse_project_file_text (text, 
627                                             Project::get_project_file_name (),
628                                             project);
629      //project_use->done      = true;
630      }
631    }
632
633
634
635  CmtSystem::cd (here);
636
637  return (project);
638}
639
640/*----------------------------------------------------------*/
641/*                                                          */
642/*  Operations on Projects                                  */
643/*                                                          */
644/*----------------------------------------------------------*/
645
646//----------------------------------------------------------
647bool Project::create (const cmt_string& name, 
648                      const cmt_string& release, 
649                      const cmt_string& path)
650{
651  cout << "------------------------------------------" << endl;
652  cout << "Configuring environment for project " << name << " " << release;
653
654  if (path != "")
655    {
656      cout << " in " << path;
657    }
658
659  cout << endl;
660  cout << "CMT version " << Cmt::get_cmt_version () << "." << endl;
661  cout << "------------------------------------------" << endl;
662
663  if (path != "")
664    {
665      if (!CmtSystem::mkdir (path))
666        {
667          cout << "Cannot create the " << path << " directory" << endl;
668          return (false);
669        }
670
671      if (!CmtSystem::cd (path))
672        {
673          cout << "Cannot access the " << path << " directory" << endl;
674          return (false);
675        }
676    }
677
678  if (!CmtSystem::mkdir (name))
679    {
680      cout << "Cannot create the " << name << " directory" << endl;
681      return (false);
682    }
683
684  if (!CmtSystem::cd (name))
685    {
686      cout << "Cannot access the " << name << " directory" << endl;
687      return (false);
688    }
689
690  if (release != "")
691    {
692      if (!CmtSystem::mkdir (release))
693        {
694          cout << "Cannot create the " << release << " directory" << endl;
695          return (false);
696        }
697     
698      if (!CmtSystem::cd (release))
699        {
700          cout << "Cannot access the " << release << " directory" << endl;
701          return (false);
702        }
703    }
704
705  if (!CmtSystem::test_directory ("cmt"))
706    {
707      if (!CmtSystem::mkdir ("cmt"))
708        {
709          cout << "Cannot create the cmt directory" << endl;
710          return (false);
711        }
712      else
713        {
714          cout << "Installing the cmt directory" << endl;
715        }
716    }
717
718  CmtSystem::cd ("cmt");
719
720  if (!CmtSystem::test_file (get_project_file_name ()))
721    {
722      cout << "Creating a new project file" << endl;
723
724      ofstream f (get_project_file_name ());
725      if (f)
726        {
727          f << "project " << name << endl;
728          f << endl;
729          f.close ();
730        }
731      else
732        {
733          cout << "Cannot create the project file" << endl;
734          return (false);
735        }
736    }
737  else
738    {
739      cmt_string text;
740      text.read (get_project_file_name ());
741
742      ProjectPatcher p (name);
743
744      p.run (text);
745      p.commit ();
746
747      cout << "project file already there" << endl;
748    }
749
750  return (true);
751}
752
753//----------------------------------------------------------
754Project* Project::find_by_name (const cmt_string& name)
755{
756  static ProjectVector& Projects = projects ();
757
758  for (int i = 0; i < Projects.size (); i++)
759    {
760      Project& p = Projects[i];
761      if (p.m_name == name) return (&p);
762     
763    }
764
765  return (0);
766}
767
768//----------------------------------------------------------
769Project* Project::find_by_cmtpath (const cmt_string& cmtpath)
770{
771  cmt_string compressed_path = cmtpath;
772  CmtSystem::compress_path (compressed_path);
773
774  static ProjectVector& Projects = projects ();
775
776  for (int i = 0; i < Projects.size (); i++)
777    {
778      Project& p = Projects[i];
779
780      if (p.m_cmtpath == compressed_path) return (&p);
781      if (p.m_cmtpath_pwd == compressed_path) return (&p);
782    }
783
784  return (0);
785}
786
787//----------------------------------------------------------
788Project* Project::get_current ()
789{
790  cmt_string here = CmtSystem::pwd ();
791
792  static ProjectVector& Projects = projects ();
793
794  Project* result = 0;
795
796  for (int i = (Projects.size () - 1); i >= 0; i--)
797    {
798      Project& p = Projects[i];
799
800      if (here.find (p.m_cmtpath_pwd) == 0) 
801        {
802          result = &p;
803        }
804
805      if (here.find (p.m_cmtpath) == 0) 
806        {
807          result = &p;
808        }
809    }
810
811  return (result);
812}
813
814//----------------------------------------------------------
815Project* Project::add (const cmt_string& name,
816                       const cmt_string& release)
817{
818  static ProjectVector& Projects = projects ();
819
820  //cout << "Project::add> name=" << name << endl;
821
822  {
823    Project* project;
824
825    project = find_by_name (name);
826    if (project != 0) 
827      {
828        if (!Cmt::get_quiet ())
829          {
830            if (release != project->get_release ())
831              {
832                cerr << "#CMT> Project " << name << " requested with conflicting releases " << project->get_release () << " and " << release << endl;
833                CmtError::set (CmtError::project_release_conflict, name);
834              }
835          }
836
837        // Project objects are recreated here to follow the hierarchy
838        // This duplication is needed for properly applying the strategies
839        Project& p = Projects.add ();
840
841        p.set_name (name);
842        p.set_release (release);
843        p.configure ();
844
845        return (&p);
846
847        //return (project);
848      }
849  }
850
851  Project& project = Projects.add ();
852  project.clear ();
853  project.set_name (name);
854  project.set_release (release);
855  project.configure ();
856
857  return (&project);
858}
859
860//----------------------------------------------------------
861Project::ProjectVector& Project::projects ()
862{
863  static Database& db = Database::instance ();
864  static ProjectVector& Projects = db.projects ();
865
866  return (Projects);
867}
868
869/*----------------------------------------------------------*/
870void Project::clear_all ()
871{
872  static ProjectVector& Projects = projects ();
873
874  for (int i = 0; i < Projects.size (); i++)
875    {
876      Project& project = Projects[i];
877      project.clear ();
878    }
879
880  Projects.clear ();
881}
882
883/*----------------------------------------------------------*/
884void Project::show_all ()
885{
886  static Project::ProjectVector& Projects = Project::projects ();
887 
888  for (int i = 0; i < Projects.size (); i++)
889    {
890      Project& p = Projects[i];
891      p.m_visited = false;
892    }
893
894  Project* p = get_current ();
895
896  if (p == 0)
897    {
898      if (Projects.size () == 0) return;
899
900      p = &(Projects[0]);
901    }
902
903  p->show ();
904}
905
906/*----------------------------------------------------------*/
907void Project::show_specified_strategies_for_all ()
908{
909  static ProjectVector& Projects = projects ();
910
911  for (int i = 0; i < Projects.size (); i++)
912    {
913      const Project& project = Projects[i];
914      project.show_specified_strategies ();
915    }
916}
917
918/*----------------------------------------------------------*/
919class VisitorForShowPaths : public IProjectVisitor
920{
921public:
922  VisitorForShowPaths ()
923  {
924  }
925
926  void pre (Project* p)
927  {
928    const cmt_string& w = p->get_cmtpath_pwd ();
929    const cmt_string& s = p->get_cmtpath_source ();
930
931    if (s == "default path") return;
932
933    if (CmtSystem::test_directory (w))
934      {
935        cout << "# Add path " << w << " from " << s << endl;
936      }
937  }
938
939  void in (Project* p)
940  {
941    const cmt_string& w = p->get_cmtpath_pwd ();
942    const cmt_string& s = p->get_cmtpath_source ();
943
944    if (s == "default path") return;
945
946    if (CmtSystem::test_directory (w))
947      {
948        cout << "# Add path " << w << " from " << s << endl;
949      }
950  }
951
952  void post (Project* p)
953  {
954  }
955};
956
957/*----------------------------------------------------------*/
958void Project::show_paths ()
959{
960  VisitorForShowPaths visitor;
961
962  start_visit (visitor);
963}
964
965//----------------------------------------------------------
966const cmt_string& Project::get_project_file_name ()
967{
968  static const cmt_string name = "project.cmt";
969
970  return (name);
971}
972
973//----------------------------------------------------------
974void Project::fill_selection (int depth, CmtSystem::cmt_string_vector& path_selections)
975{
976  static ProjectVector& Projects = projects ();
977
978  for (int i = 0; i < Projects.size (); i++)
979    {
980      Project& project = Projects[i];
981
982      const cmt_string& p = project.get_cmtpath ();
983      const cmt_string& pwd = project.get_cmtpath_pwd ();
984      const cmt_string& src = project.get_cmtpath_source ();
985
986      if (src != "default path")
987        {
988          if (depth > 0)
989            {
990              cmt_string& s1 = path_selections.add ();
991              s1 = p;
992              cmt_string& s2 = path_selections.add ();
993              s2 = pwd;
994              depth--;
995
996              if (depth == 0) break;
997            }
998        }
999    }
1000}
1001
1002//----------------------------------------------------------
1003void Project::broadcast (IProjectAction& action)
1004{
1005  static ProjectVector& Projects = projects ();
1006
1007  for (int i = 0; i < Projects.size (); i++)
1008    {
1009      const Project& project = Projects[i];
1010
1011      if (!action.run (project)) break;
1012    }
1013}
1014
1015//----------------------------------------------------------
1016void Project::reverse_broadcast (IProjectAction& action)
1017{
1018  static ProjectVector& Projects = projects ();
1019
1020  for (int i = (Projects.size () - 1); i >= 0; i--)
1021    {
1022      const Project& project = Projects[i];
1023
1024      if (!action.run (project)) break;
1025    }
1026}
1027
1028//----------------------------------------------------------
1029void Project::scan_paths (PathScanner& scanner, PathScanner::actor& a)
1030{
1031  static ProjectVector& Projects = projects ();
1032
1033  int i;
1034
1035  for (i = 0; i < Projects.size (); i++)
1036    {
1037      Project& p  = Projects[i];
1038      p.m_visited = false;
1039    }
1040
1041  for (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_path (p, a);
1047    }
1048}
1049
1050//----------------------------------------------------------
1051void Project::scan_paths_for_package (PathScanner& scanner, const cmt_string& name)
1052{
1053  static ProjectVector& Projects = projects ();
1054
1055  for (int i = 0; i < Projects.size (); i++)
1056    {
1057      const Project& project = Projects[i];
1058
1059      const cmt_string& p = project.m_cmtpath;
1060      scanner.scan_package (p, name);
1061    }
1062}
1063
1064//----------------------------------------------------------
1065cmt_string Project::find_in_cmt_paths (const cmt_string& path)
1066{
1067  const cmt_string pwd = CmtSystem::pwd ();
1068
1069  static ProjectVector& Projects = projects ();
1070
1071  for (int i = 0; i < Projects.size (); i++)
1072    {
1073      const Project& project = Projects[i];
1074
1075      const cmt_string& p = project.m_cmtpath;
1076      const cmt_string& w = project.m_cmtpath_pwd;
1077      const cmt_string& s = project.m_cmtpath_source;
1078
1079      if (s == "default path") continue;
1080
1081      if (CmtSystem::test_directory (p))
1082        {
1083          if (path.find (p) != cmt_string::npos)
1084            {
1085              return (p);
1086            }
1087
1088          // To become the current area, a path must correspond to the current package
1089          if (path.find (w) != cmt_string::npos)
1090            {
1091              return (p);
1092            }
1093        }
1094
1095      if (p == w) continue;
1096
1097      if (CmtSystem::test_directory (w))
1098        {
1099          if (path.find (w) != cmt_string::npos)
1100            {
1101              return (w);
1102            }
1103        }
1104    }
1105
1106  return ("");
1107}
1108
1109//----------------------------------------------------------
1110void Project::visit (IProjectVisitor& visitor)
1111{
1112  if (m_visited) return;
1113  m_visited = true;
1114
1115  int i;
1116
1117  for (i = 0; i < get_children_size (); i++)
1118    {
1119      Project* child = get_child (i);
1120
1121      if (child->visited ()) continue;
1122
1123      visitor.in (child);
1124    }
1125
1126  for (i = 0; i < m_children.size (); i++)
1127    {
1128      Project* child = m_children[i];
1129      child->visit (visitor);
1130    }
1131}
1132
1133//----------------------------------------------------------
1134void Project::start_visit (IProjectVisitor& visitor)
1135{
1136  static Project::ProjectVector& Projects = Project::projects ();
1137 
1138  for (int i = 0; i < Projects.size (); i++)
1139    {
1140      Project& p = Projects[i];
1141      p.m_visited = false;
1142    }
1143
1144  Project* p = get_current ();
1145
1146  if (p == 0)
1147    {
1148      if (Projects.size () == 0) return;
1149
1150      p = &(Projects[0]);
1151    }
1152
1153  visitor.pre (p);
1154  p->visit (visitor);
1155  visitor.post (p);
1156}
1157
1158//----------------------------------------------------------
1159class VisitorForFillCMTPATH : public IProjectVisitor
1160{
1161public:
1162  VisitorForFillCMTPATH (cmt_string& buffer) : m_buffer (buffer)
1163  {
1164    buffer = "path CMTPATH \"\" \n";
1165  }
1166
1167  void pre (Project* p)
1168  {
1169    const cmt_string& w = p->get_cmtpath_pwd ();
1170    const cmt_string& s = p->get_cmtpath_source ();
1171
1172    if (s == "default path") return;
1173
1174    if (CmtSystem::test_directory (w))
1175      {
1176        m_buffer += "path_append CMTPATH \"";
1177        m_buffer += w;
1178        m_buffer += "\" \n";
1179      }
1180  }
1181
1182  void in (Project* p)
1183  {
1184    const cmt_string& w = p->get_cmtpath_pwd ();
1185    const cmt_string& s = p->get_cmtpath_source ();
1186
1187    if (s == "default path") return;
1188
1189    if (CmtSystem::test_directory (w))
1190      {
1191        m_buffer += "path_append CMTPATH \"";
1192        m_buffer += w;
1193        m_buffer += "\" \n";
1194      }
1195  }
1196
1197  void post (Project* p)
1198  {
1199    //cerr << "Buffer = " << m_buffer << endl;
1200  }
1201
1202private:
1203  cmt_string& m_buffer;
1204
1205};
1206
1207//----------------------------------------------------------
1208void Project::fill_cmtpaths (cmt_string& buffer)
1209{
1210  /*
1211    Try to re-create all CMTPATH items from project definitions.
1212    The goal is to generate CMTPATH even if this EV was not pre-set
1213    which is the case when CMTPROJECTPATH is only used
1214   */
1215
1216  VisitorForFillCMTPATH visitor (buffer);
1217
1218  start_visit (visitor);
1219}
1220
1221//----------------------------------------------------------
1222Project::Project () : m_name (""), m_author("")
1223{
1224  clear ();
1225}
1226
1227//----------------------------------------------------------
1228const cmt_string& Project::get_name () const
1229{
1230  return (m_name);
1231}
1232
1233//----------------------------------------------------------
1234const cmt_string& Project::get_release () const
1235{
1236  return (m_release);
1237}
1238
1239//----------------------------------------------------------
1240const cmt_string& Project::get_container () const
1241{
1242  return (m_container);
1243}
1244
1245//----------------------------------------------------------
1246const cmt_string& Project::get_container_version () const
1247{
1248  return (m_container_version);
1249}
1250
1251//----------------------------------------------------------
1252const cmt_string& Project::get_cmtpath () const
1253{
1254  return (m_cmtpath);
1255}
1256
1257//----------------------------------------------------------
1258const cmt_string& Project::get_cmtpath_pwd () const
1259{
1260  return (m_cmtpath_pwd);
1261}
1262
1263//----------------------------------------------------------
1264const cmt_string& Project::get_cmtpath_source () const
1265{
1266  return (m_cmtpath_source);
1267}
1268
1269//----------------------------------------------------------
1270int Project::get_children_size () const
1271{
1272  return (m_children.size ());
1273}
1274
1275//----------------------------------------------------------
1276Project* Project::get_child (int index) const
1277{
1278  if (index < 0) return (0);
1279  if (index >= m_children.size ()) return (0);
1280  return (m_children[index]);
1281}
1282
1283//----------------------------------------------------------
1284bool Project::visited () const
1285{
1286  return (m_visited);
1287}
1288
1289//----------------------------------------------------------
1290void Project::set_name (const cmt_string& name)
1291{
1292  m_name = name;
1293}
1294
1295//----------------------------------------------------------
1296void Project::set_release (const cmt_string& release)
1297{
1298  m_release = release;
1299}
1300
1301//----------------------------------------------------------
1302void Project::set_container (const cmt_string& container)
1303{
1304  m_container = container;
1305}
1306
1307//----------------------------------------------------------
1308void Project::set_container_version (const cmt_string& container_version)
1309{
1310  m_container_version = container_version;
1311}
1312
1313//----------------------------------------------------------
1314void Project::set_cmtpath (const cmt_string& path)
1315{
1316  m_cmtpath = path;
1317}
1318
1319//----------------------------------------------------------
1320void Project::set_cmtpath_pwd (const cmt_string& path)
1321{
1322  m_cmtpath_pwd = path;
1323}
1324
1325//----------------------------------------------------------
1326void Project::set_cmtpath_source (const cmt_string& source)
1327{
1328  m_cmtpath_source = source;
1329}
1330
1331//----------------------------------------------------------
1332void Project::clear ()
1333{
1334  m_name    = "";
1335  m_release = "";
1336  m_cmtpath = "";
1337  m_cmtpath_pwd    = "";
1338  m_cmtpath_source = "";
1339  m_use            = 0;
1340
1341  m_parents.clear ();
1342  m_children.clear ();
1343
1344  m_configured = false;
1345
1346  m_strategies.clear ();
1347}
1348
1349//----------------------------------------------------------
1350bool Project::has_parents () const
1351{
1352  return ((m_parents.size () > 0));
1353}
1354
1355//----------------------------------------------------------
1356bool Project::has_parent (Project* p) const
1357{
1358  if (p == 0) return (false);
1359  if (p == this) return (false);
1360
1361  const cmt_string& name = p->get_name ();
1362
1363  int i;
1364
1365  for (i = 0; i < m_parents.size (); i++)
1366    {
1367      const Project* parent = m_parents[i];
1368      if (parent == 0) continue;
1369
1370      if (parent->get_name () == name)
1371        {
1372          // registered as a parent
1373          return (true);
1374        }
1375
1376      if (parent->has_parent (p))
1377        {
1378          // recurse
1379          return (true);
1380        }
1381    }
1382
1383  return (false);
1384}
1385
1386//----------------------------------------------------------
1387bool Project::has_child (Project* p) const
1388{
1389  if (p == 0) return (false);
1390  if (p == this) return (false);
1391
1392  const cmt_string& name = p->get_name ();
1393
1394  int i;
1395
1396  for (i = 0; i < m_children.size (); i++)
1397    {
1398      const Project* child = m_children[i];
1399      if (child == 0) continue;
1400
1401      if (child->get_name () == name)
1402        {
1403          // registered as a child
1404          return (true);
1405        }
1406
1407      if (child->has_child (p))
1408        {
1409          // recurse
1410          return (true);
1411        }
1412    }
1413
1414  return (false);
1415}
1416
1417//----------------------------------------------------------
1418void Project::add_parent (Project* p)
1419{
1420  if (p == 0) return;
1421  if (p == this) return;
1422
1423  //cerr << "Adding parent " << p->get_name () << " to " << m_name << endl;
1424
1425  if (has_child (p)) return;
1426  if (has_parent (p)) return;
1427
1428  m_parents.push_back (p);
1429}
1430
1431//----------------------------------------------------------
1432void Project::add_child (Project* p)
1433{
1434  if (p == 0) return;
1435  if (p == this) return;
1436
1437  if (has_child (p)) return;
1438  if (has_parent (p)) return;
1439
1440  m_children.push_back (p);
1441}
1442
1443//----------------------------------------------------------
1444void Project::configure ()
1445{
1446  if (m_configured) return;
1447  m_configured = true;
1448
1449  set_default_strategy ("SetupConfig");
1450  set_default_strategy ("SetupRoot");
1451  set_default_strategy ("SetupCleanup");
1452  set_default_strategy ("BuildPrototypes");
1453  set_default_strategy ("InstallArea");
1454  set_default_strategy ("VersionDirectory");
1455}
1456
1457/**---------------------------------------------------------
1458 A container statement is met in the project file
1459*/
1460void Project::container_action (const cmt_string& name, const cmt_string& version)
1461{
1462  //cerr << "Container action " << name << " " << version << endl;
1463
1464  set_container (name);
1465  set_container_version (version);
1466}
1467
1468/**---------------------------------------------------------
1469 A use statement is met in the project file
1470*/
1471void Project::use_action (const cmt_string& name, const cmt_string& release)
1472{
1473  if (Cmt::get_debug ())
1474    {
1475      cout << "Use action " << name << " " << release << endl;
1476    }
1477
1478  // A project with its release is specified
1479  //
1480  // Is this project already visible?
1481  // If not: look for it
1482  //   + get CMTPROJECTPATH
1483  //   + search from all entries of CMTPROJECTPATH : p(i)/<name>/<release>
1484  //   + when found, this should become a new CMTPATH entry
1485  //   +             the new project is then parsed ... etc...
1486
1487  // First test it wilcard is used
1488  int v = -1;
1489  int r = -1;
1490  int p = -1;
1491  cmt_string new_release = release;
1492  CmtSystem::is_version_directory (new_release, v, r, p); 
1493  bool use_has_wild_card = (v == -1) || (r == -1) || (p == -1);
1494  if (use_has_wild_card)
1495  {
1496      cmt_string selected_release = "";
1497      if (select_release(name, new_release,selected_release))
1498      { // yes
1499          // cout <<"selected_release: "<<selected_release<<endl;   
1500          new_release = selected_release;
1501      }         
1502   }
1503
1504  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
1505  cmt_string sep;
1506  sep = CmtSystem::path_separator ();
1507
1508  //cerr << "cmtprojectpath = " << cmtprojectpath << endl;
1509  CmtSystem::cmt_string_vector items;
1510  CmtSystem::split (cmtprojectpath, sep, items);
1511
1512  bool found = false;
1513
1514  for (int i = 0; i < items.size (); i++)
1515    {
1516      const cmt_string& item = items[i];
1517      cmt_string p = item;
1518      p += CmtSystem::file_separator ();
1519      p += name;
1520      if (new_release != "")
1521        {
1522          p += CmtSystem::file_separator ();
1523          p += new_release;
1524        }
1525
1526    if (CmtSystem::test_directory (p))
1527        {
1528          //cerr << "Project directory " << p << " exists " << endl;
1529
1530          found = true;
1531
1532          IProjectFactory& factory = ProjectFactory::instance ();
1533
1534          factory.create_project (name, p, "ProjectPath", this);
1535
1536          break;
1537        }
1538    }
1539
1540  if (!found)
1541    {
1542      Project* p = Project::find_by_name (name);
1543
1544      if (p != 0)
1545          {
1546              found = true;
1547              p->add_parent (this);
1548              add_child (p);
1549
1550              update_strategies_from_children ();
1551            }
1552    }
1553   
1554  if (!found && (cmtprojectpath != ""))
1555    {
1556      cerr << "#CMT> Project " << name << " " << release << " requested by " << m_name << " not found in CMTPROJECTPATH" << endl;
1557    }
1558}
1559
1560//---------------------------------------------------------
1561bool Project::select_release(const cmt_string& name, const cmt_string& release, cmt_string& result)
1562{
1563    cmt_string selected_release = "";
1564
1565    int v = -1;
1566    int r = -1;
1567    int p = -1;
1568    CmtSystem::is_version_directory (release, v, r, p); 
1569
1570    int selected_v = -1;
1571    int selected_r = -1;
1572    int selected_p = -1;
1573    CmtSystem::cmt_string_vector releases = get_project_releases(name);
1574    for (int j = 0; j < releases.size (); j++)
1575    {
1576         //cout <<releases[j]<<endl; 
1577         int new_v = -1;
1578         int new_r = -1;
1579         int new_p = -1;
1580         CmtSystem::is_version_directory (releases[j], new_v, new_r, new_p);
1581         if (v == -1)
1582         {
1583             if (selected_v<new_v)
1584             {
1585                 selected_v       = new_v;
1586                 selected_r = -1;
1587                 selected_p = -1;
1588                 selected_release = releases[j];
1589             }
1590             else if (selected_v==new_v)
1591             { // We compare the r
1592                 if (selected_r<new_r)
1593                 {
1594                     selected_r = new_r;
1595                     selected_p = -1;
1596                     selected_release = releases[j];                               
1597                 }
1598                 else if (selected_r==new_r)
1599                 { // We compare the p
1600                     if (selected_p<new_p)
1601                     {
1602                         selected_p = new_p;
1603                         selected_release = releases[j];                               
1604                     }
1605                     // else if ? not possible                                                           
1606                 }                               
1607             }
1608         }
1609         else if (r == -1)
1610         {
1611             if (v==new_v)
1612             { // We compare the r                                                     
1613                 if (selected_r<new_r)
1614                 {
1615                     selected_r = new_r;
1616                     selected_p = -1;
1617                     selected_release = releases[j];                               
1618                 }
1619                 else if (selected_r==new_r)
1620                 { // We compare the p
1621                     if (selected_p<new_p)
1622                     {
1623                         selected_p = new_p;
1624                         selected_release = releases[j];                               
1625                     }
1626                     // else if ? not possible
1627                 }
1628             }                                               
1629         }
1630         else if (p == -1)
1631         {
1632             if (v==new_v && r==new_r)
1633                 { // We compare the p
1634                     if (selected_p<new_p)
1635                     {
1636                         selected_p = new_p;
1637                         selected_release = releases[j];                               
1638                     }
1639                     // else if ? not possible
1640                 }       
1641         }       
1642         //cerr<<"v:"<<new_v<<", r:"<<new_r<<", p:"<<new_p<<endl;             
1643         //cerr<<"req v:"<<v<<", req r:"<<r<<", req p:"<<p<<endl;       
1644    }
1645    //cerr <<"selected release: "<<selected_release<<endl; 
1646    if (selected_release == "")
1647        return false;
1648    result = selected_release;   
1649    return true;
1650}
1651
1652//---------------------------------------------------------
1653const CmtSystem::cmt_string_vector Project::get_project_releases(const cmt_string& name) const
1654{
1655        CmtSystem::cmt_string_vector releases;
1656    cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
1657    cmt_string sep;
1658    sep = CmtSystem::path_separator ();
1659
1660    CmtSystem::cmt_string_vector items;
1661    CmtSystem::split (cmtprojectpath, sep, items);   
1662    for (int i = 0; i < items.size (); i++)
1663    {
1664        const cmt_string& item = items[i];
1665        cmt_string p = item;
1666        p += CmtSystem::file_separator ();
1667        p += name;
1668        if (CmtSystem::test_directory (p))
1669            { 
1670                CmtSystem::cmt_string_vector directories;
1671            CmtSystem::scan_dir (p, directories);
1672                for (int j = 0; j < directories.size (); j++)
1673                {
1674                    if  (CmtSystem::test_directory(directories[j]))
1675                    {
1676                        cmt_string release;
1677                        CmtSystem:: basename(directories[j], release);
1678                        if (CmtSystem::is_version_directory(release))
1679                        {                                 
1680                             cmt_string& name_entry = releases.add ();
1681                             name_entry = release; 
1682                             //cout << release <<endl; 
1683                        }             
1684                    }                       
1685                }                               
1686            }
1687    }
1688    return (releases);
1689}
1690
1691//----------------------------------------------------------
1692Project& Project::operator = (const Project& other)
1693{
1694  m_name = other.m_name;
1695  m_cmtpath = other.m_cmtpath;
1696  m_cmtpath_pwd = other.m_cmtpath_pwd;
1697  m_cmtpath_source = other.m_cmtpath_source;
1698
1699  return (*this);
1700}
1701
1702//----------------------------------------------------------
1703bool Project::operator == (const cmt_string& name) const
1704{
1705  return ((m_name == name));
1706}
1707
1708//----------------------------------------------------------
1709bool Project::operator != (const cmt_string& name) const
1710{
1711  return ((m_name != name));
1712}
1713
1714//----------------------------------------------------------
1715void Project::show ()
1716{
1717  static int level = 0;
1718
1719  bool is_current = false;
1720
1721  cmt_string here = CmtSystem::pwd ();
1722
1723  if (here.find (m_cmtpath) == 0) 
1724    {
1725      if (m_cmtpath_source != "default path")
1726        {
1727          is_current = true;
1728        }
1729    }
1730
1731  for (int tab = 0; tab < level; tab++) cout << "  ";
1732  cout << m_name << " " << m_release << " (in " << m_cmtpath << ")";
1733
1734  if (is_current) cout << " (current)";
1735
1736  int i;
1737
1738  for (i = 0; i < m_parents.size (); i++)
1739    {
1740      Project* p = m_parents[i];
1741      if (p == 0) continue;
1742      cout << " P=" << p->get_name ();
1743    }
1744
1745  for (i = 0; i < m_children.size (); i++)
1746    {
1747      Project* p = m_children[i];
1748      if (p == 0) continue;
1749      cout << " C=" << p->get_name ();
1750    }
1751
1752  cout << endl;
1753
1754  if (m_visited) return;
1755
1756  m_visited = true;
1757
1758  for (i = 0; i < m_children.size (); i++)
1759    {
1760      Project* p = m_children[i];
1761      if (p == 0) continue;
1762      level++;
1763      p->show ();
1764      level--;
1765    }
1766}
1767
1768
1769//----------------------------------------------------------
1770void Project::show_specified_strategies () const
1771{
1772  int i;
1773
1774  for (i = 0; i < m_strategies.size (); i++)
1775    {
1776      const Strategy& s = m_strategies[i];
1777      if (s.m_specified)
1778        {
1779          const StrategyDef* def = s.m_definition;
1780 
1781          cout << "# Project " << m_name
1782               << " sets " << def->m_keyword
1783               << " strategy to " << ((s.m_value) ? def->m_on_value : def->m_off_value);
1784
1785          if (s.m_context != "")
1786            {
1787              cout << " (from package " << s.m_context << ")";
1788            }
1789
1790          cout << endl;
1791        }
1792    }
1793}
1794
1795//----------------------------------------------------------
1796bool Project::has_strategy (const StrategyDef* definition) const
1797{
1798  int i;
1799
1800  for (i = 0; i < m_strategies.size (); i++)
1801    {
1802      const Strategy& s = m_strategies[i];
1803      if (s.m_definition == definition)
1804        {
1805          return (true);
1806        }
1807    }
1808
1809  return (false);
1810}
1811
1812//----------------------------------------------------------
1813bool Project::get_strategy (const cmt_string& name) const
1814{
1815  static StrategyMgr& mgr = StrategyMgr::instance ();
1816
1817  StrategyDef* def = mgr.find_strategy (name);
1818  if (def == 0)
1819    {
1820      cerr << "#CMT> strategy " << name << " undefined" << endl;
1821      return (false);
1822    }
1823
1824  return (get_strategy (def));
1825}
1826
1827//----------------------------------------------------------
1828bool Project::is_specified (const StrategyDef* definition) const
1829{
1830  int i;
1831
1832  for (i = 0; i < m_strategies.size (); i++)
1833    {
1834      Strategy& s = m_strategies[i];
1835      if (s.m_definition == definition)
1836        {
1837          // This strategy is applied in this project
1838          return (s.m_specified);
1839        }
1840    }
1841
1842  // This strategy is not applied in this project
1843  return (false);
1844}
1845
1846//----------------------------------------------------------
1847bool Project::get_strategy (const StrategyDef* def) const
1848{
1849  int i;
1850
1851  for (i = 0; i < m_strategies.size (); i++)
1852    {
1853      Strategy& s = m_strategies[i];
1854      if (s.m_definition == def)
1855        {
1856          // This strategy is applied in this project
1857          if (s.m_specified)
1858            {
1859              return (s.m_specified_value);
1860            }
1861          return (s.m_value);
1862        }
1863    }
1864
1865  // This strategy is not applied in this project
1866  return (def->m_default_value);
1867}
1868
1869//----------------------------------------------------------
1870void Project::set_default_strategy (const cmt_string& name)
1871{
1872  static StrategyMgr& mgr = StrategyMgr::instance ();
1873
1874  StrategyDef* def = mgr.find_strategy (name);
1875  if (def == 0)
1876    {
1877      cerr << "#CMT> strategy " << name << " undefined" << endl;
1878      return;
1879    }
1880
1881  update_strategy (def, def->m_default_value);
1882}
1883
1884
1885//----------------------------------------------------------
1886void Project::set_strategy (const cmt_string& name, const cmt_string& value, const cmt_string& context)
1887{
1888  static StrategyMgr& mgr = StrategyMgr::instance ();
1889
1890  StrategyDef* def = mgr.find_strategy (name);
1891  if (def == 0)
1892    {
1893      cerr << "#CMT> strategy " << name << " undefined" << endl;
1894      return;
1895    }
1896
1897  bool b_value = false;
1898
1899  if (value == def->m_on_value)
1900    {
1901      b_value = true;
1902    }
1903  else if (value == def->m_off_value)
1904    {
1905      b_value = false;
1906    }
1907  else
1908    {
1909      cerr << "#CMT> requested strategy value " << value << " undefined in strategy " << name << endl;
1910      return;
1911    }
1912
1913  set_strategy (def, b_value, context);
1914}
1915
1916//----------------------------------------------------------
1917void Project::set_strategy (StrategyDef* definition, bool b_value, const cmt_string& context)
1918{
1919  bool need_strategy = true;
1920
1921  int i;
1922
1923  for (i = 0; i < m_strategies.size (); i++)
1924    {
1925      Strategy& s = m_strategies[i];
1926      if (s.m_definition == definition)
1927        {
1928          // This strategy is already applied in this project. Let's change it's value
1929          s.set (definition, b_value, get_name ());
1930          if (context != "")
1931            {
1932              if (s.m_context != "") s.m_context += " ";
1933              s.m_context += context;
1934            }
1935          need_strategy = false;
1936          break;
1937        }
1938    }
1939
1940  if (need_strategy)
1941    {
1942      // This strategy is not yet applied in this project.
1943
1944      Strategy& s = m_strategies.add ();
1945      s.clear ();
1946      s.set (definition, b_value, get_name ());
1947      s.m_context = context;
1948    }
1949 
1950  for (i = 0; i < m_parents.size (); i++)
1951    {
1952      Project* project = m_parents[i];
1953
1954      project->update_strategy (definition, b_value);
1955    }
1956}
1957
1958/**----------------------------------------------------------
1959   The strategy value is changed because of indirect influences
1960   - default strategy at initialization time
1961   - change in the children
1962   - change in the children list
1963
1964   (This is not a specification : see the set_strategy method)
1965 */
1966void Project::update_strategy (StrategyDef* definition, bool b_value)
1967{
1968  bool need_strategy = true;
1969  bool specified = false;
1970
1971  int i;
1972
1973  for (i = 0; i < m_strategies.size (); i++)
1974    {
1975      Strategy& s = m_strategies[i];
1976      if (s.m_definition == definition)
1977        {
1978          need_strategy = false;
1979
1980          if (!s.m_specified)
1981            {
1982              // This strategy is already applied in this project. Let's change it's value
1983              s.update (definition, b_value, get_name ());
1984            }
1985          else
1986            {
1987              specified = true;
1988            }
1989          break;
1990        }
1991    }
1992
1993  if (need_strategy)
1994    {
1995      // This strategy is not yet applied in this project.
1996
1997      Strategy& s = m_strategies.add ();
1998      s.clear ();
1999      s.update (definition, b_value, get_name ());
2000    }
2001
2002  if (!specified)
2003    {
2004      for (i = 0; i < m_parents.size (); i++)
2005        {
2006          Project* project = m_parents[i];
2007
2008          project->update_strategy (definition, b_value);
2009        }
2010    }
2011}
2012
2013/**----------------------------------------------------------
2014   At least one of the children has changed this strategy
2015   Or the list of children has changed.
2016   We need to update the strategy value accordingly
2017   This will not change the specified value for this strategy
2018 */
2019void Project::update_strategy_from_children (StrategyDef* definition)
2020{
2021  // If this strategy is specified we don't care what happens from the children
2022
2023  //cerr << "Updating strategy " << definition->m_name << " from children for project " << m_name << endl;
2024
2025  int i;
2026
2027  for (i = 0; i < m_strategies.size (); i++)
2028    {
2029      Strategy& s = m_strategies[i];
2030      if (s.m_definition == definition)
2031        {
2032          // This strategy is applied in this project.
2033
2034          if (s.m_specified)
2035            {
2036              // There will be no impact since the strategy is specified
2037
2038              //cerr << "This strategy is specified in this project" << endl;
2039              return;
2040            }
2041
2042          break;
2043        }
2044    }
2045
2046  // The strategy is not specified locally so we will now figure out
2047  // which strategy has to be considered from the mixture of specifications
2048  // from all children.
2049
2050  // Algorithm:
2051  // - We consider children by pairs
2052  // - a child that specifies its strategy wins over a child that does not
2053  // - when the two children have the same level of priority we consider the priority value
2054
2055  Project* selected = 0;
2056  bool selected_is_specified = false;
2057  bool selected_value = definition->m_default_value;
2058
2059  for (i = 0; i < m_children.size (); i++)
2060    {
2061      Project* p = m_children[i];
2062
2063      //cerr << "Checking strategy for child " << p->get_name () << endl;
2064
2065      bool is_specified = p->is_specified (definition);
2066      bool value = p->get_strategy (definition);
2067
2068      if (selected == 0)
2069        {
2070          selected = p;
2071          selected_is_specified = is_specified;
2072          selected_value = value;
2073          continue;
2074        }
2075
2076      if (is_specified == selected_is_specified)
2077        {
2078          if (selected_value != value)
2079            {
2080              // same level of priority but different values -> we must decide
2081              bool priority_value = definition->m_priority_value;
2082              if (value == priority_value)
2083                {
2084                  selected = p;
2085                  selected_is_specified = is_specified;
2086                  selected_value = value;
2087                }
2088            }
2089        }
2090      else
2091        {
2092          if (is_specified)
2093            {
2094              selected = p;
2095              selected_is_specified = is_specified;
2096              selected_value = value;
2097            }
2098        }
2099    }
2100
2101  update_strategy (definition, selected_value); 
2102}
2103
2104/**----------------------------------------------------------
2105   At least one of the children has changed its strategies
2106   Or the list of children has changed.
2107   We need to update the strategy values accordingly
2108   This will not change the specified values
2109 */
2110void Project::update_strategies_from_children ()
2111{
2112  StrategyDef::StrategyDefs& defs = StrategyMgr::get_definitions ();
2113
2114  //cerr << "Updating strategies from children for project " << m_name << endl;
2115
2116  int i;
2117
2118  for (i = 0; i < defs.size (); i++)
2119    {
2120      StrategyDef* def = defs[i];
2121     
2122      update_strategy_from_children (def);
2123    }
2124
2125  for (i = 0; i < m_parents.size (); i++)
2126    {
2127      Project* p = m_parents[i];
2128      p->update_strategies_from_children ();
2129    }
2130}
2131
2132/**----------------------------------------------------------
2133   The StrategyMgr singleton
2134 */
2135StrategyMgr& StrategyMgr::instance ()
2136{
2137  static StrategyMgr me;
2138  return (me);
2139}
2140
2141/**----------------------------------------------------------
2142   The StrategyMgr constructor
2143   Here are primarily constructed all strategy definitions
2144 */
2145StrategyMgr::StrategyMgr ()
2146{
2147  m_defs.clear ();
2148
2149  StrategyDef* s;
2150
2151  s = new StrategyDef;
2152  s->m_keyword = "build";
2153  s->m_name = "BuildPrototypes";
2154  s->m_on_value = "prototypes";
2155  s->m_off_value = "no_prototypes";
2156  s->m_default_value = true;
2157  s->m_priority_value = false;
2158
2159  m_defs.push_back (s);
2160
2161  s = new StrategyDef;
2162  s->m_keyword = "build";
2163  s->m_name = "InstallArea";
2164  s->m_on_value = "with_installarea";
2165  s->m_off_value = "without_installarea";
2166  s->m_default_value = false;
2167  s->m_priority_value = true;
2168
2169  m_defs.push_back (s);
2170
2171  s = new StrategyDef;
2172  s->m_keyword = "setup";
2173  s->m_name = "SetupConfig";
2174  s->m_on_value = "config";
2175  s->m_off_value = "no_config";
2176  s->m_default_value = true;
2177  s->m_priority_value = false;
2178
2179  m_defs.push_back (s);
2180
2181  s = new StrategyDef;
2182  s->m_keyword = "setup";
2183  s->m_name = "SetupRoot";
2184  s->m_on_value = "root";
2185  s->m_off_value = "no_root";
2186  s->m_default_value = true;
2187  s->m_priority_value = false;
2188
2189  m_defs.push_back (s);
2190
2191  s = new StrategyDef;
2192  s->m_keyword = "setup";
2193  s->m_name = "SetupCleanup";
2194  s->m_on_value = "cleanup";
2195  s->m_off_value = "no_cleanup";
2196  s->m_default_value = true;
2197  s->m_priority_value = false;
2198
2199  m_defs.push_back (s);
2200
2201  s = new StrategyDef;
2202  s->m_keyword = "structure";
2203  s->m_name = "VersionDirectory";
2204  s->m_on_value = "with_version_directory";
2205  s->m_off_value = "without_version_directory";
2206  if (Cmt::get_current_structuring_style () != without_version_directory)
2207    {
2208      s->m_default_value = true;
2209      s->m_priority_value = false;
2210    }
2211  else
2212    {
2213      s->m_default_value = false;
2214      s->m_priority_value = true;
2215    }
2216
2217  m_defs.push_back (s);
2218}
2219
2220/**----------------------------------------------------------
2221   Find a strategy definition by its name
2222 */
2223StrategyDef* StrategyMgr::find_strategy (const cmt_string& name)
2224{
2225  static StrategyMgr& me = instance ();
2226
2227  int i;
2228
2229  for (i = 0; i < me.m_defs.size (); i++)
2230    {
2231      StrategyDef* def = me.m_defs[i];
2232      if (def->m_name == name)
2233        {
2234          return (def);
2235        }
2236    }
2237
2238  return (0);
2239}
2240
2241/**----------------------------------------------------------
2242   Retreive the default value defined for a given strategy
2243 */
2244bool StrategyMgr::get_default_strategy (const cmt_string& name)
2245{
2246  StrategyDef* def = find_strategy (name);
2247  if (def == 0) return (false);
2248  return (def->m_default_value);
2249}
2250
2251/**----------------------------------------------------------
2252   Retreive the priority value defined for a given strategy
2253   This value is used when two children of a project request two conflicting strategy values
2254 */
2255bool StrategyMgr::get_priority_strategy (const cmt_string& name)
2256{
2257  StrategyDef* def = find_strategy (name);
2258  if (def == 0) return (false);
2259  return (def->m_priority_value);
2260}
2261
2262/**----------------------------------------------------------
2263   Return the vector of all existing strategy definitions
2264 */
2265StrategyDef::StrategyDefs& StrategyMgr::get_definitions ()
2266{
2267  static StrategyMgr& me = instance ();
2268
2269  return (me.m_defs);
2270}
2271
2272//-----------------------------------------------------------
2273Strategy::Strategy ()
2274{
2275  clear ();
2276}
2277
2278//-----------------------------------------------------------
2279void Strategy::clear ()
2280{
2281  m_definition = 0;
2282  m_specified = false;
2283  m_specified_value = false;
2284  m_value = false;
2285  m_on_tag = 0;
2286  m_off_tag = 0;
2287}
2288
2289/**----------------------------------------------------------
2290   Specify a new value for this strategy.
2291   This only happens when a strategy statement is met in a project file or in a requirements file.
2292 */
2293void Strategy::set (StrategyDef* definition, bool value, const cmt_string& project_name)
2294{
2295  //cerr << "Setting strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
2296
2297  m_definition = definition;
2298  m_specified = true;
2299  m_specified_value = value;
2300
2301  update (definition, value, project_name);
2302}
2303
2304/**----------------------------------------------------------
2305   Change the effective value for this strategy.
2306   This has no impact on to the specified value.
2307   This will adapt the tag settings
2308 */
2309void Strategy::update (StrategyDef* definition, bool value, const cmt_string& project_name)
2310{
2311  //cerr << "Updating strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
2312
2313  m_value = value;
2314  m_definition = definition;
2315
2316  cmt_string to_tag_name = project_name;
2317  cmt_string to_untag_name = project_name;
2318
2319  to_tag_name += "_";
2320  to_untag_name += "_";
2321
2322  if (m_value)
2323    {
2324      to_tag_name += m_definition->m_on_value;
2325      to_untag_name += m_definition->m_off_value;
2326    }
2327  else
2328    {
2329      to_tag_name += m_definition->m_off_value;
2330      to_untag_name += m_definition->m_on_value;
2331    }
2332
2333  m_on_tag = Tag::find (to_tag_name);
2334  m_off_tag = Tag::find (to_untag_name);
2335
2336  if (m_on_tag == 0) 
2337    {
2338      m_on_tag = Tag::add (to_tag_name, PriorityConfig, "PROJECT", 0);
2339      m_off_tag = Tag::add (to_untag_name, PriorityConfig, "PROJECT", 0);
2340
2341      m_on_tag->add_tag_exclude (m_off_tag);
2342      m_off_tag->add_tag_exclude (m_on_tag);
2343    }
2344
2345  m_off_tag->unmark ();
2346  m_on_tag->mark ();
2347}
2348//-----------------------------------------------------------
2349const cmt_string& StrategyDef::get_default_value () const
2350{
2351  if (m_default_value)
2352    {
2353      return (m_on_value);
2354    }
2355  else
2356    {
2357      return (m_off_value);
2358    }
2359}
2360//-----------------------------------------------------------
2361void Project::set_author (const cmt_string& name)
2362{
2363  cout<<"set_author"<<name<<endl;     
2364  this->m_author = name;
2365}
2366//-----------------------------------------------------------
2367const cmt_string& Project::get_author () const
2368{
2369  return (m_author);
2370}
2371//-----------------------------------------------------------
2372void Project::project_author_action (const CmtSystem::cmt_string_vector& words)
2373{
2374  if (m_author != "") m_author += "\n";
2375  for (int i = 1; i < words.size (); i++)
2376    {
2377      const cmt_string& w = words[i];
2378     
2379      if (i > 1) m_author += " ";
2380      m_author += w; 
2381    }
2382}
2383//-----------------------------------------------------------
2384Use*  Project::get_use () const
2385{
2386    return m_use;   
2387} 
2388//-----------------------------------------------------------
2389void  Project::set_use (Use* use)
2390{ 
2391    this->m_use = use;
2392}
2393//-----------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.