source: CMT/HEAD/source/cmt_project.cxx @ 515

Last change on this file since 515 was 515, checked in by rybkin, 15 years ago

See C.L. 404

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