source: CMT/v1r20p20080222/source/cmt_project.cxx @ 615

Last change on this file since 615 was 437, checked in by rybkin, 16 years ago

See C.L. 342

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