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

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

See C.L. 437

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