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

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

See C.L. 412

  • Property svn:eol-style set to native
File size: 73.4 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  for (int i = 0; i < Projects.size (); i++)
1425    {
1426      const Project& project = Projects[i];
1427
1428      const cmt_string& p = project.m_cmtpath;
1429      scanner.scan_package (p, name);
1430    }
1431}
1432
1433//----------------------------------------------------------
1434cmt_string Project::find_in_cmt_paths (const cmt_string& path)
1435{
1436  const cmt_string pwd = CmtSystem::pwd ();
1437
1438  // In case there are symlinks
1439  cmt_string path_real;
1440  //cerr << "realpath_: find_in_cmt_paths" << endl;
1441  CmtSystem::realpath_ (path, path_real);
1442
1443  static ProjectVector& Projects = projects ();
1444
1445  for (int i = 0; i < Projects.size (); i++)
1446    {
1447      const Project& project = Projects[i];
1448
1449      const cmt_string& p = project.m_cmtpath;
1450      const cmt_string& p_real = project.m_cmtpath_real;
1451      const cmt_string& w = project.m_cmtpath_pwd;
1452      const cmt_string& s = project.m_cmtpath_source;
1453
1454      if (s == "default path") continue;
1455
1456      if (CmtSystem::test_directory (p))
1457        {
1458//        if (path.find (p) != cmt_string::npos)
1459//          {
1460//            return (p);
1461//          }
1462
1463          if (path_real.find (p_real) != cmt_string::npos)
1464            {
1465              return (p);
1466            }
1467
1468          // To become the current area, a path must correspond to the current package
1469          if (path.find (w) != cmt_string::npos)
1470            {
1471              return (p);
1472            }
1473        }
1474
1475      if (p == w) continue;
1476
1477      if (CmtSystem::test_directory (w))
1478        {
1479          if (path.find (w) != cmt_string::npos)
1480            {
1481              return (w);
1482            }
1483        }
1484    }
1485
1486  return ("");
1487}
1488
1489//----------------------------------------------------------
1490void Project::visit (IProjectVisitor& visitor)
1491{
1492  if (m_visited) return;
1493  m_visited = true;
1494
1495  int i;
1496
1497  for (i = 0; i < get_children_size (); i++)
1498    {
1499      Project* child = get_child (i);
1500
1501      if (child->visited ()) continue;
1502
1503      visitor.in (child);
1504    }
1505
1506  for (i = 0; i < m_children.size (); i++)
1507    {
1508      Project* child = m_children[i];
1509      child->visit (visitor);
1510    }
1511}
1512
1513//----------------------------------------------------------
1514void Project::visit (IProjectVisitor& visitor, ProjectPtrVector& projects)
1515{
1516  int size = projects.size ();
1517  if (0 == size) return;
1518
1519  ProjectPtrVector children;
1520  for (int j = 0; j < size; j++)
1521    {
1522      Project* p = projects[j];
1523      if (20 == p->m_visits)
1524        continue;
1525      for (int i = 0; i < p->get_children_size (); i++)
1526        {
1527          Project* child = p->get_child (i);
1528          if (0 == child->m_visits)       
1529            visitor.in (child);
1530          else
1531            visitor.in_again (child);
1532          child->m_visits++;
1533          children.push_back (child);
1534        }
1535    }
1536
1537  visit (visitor, children);
1538}
1539
1540//----------------------------------------------------------
1541/**
1542 *  Visit the projects tree and order the projects.
1543 *  Order is the projects upon which the project depends directly,
1544 *  then the direct dependencies of the of the first dependency, of the second
1545 *  dependency and so on. That is first left to right, then downwards.
1546 *  @param offset the offset from which to use all the projects
1547 *  @param order the order of the last project visited
1548 *  @param projs vector of projects to visit and order
1549 */
1550void Project::visit (const int offset, int& order, ProjectPtrVector& projs)
1551{
1552  int size = projs.size ();
1553  if (0 == size) return;
1554  static ProjectVector& all = Project::projects ();
1555  /*
1556  cerr << "@ visit: " << order;
1557  for (int j = 0; j < size; j++)
1558    {
1559      Project* p = projs[j];
1560      cerr << " " << p->get_name ();
1561    }
1562  cerr << " @" << endl;
1563  */
1564  ProjectPtrVector children;
1565  for (int j = 0; j < size; j++)
1566    {
1567      Project* p = projs[j];
1568      p->m_visits++;
1569      // Avoid looping in case of circular project dependencies
1570      if (500 <= p->m_visits)
1571        //      if (100 <= p->m_visits)
1572        continue;
1573      for (int i = 0; i < p->get_children_size (); i++)
1574        {
1575          Project* child = p->get_child (i);
1576          const int chorder = child->m_order;
1577          const int porder = p->m_order;
1578          /*
1579          cerr << ">>> " << p->get_name () << " child: " << i << endl;
1580          cerr << child->get_name () << " in: " << chorder << endl;
1581          */
1582          if (-2 == chorder)
1583            continue;
1584          else if (-1 == chorder)
1585            { // not ordered yet, i.e. visited for the first time
1586              child->m_order = ++order;
1587            }
1588          else if (0 == chorder)
1589            { // the project we started with, i. e. the current project:
1590              //     o circular dependency
1591              //     o do want to keep it first no matter what
1592              if (CmtMessage::active (Verbose))
1593                CmtMessage::warning ("Circular dependency on project: "
1594                                     + child->get_name ()
1595                                     + " " + child->get_release ()
1596                                     + " " + child->get_cmtpath ());
1597            }
1598          else if ((0 < chorder) && (chorder < porder))
1599            { // ordered already, want to put it after the parent in the order
1600              for (int k = offset; k < all.size (); k++)
1601                {
1602                  Project& q = all[k];
1603                  if (&q == child)
1604                    {// the child we are putting after the parent in the order
1605                      q.m_order = porder;
1606                      //     cerr << "Moved back: " << q.get_name () << " order: " << q.m_order << endl;
1607                    }
1608                  else if ((chorder < q.m_order) && (q.m_order <= porder))
1609                    q.m_order--;
1610                }
1611            }
1612          //      cerr << child->get_name () << " out: " << child->m_order << endl;
1613          //      child->m_visits++;
1614          bool unknown (true);
1615          for (int j = 0; j < children.size (); j++)
1616            {
1617              if (children[j] == child)
1618                {
1619                  unknown = false;
1620                  break;
1621                }
1622            }
1623          if (unknown)
1624            {
1625              children.push_back (child);
1626            }
1627        }
1628    }
1629
1630  visit (offset, order, children);
1631}
1632
1633//----------------------------------------------------------
1634void Project::start_visit (IProjectVisitor& visitor)
1635{
1636  static Project::ProjectVector& Projects = Project::projects ();
1637 
1638  for (int i = 0; i < Projects.size (); i++)
1639    {
1640      Project& p = Projects[i];
1641      p.m_visited = false;
1642      p.m_visits = 0;
1643    }
1644
1645  Project* p = get_current ();
1646
1647  if (p == 0)
1648    {
1649      if (Projects.size () == 0) return;
1650
1651      p = &(Projects[0]);
1652    }
1653
1654  //  visitor.pre (p);
1655  //p->visit (visitor);
1656  //  visitor.post (p);
1657  visitor.in (p);
1658  p->m_visits++;
1659  ProjectPtrVector projs;
1660  projs.push_back (p);
1661  visit (visitor, projs);
1662}
1663
1664//----------------------------------------------------------
1665class VisitorForFillCMTPATH : public IProjectVisitor
1666{
1667public:
1668  VisitorForFillCMTPATH (cmt_string& buffer) : m_buffer (buffer)
1669  {
1670    buffer = "path CMTPATH \"\" \n";
1671  }
1672
1673  void pre (Project* p)
1674  {
1675    const cmt_string& w = p->get_cmtpath_pwd ();
1676    const cmt_string& s = p->get_cmtpath_source ();
1677
1678    if (s == "default path") return;
1679
1680    if (CmtSystem::test_directory (w))
1681      {
1682        m_buffer += "path_append CMTPATH \"";
1683        m_buffer += w;
1684        m_buffer += "\" \n";
1685      }
1686  }
1687
1688  void in (Project* p)
1689  {
1690    const cmt_string& w = p->get_cmtpath_pwd ();
1691    const cmt_string& s = p->get_cmtpath_source ();
1692
1693    if (s == "default path") return;
1694
1695    if (CmtSystem::test_directory (w))
1696      {
1697        m_buffer += "path_append CMTPATH \"";
1698        m_buffer += w;
1699        m_buffer += "\" \n";
1700      }
1701  }
1702
1703  void in_again (Project* p)
1704  {
1705    const cmt_string& w = p->get_cmtpath_pwd ();
1706    const cmt_string& s = p->get_cmtpath_source ();
1707
1708    if (s == "default path") return;
1709
1710    if (CmtSystem::test_directory (w))
1711      {
1712        m_buffer += "path_remove CMTPATH \"";
1713        m_buffer += w;
1714        m_buffer += "\" \n";
1715        m_buffer += "path_append CMTPATH \"";
1716        m_buffer += w;
1717        m_buffer += "\" \n";
1718      }
1719  }
1720
1721  void post (Project* p)
1722  {
1723    //cerr << "Buffer = " << m_buffer << endl;
1724  }
1725
1726private:
1727  cmt_string& m_buffer;
1728
1729};
1730
1731//----------------------------------------------------------
1732void Project::fill_cmtpaths (cmt_string& buffer)
1733{
1734  /*
1735    Try to re-create all CMTPATH items from project definitions.
1736    The goal is to generate CMTPATH even if this EV was not pre-set
1737    which is the case when CMTPROJECTPATH is only used
1738  */
1739
1740  /*
1741  VisitorForFillCMTPATH visitor (buffer);
1742
1743  start_visit (visitor);
1744  */
1745  const ProjectPtrVector Ordered = Project::ordered_projects ();
1746
1747  buffer = "path CMTPATH \"\" \n";
1748  for (int i = 0; i < Ordered.size (); i++)
1749    {
1750      const Project* p = Ordered[i];
1751      const cmt_string& w = p->get_cmtpath_pwd ();
1752      const cmt_string& s = p->get_cmtpath_source ();
1753     
1754      if (s == "default path") continue;
1755     
1756      if (CmtSystem::test_directory (w))
1757        {
1758          buffer += "path_append CMTPATH \"";
1759          buffer += w;
1760          buffer += "\" \n";
1761        }
1762    }
1763}
1764
1765//----------------------------------------------------------
1766Project::Project () : m_name (""), m_author("")
1767{
1768  clear ();
1769}
1770
1771//----------------------------------------------------------
1772const cmt_string& Project::get_name () const
1773{
1774  return (m_name);
1775}
1776
1777//----------------------------------------------------------
1778const cmt_string& Project::get_release () const
1779{
1780  return (m_release);
1781}
1782
1783//----------------------------------------------------------
1784const cmt_string& Project::get_container_name () const
1785{
1786  return (m_container_name);
1787}
1788
1789//----------------------------------------------------------
1790const cmt_string& Project::get_container_version () const
1791{
1792  return (m_container_version);
1793}
1794
1795//----------------------------------------------------------
1796const cmt_string& Project::get_container_path () const
1797{
1798  return (m_container_path);
1799}
1800
1801//----------------------------------------------------------
1802const cmt_string& Project::get_cmtpath () const
1803{
1804  return (m_cmtpath);
1805}
1806
1807//----------------------------------------------------------
1808const cmt_string& Project::get_cmtpath_real () const
1809{
1810  return (m_cmtpath_real);
1811}
1812
1813//----------------------------------------------------------
1814const cmt_string& Project::get_cmtpath_pwd () const
1815{
1816  return (m_cmtpath_pwd);
1817}
1818
1819//----------------------------------------------------------
1820const cmt_string& Project::get_cmtpath_source () const
1821{
1822  return (m_cmtpath_source);
1823}
1824
1825//----------------------------------------------------------
1826int Project::get_children_size () const
1827{
1828  return (m_children.size ());
1829}
1830
1831//----------------------------------------------------------
1832Project* Project::get_child (int index) const
1833{
1834  if (index < 0) return (0);
1835  if (index >= m_children.size ()) return (0);
1836  return (m_children[index]);
1837}
1838
1839//----------------------------------------------------------
1840bool Project::visited () const
1841{
1842  return (m_visited);
1843}
1844
1845//----------------------------------------------------------
1846void Project::set_name (const cmt_string& name)
1847{
1848  m_name = name;
1849}
1850
1851//----------------------------------------------------------
1852void Project::set_release (const cmt_string& release)
1853{
1854  m_release = release;
1855}
1856
1857//----------------------------------------------------------
1858void Project::set_container_name (const cmt_string& name)
1859{
1860  m_container_name = name;
1861}
1862
1863//----------------------------------------------------------
1864void Project::set_container_version (const cmt_string& container_version)
1865{
1866  m_container_version = container_version;
1867}
1868
1869//----------------------------------------------------------
1870void Project::set_container_path (const cmt_string& container_path)
1871{
1872  m_container_path = container_path;
1873}
1874
1875//----------------------------------------------------------
1876void Project::set_cmtpath (const cmt_string& path)
1877{
1878  m_cmtpath = path;
1879}
1880
1881//----------------------------------------------------------
1882void Project::set_cmtpath_real (const cmt_string& path)
1883{
1884  m_cmtpath_real = path;
1885}
1886
1887//----------------------------------------------------------
1888void Project::set_cmtpath_pwd (const cmt_string& path)
1889{
1890  m_cmtpath_pwd = path;
1891}
1892
1893//----------------------------------------------------------
1894void Project::set_cmtpath_source (const cmt_string& source)
1895{
1896  m_cmtpath_source = source;
1897}
1898
1899//----------------------------------------------------------
1900void Project::clear ()
1901{
1902  m_name    = "";
1903  m_release = "";
1904  m_cmtpath = "";
1905  m_cmtpath_real = "";
1906  m_cmtpath_pwd    = "";
1907  m_cmtpath_source = "";
1908  m_use            = 0;
1909
1910  m_parents.clear ();
1911  m_children.clear ();
1912
1913  m_configured = false;
1914
1915  m_strategies.clear ();
1916}
1917
1918//----------------------------------------------------------
1919bool Project::has_parents () const
1920{
1921  return ((m_parents.size () > 0));
1922}
1923
1924//----------------------------------------------------------
1925bool Project::has_parent (Project* p) const
1926{
1927  if (p == 0) return (false);
1928  if (p == this) return (false);
1929
1930  const cmt_string& name = p->get_name ();
1931
1932  int i;
1933
1934  for (i = 0; i < m_parents.size (); i++)
1935    {
1936      const Project* parent = m_parents[i];
1937      if (parent == 0) continue;
1938
1939      if (parent->get_name () == name)
1940        {
1941          // registered as a parent
1942          return (true);
1943        }
1944
1945      if (parent->has_parent (p))
1946        {
1947          // recurse
1948          return (true);
1949        }
1950    }
1951
1952  return (false);
1953}
1954
1955//----------------------------------------------------------
1956bool Project::has_child (Project* p) const
1957{
1958  if (p == 0) return (false);
1959  if (p == this) return (false);
1960
1961  const cmt_string& name = p->get_name ();
1962
1963  int i;
1964
1965  for (i = 0; i < m_children.size (); i++)
1966    {
1967      const Project* child = m_children[i];
1968      if (child == 0) continue;
1969
1970      if (child->get_name () == name)
1971        {
1972          // registered as a child
1973          return (true);
1974        }
1975
1976      if (child->has_child (p))
1977        {
1978          // recurse
1979          return (true);
1980        }
1981    }
1982
1983  return (false);
1984}
1985
1986//----------------------------------------------------------
1987void Project::add_parent (Project* p)
1988{
1989  if (p == 0) return;
1990  if (p == this) return;
1991
1992  //cerr << "Adding parent " << p->get_name () << " to " << m_name << endl;
1993
1994  if (has_child (p)) return;
1995  if (has_parent (p)) return;
1996
1997  m_parents.push_back (p);
1998}
1999
2000//----------------------------------------------------------
2001void Project::add_child (Project* p)
2002{
2003  if (p == 0) return;
2004  if (p == this) return;
2005
2006  if (has_child (p)) return;
2007  if (has_parent (p)) return;
2008
2009  m_children.push_back (p);
2010}
2011
2012//----------------------------------------------------------
2013void Project::configure ()
2014{
2015  if (m_configured) return;
2016  m_configured = true;
2017
2018  set_default_strategy ("SetupConfig");
2019  set_default_strategy ("SetupRoot");
2020  set_default_strategy ("SetupCleanup");
2021  set_default_strategy ("SetupScripts");
2022  set_default_strategy ("BuildPrototypes");
2023  set_default_strategy ("InstallArea");
2024  set_default_strategy ("VersionDirectory");
2025}
2026
2027/**---------------------------------------------------------
2028   A container statement is met in the project file
2029*/
2030void Project::container_action (const CmtSystem::cmt_string_vector& words)
2031//void Project::container_action (const cmt_string& name, const cmt_string& version)
2032{
2033  //
2034  // complete syntax : "container <package> <version> <path>" 
2035  // minimal syntax  : "container <package>"
2036  //
2037  //  o if <version> is omitted then take any version available
2038  //  o <version> can be specified using "v*" or "v<n>r*" or "v<n>r<m>p*"
2039  //
2040  //  o the notation "v*" is preferred to omission (particularly since
2041  //    omission does not permit <path>)
2042  //
2043  Use* use = &m_container;
2044  use->~Use ();
2045  if (words.size () < 2) return;
2046
2047  CmtSystem::cmt_string_vector ewords;
2048  for (int i = 1; i < words.size (); i++)
2049    {
2050      const cmt_string& w = words[i];
2051      cmt_string ew = w;
2052
2053      Symbol::expand (ew);
2054      if (ew != w)
2055        {
2056          CmtSystem::cmt_string_vector ws;
2057          CmtSystem::split (ew, " ", ws);
2058
2059          for (int j = 0; j < ws.size (); ++j)
2060            {
2061              ewords.push_back (ws[j]);
2062            }
2063        }
2064      else
2065        {
2066          ewords.push_back (w);
2067        }
2068    }
2069
2070  cmt_string name, version, path;
2071  if (ewords.size () > 0) name = ewords[0];
2072  if (ewords.size () > 1) version = ewords[1];
2073  if (ewords.size () > 2) path = ewords[2];
2074
2075  if (name != "")
2076    {
2077      use->set (name, version, path);
2078      use->get_package ()->remove_use (use);
2079      if (use->move_to ())
2080        {
2081          cmt_string use_real;
2082          bool ok (false);
2083          if (!CmtSystem::absolute_path (use->path))
2084            {
2085              ok = CmtSystem::realpath_ (use->real_path, use_real);
2086            }
2087          else
2088            {
2089              ok = CmtSystem::realpath_ (use->path, use_real);
2090            }
2091          if (ok && use_real.find (m_cmtpath_real) != 0)
2092            {
2093              use->~Use ();
2094            }
2095        }
2096      CmtSystem::cd (m_cmtpath_pwd + CmtSystem::file_separator () + "cmt");
2097    }
2098  //  cerr << CmtSystem::pwd () << endl;
2099
2100  set_container_name (name);
2101  set_container_version (version);
2102  set_container_path (path);
2103}
2104
2105/**---------------------------------------------------------
2106   A use statement is met in the project file
2107*/
2108void Project::use_action (const cmt_string& name, const cmt_string& release)
2109{
2110  if (Cmt::get_debug ())
2111    {
2112      cout << "Use action " << name << " " << release << endl;
2113    }
2114
2115  // A project with its release is specified
2116  //
2117  // Is this project already visible?
2118  // If not: look for it
2119  //   + get CMTPROJECTPATH
2120  //   + search from all entries of CMTPROJECTPATH : p(i)/<name>/<release>
2121  //   + when found, this should become a new CMTPATH entry
2122  //   +             the new project is then parsed ... etc...
2123
2124  // First test it wilcard is used
2125  int v = -1;
2126  int r = -1;
2127  int p = -1;
2128  cmt_string new_release = release;
2129  CmtSystem::is_version_directory (new_release, v, r, p); 
2130  bool use_has_wild_card = (v == -1) || (r == -1) || (p == -1);
2131  if (use_has_wild_card)
2132    {
2133      cmt_string selected_release = "";
2134
2135      if (select_release(name, new_release,selected_release))
2136        {
2137          // cerr <<"selected_release: "<<selected_release<<endl;   
2138          new_release = selected_release;
2139        }         
2140    }
2141
2142  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2143  cmt_string sep;
2144  sep = CmtSystem::path_separator ();
2145
2146  CmtSystem::cmt_string_vector items;
2147  CmtSystem::split (cmtprojectpath, sep, items);
2148
2149  bool found = false;
2150
2151  for (int i = 0; i < items.size (); i++)
2152    {
2153      const cmt_string& item = items[i];
2154      cmt_string p = item;
2155      p += CmtSystem::file_separator ();
2156      p += name;
2157      if (new_release != "")
2158        {
2159          p += CmtSystem::file_separator ();
2160          p += new_release;
2161        }
2162
2163      if (CmtSystem::test_directory (p))
2164        {
2165          //cerr << "Project directory " << p << " exists " << endl;
2166
2167          found = true;
2168
2169          IProjectFactory& factory = ProjectFactory::instance ();
2170
2171          factory.create_project (name, p, "ProjectPath", this);
2172
2173          break;
2174        }
2175    }
2176
2177  if (!found)
2178    {
2179      Project* p = Project::find_by_name (name);
2180
2181      if (p != 0)
2182        {
2183          found = true;
2184          p->add_parent (this);
2185          add_child (p);
2186
2187          update_strategies_from_children ();
2188        }
2189    }
2190   
2191  if (!found && (cmtprojectpath != ""))
2192    {
2193      CmtMessage::warning ("Project " + name + " " + release + " requested by " + m_name + " not found in CMTPROJECTPATH");
2194      //      cerr << "#CMT> Project " << name << " " << release << " requested by " << m_name << " not found in CMTPROJECTPATH" << endl;
2195    }
2196}
2197
2198//---------------------------------------------------------
2199bool Project::select_release(const cmt_string& name, const cmt_string& release, cmt_string& result)
2200{
2201  cmt_string selected_release = "";
2202
2203  int v = -1;
2204  int r = -1;
2205  int p = -1;
2206  CmtSystem::is_version_directory (release, v, r, p); 
2207
2208  int selected_v = -1;
2209  int selected_r = -1;
2210  int selected_p = -1;
2211  CmtSystem::cmt_string_vector releases = get_project_releases(name);
2212  for (int j = 0; j < releases.size (); j++)
2213    {
2214      int new_v = -1;
2215      int new_r = -1;
2216      int new_p = -1;
2217      CmtSystem::is_version_directory (releases[j], new_v, new_r, new_p);
2218      if (v == -1)
2219        {
2220          if (selected_v < new_v)
2221            {
2222              selected_v = new_v;
2223              selected_r = -1;
2224              selected_p = -1;
2225              selected_release = releases[j];
2226            }
2227          else if (selected_v == new_v)
2228            {
2229              // We compare the r
2230              if (selected_r < new_r)
2231                {
2232                  selected_r = new_r;
2233                  selected_p = -1;
2234                  selected_release = releases[j];                               
2235                }
2236              else if (selected_r == new_r)
2237                {
2238                  // We compare the p
2239                  if (selected_p < new_p)
2240                    {
2241                      selected_p = new_p;
2242                      selected_release = releases[j];                               
2243                    }
2244                  // else if ? not possible                                                           
2245                }                               
2246            }
2247        }
2248      else if (r == -1)
2249        {
2250          if (v == new_v)
2251            {
2252              // We compare the r                                                     
2253              if (selected_r < new_r)
2254                {
2255                  selected_r = new_r;
2256                  selected_p = -1;
2257                  selected_release = releases[j];                               
2258                }
2259              else if (selected_r == new_r)
2260                { 
2261                  // We compare the p
2262                  if (selected_p < new_p)
2263                    {
2264                      selected_p = new_p;
2265                      selected_release = releases[j];                               
2266                    }
2267                  // else if ? not possible
2268                }
2269            }
2270        }
2271      else if (p == -1)
2272        {
2273          if ((v == new_v) && (r == new_r))
2274            { 
2275              // We compare the p
2276              if (selected_p < new_p)
2277                {
2278                  selected_p = new_p;
2279                  selected_release = releases[j];                               
2280                }
2281              // else if ? not possible
2282            }       
2283        }       
2284
2285      //cerr << "v:" << new_v << ", r:" << new_r << ", p:" << new_p << endl;             
2286      //cerr << "req v:" << v << ", req r:" << r << ", req p:" << p << endl;       
2287
2288    }
2289
2290  // cerr << "selected release: " << selected_release << endl; 
2291
2292  if (selected_release == "") return false;
2293
2294  result = selected_release;   
2295
2296  return (true);
2297}
2298
2299//---------------------------------------------------------
2300const CmtSystem::cmt_string_vector Project::get_project_releases (const cmt_string& name) const
2301{
2302  CmtSystem::cmt_string_vector releases;
2303  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2304
2305  static cmt_string sep = CmtSystem::path_separator ();
2306
2307  CmtSystem::cmt_string_vector items;
2308  CmtSystem::split (cmtprojectpath, sep, items);   
2309
2310  for (int i = 0; i < items.size (); i++)
2311    {
2312      const cmt_string& item = items[i];
2313      cmt_string p = item;
2314      p += CmtSystem::file_separator ();
2315      p += name;
2316
2317      if (CmtSystem::test_directory (p))
2318        { 
2319          CmtSystem::cmt_string_vector directories;
2320          CmtSystem::scan_dir (p, directories);
2321
2322          for (int j = 0; j < directories.size (); j++)
2323            {
2324              if  (CmtSystem::test_directory(directories[j]))
2325                {
2326                  cmt_string release;
2327                  CmtSystem:: basename(directories[j], release);
2328
2329                  if (CmtSystem::is_version_directory(release))
2330                    {                             
2331                      cmt_string& name_entry = releases.add ();
2332                      name_entry = release; 
2333                    }             
2334                }                           
2335            }                           
2336        }
2337    }
2338  return (releases);
2339}
2340
2341//----------------------------------------------------------
2342Project& Project::operator = (const Project& other)
2343{
2344  m_name = other.m_name;
2345  m_cmtpath = other.m_cmtpath;
2346  m_cmtpath_real = other.m_cmtpath_real;
2347  m_cmtpath_pwd = other.m_cmtpath_pwd;
2348  m_cmtpath_source = other.m_cmtpath_source;
2349
2350  return (*this);
2351}
2352
2353//----------------------------------------------------------
2354bool Project::operator == (const cmt_string& name) const
2355{
2356  return ((m_name == name));
2357}
2358
2359//----------------------------------------------------------
2360bool Project::operator != (const cmt_string& name) const
2361{
2362  return ((m_name != name));
2363}
2364
2365//----------------------------------------------------------
2366void Project::show ()
2367{
2368  if (m_visited) return;
2369  m_visited = true;
2370
2371  static int level = 0;
2372
2373  bool is_current = false;
2374
2375  //  cmt_string here = CmtSystem::pwd ();
2376  // In case there are symlinks
2377  cmt_string here_real;
2378  CmtSystem::realpath_ (CmtSystem::pwd (), here_real);
2379
2380  //  if (here.find (m_cmtpath) == 0)
2381  if (here_real.find (m_cmtpath_real) == 0) 
2382    {
2383      if (m_cmtpath_source != "default path")
2384        {
2385          is_current = true;
2386        }
2387    }
2388
2389  for (int tab = 0; tab < level; tab++) cout << "  ";
2390  cout << m_name << " " << (m_name != "CMTUSERCONTEXT" && m_name != "CMTHOME" ? m_release : "v0") << " (in " << m_cmtpath << ")";
2391  //  cout << m_name << " " << m_release << " (in " << m_cmtpath << ")";
2392
2393  if (is_current) cout << " (current)";
2394
2395  int i;
2396
2397  for (i = 0; i < m_parents.size (); i++)
2398    {
2399      Project* p = m_parents[i];
2400      if (p == 0) continue;
2401      cout << " P=" << p->get_name ();
2402    }
2403
2404  for (i = 0; i < m_children.size (); i++)
2405    {
2406      Project* p = m_children[i];
2407      if (p == 0) continue;
2408      cout << " C=" << p->get_name ();
2409    }
2410
2411  cout << endl;
2412
2413/*
2414  if (m_visited) return;
2415
2416  m_visited = true;
2417*/
2418
2419  for (i = 0; i < m_children.size (); i++)
2420    {
2421      Project* p = m_children[i];
2422      if (p == 0) continue;
2423      level++;
2424      p->show ();
2425      level--;
2426    }
2427}
2428
2429
2430//----------------------------------------------------------
2431void Project::show_specified_strategies () const
2432{
2433  int i;
2434
2435  for (i = 0; i < m_strategies.size (); i++)
2436    {
2437      const Strategy& s = m_strategies[i];
2438      if (s.m_specified)
2439        {
2440          const StrategyDef* def = s.m_definition;
2441 
2442          cout << "# Project " << m_name
2443               << " sets " << def->m_keyword
2444               << " strategy to " << ((s.m_value) ? def->m_on_value : def->m_off_value);
2445
2446          if (s.m_context != "")
2447            {
2448              cout << " (from package " << s.m_context << ")";
2449            }
2450
2451          cout << endl;
2452        }
2453    }
2454}
2455
2456//----------------------------------------------------------
2457bool Project::has_strategy (const StrategyDef* definition) const
2458{
2459  int i;
2460
2461  for (i = 0; i < m_strategies.size (); i++)
2462    {
2463      const Strategy& s = m_strategies[i];
2464      if (s.m_definition == definition)
2465        {
2466          return (true);
2467        }
2468    }
2469
2470  return (false);
2471}
2472
2473//----------------------------------------------------------
2474bool Project::get_strategy (const cmt_string& name) const
2475{
2476  static StrategyMgr& mgr = StrategyMgr::instance ();
2477
2478  StrategyDef* def = mgr.find_strategy (name);
2479  if (def == 0)
2480    {
2481      CmtMessage::warning ("strategy " + name + " undefined");
2482      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2483      return (false);
2484    }
2485
2486  return (get_strategy (def));
2487}
2488
2489//----------------------------------------------------------
2490bool Project::is_specified (const StrategyDef* definition) const
2491{
2492  int i;
2493
2494  for (i = 0; i < m_strategies.size (); i++)
2495    {
2496      Strategy& s = m_strategies[i];
2497      if (s.m_definition == definition)
2498        {
2499          // This strategy is applied in this project
2500          return (s.m_specified);
2501        }
2502    }
2503
2504  // This strategy is not applied in this project
2505  return (false);
2506}
2507
2508//----------------------------------------------------------
2509bool Project::get_strategy (const StrategyDef* def) const
2510{
2511  int i;
2512
2513  for (i = 0; i < m_strategies.size (); i++)
2514    {
2515      Strategy& s = m_strategies[i];
2516      if (s.m_definition == def)
2517        {
2518          // This strategy is applied in this project
2519          if (s.m_specified)
2520            {
2521              return (s.m_specified_value);
2522            }
2523          return (s.m_value);
2524        }
2525    }
2526
2527  // This strategy is not applied in this project
2528  return (def->m_default_value);
2529}
2530
2531//----------------------------------------------------------
2532void Project::set_default_strategy (const cmt_string& name)
2533{
2534  static StrategyMgr& mgr = StrategyMgr::instance ();
2535
2536  StrategyDef* def = mgr.find_strategy (name);
2537  if (def == 0)
2538    {
2539      CmtMessage::warning ("strategy " + name + " undefined");
2540      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2541      return;
2542    }
2543
2544  update_strategy (def, def->m_default_value);
2545}
2546
2547
2548//----------------------------------------------------------
2549void Project::set_strategy (const cmt_string& name, const cmt_string& value, const cmt_string& context)
2550{
2551  static StrategyMgr& mgr = StrategyMgr::instance ();
2552
2553  StrategyDef* def = mgr.find_strategy (name);
2554  if (def == 0)
2555    {
2556      CmtMessage::warning ("strategy " + name + " undefined");
2557      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2558      return;
2559    }
2560
2561  bool b_value = false;
2562
2563  if (value == def->m_on_value)
2564    {
2565      b_value = true;
2566    }
2567  else if (value == def->m_off_value)
2568    {
2569      b_value = false;
2570    }
2571  else
2572    {
2573      CmtMessage::warning ("requested strategy value " + value + " undefined in strategy " + name);
2574      //      cerr << "#CMT> requested strategy value " << value << " undefined in strategy " << name << endl;
2575      return;
2576    }
2577
2578  set_strategy (def, b_value, context);
2579}
2580
2581//----------------------------------------------------------
2582void Project::set_strategy (StrategyDef* definition, bool b_value, const cmt_string& context)
2583{
2584  bool need_strategy = true;
2585
2586  int i;
2587
2588  for (i = 0; i < m_strategies.size (); i++)
2589    {
2590      Strategy& s = m_strategies[i];
2591      if (s.m_definition == definition)
2592        {
2593          // This strategy is already applied in this project. Let's change it's value
2594          s.set (definition, b_value, get_name ());
2595          if (context != "")
2596            {
2597              if (s.m_context != "") s.m_context += " ";
2598              s.m_context += context;
2599            }
2600          need_strategy = false;
2601          break;
2602        }
2603    }
2604
2605  if (need_strategy)
2606    {
2607      // This strategy is not yet applied in this project.
2608
2609      Strategy& s = m_strategies.add ();
2610      s.clear ();
2611      s.set (definition, b_value, get_name ());
2612      s.m_context = context;
2613    }
2614 
2615  for (i = 0; i < m_parents.size (); i++)
2616    {
2617      Project* project = m_parents[i];
2618
2619      project->update_strategy (definition, b_value);
2620    }
2621}
2622
2623/**----------------------------------------------------------
2624   The strategy value is changed because of indirect influences
2625   - default strategy at initialization time
2626   - change in the children
2627   - change in the children list
2628
2629   (This is not a specification : see the set_strategy method)
2630*/
2631void Project::update_strategy (StrategyDef* definition, bool b_value)
2632{
2633  bool need_strategy = true;
2634  bool specified = false;
2635
2636  int i;
2637
2638  for (i = 0; i < m_strategies.size (); i++)
2639    {
2640      Strategy& s = m_strategies[i];
2641      if (s.m_definition == definition)
2642        {
2643          need_strategy = false;
2644
2645          if (!s.m_specified)
2646            {
2647              // This strategy is already applied in this project. Let's change it's value
2648              s.update (definition, b_value, get_name ());
2649            }
2650          else
2651            {
2652              specified = true;
2653            }
2654          break;
2655        }
2656    }
2657
2658  if (need_strategy)
2659    {
2660      // This strategy is not yet applied in this project.
2661
2662      Strategy& s = m_strategies.add ();
2663      s.clear ();
2664      s.update (definition, b_value, get_name ());
2665    }
2666
2667  if (!specified)
2668    {
2669      for (i = 0; i < m_parents.size (); i++)
2670        {
2671          Project* project = m_parents[i];
2672
2673          project->update_strategy (definition, b_value);
2674        }
2675    }
2676}
2677
2678/**----------------------------------------------------------
2679   At least one of the children has changed this strategy
2680   Or the list of children has changed.
2681   We need to update the strategy value accordingly
2682   This will not change the specified value for this strategy
2683*/
2684void Project::update_strategy_from_children (StrategyDef* definition)
2685{
2686  // If this strategy is specified we don't care what happens from the children
2687
2688  //cerr << "Updating strategy " << definition->m_name << " from children for project " << m_name << endl;
2689
2690  int i;
2691
2692  for (i = 0; i < m_strategies.size (); i++)
2693    {
2694      Strategy& s = m_strategies[i];
2695      if (s.m_definition == definition)
2696        {
2697          // This strategy is applied in this project.
2698
2699          if (s.m_specified)
2700            {
2701              // There will be no impact since the strategy is specified
2702
2703              //cerr << "This strategy is specified in this project" << endl;
2704              return;
2705            }
2706
2707          break;
2708        }
2709    }
2710
2711  // The strategy is not specified locally so we will now figure out
2712  // which strategy has to be considered from the mixture of specifications
2713  // from all children.
2714
2715  // Algorithm:
2716  // - We consider children by pairs
2717  // - a child that specifies its strategy wins over a child that does not
2718  // - when the two children have the same level of priority we consider the priority value
2719
2720  Project* selected = 0;
2721  bool selected_is_specified = false;
2722  bool selected_value = definition->m_default_value;
2723
2724  for (i = 0; i < m_children.size (); i++)
2725    {
2726      Project* p = m_children[i];
2727
2728      //cerr << "Checking strategy for child " << p->get_name () << endl;
2729
2730      bool is_specified = p->is_specified (definition);
2731      bool value = p->get_strategy (definition);
2732
2733      if (selected == 0)
2734        {
2735          selected = p;
2736          selected_is_specified = is_specified;
2737          selected_value = value;
2738          continue;
2739        }
2740
2741      if (is_specified == selected_is_specified)
2742        {
2743          if (selected_value != value)
2744            {
2745              // same level of priority but different values -> we must decide
2746              bool priority_value = definition->m_priority_value;
2747              if (value == priority_value)
2748                {
2749                  selected = p;
2750                  selected_is_specified = is_specified;
2751                  selected_value = value;
2752                }
2753            }
2754        }
2755      else
2756        {
2757          if (is_specified)
2758            {
2759              selected = p;
2760              selected_is_specified = is_specified;
2761              selected_value = value;
2762            }
2763        }
2764    }
2765
2766  update_strategy (definition, selected_value); 
2767}
2768
2769/**----------------------------------------------------------
2770   At least one of the children has changed its strategies
2771   Or the list of children has changed.
2772   We need to update the strategy values accordingly
2773   This will not change the specified values
2774*/
2775void Project::update_strategies_from_children ()
2776{
2777  StrategyDef::StrategyDefs& defs = StrategyMgr::get_definitions ();
2778
2779  //cerr << "Updating strategies from children for project " << m_name << endl;
2780
2781  int i;
2782
2783  for (i = 0; i < defs.size (); i++)
2784    {
2785      StrategyDef* def = defs[i];
2786     
2787      update_strategy_from_children (def);
2788    }
2789
2790  for (i = 0; i < m_parents.size (); i++)
2791    {
2792      Project* p = m_parents[i];
2793      p->update_strategies_from_children ();
2794    }
2795}
2796
2797/**----------------------------------------------------------
2798   The StrategyMgr singleton
2799*/
2800StrategyMgr& StrategyMgr::instance ()
2801{
2802  static StrategyMgr me;
2803  return (me);
2804}
2805
2806/**----------------------------------------------------------
2807   The StrategyMgr constructor
2808   Here are primarily constructed all strategy definitions
2809*/
2810StrategyMgr::StrategyMgr ()
2811{
2812  m_defs.clear ();
2813
2814  StrategyDef* s;
2815
2816  s = new StrategyDef;
2817  s->m_keyword = "build";
2818  s->m_name = "BuildPrototypes";
2819  s->m_on_value = "prototypes";
2820  s->m_off_value = "no_prototypes";
2821  s->m_default_value = true;
2822  s->m_priority_value = false;
2823
2824  m_defs.push_back (s);
2825
2826  s = new StrategyDef;
2827  s->m_keyword = "build";
2828  s->m_name = "InstallArea";
2829  s->m_on_value = "with_installarea";
2830  s->m_off_value = "without_installarea";
2831  s->m_default_value = false;
2832  s->m_priority_value = true;
2833
2834  m_defs.push_back (s);
2835
2836  s = new StrategyDef;
2837  s->m_keyword = "setup";
2838  s->m_name = "SetupConfig";
2839  s->m_on_value = "config";
2840  s->m_off_value = "no_config";
2841  s->m_default_value = true;
2842  s->m_priority_value = false;
2843
2844  m_defs.push_back (s);
2845
2846  s = new StrategyDef;
2847  s->m_keyword = "setup";
2848  s->m_name = "SetupRoot";
2849  s->m_on_value = "root";
2850  s->m_off_value = "no_root";
2851  s->m_default_value = true;
2852  s->m_priority_value = false;
2853
2854  m_defs.push_back (s);
2855
2856  s = new StrategyDef;
2857  s->m_keyword = "setup";
2858  s->m_name = "SetupCleanup";
2859  s->m_on_value = "cleanup";
2860  s->m_off_value = "no_cleanup";
2861  s->m_default_value = true;
2862  s->m_priority_value = false;
2863
2864  m_defs.push_back (s);
2865
2866  s = new StrategyDef;
2867  s->m_keyword = "setup";
2868  s->m_name = "SetupScripts";
2869  s->m_on_value = "scripts";
2870  s->m_off_value = "no_scripts";
2871  s->m_default_value = true;
2872  s->m_priority_value = false;
2873
2874  m_defs.push_back (s);
2875
2876  s = new StrategyDef;
2877  s->m_keyword = "structure";
2878  s->m_name = "VersionDirectory";
2879  s->m_on_value = "with_version_directory";
2880  s->m_off_value = "without_version_directory";
2881  if (Cmt::get_current_structuring_style () != without_version_directory)
2882    {
2883      s->m_default_value = true;
2884      s->m_priority_value = false;
2885    }
2886  else
2887    {
2888      s->m_default_value = false;
2889      s->m_priority_value = true;
2890    }
2891
2892  m_defs.push_back (s);
2893}
2894
2895/**----------------------------------------------------------
2896   Find a strategy definition by its name
2897*/
2898StrategyDef* StrategyMgr::find_strategy (const cmt_string& name)
2899{
2900  static StrategyMgr& me = instance ();
2901
2902  int i;
2903
2904  for (i = 0; i < me.m_defs.size (); i++)
2905    {
2906      StrategyDef* def = me.m_defs[i];
2907      if (def->m_name == name)
2908        {
2909          return (def);
2910        }
2911    }
2912
2913  return (0);
2914}
2915
2916/**----------------------------------------------------------
2917   Retreive the default value defined for a given strategy
2918*/
2919bool StrategyMgr::get_default_strategy (const cmt_string& name)
2920{
2921  StrategyDef* def = find_strategy (name);
2922  if (def == 0) return (false);
2923  return (def->m_default_value);
2924}
2925
2926/**----------------------------------------------------------
2927   Retreive the priority value defined for a given strategy
2928   This value is used when two children of a project request two conflicting strategy values
2929*/
2930bool StrategyMgr::get_priority_strategy (const cmt_string& name)
2931{
2932  StrategyDef* def = find_strategy (name);
2933  if (def == 0) return (false);
2934  return (def->m_priority_value);
2935}
2936
2937/**----------------------------------------------------------
2938   Return the vector of all existing strategy definitions
2939*/
2940StrategyDef::StrategyDefs& StrategyMgr::get_definitions ()
2941{
2942  static StrategyMgr& me = instance ();
2943
2944  return (me.m_defs);
2945}
2946
2947//-----------------------------------------------------------
2948Strategy::Strategy ()
2949{
2950  clear ();
2951}
2952
2953//-----------------------------------------------------------
2954void Strategy::clear ()
2955{
2956  m_definition = 0;
2957  m_specified = false;
2958  m_specified_value = false;
2959  m_value = false;
2960  m_on_tag = 0;
2961  m_off_tag = 0;
2962}
2963
2964/**----------------------------------------------------------
2965   Specify a new value for this strategy.
2966   This only happens when a strategy statement is met in a project file or in a requirements file.
2967*/
2968void Strategy::set (StrategyDef* definition, bool value, const cmt_string& project_name)
2969{
2970  //cerr << "Setting strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
2971
2972  m_definition = definition;
2973  m_specified = true;
2974  m_specified_value = value;
2975
2976  update (definition, value, project_name);
2977}
2978
2979/**----------------------------------------------------------
2980   Change the effective value for this strategy.
2981   This has no impact on to the specified value.
2982   This will adapt the tag settings
2983*/
2984void Strategy::update (StrategyDef* definition, bool value, const cmt_string& project_name)
2985{
2986  //cerr << "Updating strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
2987
2988  m_value = value;
2989  m_definition = definition;
2990
2991  cmt_string to_tag_name = project_name;
2992  cmt_string to_untag_name = project_name;
2993
2994  to_tag_name += "_";
2995  to_untag_name += "_";
2996
2997  if (m_value)
2998    {
2999      to_tag_name += m_definition->m_on_value;
3000      to_untag_name += m_definition->m_off_value;
3001    }
3002  else
3003    {
3004      to_tag_name += m_definition->m_off_value;
3005      to_untag_name += m_definition->m_on_value;
3006    }
3007
3008  m_on_tag = Tag::find (to_tag_name);
3009  m_off_tag = Tag::find (to_untag_name);
3010
3011  if (m_on_tag == 0 || m_off_tag == 0)
3012    {
3013      m_on_tag = Tag::add (to_tag_name, PriorityConfig, "PROJECT", 0);
3014      m_off_tag = Tag::add (to_untag_name, PriorityConfig, "PROJECT", 0);
3015
3016      m_on_tag->add_tag_exclude (m_off_tag);
3017      m_off_tag->add_tag_exclude (m_on_tag);
3018    }
3019
3020  m_off_tag->unmark ();
3021  m_on_tag->mark ();
3022}
3023
3024//-----------------------------------------------------------
3025const cmt_string& StrategyDef::get_default_value () const
3026{
3027  if (m_default_value)
3028    {
3029      return (m_on_value);
3030    }
3031  else
3032    {
3033      return (m_off_value);
3034    }
3035}
3036
3037//-----------------------------------------------------------
3038void Project::set_author (const cmt_string& name)
3039{
3040  // cerr << "set_author" << name << endl;     
3041  this->m_author = name;
3042}
3043
3044//-----------------------------------------------------------
3045const cmt_string& Project::get_author () const
3046{
3047  return (m_author);
3048}
3049
3050//-----------------------------------------------------------
3051void Project::project_author_action (const CmtSystem::cmt_string_vector& words)
3052{
3053  if (m_author != "") m_author += "\n";
3054
3055  for (int i = 1; i < words.size (); i++)
3056    {
3057      const cmt_string& w = words[i];
3058     
3059      if (i > 1) m_author += " ";
3060      m_author += w; 
3061    }
3062}
3063
3064//-----------------------------------------------------------
3065Use*  Project::get_use () const
3066{
3067  return m_use;   
3068} 
3069
3070//-----------------------------------------------------------
3071void  Project::set_use (Use* use)
3072{ 
3073  this->m_use = use;
3074}
3075
3076//-----------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.