source: CMT/v1r20p20070517/source/cmt_project.cxx

Last change on this file was 411, checked in by arnault, 17 years ago

Management of the -quiet option
Bug fixing in cmt_cvs.cxx
CL 329

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