source: CMT/v1r20b1/source/cmt_project.cxx @ 325

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

see C.L. 320

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