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

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

See C.L. 415

  • Property svn:eol-style set to native
File size: 73.6 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
913  static Project::ProjectVector& Projects = Project::projects ();
914  const int size = Projects.size ();
915 
916  int offset (0);
917  int iuser (-1);
918  int ihome (-1);
919  for (int i = 0; i < 2; i++)
920    {
921      if (offset < size)
922        {
923          const cmt_string& name = Projects[offset].get_name ();
924          if (name == "CMTUSERCONTEXT")
925            {
926              iuser = offset;
927              ++offset;
928            }
929          else if (name == "CMTHOME")
930            {
931              ihome = offset;
932              ++offset;
933            }
934          else
935            break;
936        }
937    }
938
939  OrderedProjects.resize (size);
940
941  for (int i = 0; i < size; i++)
942    {
943      Project& p = Projects[i];
944      if (i >= offset)
945        p.m_order = -1;
946      else
947        p.m_order = -2;
948      p.m_visits = 0;
949    }
950
951  if (size == offset)
952    {
953      for (int i = 0; i < offset; i++)
954        {
955          Project* p = &(Projects[i]);
956          OrderedProjects[i] = p;
957        }
958      if (2 == offset)
959        {
960          OrderedProjects[0]->add_child (OrderedProjects[1]);
961          OrderedProjects[1]->add_parent (OrderedProjects[0]);
962          OrderedProjects[0]->update_strategies_from_children ();
963        }
964      return OrderedProjects;
965    }
966
967  Project* p = get_current ();
968
969  //  cerr << "get_current: " << p << " offset: " << offset << endl;
970  if (p == 0)
971    {
972      p = &(Projects[offset]);
973      //      p = &(Projects[0]);
974    }
975  //  cerr << "p: " << p << " offset: " << offset << " name: " << p->get_name () << endl;
976
977  int order (-1);
978
979  if ((p->get_name () != "CMTUSERCONTEXT") && (p->get_name () != "CMTHOME"))
980    {
981      ProjectPtrVector projs;
982      p->m_order = ++order;
983      //      p->m_visits++;
984      projs.push_back (p);
985     
986      visit (offset, order, projs);
987      //  visit (order, projs);
988    }
989  //  cerr << "order: " << order << endl;
990  //  int unordered = size - offset - (order + 1);
991
992  int beg (0);
993  if  (-1 != iuser)
994    {
995      OrderedProjects[0] = &(Projects[iuser]);
996      //      cerr << "OrderedProjects[0]: " << (OrderedProjects[0])->get_name () << endl;
997      ++beg;
998    }
999
1000  int noorder (0);
1001  for (int i = offset; i < size; i++)
1002    //  for (int i = 0; i < size; i++)
1003    {
1004      Project* p = &(Projects[i]);
1005      int j = p->m_order;
1006      if (-1 == j)
1007        {
1008          OrderedProjects[beg + order + 1 + noorder++] = p;
1009          //      cerr << "no: OrderedProjects[" << beg + order + noorder << "]: " << (OrderedProjects[beg + order + noorder])->get_name () << endl;
1010          //      OrderedProjects[order + 1 + noorder++] = p;
1011          /*
1012          if (CmtMessage::active (Verbose))
1013            CmtMessage::warning ("Not ordered project " + p->get_name () +
1014                                 " in path " + p->get_cmtpath_pwd () +
1015                                 " from " + p->get_cmtpath_source ());
1016          continue;
1017          */
1018        }
1019      else if  (-2 == j)
1020        {
1021        }
1022      else
1023        {
1024          OrderedProjects[beg + j] = p;
1025      //      OrderedProjects[j] = p;
1026          //      cerr << "OrderedProjects[" << beg + j << "]: " << (OrderedProjects[beg + j])->get_name () << endl;
1027        }
1028    }
1029
1030  if  (-1 != ihome)
1031    {
1032      OrderedProjects[size - 1] = &(Projects[ihome]);
1033    }
1034
1035  if  (-1 != iuser)
1036    {
1037      OrderedProjects[0]->add_child (OrderedProjects[1]);
1038      OrderedProjects[1]->add_parent (OrderedProjects[0]);
1039      OrderedProjects[0]->update_strategies_from_children ();
1040    }
1041
1042  if  (-1 != ihome)
1043    {
1044      /*
1045      cerr << "beg: " << beg << " order: " << order << endl;
1046      cerr << "noorder: " << noorder << " size - offset: " << size - offset << endl;
1047      */
1048      if (noorder != size - offset)
1049        {  // the last ordered project
1050          OrderedProjects[beg + order]->add_child (OrderedProjects[size - 1]);
1051          OrderedProjects[size - 1]->add_parent (OrderedProjects[beg + order]);
1052          OrderedProjects[beg + order]->update_strategies_from_children ();
1053        }
1054      else
1055        {
1056          OrderedProjects[size - 2]->add_child (OrderedProjects[size - 1]);
1057          OrderedProjects[size - 1]->add_parent (OrderedProjects[size - 2]);
1058          OrderedProjects[size - 2]->update_strategies_from_children ();
1059        }
1060    }
1061
1062  return OrderedProjects;
1063}
1064
1065/*----------------------------------------------------------*/
1066void Project::clear_all ()
1067{
1068  static ProjectVector& Projects = projects ();
1069
1070  for (int i = 0; i < Projects.size (); i++)
1071    {
1072      Project& project = Projects[i];
1073      project.clear ();
1074    }
1075
1076  Projects.clear ();
1077}
1078
1079/*----------------------------------------------------------*/
1080void Project::show_all ()
1081{
1082  const Project::ProjectPtrVector& Ordered = Project::ordered_projects ();
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  Project* p = get_current ();
1092
1093  if (p == 0)
1094    {
1095      if (Ordered.size () == 0) return;
1096
1097      p = Ordered[0];
1098    }
1099  /*
1100  static Project::ProjectVector& Projects = Project::projects ();
1101 
1102  for (int i = 0; i < Projects.size (); i++)
1103    {
1104      Project& p = Projects[i];
1105      p.m_visited = false;
1106    }
1107
1108  Project* p = get_current ();
1109
1110  if (p == 0)
1111    {
1112      if (Projects.size () == 0) return;
1113
1114      p = &(Projects[0]);
1115    }
1116  */
1117
1118  p->show ();
1119}
1120
1121/*----------------------------------------------------------*/
1122void Project::show_container ()
1123{
1124  Project* p = get_current ();
1125
1126  if (p == 0) return;
1127  Use* use = &(p->m_container);
1128  if (use->get_package_name () == "") return;
1129
1130          if (!use->located ())
1131            {
1132              CmtMessage::warning ("container " + use->get_package_name ()
1133                                   + " " + use->version + " " + use->path
1134                                   + " not found");
1135              /*
1136              if (!Cmt::get_quiet ())
1137                {
1138                  cout << "# package " << use->get_package_name () <<
1139                    " " << use->version << " " << use->path <<
1140                    " not found" <<
1141                    endl;
1142                }
1143              */
1144              CmtError::set (CmtError::package_not_found, use->get_package_name ());
1145            }
1146          else
1147            {
1148              static const cmt_string empty;
1149              cmt_string p = use->real_path;
1150              if (use->path != "")
1151                {
1152                  int pos = p.find_last_of (use->path);
1153                  if (pos != cmt_string::npos)
1154                    {
1155                      p.erase (pos);
1156                    }
1157                }
1158             
1159              cout << "container " << use->get_package_name ()
1160                   << " " << use->version;
1161
1162              if (CmtSystem::absolute_path (use->path))
1163                {
1164                  if (!Cmt::get_quiet ()) 
1165                    {
1166                      cout << " (" << use->path << ")";
1167                    }
1168                }
1169              else
1170                {
1171                  cout << " " << use->path;
1172                }
1173
1174              if (!Cmt::get_quiet ()) 
1175                {
1176                  if (p != "") cout << " (" << p << ")";
1177                  if (use->auto_imports == Off) cout << " (no_auto_imports)";
1178                }
1179
1180              cout << endl;
1181            }
1182}
1183/*----------------------------------------------------------*/
1184void Project::show_specified_strategies_for_all ()
1185{
1186  static ProjectVector& Projects = projects ();
1187
1188  for (int i = 0; i < Projects.size (); i++)
1189    {
1190      const Project& project = Projects[i];
1191      project.show_specified_strategies ();
1192    }
1193}
1194
1195/*----------------------------------------------------------*/
1196class VisitorForShowPaths : public IProjectVisitor
1197{
1198public:
1199  VisitorForShowPaths ()
1200  {
1201  }
1202
1203  void pre (Project* p)
1204  {
1205    const cmt_string& w = p->get_cmtpath_pwd ();
1206    const cmt_string& s = p->get_cmtpath_source ();
1207
1208    if (s == "default path") return;
1209
1210    if (CmtSystem::test_directory (w))
1211      {
1212        cout << "# Add path " << w << " from " << s << endl;
1213      }
1214  }
1215
1216  void in (Project* p)
1217  {
1218    const cmt_string& w = p->get_cmtpath_pwd ();
1219    const cmt_string& s = p->get_cmtpath_source ();
1220
1221    if (s == "default path") return;
1222
1223    if (CmtSystem::test_directory (w))
1224      {
1225        cout << "# Add path " << w << " from " << s << endl;
1226      }
1227  }
1228
1229  void in_again (Project* p)
1230  {
1231    const cmt_string& w = p->get_cmtpath_pwd ();
1232    const cmt_string& s = p->get_cmtpath_source ();
1233
1234    if (s == "default path") return;
1235
1236    if (CmtSystem::test_directory (w))
1237      {
1238        cout << "# Remove path " << w << " from " << s << endl;
1239        cout << "# Add path " << w << " from " << s << endl;
1240      }
1241  }
1242
1243  void post (Project* p)
1244  {
1245  }
1246};
1247
1248/*----------------------------------------------------------*/
1249void Project::show_paths (const CmtSystem::cmt_string_vector& arguments)
1250//void Project::show_paths ()
1251{
1252  if (arguments.size () == 0)
1253    {
1254      const ProjectPtrVector& Ordered = Project::ordered_projects ();
1255      for (int i = 0; i < Ordered.size (); i++)
1256        {
1257          const Project* p = Ordered[i];
1258          const cmt_string& w = p->get_cmtpath_pwd ();
1259          const cmt_string& s = p->get_cmtpath_source ();
1260         
1261          if (s == "default path") continue;
1262         
1263          if (CmtSystem::test_directory (w))
1264            {
1265              cout << "# Add path " << w << " from " << s << endl;
1266            }
1267        }
1268    }
1269  else if (arguments.size () == 1 && cmt_string (arguments[0]) == "-d")
1270    {
1271      const ProjectVector& Projects = projects ();
1272      for (int i = 0; i < Projects.size (); i++)
1273        {
1274          Project& p = Projects[i];
1275          const cmt_string& w = p.get_cmtpath_pwd ();
1276          const cmt_string& s = p.get_cmtpath_source ();
1277         
1278          if (s == "default path") continue;
1279         
1280          if (CmtSystem::test_directory (w))
1281            {
1282              cout << "# Create path " << w << " from " << s << endl;
1283            }
1284        }
1285      /*
1286      VisitorForShowPaths visitor;
1287      start_visit (visitor);
1288      */
1289    }
1290  else
1291    CmtMessage::error ("show_paths: unexpected argument(s)");
1292}
1293
1294//----------------------------------------------------------
1295const cmt_string& Project::get_project_file_name ()
1296{
1297  static const cmt_string name = "project.cmt";
1298
1299  return (name);
1300}
1301
1302//----------------------------------------------------------
1303void Project::fill_selection (int depth, CmtSystem::cmt_string_vector& path_selections)
1304{
1305  static ProjectPtrVector Ordered = Project::ordered_projects ();
1306  for (int i = 0; i < Ordered.size (); i++)
1307    {
1308      const Project* project = Ordered[i];
1309
1310      const cmt_string& p = project->get_cmtpath ();
1311      const cmt_string& pwd = project->get_cmtpath_pwd ();
1312      const cmt_string& p_real = project->get_cmtpath_real ();
1313      const cmt_string& src = project->get_cmtpath_source ();
1314      /*
1315  static ProjectVector& Projects = projects ();
1316
1317  for (int i = 0; i < Projects.size (); i++)
1318    {
1319      Project& project = Projects[i];
1320
1321      const cmt_string& p = project.get_cmtpath ();
1322      const cmt_string& pwd = project.get_cmtpath_pwd ();
1323      const cmt_string& p_real = project.get_cmtpath_real ();
1324      const cmt_string& src = project.get_cmtpath_source ();
1325      */
1326      if (src != "default path")
1327        {
1328          if (depth > 0)
1329            {
1330              cmt_string& s1 = path_selections.add ();
1331              s1 = p;
1332              if (pwd != p)
1333                {
1334                  cmt_string& s2 = path_selections.add ();
1335                  s2 = pwd;
1336                }
1337              if (p_real != p && p_real != pwd)
1338                {
1339                  cmt_string& s3 = path_selections.add ();
1340                  s3 = p_real;
1341                }
1342              if (src != "CMTHOME" && src != "CMTUSERCONTEXT")
1343                depth--;
1344
1345              if (depth == 0) break;
1346            }
1347        }
1348    }
1349}
1350
1351//----------------------------------------------------------
1352void Project::broadcast (IProjectAction& action)
1353{
1354  static ProjectPtrVector Projects = Project::ordered_projects ();
1355
1356  for (int i = 0; i < Projects.size (); i++)
1357    {
1358      const Project* project = Projects[i];
1359
1360      if (!action.run (*project)) break;
1361    }
1362  /*
1363  static ProjectVector& Projects = projects ();
1364
1365  for (int i = 0; i < Projects.size (); i++)
1366    {
1367      const Project& project = Projects[i];
1368
1369      if (!action.run (project)) break;
1370    }
1371  */
1372}
1373
1374//----------------------------------------------------------
1375void Project::reverse_broadcast (IProjectAction& action)
1376{
1377  static ProjectPtrVector Projects = Project::ordered_projects ();
1378
1379  for (int i = (Projects.size () - 1); i >= 0; i--)
1380    {
1381      const Project* project = Projects[i];
1382
1383      if (!action.run (*project)) break;
1384    }
1385  /*
1386  static ProjectVector& Projects = projects ();
1387
1388  for (int i = (Projects.size () - 1); i >= 0; i--)
1389    {
1390      const Project& project = Projects[i];
1391
1392      if (!action.run (project)) break;
1393    }
1394  */
1395}
1396
1397//----------------------------------------------------------
1398void Project::scan_paths (PathScanner& scanner, PathScanner::actor& a)
1399{
1400  static ProjectVector& Projects = projects ();
1401
1402  int i;
1403
1404  for (i = 0; i < Projects.size (); i++)
1405    {
1406      Project& p  = Projects[i];
1407      p.m_visited = false;
1408    }
1409
1410  for (i = 0; i < Projects.size (); i++)
1411    {
1412      const Project& project = Projects[i];
1413       
1414      const cmt_string& p = project.m_cmtpath;
1415      scanner.scan_path (p, a);
1416    }
1417}
1418
1419//----------------------------------------------------------
1420void Project::scan_paths_for_package (PathScanner& scanner, const cmt_string& name)
1421{
1422  static ProjectVector& Projects = projects ();
1423
1424  bool found (false);
1425  for (int i = 0; i < Projects.size (); i++)
1426    {
1427      const Project& project = Projects[i];
1428
1429      const cmt_string& p = project.m_cmtpath;
1430      if (scanner.scan_package (p, name))
1431        found = true;
1432    }
1433
1434  if (!found)
1435    CmtError::set (CmtError::package_not_found, name);
1436}
1437
1438//----------------------------------------------------------
1439cmt_string Project::find_in_cmt_paths (const cmt_string& path)
1440{
1441  const cmt_string pwd = CmtSystem::pwd ();
1442
1443  // In case there are symlinks
1444  cmt_string path_real;
1445  //cerr << "realpath_: find_in_cmt_paths" << endl;
1446  CmtSystem::realpath_ (path, path_real);
1447
1448  static ProjectVector& Projects = projects ();
1449
1450  for (int i = 0; i < Projects.size (); i++)
1451    {
1452      const Project& project = Projects[i];
1453
1454      const cmt_string& p = project.m_cmtpath;
1455      const cmt_string& p_real = project.m_cmtpath_real;
1456      const cmt_string& w = project.m_cmtpath_pwd;
1457      const cmt_string& s = project.m_cmtpath_source;
1458
1459      if (s == "default path") continue;
1460
1461      if (CmtSystem::test_directory (p))
1462        {
1463//        if (path.find (p) != cmt_string::npos)
1464//          {
1465//            return (p);
1466//          }
1467
1468          if (path_real.find (p_real) != cmt_string::npos)
1469            {
1470              return (p);
1471            }
1472
1473          // To become the current area, a path must correspond to the current package
1474          if (path.find (w) != cmt_string::npos)
1475            {
1476              return (p);
1477            }
1478        }
1479
1480      if (p == w) continue;
1481
1482      if (CmtSystem::test_directory (w))
1483        {
1484          if (path.find (w) != cmt_string::npos)
1485            {
1486              return (w);
1487            }
1488        }
1489    }
1490
1491  return ("");
1492}
1493
1494//----------------------------------------------------------
1495void Project::visit (IProjectVisitor& visitor)
1496{
1497  if (m_visited) return;
1498  m_visited = true;
1499
1500  int i;
1501
1502  for (i = 0; i < get_children_size (); i++)
1503    {
1504      Project* child = get_child (i);
1505
1506      if (child->visited ()) continue;
1507
1508      visitor.in (child);
1509    }
1510
1511  for (i = 0; i < m_children.size (); i++)
1512    {
1513      Project* child = m_children[i];
1514      child->visit (visitor);
1515    }
1516}
1517
1518//----------------------------------------------------------
1519void Project::visit (IProjectVisitor& visitor, ProjectPtrVector& projects)
1520{
1521  int size = projects.size ();
1522  if (0 == size) return;
1523
1524  ProjectPtrVector children;
1525  for (int j = 0; j < size; j++)
1526    {
1527      Project* p = projects[j];
1528      if (20 == p->m_visits)
1529        continue;
1530      for (int i = 0; i < p->get_children_size (); i++)
1531        {
1532          Project* child = p->get_child (i);
1533          if (0 == child->m_visits)       
1534            visitor.in (child);
1535          else
1536            visitor.in_again (child);
1537          child->m_visits++;
1538          children.push_back (child);
1539        }
1540    }
1541
1542  visit (visitor, children);
1543}
1544
1545//----------------------------------------------------------
1546/**
1547 *  Visit the projects tree and order the projects.
1548 *  Order is the projects upon which the project depends directly,
1549 *  then the direct dependencies of the of the first dependency, of the second
1550 *  dependency and so on. That is first left to right, then downwards.
1551 *  @param offset the offset from which to use all the projects
1552 *  @param order the order of the last project visited
1553 *  @param projs vector of projects to visit and order
1554 */
1555void Project::visit (const int offset, int& order, ProjectPtrVector& projs)
1556{
1557  int size = projs.size ();
1558  if (0 == size) return;
1559  static ProjectVector& all = Project::projects ();
1560  /*
1561  cerr << "@ visit: " << order;
1562  for (int j = 0; j < size; j++)
1563    {
1564      Project* p = projs[j];
1565      cerr << " " << p->get_name ();
1566    }
1567  cerr << " @" << endl;
1568  */
1569  ProjectPtrVector children;
1570  for (int j = 0; j < size; j++)
1571    {
1572      Project* p = projs[j];
1573      p->m_visits++;
1574      // Avoid looping in case of circular project dependencies
1575      if (500 <= p->m_visits)
1576        //      if (100 <= p->m_visits)
1577        continue;
1578      for (int i = 0; i < p->get_children_size (); i++)
1579        {
1580          Project* child = p->get_child (i);
1581          const int chorder = child->m_order;
1582          const int porder = p->m_order;
1583          /*
1584          cerr << ">>> " << p->get_name () << " child: " << i << endl;
1585          cerr << child->get_name () << " in: " << chorder << endl;
1586          */
1587          if (-2 == chorder)
1588            continue;
1589          else if (-1 == chorder)
1590            { // not ordered yet, i.e. visited for the first time
1591              child->m_order = ++order;
1592            }
1593          else if (0 == chorder)
1594            { // the project we started with, i. e. the current project:
1595              //     o circular dependency
1596              //     o do want to keep it first no matter what
1597              if (CmtMessage::active (Verbose))
1598                CmtMessage::warning ("Circular dependency on project: "
1599                                     + child->get_name ()
1600                                     + " " + child->get_release ()
1601                                     + " " + child->get_cmtpath ());
1602            }
1603          else if ((0 < chorder) && (chorder < porder))
1604            { // ordered already, want to put it after the parent in the order
1605              for (int k = offset; k < all.size (); k++)
1606                {
1607                  Project& q = all[k];
1608                  if (&q == child)
1609                    {// the child we are putting after the parent in the order
1610                      q.m_order = porder;
1611                      //     cerr << "Moved back: " << q.get_name () << " order: " << q.m_order << endl;
1612                    }
1613                  else if ((chorder < q.m_order) && (q.m_order <= porder))
1614                    q.m_order--;
1615                }
1616            }
1617          //      cerr << child->get_name () << " out: " << child->m_order << endl;
1618          //      child->m_visits++;
1619          bool unknown (true);
1620          for (int j = 0; j < children.size (); j++)
1621            {
1622              if (children[j] == child)
1623                {
1624                  unknown = false;
1625                  break;
1626                }
1627            }
1628          if (unknown)
1629            {
1630              children.push_back (child);
1631            }
1632        }
1633    }
1634
1635  visit (offset, order, children);
1636}
1637
1638//----------------------------------------------------------
1639void Project::start_visit (IProjectVisitor& visitor)
1640{
1641  static Project::ProjectVector& Projects = Project::projects ();
1642 
1643  for (int i = 0; i < Projects.size (); i++)
1644    {
1645      Project& p = Projects[i];
1646      p.m_visited = false;
1647      p.m_visits = 0;
1648    }
1649
1650  Project* p = get_current ();
1651
1652  if (p == 0)
1653    {
1654      if (Projects.size () == 0) return;
1655
1656      p = &(Projects[0]);
1657    }
1658
1659  //  visitor.pre (p);
1660  //p->visit (visitor);
1661  //  visitor.post (p);
1662  visitor.in (p);
1663  p->m_visits++;
1664  ProjectPtrVector projs;
1665  projs.push_back (p);
1666  visit (visitor, projs);
1667}
1668
1669//----------------------------------------------------------
1670class VisitorForFillCMTPATH : public IProjectVisitor
1671{
1672public:
1673  VisitorForFillCMTPATH (cmt_string& buffer) : m_buffer (buffer)
1674  {
1675    buffer = "path CMTPATH \"\" \n";
1676  }
1677
1678  void pre (Project* p)
1679  {
1680    const cmt_string& w = p->get_cmtpath_pwd ();
1681    const cmt_string& s = p->get_cmtpath_source ();
1682
1683    if (s == "default path") return;
1684
1685    if (CmtSystem::test_directory (w))
1686      {
1687        m_buffer += "path_append CMTPATH \"";
1688        m_buffer += w;
1689        m_buffer += "\" \n";
1690      }
1691  }
1692
1693  void in (Project* p)
1694  {
1695    const cmt_string& w = p->get_cmtpath_pwd ();
1696    const cmt_string& s = p->get_cmtpath_source ();
1697
1698    if (s == "default path") return;
1699
1700    if (CmtSystem::test_directory (w))
1701      {
1702        m_buffer += "path_append CMTPATH \"";
1703        m_buffer += w;
1704        m_buffer += "\" \n";
1705      }
1706  }
1707
1708  void in_again (Project* p)
1709  {
1710    const cmt_string& w = p->get_cmtpath_pwd ();
1711    const cmt_string& s = p->get_cmtpath_source ();
1712
1713    if (s == "default path") return;
1714
1715    if (CmtSystem::test_directory (w))
1716      {
1717        m_buffer += "path_remove CMTPATH \"";
1718        m_buffer += w;
1719        m_buffer += "\" \n";
1720        m_buffer += "path_append CMTPATH \"";
1721        m_buffer += w;
1722        m_buffer += "\" \n";
1723      }
1724  }
1725
1726  void post (Project* p)
1727  {
1728    //cerr << "Buffer = " << m_buffer << endl;
1729  }
1730
1731private:
1732  cmt_string& m_buffer;
1733
1734};
1735
1736//----------------------------------------------------------
1737void Project::fill_cmtpaths (cmt_string& buffer)
1738{
1739  /*
1740    Try to re-create all CMTPATH items from project definitions.
1741    The goal is to generate CMTPATH even if this EV was not pre-set
1742    which is the case when CMTPROJECTPATH is only used
1743  */
1744
1745  /*
1746  VisitorForFillCMTPATH visitor (buffer);
1747
1748  start_visit (visitor);
1749  */
1750  const ProjectPtrVector Ordered = Project::ordered_projects ();
1751
1752  buffer = "path CMTPATH \"\" \n";
1753  for (int i = 0; i < Ordered.size (); i++)
1754    {
1755      const Project* p = Ordered[i];
1756      const cmt_string& w = p->get_cmtpath_pwd ();
1757      const cmt_string& s = p->get_cmtpath_source ();
1758     
1759      if (s == "default path") continue;
1760     
1761      if (CmtSystem::test_directory (w))
1762        {
1763          buffer += "path_append CMTPATH \"";
1764          buffer += w;
1765          buffer += "\" \n";
1766        }
1767    }
1768}
1769
1770//----------------------------------------------------------
1771Project::Project () : m_name (""), m_author("")
1772{
1773  clear ();
1774}
1775
1776//----------------------------------------------------------
1777const cmt_string& Project::get_name () const
1778{
1779  return (m_name);
1780}
1781
1782//----------------------------------------------------------
1783const cmt_string& Project::get_release () const
1784{
1785  return (m_release);
1786}
1787
1788//----------------------------------------------------------
1789const cmt_string& Project::get_container_name () const
1790{
1791  return (m_container_name);
1792}
1793
1794//----------------------------------------------------------
1795const cmt_string& Project::get_container_version () const
1796{
1797  return (m_container_version);
1798}
1799
1800//----------------------------------------------------------
1801const cmt_string& Project::get_container_path () const
1802{
1803  return (m_container_path);
1804}
1805
1806//----------------------------------------------------------
1807const Use& Project::get_container () const
1808{
1809  return (m_container);
1810}
1811
1812//----------------------------------------------------------
1813const cmt_string& Project::get_cmtpath () const
1814{
1815  return (m_cmtpath);
1816}
1817
1818//----------------------------------------------------------
1819const cmt_string& Project::get_cmtpath_real () const
1820{
1821  return (m_cmtpath_real);
1822}
1823
1824//----------------------------------------------------------
1825const cmt_string& Project::get_cmtpath_pwd () const
1826{
1827  return (m_cmtpath_pwd);
1828}
1829
1830//----------------------------------------------------------
1831const cmt_string& Project::get_cmtpath_source () const
1832{
1833  return (m_cmtpath_source);
1834}
1835
1836//----------------------------------------------------------
1837int Project::get_children_size () const
1838{
1839  return (m_children.size ());
1840}
1841
1842//----------------------------------------------------------
1843Project* Project::get_child (int index) const
1844{
1845  if (index < 0) return (0);
1846  if (index >= m_children.size ()) return (0);
1847  return (m_children[index]);
1848}
1849
1850//----------------------------------------------------------
1851bool Project::visited () const
1852{
1853  return (m_visited);
1854}
1855
1856//----------------------------------------------------------
1857void Project::set_name (const cmt_string& name)
1858{
1859  m_name = name;
1860}
1861
1862//----------------------------------------------------------
1863void Project::set_release (const cmt_string& release)
1864{
1865  m_release = release;
1866}
1867
1868//----------------------------------------------------------
1869void Project::set_container_name (const cmt_string& name)
1870{
1871  m_container_name = name;
1872}
1873
1874//----------------------------------------------------------
1875void Project::set_container_version (const cmt_string& container_version)
1876{
1877  m_container_version = container_version;
1878}
1879
1880//----------------------------------------------------------
1881void Project::set_container_path (const cmt_string& container_path)
1882{
1883  m_container_path = container_path;
1884}
1885
1886//----------------------------------------------------------
1887void Project::set_cmtpath (const cmt_string& path)
1888{
1889  m_cmtpath = path;
1890}
1891
1892//----------------------------------------------------------
1893void Project::set_cmtpath_real (const cmt_string& path)
1894{
1895  m_cmtpath_real = path;
1896}
1897
1898//----------------------------------------------------------
1899void Project::set_cmtpath_pwd (const cmt_string& path)
1900{
1901  m_cmtpath_pwd = path;
1902}
1903
1904//----------------------------------------------------------
1905void Project::set_cmtpath_source (const cmt_string& source)
1906{
1907  m_cmtpath_source = source;
1908}
1909
1910//----------------------------------------------------------
1911void Project::clear ()
1912{
1913  m_name    = "";
1914  m_release = "";
1915  m_cmtpath = "";
1916  m_cmtpath_real = "";
1917  m_cmtpath_pwd    = "";
1918  m_cmtpath_source = "";
1919  m_use            = 0;
1920
1921  m_parents.clear ();
1922  m_children.clear ();
1923
1924  m_configured = false;
1925
1926  m_strategies.clear ();
1927}
1928
1929//----------------------------------------------------------
1930bool Project::has_parents () const
1931{
1932  return ((m_parents.size () > 0));
1933}
1934
1935//----------------------------------------------------------
1936bool Project::has_parent (Project* p) const
1937{
1938  if (p == 0) return (false);
1939  if (p == this) return (false);
1940
1941  const cmt_string& name = p->get_name ();
1942
1943  int i;
1944
1945  for (i = 0; i < m_parents.size (); i++)
1946    {
1947      const Project* parent = m_parents[i];
1948      if (parent == 0) continue;
1949
1950      if (parent->get_name () == name)
1951        {
1952          // registered as a parent
1953          return (true);
1954        }
1955
1956      if (parent->has_parent (p))
1957        {
1958          // recurse
1959          return (true);
1960        }
1961    }
1962
1963  return (false);
1964}
1965
1966//----------------------------------------------------------
1967bool Project::has_child (Project* p) const
1968{
1969  if (p == 0) return (false);
1970  if (p == this) return (false);
1971
1972  const cmt_string& name = p->get_name ();
1973
1974  int i;
1975
1976  for (i = 0; i < m_children.size (); i++)
1977    {
1978      const Project* child = m_children[i];
1979      if (child == 0) continue;
1980
1981      if (child->get_name () == name)
1982        {
1983          // registered as a child
1984          return (true);
1985        }
1986
1987      if (child->has_child (p))
1988        {
1989          // recurse
1990          return (true);
1991        }
1992    }
1993
1994  return (false);
1995}
1996
1997//----------------------------------------------------------
1998void Project::add_parent (Project* p)
1999{
2000  if (p == 0) return;
2001  if (p == this) return;
2002
2003  //cerr << "Adding parent " << p->get_name () << " to " << m_name << endl;
2004
2005  if (has_child (p)) return;
2006  if (has_parent (p)) return;
2007
2008  m_parents.push_back (p);
2009}
2010
2011//----------------------------------------------------------
2012void Project::add_child (Project* p)
2013{
2014  if (p == 0) return;
2015  if (p == this) return;
2016
2017  if (has_child (p)) return;
2018  if (has_parent (p)) return;
2019
2020  m_children.push_back (p);
2021}
2022
2023//----------------------------------------------------------
2024void Project::configure ()
2025{
2026  if (m_configured) return;
2027  m_configured = true;
2028
2029  set_default_strategy ("SetupConfig");
2030  set_default_strategy ("SetupRoot");
2031  set_default_strategy ("SetupCleanup");
2032  set_default_strategy ("SetupScripts");
2033  set_default_strategy ("BuildPrototypes");
2034  set_default_strategy ("InstallArea");
2035  set_default_strategy ("VersionDirectory");
2036}
2037
2038/**---------------------------------------------------------
2039   A container statement is met in the project file
2040*/
2041void Project::container_action (const CmtSystem::cmt_string_vector& words)
2042//void Project::container_action (const cmt_string& name, const cmt_string& version)
2043{
2044  //
2045  // complete syntax : "container <package> <version> <path>" 
2046  // minimal syntax  : "container <package>"
2047  //
2048  //  o if <version> is omitted then take any version available
2049  //  o <version> can be specified using "v*" or "v<n>r*" or "v<n>r<m>p*"
2050  //
2051  //  o the notation "v*" is preferred to omission (particularly since
2052  //    omission does not permit <path>)
2053  //
2054  Use* use = &m_container;
2055  use->~Use ();
2056  if (words.size () < 2) return;
2057
2058  CmtSystem::cmt_string_vector ewords;
2059  for (int i = 1; i < words.size (); i++)
2060    {
2061      const cmt_string& w = words[i];
2062      cmt_string ew = w;
2063
2064      Symbol::expand (ew);
2065      if (ew != w)
2066        {
2067          CmtSystem::cmt_string_vector ws;
2068          CmtSystem::split (ew, " ", ws);
2069
2070          for (int j = 0; j < ws.size (); ++j)
2071            {
2072              ewords.push_back (ws[j]);
2073            }
2074        }
2075      else
2076        {
2077          ewords.push_back (w);
2078        }
2079    }
2080
2081  cmt_string name, version, path;
2082  if (ewords.size () > 0) name = ewords[0];
2083  if (ewords.size () > 1) version = ewords[1];
2084  if (ewords.size () > 2) path = ewords[2];
2085
2086  if (name != "")
2087    {
2088      use->set (name, version, path);
2089      use->get_package ()->remove_use (use);
2090      if (use->move_to ())
2091        {
2092          cmt_string use_real;
2093          bool ok (false);
2094          if (!CmtSystem::absolute_path (use->path))
2095            {
2096              ok = CmtSystem::realpath_ (use->real_path, use_real);
2097            }
2098          else
2099            {
2100              ok = CmtSystem::realpath_ (use->path, use_real);
2101            }
2102          if (ok && use_real.find (m_cmtpath_real) != 0)
2103            {
2104              use->~Use ();
2105            }
2106        }
2107      CmtSystem::cd (m_cmtpath_pwd + CmtSystem::file_separator () + "cmt");
2108    }
2109  //  cerr << CmtSystem::pwd () << endl;
2110
2111  set_container_name (name);
2112  set_container_version (version);
2113  set_container_path (path);
2114}
2115
2116/**---------------------------------------------------------
2117   A use statement is met in the project file
2118*/
2119void Project::use_action (const cmt_string& name, const cmt_string& release)
2120{
2121  if (Cmt::get_debug ())
2122    {
2123      cout << "Use action " << name << " " << release << endl;
2124    }
2125
2126  // A project with its release is specified
2127  //
2128  // Is this project already visible?
2129  // If not: look for it
2130  //   + get CMTPROJECTPATH
2131  //   + search from all entries of CMTPROJECTPATH : p(i)/<name>/<release>
2132  //   + when found, this should become a new CMTPATH entry
2133  //   +             the new project is then parsed ... etc...
2134
2135  // First test it wilcard is used
2136  int v = -1;
2137  int r = -1;
2138  int p = -1;
2139  cmt_string new_release = release;
2140  CmtSystem::is_version_directory (new_release, v, r, p); 
2141  bool use_has_wild_card = (v == -1) || (r == -1) || (p == -1);
2142  if (use_has_wild_card)
2143    {
2144      cmt_string selected_release = "";
2145
2146      if (select_release(name, new_release,selected_release))
2147        {
2148          // cerr <<"selected_release: "<<selected_release<<endl;   
2149          new_release = selected_release;
2150        }         
2151    }
2152
2153  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2154  cmt_string sep;
2155  sep = CmtSystem::path_separator ();
2156
2157  CmtSystem::cmt_string_vector items;
2158  CmtSystem::split (cmtprojectpath, sep, items);
2159
2160  bool found = false;
2161
2162  for (int i = 0; i < items.size (); i++)
2163    {
2164      const cmt_string& item = items[i];
2165      cmt_string p = item;
2166      p += CmtSystem::file_separator ();
2167      p += name;
2168      if (new_release != "")
2169        {
2170          p += CmtSystem::file_separator ();
2171          p += new_release;
2172        }
2173
2174      if (CmtSystem::test_directory (p))
2175        {
2176          //cerr << "Project directory " << p << " exists " << endl;
2177
2178          found = true;
2179
2180          IProjectFactory& factory = ProjectFactory::instance ();
2181
2182          factory.create_project (name, p, "ProjectPath", this);
2183
2184          break;
2185        }
2186    }
2187
2188  if (!found)
2189    {
2190      Project* p = Project::find_by_name (name);
2191
2192      if (p != 0)
2193        {
2194          found = true;
2195          p->add_parent (this);
2196          add_child (p);
2197
2198          update_strategies_from_children ();
2199        }
2200    }
2201   
2202  if (!found && (cmtprojectpath != ""))
2203    {
2204      CmtMessage::warning ("Project " + name + " " + release + " requested by " + m_name + " not found in CMTPROJECTPATH");
2205      //      cerr << "#CMT> Project " << name << " " << release << " requested by " << m_name << " not found in CMTPROJECTPATH" << endl;
2206    }
2207}
2208
2209//---------------------------------------------------------
2210bool Project::select_release(const cmt_string& name, const cmt_string& release, cmt_string& result)
2211{
2212  cmt_string selected_release = "";
2213
2214  int v = -1;
2215  int r = -1;
2216  int p = -1;
2217  CmtSystem::is_version_directory (release, v, r, p); 
2218
2219  int selected_v = -1;
2220  int selected_r = -1;
2221  int selected_p = -1;
2222  CmtSystem::cmt_string_vector releases = get_project_releases(name);
2223  for (int j = 0; j < releases.size (); j++)
2224    {
2225      int new_v = -1;
2226      int new_r = -1;
2227      int new_p = -1;
2228      CmtSystem::is_version_directory (releases[j], new_v, new_r, new_p);
2229      if (v == -1)
2230        {
2231          if (selected_v < new_v)
2232            {
2233              selected_v = new_v;
2234              selected_r = -1;
2235              selected_p = -1;
2236              selected_release = releases[j];
2237            }
2238          else if (selected_v == new_v)
2239            {
2240              // We compare the r
2241              if (selected_r < new_r)
2242                {
2243                  selected_r = new_r;
2244                  selected_p = -1;
2245                  selected_release = releases[j];                               
2246                }
2247              else if (selected_r == new_r)
2248                {
2249                  // We compare the p
2250                  if (selected_p < new_p)
2251                    {
2252                      selected_p = new_p;
2253                      selected_release = releases[j];                               
2254                    }
2255                  // else if ? not possible                                                           
2256                }                               
2257            }
2258        }
2259      else if (r == -1)
2260        {
2261          if (v == new_v)
2262            {
2263              // We compare the r                                                     
2264              if (selected_r < new_r)
2265                {
2266                  selected_r = new_r;
2267                  selected_p = -1;
2268                  selected_release = releases[j];                               
2269                }
2270              else if (selected_r == new_r)
2271                { 
2272                  // We compare the p
2273                  if (selected_p < new_p)
2274                    {
2275                      selected_p = new_p;
2276                      selected_release = releases[j];                               
2277                    }
2278                  // else if ? not possible
2279                }
2280            }
2281        }
2282      else if (p == -1)
2283        {
2284          if ((v == new_v) && (r == new_r))
2285            { 
2286              // We compare the p
2287              if (selected_p < new_p)
2288                {
2289                  selected_p = new_p;
2290                  selected_release = releases[j];                               
2291                }
2292              // else if ? not possible
2293            }       
2294        }       
2295
2296      //cerr << "v:" << new_v << ", r:" << new_r << ", p:" << new_p << endl;             
2297      //cerr << "req v:" << v << ", req r:" << r << ", req p:" << p << endl;       
2298
2299    }
2300
2301  // cerr << "selected release: " << selected_release << endl; 
2302
2303  if (selected_release == "") return false;
2304
2305  result = selected_release;   
2306
2307  return (true);
2308}
2309
2310//---------------------------------------------------------
2311const CmtSystem::cmt_string_vector Project::get_project_releases (const cmt_string& name) const
2312{
2313  CmtSystem::cmt_string_vector releases;
2314  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2315
2316  static cmt_string sep = CmtSystem::path_separator ();
2317
2318  CmtSystem::cmt_string_vector items;
2319  CmtSystem::split (cmtprojectpath, sep, items);   
2320
2321  for (int i = 0; i < items.size (); i++)
2322    {
2323      const cmt_string& item = items[i];
2324      cmt_string p = item;
2325      p += CmtSystem::file_separator ();
2326      p += name;
2327
2328      if (CmtSystem::test_directory (p))
2329        { 
2330          CmtSystem::cmt_string_vector directories;
2331          CmtSystem::scan_dir (p, directories);
2332
2333          for (int j = 0; j < directories.size (); j++)
2334            {
2335              if  (CmtSystem::test_directory(directories[j]))
2336                {
2337                  cmt_string release;
2338                  CmtSystem:: basename(directories[j], release);
2339
2340                  if (CmtSystem::is_version_directory(release))
2341                    {                             
2342                      cmt_string& name_entry = releases.add ();
2343                      name_entry = release; 
2344                    }             
2345                }                           
2346            }                           
2347        }
2348    }
2349  return (releases);
2350}
2351
2352//----------------------------------------------------------
2353Project& Project::operator = (const Project& other)
2354{
2355  m_name = other.m_name;
2356  m_cmtpath = other.m_cmtpath;
2357  m_cmtpath_real = other.m_cmtpath_real;
2358  m_cmtpath_pwd = other.m_cmtpath_pwd;
2359  m_cmtpath_source = other.m_cmtpath_source;
2360
2361  return (*this);
2362}
2363
2364//----------------------------------------------------------
2365bool Project::operator == (const cmt_string& name) const
2366{
2367  return ((m_name == name));
2368}
2369
2370//----------------------------------------------------------
2371bool Project::operator != (const cmt_string& name) const
2372{
2373  return ((m_name != name));
2374}
2375
2376//----------------------------------------------------------
2377void Project::show ()
2378{
2379  if (m_visited) return;
2380  m_visited = true;
2381
2382  static int level = 0;
2383
2384  bool is_current = false;
2385
2386  //  cmt_string here = CmtSystem::pwd ();
2387  // In case there are symlinks
2388  cmt_string here_real;
2389  CmtSystem::realpath_ (CmtSystem::pwd (), here_real);
2390
2391  //  if (here.find (m_cmtpath) == 0)
2392  if (here_real.find (m_cmtpath_real) == 0) 
2393    {
2394      if (m_cmtpath_source != "default path")
2395        {
2396          is_current = true;
2397        }
2398    }
2399
2400  for (int tab = 0; tab < level; tab++) cout << "  ";
2401  cout << m_name << " " << (m_name != "CMTUSERCONTEXT" && m_name != "CMTHOME" ? m_release : "v0") << " (in " << m_cmtpath << ")";
2402  //  cout << m_name << " " << m_release << " (in " << m_cmtpath << ")";
2403
2404  if (is_current) cout << " (current)";
2405
2406  int i;
2407
2408  for (i = 0; i < m_parents.size (); i++)
2409    {
2410      Project* p = m_parents[i];
2411      if (p == 0) continue;
2412      cout << " P=" << p->get_name ();
2413    }
2414
2415  for (i = 0; i < m_children.size (); i++)
2416    {
2417      Project* p = m_children[i];
2418      if (p == 0) continue;
2419      cout << " C=" << p->get_name ();
2420    }
2421
2422  cout << endl;
2423
2424/*
2425  if (m_visited) return;
2426
2427  m_visited = true;
2428*/
2429
2430  for (i = 0; i < m_children.size (); i++)
2431    {
2432      Project* p = m_children[i];
2433      if (p == 0) continue;
2434      level++;
2435      p->show ();
2436      level--;
2437    }
2438}
2439
2440
2441//----------------------------------------------------------
2442void Project::show_specified_strategies () const
2443{
2444  int i;
2445
2446  for (i = 0; i < m_strategies.size (); i++)
2447    {
2448      const Strategy& s = m_strategies[i];
2449      if (s.m_specified)
2450        {
2451          const StrategyDef* def = s.m_definition;
2452 
2453          cout << "# Project " << m_name
2454               << " sets " << def->m_keyword
2455               << " strategy to " << ((s.m_value) ? def->m_on_value : def->m_off_value);
2456
2457          if (s.m_context != "")
2458            {
2459              cout << " (from package " << s.m_context << ")";
2460            }
2461
2462          cout << endl;
2463        }
2464    }
2465}
2466
2467//----------------------------------------------------------
2468bool Project::has_strategy (const StrategyDef* definition) const
2469{
2470  int i;
2471
2472  for (i = 0; i < m_strategies.size (); i++)
2473    {
2474      const Strategy& s = m_strategies[i];
2475      if (s.m_definition == definition)
2476        {
2477          return (true);
2478        }
2479    }
2480
2481  return (false);
2482}
2483
2484//----------------------------------------------------------
2485bool Project::get_strategy (const cmt_string& name) const
2486{
2487  static StrategyMgr& mgr = StrategyMgr::instance ();
2488
2489  StrategyDef* def = mgr.find_strategy (name);
2490  if (def == 0)
2491    {
2492      CmtMessage::warning ("strategy " + name + " undefined");
2493      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2494      return (false);
2495    }
2496
2497  return (get_strategy (def));
2498}
2499
2500//----------------------------------------------------------
2501bool Project::is_specified (const StrategyDef* definition) const
2502{
2503  int i;
2504
2505  for (i = 0; i < m_strategies.size (); i++)
2506    {
2507      Strategy& s = m_strategies[i];
2508      if (s.m_definition == definition)
2509        {
2510          // This strategy is applied in this project
2511          return (s.m_specified);
2512        }
2513    }
2514
2515  // This strategy is not applied in this project
2516  return (false);
2517}
2518
2519//----------------------------------------------------------
2520bool Project::get_strategy (const StrategyDef* def) const
2521{
2522  int i;
2523
2524  for (i = 0; i < m_strategies.size (); i++)
2525    {
2526      Strategy& s = m_strategies[i];
2527      if (s.m_definition == def)
2528        {
2529          // This strategy is applied in this project
2530          if (s.m_specified)
2531            {
2532              return (s.m_specified_value);
2533            }
2534          return (s.m_value);
2535        }
2536    }
2537
2538  // This strategy is not applied in this project
2539  return (def->m_default_value);
2540}
2541
2542//----------------------------------------------------------
2543void Project::set_default_strategy (const cmt_string& name)
2544{
2545  static StrategyMgr& mgr = StrategyMgr::instance ();
2546
2547  StrategyDef* def = mgr.find_strategy (name);
2548  if (def == 0)
2549    {
2550      CmtMessage::warning ("strategy " + name + " undefined");
2551      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2552      return;
2553    }
2554
2555  update_strategy (def, def->m_default_value);
2556}
2557
2558
2559//----------------------------------------------------------
2560void Project::set_strategy (const cmt_string& name, const cmt_string& value, const cmt_string& context)
2561{
2562  static StrategyMgr& mgr = StrategyMgr::instance ();
2563
2564  StrategyDef* def = mgr.find_strategy (name);
2565  if (def == 0)
2566    {
2567      CmtMessage::warning ("strategy " + name + " undefined");
2568      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2569      return;
2570    }
2571
2572  bool b_value = false;
2573
2574  if (value == def->m_on_value)
2575    {
2576      b_value = true;
2577    }
2578  else if (value == def->m_off_value)
2579    {
2580      b_value = false;
2581    }
2582  else
2583    {
2584      CmtMessage::warning ("requested strategy value " + value + " undefined in strategy " + name);
2585      //      cerr << "#CMT> requested strategy value " << value << " undefined in strategy " << name << endl;
2586      return;
2587    }
2588
2589  set_strategy (def, b_value, context);
2590}
2591
2592//----------------------------------------------------------
2593void Project::set_strategy (StrategyDef* definition, bool b_value, const cmt_string& context)
2594{
2595  bool need_strategy = true;
2596
2597  int i;
2598
2599  for (i = 0; i < m_strategies.size (); i++)
2600    {
2601      Strategy& s = m_strategies[i];
2602      if (s.m_definition == definition)
2603        {
2604          // This strategy is already applied in this project. Let's change it's value
2605          s.set (definition, b_value, get_name ());
2606          if (context != "")
2607            {
2608              if (s.m_context != "") s.m_context += " ";
2609              s.m_context += context;
2610            }
2611          need_strategy = false;
2612          break;
2613        }
2614    }
2615
2616  if (need_strategy)
2617    {
2618      // This strategy is not yet applied in this project.
2619
2620      Strategy& s = m_strategies.add ();
2621      s.clear ();
2622      s.set (definition, b_value, get_name ());
2623      s.m_context = context;
2624    }
2625 
2626  for (i = 0; i < m_parents.size (); i++)
2627    {
2628      Project* project = m_parents[i];
2629
2630      project->update_strategy (definition, b_value);
2631    }
2632}
2633
2634/**----------------------------------------------------------
2635   The strategy value is changed because of indirect influences
2636   - default strategy at initialization time
2637   - change in the children
2638   - change in the children list
2639
2640   (This is not a specification : see the set_strategy method)
2641*/
2642void Project::update_strategy (StrategyDef* definition, bool b_value)
2643{
2644  bool need_strategy = true;
2645  bool specified = false;
2646
2647  int i;
2648
2649  for (i = 0; i < m_strategies.size (); i++)
2650    {
2651      Strategy& s = m_strategies[i];
2652      if (s.m_definition == definition)
2653        {
2654          need_strategy = false;
2655
2656          if (!s.m_specified)
2657            {
2658              // This strategy is already applied in this project. Let's change it's value
2659              s.update (definition, b_value, get_name ());
2660            }
2661          else
2662            {
2663              specified = true;
2664            }
2665          break;
2666        }
2667    }
2668
2669  if (need_strategy)
2670    {
2671      // This strategy is not yet applied in this project.
2672
2673      Strategy& s = m_strategies.add ();
2674      s.clear ();
2675      s.update (definition, b_value, get_name ());
2676    }
2677
2678  if (!specified)
2679    {
2680      for (i = 0; i < m_parents.size (); i++)
2681        {
2682          Project* project = m_parents[i];
2683
2684          project->update_strategy (definition, b_value);
2685        }
2686    }
2687}
2688
2689/**----------------------------------------------------------
2690   At least one of the children has changed this strategy
2691   Or the list of children has changed.
2692   We need to update the strategy value accordingly
2693   This will not change the specified value for this strategy
2694*/
2695void Project::update_strategy_from_children (StrategyDef* definition)
2696{
2697  // If this strategy is specified we don't care what happens from the children
2698
2699  //cerr << "Updating strategy " << definition->m_name << " from children for project " << m_name << endl;
2700
2701  int i;
2702
2703  for (i = 0; i < m_strategies.size (); i++)
2704    {
2705      Strategy& s = m_strategies[i];
2706      if (s.m_definition == definition)
2707        {
2708          // This strategy is applied in this project.
2709
2710          if (s.m_specified)
2711            {
2712              // There will be no impact since the strategy is specified
2713
2714              //cerr << "This strategy is specified in this project" << endl;
2715              return;
2716            }
2717
2718          break;
2719        }
2720    }
2721
2722  // The strategy is not specified locally so we will now figure out
2723  // which strategy has to be considered from the mixture of specifications
2724  // from all children.
2725
2726  // Algorithm:
2727  // - We consider children by pairs
2728  // - a child that specifies its strategy wins over a child that does not
2729  // - when the two children have the same level of priority we consider the priority value
2730
2731  Project* selected = 0;
2732  bool selected_is_specified = false;
2733  bool selected_value = definition->m_default_value;
2734
2735  for (i = 0; i < m_children.size (); i++)
2736    {
2737      Project* p = m_children[i];
2738
2739      //cerr << "Checking strategy for child " << p->get_name () << endl;
2740
2741      bool is_specified = p->is_specified (definition);
2742      bool value = p->get_strategy (definition);
2743
2744      if (selected == 0)
2745        {
2746          selected = p;
2747          selected_is_specified = is_specified;
2748          selected_value = value;
2749          continue;
2750        }
2751
2752      if (is_specified == selected_is_specified)
2753        {
2754          if (selected_value != value)
2755            {
2756              // same level of priority but different values -> we must decide
2757              bool priority_value = definition->m_priority_value;
2758              if (value == priority_value)
2759                {
2760                  selected = p;
2761                  selected_is_specified = is_specified;
2762                  selected_value = value;
2763                }
2764            }
2765        }
2766      else
2767        {
2768          if (is_specified)
2769            {
2770              selected = p;
2771              selected_is_specified = is_specified;
2772              selected_value = value;
2773            }
2774        }
2775    }
2776
2777  update_strategy (definition, selected_value); 
2778}
2779
2780/**----------------------------------------------------------
2781   At least one of the children has changed its strategies
2782   Or the list of children has changed.
2783   We need to update the strategy values accordingly
2784   This will not change the specified values
2785*/
2786void Project::update_strategies_from_children ()
2787{
2788  StrategyDef::StrategyDefs& defs = StrategyMgr::get_definitions ();
2789
2790  //cerr << "Updating strategies from children for project " << m_name << endl;
2791
2792  int i;
2793
2794  for (i = 0; i < defs.size (); i++)
2795    {
2796      StrategyDef* def = defs[i];
2797     
2798      update_strategy_from_children (def);
2799    }
2800
2801  for (i = 0; i < m_parents.size (); i++)
2802    {
2803      Project* p = m_parents[i];
2804      p->update_strategies_from_children ();
2805    }
2806}
2807
2808/**----------------------------------------------------------
2809   The StrategyMgr singleton
2810*/
2811StrategyMgr& StrategyMgr::instance ()
2812{
2813  static StrategyMgr me;
2814  return (me);
2815}
2816
2817/**----------------------------------------------------------
2818   The StrategyMgr constructor
2819   Here are primarily constructed all strategy definitions
2820*/
2821StrategyMgr::StrategyMgr ()
2822{
2823  m_defs.clear ();
2824
2825  StrategyDef* s;
2826
2827  s = new StrategyDef;
2828  s->m_keyword = "build";
2829  s->m_name = "BuildPrototypes";
2830  s->m_on_value = "prototypes";
2831  s->m_off_value = "no_prototypes";
2832  s->m_default_value = true;
2833  s->m_priority_value = false;
2834
2835  m_defs.push_back (s);
2836
2837  s = new StrategyDef;
2838  s->m_keyword = "build";
2839  s->m_name = "InstallArea";
2840  s->m_on_value = "with_installarea";
2841  s->m_off_value = "without_installarea";
2842  s->m_default_value = false;
2843  s->m_priority_value = true;
2844
2845  m_defs.push_back (s);
2846
2847  s = new StrategyDef;
2848  s->m_keyword = "setup";
2849  s->m_name = "SetupConfig";
2850  s->m_on_value = "config";
2851  s->m_off_value = "no_config";
2852  s->m_default_value = true;
2853  s->m_priority_value = false;
2854
2855  m_defs.push_back (s);
2856
2857  s = new StrategyDef;
2858  s->m_keyword = "setup";
2859  s->m_name = "SetupRoot";
2860  s->m_on_value = "root";
2861  s->m_off_value = "no_root";
2862  s->m_default_value = true;
2863  s->m_priority_value = false;
2864
2865  m_defs.push_back (s);
2866
2867  s = new StrategyDef;
2868  s->m_keyword = "setup";
2869  s->m_name = "SetupCleanup";
2870  s->m_on_value = "cleanup";
2871  s->m_off_value = "no_cleanup";
2872  s->m_default_value = true;
2873  s->m_priority_value = false;
2874
2875  m_defs.push_back (s);
2876
2877  s = new StrategyDef;
2878  s->m_keyword = "setup";
2879  s->m_name = "SetupScripts";
2880  s->m_on_value = "scripts";
2881  s->m_off_value = "no_scripts";
2882  s->m_default_value = true;
2883  s->m_priority_value = false;
2884
2885  m_defs.push_back (s);
2886
2887  s = new StrategyDef;
2888  s->m_keyword = "structure";
2889  s->m_name = "VersionDirectory";
2890  s->m_on_value = "with_version_directory";
2891  s->m_off_value = "without_version_directory";
2892  if (Cmt::get_current_structuring_style () != without_version_directory)
2893    {
2894      s->m_default_value = true;
2895      s->m_priority_value = false;
2896    }
2897  else
2898    {
2899      s->m_default_value = false;
2900      s->m_priority_value = true;
2901    }
2902
2903  m_defs.push_back (s);
2904}
2905
2906/**----------------------------------------------------------
2907   Find a strategy definition by its name
2908*/
2909StrategyDef* StrategyMgr::find_strategy (const cmt_string& name)
2910{
2911  static StrategyMgr& me = instance ();
2912
2913  int i;
2914
2915  for (i = 0; i < me.m_defs.size (); i++)
2916    {
2917      StrategyDef* def = me.m_defs[i];
2918      if (def->m_name == name)
2919        {
2920          return (def);
2921        }
2922    }
2923
2924  return (0);
2925}
2926
2927/**----------------------------------------------------------
2928   Retreive the default value defined for a given strategy
2929*/
2930bool StrategyMgr::get_default_strategy (const cmt_string& name)
2931{
2932  StrategyDef* def = find_strategy (name);
2933  if (def == 0) return (false);
2934  return (def->m_default_value);
2935}
2936
2937/**----------------------------------------------------------
2938   Retreive the priority value defined for a given strategy
2939   This value is used when two children of a project request two conflicting strategy values
2940*/
2941bool StrategyMgr::get_priority_strategy (const cmt_string& name)
2942{
2943  StrategyDef* def = find_strategy (name);
2944  if (def == 0) return (false);
2945  return (def->m_priority_value);
2946}
2947
2948/**----------------------------------------------------------
2949   Return the vector of all existing strategy definitions
2950*/
2951StrategyDef::StrategyDefs& StrategyMgr::get_definitions ()
2952{
2953  static StrategyMgr& me = instance ();
2954
2955  return (me.m_defs);
2956}
2957
2958//-----------------------------------------------------------
2959Strategy::Strategy ()
2960{
2961  clear ();
2962}
2963
2964//-----------------------------------------------------------
2965void Strategy::clear ()
2966{
2967  m_definition = 0;
2968  m_specified = false;
2969  m_specified_value = false;
2970  m_value = false;
2971  m_on_tag = 0;
2972  m_off_tag = 0;
2973}
2974
2975/**----------------------------------------------------------
2976   Specify a new value for this strategy.
2977   This only happens when a strategy statement is met in a project file or in a requirements file.
2978*/
2979void Strategy::set (StrategyDef* definition, bool value, const cmt_string& project_name)
2980{
2981  //cerr << "Setting strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
2982
2983  m_definition = definition;
2984  m_specified = true;
2985  m_specified_value = value;
2986
2987  update (definition, value, project_name);
2988}
2989
2990/**----------------------------------------------------------
2991   Change the effective value for this strategy.
2992   This has no impact on to the specified value.
2993   This will adapt the tag settings
2994*/
2995void Strategy::update (StrategyDef* definition, bool value, const cmt_string& project_name)
2996{
2997  //cerr << "Updating strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
2998
2999  m_value = value;
3000  m_definition = definition;
3001
3002  cmt_string to_tag_name = project_name;
3003  cmt_string to_untag_name = project_name;
3004
3005  to_tag_name += "_";
3006  to_untag_name += "_";
3007
3008  if (m_value)
3009    {
3010      to_tag_name += m_definition->m_on_value;
3011      to_untag_name += m_definition->m_off_value;
3012    }
3013  else
3014    {
3015      to_tag_name += m_definition->m_off_value;
3016      to_untag_name += m_definition->m_on_value;
3017    }
3018
3019  m_on_tag = Tag::find (to_tag_name);
3020  m_off_tag = Tag::find (to_untag_name);
3021
3022  if (m_on_tag == 0 || m_off_tag == 0)
3023    {
3024      m_on_tag = Tag::add (to_tag_name, PriorityConfig, "PROJECT", 0);
3025      m_off_tag = Tag::add (to_untag_name, PriorityConfig, "PROJECT", 0);
3026
3027      m_on_tag->add_tag_exclude (m_off_tag);
3028      m_off_tag->add_tag_exclude (m_on_tag);
3029    }
3030
3031  m_off_tag->unmark ();
3032  m_on_tag->mark ();
3033}
3034
3035//-----------------------------------------------------------
3036const cmt_string& StrategyDef::get_default_value () const
3037{
3038  if (m_default_value)
3039    {
3040      return (m_on_value);
3041    }
3042  else
3043    {
3044      return (m_off_value);
3045    }
3046}
3047
3048//-----------------------------------------------------------
3049void Project::set_author (const cmt_string& name)
3050{
3051  // cerr << "set_author" << name << endl;     
3052  this->m_author = name;
3053}
3054
3055//-----------------------------------------------------------
3056const cmt_string& Project::get_author () const
3057{
3058  return (m_author);
3059}
3060
3061//-----------------------------------------------------------
3062void Project::project_author_action (const CmtSystem::cmt_string_vector& words)
3063{
3064  if (m_author != "") m_author += "\n";
3065
3066  for (int i = 1; i < words.size (); i++)
3067    {
3068      const cmt_string& w = words[i];
3069     
3070      if (i > 1) m_author += " ";
3071      m_author += w; 
3072    }
3073}
3074
3075//-----------------------------------------------------------
3076Use*  Project::get_use () const
3077{
3078  return m_use;   
3079} 
3080
3081//-----------------------------------------------------------
3082void  Project::set_use (Use* use)
3083{ 
3084  this->m_use = use;
3085}
3086
3087//-----------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.