source: CMT/v1r18p20050901/source/cmt_project.cxx @ 608

Last change on this file since 608 was 84, checked in by arnault, 19 years ago

Fix cmt_cvs WRT structure strategy - see CL#279

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