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

Last change on this file since 581 was 581, checked in by rybkin, 13 years ago

See C.L. 459

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