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

Last change on this file since 535 was 535, checked in by rybkin, 14 years ago

See C.L. 422

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