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

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

See C.L. 448

  • Property svn:eol-style set to native
File size: 81.3 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 ();
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  Use* use = &m_container;
2308  use->~Use ();
2309  if (words.size () < 2) return;
2310
2311  CmtSystem::cmt_string_vector ewords;
2312  for (int i = 1; i < words.size (); i++)
2313    {
2314      const cmt_string& w = words[i];
2315      cmt_string ew = w;
2316
2317      Symbol::expand (ew);
2318      if (ew != w)
2319        {
2320          CmtSystem::cmt_string_vector ws;
2321          CmtSystem::split (ew, " ", ws);
2322
2323          for (int j = 0; j < ws.size (); ++j)
2324            {
2325              ewords.push_back (ws[j]);
2326            }
2327        }
2328      else
2329        {
2330          ewords.push_back (w);
2331        }
2332    }
2333
2334  cmt_string name, version, path;
2335  if (ewords.size () > 0) name = ewords[0];
2336  if (ewords.size () > 1) version = ewords[1];
2337  if (ewords.size () > 2) path = ewords[2];
2338
2339  if (name != "")
2340    {
2341      use->set (name, version, path);
2342      use->get_package ()->remove_use (use);
2343      CmtSystem::cd (m_cmtpath_pwd);
2344      if (use->move_to ("", true) &&
2345          !CmtSystem::absolute_path (use->real_path))
2346        {
2347          use->change_path (m_cmtpath_pwd);
2348        }
2349      CmtSystem::cd (m_cmtpath_pwd + CmtSystem::file_separator () + "cmt");
2350    }
2351
2352  set_container_name (name);
2353  set_container_version (version);
2354  set_container_path (path);
2355}
2356
2357/**---------------------------------------------------------
2358   A use statement is met in the project file
2359*/
2360void Project::use_action (const cmt_string& name, const cmt_string& release)
2361{
2362  if (Cmt::get_debug ())
2363    {
2364      cout << "Use action " << name << " " << release << endl;
2365    }
2366
2367  // A project with its release is specified
2368  //
2369  // Is this project already visible?
2370  // If not: look for it
2371  //   + get CMTPROJECTPATH
2372  //   + search from all entries of CMTPROJECTPATH : p(i)/<name>/<release>
2373  //   + when found, this should become a new CMTPATH entry
2374  //   +             the new project is then parsed ... etc...
2375
2376  // First test it wilcard is used
2377  int v = -1;
2378  int r = -1;
2379  int p = -1;
2380  cmt_string new_release = release;
2381  CmtSystem::is_version_directory (new_release, v, r, p); 
2382  bool use_has_wild_card = (v == -1) || (r == -1) || (p == -1);
2383  if (use_has_wild_card)
2384    {
2385      cmt_string selected_release = "";
2386
2387      if (select_release(name, new_release,selected_release))
2388        {
2389          // cerr <<"selected_release: "<<selected_release<<endl;   
2390          new_release = selected_release;
2391        }         
2392    }
2393
2394  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2395  cmt_string sep;
2396  sep = CmtSystem::path_separator ();
2397
2398  CmtSystem::cmt_string_vector items;
2399  CmtSystem::split (cmtprojectpath, sep, items);
2400
2401  bool found = false;
2402
2403  for (int i = 0; i < items.size (); i++)
2404    {
2405      const cmt_string& item = items[i];
2406      cmt_string p = item;
2407      p += CmtSystem::file_separator ();
2408      p += name;
2409      if (new_release != "")
2410        {
2411          p += CmtSystem::file_separator ();
2412          p += new_release;
2413        }
2414
2415      if (CmtSystem::test_directory (p))
2416        {
2417          //cerr << "Project directory " << p << " exists " << endl;
2418
2419          found = true;
2420
2421          IProjectFactory& factory = ProjectFactory::instance ();
2422
2423          factory.create_project (name, p, "ProjectPath", this);
2424
2425          break;
2426        }
2427    }
2428
2429  if (!found)
2430    {
2431      Project* p = Project::find_by_name (name);
2432
2433      if (p != 0)
2434        {
2435          found = true;
2436          p->add_parent (this);
2437          add_child (p);
2438
2439          update_strategies_from_children ();
2440        }
2441    }
2442   
2443  if (!found && (cmtprojectpath != ""))
2444    {
2445      CmtMessage::warning ("Project " + name + " " + release + " requested by " + m_name + " not found in CMTPROJECTPATH");
2446      //      cerr << "#CMT> Project " << name << " " << release << " requested by " << m_name << " not found in CMTPROJECTPATH" << endl;
2447    }
2448}
2449
2450//---------------------------------------------------------
2451bool Project::select_release(const cmt_string& name, const cmt_string& release, cmt_string& result)
2452{
2453  cmt_string selected_release = "";
2454
2455  int v = -1;
2456  int r = -1;
2457  int p = -1;
2458  CmtSystem::is_version_directory (release, v, r, p); 
2459
2460  int selected_v = -1;
2461  int selected_r = -1;
2462  int selected_p = -1;
2463  CmtSystem::cmt_string_vector releases = get_project_releases(name);
2464  for (int j = 0; j < releases.size (); j++)
2465    {
2466      int new_v = -1;
2467      int new_r = -1;
2468      int new_p = -1;
2469      CmtSystem::is_version_directory (releases[j], new_v, new_r, new_p);
2470      if (v == -1)
2471        {
2472          if (selected_v < new_v)
2473            {
2474              selected_v = new_v;
2475              selected_r = -1;
2476              selected_p = -1;
2477              selected_release = releases[j];
2478            }
2479          else if (selected_v == new_v)
2480            {
2481              // We compare the r
2482              if (selected_r < new_r)
2483                {
2484                  selected_r = new_r;
2485                  selected_p = -1;
2486                  selected_release = releases[j];                               
2487                }
2488              else if (selected_r == new_r)
2489                {
2490                  // We compare the p
2491                  if (selected_p < new_p)
2492                    {
2493                      selected_p = new_p;
2494                      selected_release = releases[j];                               
2495                    }
2496                  // else if ? not possible                                                           
2497                }                               
2498            }
2499        }
2500      else if (r == -1)
2501        {
2502          if (v == new_v)
2503            {
2504              // We compare the r                                                     
2505              if (selected_r < new_r)
2506                {
2507                  selected_r = new_r;
2508                  selected_p = -1;
2509                  selected_release = releases[j];                               
2510                }
2511              else if (selected_r == new_r)
2512                { 
2513                  // We compare the p
2514                  if (selected_p < new_p)
2515                    {
2516                      selected_p = new_p;
2517                      selected_release = releases[j];                               
2518                    }
2519                  // else if ? not possible
2520                }
2521            }
2522        }
2523      else if (p == -1)
2524        {
2525          if ((v == new_v) && (r == new_r))
2526            { 
2527              // We compare the p
2528              if (selected_p < new_p)
2529                {
2530                  selected_p = new_p;
2531                  selected_release = releases[j];                               
2532                }
2533              // else if ? not possible
2534            }       
2535        }       
2536
2537      //cerr << "v:" << new_v << ", r:" << new_r << ", p:" << new_p << endl;             
2538      //cerr << "req v:" << v << ", req r:" << r << ", req p:" << p << endl;       
2539
2540    }
2541
2542  // cerr << "selected release: " << selected_release << endl; 
2543
2544  if (selected_release == "") return false;
2545
2546  result = selected_release;   
2547
2548  return (true);
2549}
2550
2551//---------------------------------------------------------
2552const CmtSystem::cmt_string_vector Project::get_project_releases (const cmt_string& name) const
2553{
2554  CmtSystem::cmt_string_vector releases;
2555  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2556
2557  static cmt_string sep = CmtSystem::path_separator ();
2558
2559  CmtSystem::cmt_string_vector items;
2560  CmtSystem::split (cmtprojectpath, sep, items);   
2561
2562  for (int i = 0; i < items.size (); i++)
2563    {
2564      const cmt_string& item = items[i];
2565      cmt_string p = item;
2566      p += CmtSystem::file_separator ();
2567      p += name;
2568
2569      if (CmtSystem::test_directory (p))
2570        { 
2571          CmtSystem::cmt_string_vector directories;
2572          CmtSystem::scan_dir (p, directories);
2573
2574          for (int j = 0; j < directories.size (); j++)
2575            {
2576              if  (CmtSystem::test_directory(directories[j]))
2577                {
2578                  cmt_string release;
2579                  CmtSystem:: basename(directories[j], release);
2580
2581                  if (CmtSystem::is_version_directory(release))
2582                    {                             
2583                      cmt_string& name_entry = releases.add ();
2584                      name_entry = release; 
2585                    }             
2586                }                           
2587            }                           
2588        }
2589    }
2590  return (releases);
2591}
2592
2593//----------------------------------------------------------
2594Project& Project::operator = (const Project& other)
2595{
2596  m_name = other.m_name;
2597  m_cmtpath = other.m_cmtpath;
2598  m_cmtpath_real = other.m_cmtpath_real;
2599  m_cmtpath_pwd = other.m_cmtpath_pwd;
2600  m_cmtpath_source = other.m_cmtpath_source;
2601
2602  return (*this);
2603}
2604
2605//----------------------------------------------------------
2606bool Project::operator == (const cmt_string& name) const
2607{
2608  return ((m_name == name));
2609}
2610
2611//----------------------------------------------------------
2612bool Project::operator != (const cmt_string& name) const
2613{
2614  return ((m_name != name));
2615}
2616
2617//----------------------------------------------------------
2618void Project::show (PrintMode mode)
2619//void Project::show ()
2620{
2621  if (m_visited) return;
2622  m_visited = true;
2623
2624  static int level = 0;
2625
2626  //  bool is_current = false;
2627
2628  //  cmt_string here = CmtSystem::pwd ();
2629  // In case there are symlinks
2630  /*
2631  cmt_string here_real;
2632  CmtSystem::realpath_ (CmtSystem::pwd (), here_real);
2633
2634  //  if (here.find (m_cmtpath) == 0)
2635  if (here_real.find (m_cmtpath_real) == 0)
2636    {
2637      if (m_cmtpath_source != "default path")
2638        {
2639          is_current = true;
2640        }
2641    }
2642  */
2643  switch (mode)
2644    {
2645    case Xml :
2646      cout << "<project" << (m_is_current ? " current=\"yes\"" : "") << ">";
2647      //      if (m_order >= 0)
2648      cout << "<order>" << m_order << "</order>";
2649      cout << "<name>" << m_name << "</name><version>" << (m_name != "CMTUSERCONTEXT" && m_name != "CMTHOME" ? m_release : "v0") << "</version><cmtpath>" << m_cmtpath << "</cmtpath>";
2650      break;
2651    default :
2652  for (int tab = 0; tab < level; tab++) cout << "  ";
2653  cout << m_name << " " << (m_name != "CMTUSERCONTEXT" && m_name != "CMTHOME" ? m_release : "v0") << " (in " << m_cmtpath << ")";
2654  //  cout << m_name << " " << m_release << " (in " << m_cmtpath << ")";
2655
2656  if (m_is_current) cout << " (current)";
2657  //  if (is_current) cout << " (current)";
2658      break;
2659    }
2660
2661  int i;
2662
2663  switch (mode)
2664    {
2665    case Xml :
2666      cout << "<clients>";
2667      break;
2668    }
2669  for (i = 0; i < m_parents.size (); i++)
2670    {
2671      Project* p = m_parents[i];
2672      if (p == 0) continue;
2673      switch (mode)
2674        {
2675        case Xml :
2676          //      cout << "<name>" << p->get_name () << "</name>";
2677          cout << "<project" << (p->is_current () ? " current=\"yes\"" : "") << ">";
2678          //  if (p->m_order >= 0)
2679          cout << "<order>" << p->m_order << "</order>";
2680          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>";
2681          cout << "</project>";
2682          break;
2683        default :
2684      cout << " P=" << p->get_name ();
2685          break;
2686        }
2687    }
2688  switch (mode)
2689    {
2690    case Xml :
2691      cout << "</clients>";
2692      break;
2693    }
2694
2695  switch (mode)
2696    {
2697    case Xml :
2698      cout << "<uses>";
2699      break;
2700    }
2701  for (i = 0; i < m_children.size (); i++)
2702    {
2703      Project* p = m_children[i];
2704      if (p == 0) continue;
2705      switch (mode)
2706        {
2707        case Xml :
2708          //      cout << "<name>" << p->get_name () << "</name>";
2709          cout << "<project" << (p->is_current () ? " current=\"yes\"" : "") << ">";
2710          //      if (p->m_order >= 0)
2711          cout << "<order>" << p->m_order << "</order>";
2712          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>";
2713          cout << "</project>";
2714          break;
2715        default :
2716      cout << " C=" << p->get_name ();
2717          break;
2718        }
2719    }
2720  switch (mode)
2721    {
2722    case Xml :
2723      cout << "</uses>";
2724      cout << "</project>";
2725      break;
2726    default :
2727  cout << endl;
2728      break;
2729    }
2730
2731
2732/*
2733  if (m_visited) return;
2734
2735  m_visited = true;
2736*/
2737
2738  for (i = 0; i < m_children.size (); i++)
2739    {
2740      Project* p = m_children[i];
2741      if (p == 0) continue;
2742      level++;
2743      p->show (mode);
2744      //      p->show ();
2745      level--;
2746    }
2747}
2748
2749
2750//----------------------------------------------------------
2751void Project::show_specified_strategies () const
2752{
2753  int i;
2754
2755  for (i = 0; i < m_strategies.size (); i++)
2756    {
2757      const Strategy& s = m_strategies[i];
2758      if (s.m_specified)
2759        {
2760          const StrategyDef* def = s.m_definition;
2761 
2762          cout << "# Project " << m_name
2763               << " sets " << def->m_keyword
2764               << " strategy to " << ((s.m_value) ? def->m_on_value : def->m_off_value);
2765
2766          if (s.m_context != "")
2767            {
2768              cout << " (from package " << s.m_context << ")";
2769            }
2770
2771          cout << endl;
2772        }
2773    }
2774}
2775
2776//----------------------------------------------------------
2777bool Project::has_strategy (const StrategyDef* definition) const
2778{
2779  int i;
2780
2781  for (i = 0; i < m_strategies.size (); i++)
2782    {
2783      const Strategy& s = m_strategies[i];
2784      if (s.m_definition == definition)
2785        {
2786          return (true);
2787        }
2788    }
2789
2790  return (false);
2791}
2792
2793//----------------------------------------------------------
2794bool Project::get_strategy (const cmt_string& name) const
2795{
2796  static StrategyMgr& mgr = StrategyMgr::instance ();
2797
2798  StrategyDef* def = mgr.find_strategy (name);
2799  if (def == 0)
2800    {
2801      CmtMessage::warning ("strategy " + name + " undefined");
2802      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2803      return (false);
2804    }
2805
2806  return (get_strategy (def));
2807}
2808
2809//----------------------------------------------------------
2810bool Project::is_specified (const StrategyDef* definition) const
2811{
2812  int i;
2813
2814  for (i = 0; i < m_strategies.size (); i++)
2815    {
2816      Strategy& s = m_strategies[i];
2817      if (s.m_definition == definition)
2818        {
2819          // This strategy is applied in this project
2820          return (s.m_specified);
2821        }
2822    }
2823
2824  // This strategy is not applied in this project
2825  return (false);
2826}
2827
2828//----------------------------------------------------------
2829bool Project::get_strategy (const StrategyDef* def) const
2830{
2831  int i;
2832
2833  for (i = 0; i < m_strategies.size (); i++)
2834    {
2835      Strategy& s = m_strategies[i];
2836      if (s.m_definition == def)
2837        {
2838          // This strategy is applied in this project
2839          if (s.m_specified)
2840            {
2841              return (s.m_specified_value);
2842            }
2843          return (s.m_value);
2844        }
2845    }
2846
2847  // This strategy is not applied in this project
2848  return (def->m_default_value);
2849}
2850
2851//----------------------------------------------------------
2852void Project::set_default_strategy (const cmt_string& name)
2853{
2854  static StrategyMgr& mgr = StrategyMgr::instance ();
2855
2856  StrategyDef* def = mgr.find_strategy (name);
2857  if (def == 0)
2858    {
2859      CmtMessage::warning ("strategy " + name + " undefined");
2860      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2861      return;
2862    }
2863
2864  update_strategy (def, def->m_default_value);
2865}
2866
2867
2868//----------------------------------------------------------
2869void Project::set_strategy (const cmt_string& name, const cmt_string& value, const cmt_string& context)
2870{
2871  static StrategyMgr& mgr = StrategyMgr::instance ();
2872
2873  StrategyDef* def = mgr.find_strategy (name);
2874  if (def == 0)
2875    {
2876      CmtMessage::warning ("strategy " + name + " undefined");
2877      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2878      return;
2879    }
2880
2881  bool b_value = false;
2882
2883  if (value == def->m_on_value)
2884    {
2885      b_value = true;
2886    }
2887  else if (value == def->m_off_value)
2888    {
2889      b_value = false;
2890    }
2891  else
2892    {
2893      CmtMessage::warning ("requested strategy value " + value + " undefined in strategy " + name);
2894      //      cerr << "#CMT> requested strategy value " << value << " undefined in strategy " << name << endl;
2895      return;
2896    }
2897
2898  set_strategy (def, b_value, context);
2899}
2900
2901//----------------------------------------------------------
2902void Project::set_strategy (StrategyDef* definition, bool b_value, const cmt_string& context)
2903{
2904  bool need_strategy = true;
2905
2906  int i;
2907
2908  for (i = 0; i < m_strategies.size (); i++)
2909    {
2910      Strategy& s = m_strategies[i];
2911      if (s.m_definition == definition)
2912        {
2913          // This strategy is already applied in this project. Let's change it's value
2914          s.set (definition, b_value, get_name ());
2915          if (context != "")
2916            {
2917              if (s.m_context != "") s.m_context += " ";
2918              s.m_context += context;
2919            }
2920          need_strategy = false;
2921          break;
2922        }
2923    }
2924
2925  if (need_strategy)
2926    {
2927      // This strategy is not yet applied in this project.
2928
2929      Strategy& s = m_strategies.add ();
2930      s.clear ();
2931      s.set (definition, b_value, get_name ());
2932      s.m_context = context;
2933    }
2934 
2935  for (i = 0; i < m_parents.size (); i++)
2936    {
2937      Project* project = m_parents[i];
2938
2939      project->update_strategy (definition, b_value);
2940    }
2941}
2942
2943/**----------------------------------------------------------
2944   The strategy value is changed because of indirect influences
2945   - default strategy at initialization time
2946   - change in the children
2947   - change in the children list
2948
2949   (This is not a specification : see the set_strategy method)
2950*/
2951void Project::update_strategy (StrategyDef* definition, bool b_value)
2952{
2953  bool need_strategy = true;
2954  bool specified = false;
2955
2956  int i;
2957
2958  for (i = 0; i < m_strategies.size (); i++)
2959    {
2960      Strategy& s = m_strategies[i];
2961      if (s.m_definition == definition)
2962        {
2963          need_strategy = false;
2964
2965          if (!s.m_specified)
2966            {
2967              // This strategy is already applied in this project. Let's change it's value
2968              s.update (definition, b_value, get_name ());
2969            }
2970          else
2971            {
2972              specified = true;
2973            }
2974          break;
2975        }
2976    }
2977
2978  if (need_strategy)
2979    {
2980      // This strategy is not yet applied in this project.
2981
2982      Strategy& s = m_strategies.add ();
2983      s.clear ();
2984      s.update (definition, b_value, get_name ());
2985    }
2986
2987  if (!specified)
2988    {
2989      for (i = 0; i < m_parents.size (); i++)
2990        {
2991          Project* project = m_parents[i];
2992
2993          project->update_strategy (definition, b_value);
2994        }
2995    }
2996}
2997
2998/**----------------------------------------------------------
2999   At least one of the children has changed this strategy
3000   Or the list of children has changed.
3001   We need to update the strategy value accordingly
3002   This will not change the specified value for this strategy
3003*/
3004void Project::update_strategy_from_children (StrategyDef* definition)
3005{
3006  // If this strategy is specified we don't care what happens from the children
3007
3008  //cerr << "Updating strategy " << definition->m_name << " from children for project " << m_name << endl;
3009
3010  int i;
3011
3012  for (i = 0; i < m_strategies.size (); i++)
3013    {
3014      Strategy& s = m_strategies[i];
3015      if (s.m_definition == definition)
3016        {
3017          // This strategy is applied in this project.
3018
3019          if (s.m_specified)
3020            {
3021              // There will be no impact since the strategy is specified
3022
3023              //cerr << "This strategy is specified in this project" << endl;
3024              return;
3025            }
3026
3027          break;
3028        }
3029    }
3030
3031  // The strategy is not specified locally so we will now figure out
3032  // which strategy has to be considered from the mixture of specifications
3033  // from all children.
3034
3035  // Algorithm:
3036  // - We consider children by pairs
3037  // - a child that specifies its strategy wins over a child that does not
3038  // - when the two children have the same level of priority we consider the priority value
3039
3040  Project* selected = 0;
3041  bool selected_is_specified = false;
3042  bool selected_value = definition->m_default_value;
3043
3044  for (i = 0; i < m_children.size (); i++)
3045    {
3046      Project* p = m_children[i];
3047
3048      //cerr << "Checking strategy for child " << p->get_name () << endl;
3049
3050      bool is_specified = p->is_specified (definition);
3051      bool value = p->get_strategy (definition);
3052
3053      if (selected == 0)
3054        {
3055          selected = p;
3056          selected_is_specified = is_specified;
3057          selected_value = value;
3058          continue;
3059        }
3060
3061      if (is_specified == selected_is_specified)
3062        {
3063          if (selected_value != value)
3064            {
3065              // same level of priority but different values -> we must decide
3066              bool priority_value = definition->m_priority_value;
3067              if (value == priority_value)
3068                {
3069                  selected = p;
3070                  selected_is_specified = is_specified;
3071                  selected_value = value;
3072                }
3073            }
3074        }
3075      else
3076        {
3077          if (is_specified)
3078            {
3079              selected = p;
3080              selected_is_specified = is_specified;
3081              selected_value = value;
3082            }
3083        }
3084    }
3085
3086  update_strategy (definition, selected_value); 
3087}
3088
3089/**----------------------------------------------------------
3090   At least one of the children has changed its strategies
3091   Or the list of children has changed.
3092   We need to update the strategy values accordingly
3093   This will not change the specified values
3094*/
3095void Project::update_strategies_from_children ()
3096{
3097  StrategyDef::StrategyDefs& defs = StrategyMgr::get_definitions ();
3098
3099  //cerr << "Updating strategies from children for project " << m_name << endl;
3100
3101  int i;
3102
3103  for (i = 0; i < defs.size (); i++)
3104    {
3105      StrategyDef* def = defs[i];
3106     
3107      update_strategy_from_children (def);
3108    }
3109
3110  for (i = 0; i < m_parents.size (); i++)
3111    {
3112      Project* p = m_parents[i];
3113      p->update_strategies_from_children ();
3114    }
3115}
3116
3117/**----------------------------------------------------------
3118   The StrategyMgr singleton
3119*/
3120StrategyMgr& StrategyMgr::instance ()
3121{
3122  static StrategyMgr me;
3123  return (me);
3124}
3125
3126/**----------------------------------------------------------
3127   The StrategyMgr constructor
3128   Here are primarily constructed all strategy definitions
3129*/
3130StrategyMgr::StrategyMgr ()
3131{
3132  m_defs.clear ();
3133
3134  StrategyDef* s;
3135
3136  s = new StrategyDef;
3137  s->m_keyword = "build";
3138  s->m_name = "BuildPrototypes";
3139  s->m_on_value = "prototypes";
3140  s->m_off_value = "no_prototypes";
3141  s->m_default_value = true;
3142  s->m_priority_value = false;
3143
3144  m_defs.push_back (s);
3145
3146  s = new StrategyDef;
3147  s->m_keyword = "build";
3148  s->m_name = "InstallArea";
3149  s->m_on_value = "with_installarea";
3150  s->m_off_value = "without_installarea";
3151  s->m_default_value = false;
3152  s->m_priority_value = true;
3153
3154  m_defs.push_back (s);
3155
3156  s = new StrategyDef;
3157  s->m_keyword = "setup";
3158  s->m_name = "SetupConfig";
3159  s->m_on_value = "config";
3160  s->m_off_value = "no_config";
3161  s->m_default_value = true;
3162  s->m_priority_value = false;
3163
3164  m_defs.push_back (s);
3165
3166  s = new StrategyDef;
3167  s->m_keyword = "setup";
3168  s->m_name = "SetupRoot";
3169  s->m_on_value = "root";
3170  s->m_off_value = "no_root";
3171  s->m_default_value = true;
3172  s->m_priority_value = false;
3173
3174  m_defs.push_back (s);
3175
3176  s = new StrategyDef;
3177  s->m_keyword = "setup";
3178  s->m_name = "SetupCleanup";
3179  s->m_on_value = "cleanup";
3180  s->m_off_value = "no_cleanup";
3181  s->m_default_value = true;
3182  s->m_priority_value = false;
3183
3184  m_defs.push_back (s);
3185
3186  s = new StrategyDef;
3187  s->m_keyword = "setup";
3188  s->m_name = "SetupScripts";
3189  s->m_on_value = "scripts";
3190  s->m_off_value = "no_scripts";
3191  s->m_default_value = true;
3192  s->m_priority_value = false;
3193
3194  m_defs.push_back (s);
3195
3196  s = new StrategyDef;
3197  s->m_keyword = "structure";
3198  s->m_name = "VersionDirectory";
3199  s->m_on_value = "with_version_directory";
3200  s->m_off_value = "without_version_directory";
3201  if (Cmt::get_current_structuring_style () != without_version_directory)
3202    {
3203      s->m_default_value = true;
3204      s->m_priority_value = false;
3205    }
3206  else
3207    {
3208      s->m_default_value = false;
3209      s->m_priority_value = true;
3210    }
3211
3212  m_defs.push_back (s);
3213}
3214
3215/**----------------------------------------------------------
3216   Find a strategy definition by its name
3217*/
3218StrategyDef* StrategyMgr::find_strategy (const cmt_string& name)
3219{
3220  static StrategyMgr& me = instance ();
3221
3222  int i;
3223
3224  for (i = 0; i < me.m_defs.size (); i++)
3225    {
3226      StrategyDef* def = me.m_defs[i];
3227      if (def->m_name == name)
3228        {
3229          return (def);
3230        }
3231    }
3232
3233  return (0);
3234}
3235
3236/**----------------------------------------------------------
3237   Retreive the default value defined for a given strategy
3238*/
3239bool StrategyMgr::get_default_strategy (const cmt_string& name)
3240{
3241  StrategyDef* def = find_strategy (name);
3242  if (def == 0) return (false);
3243  return (def->m_default_value);
3244}
3245
3246/**----------------------------------------------------------
3247   Retreive the priority value defined for a given strategy
3248   This value is used when two children of a project request two conflicting strategy values
3249*/
3250bool StrategyMgr::get_priority_strategy (const cmt_string& name)
3251{
3252  StrategyDef* def = find_strategy (name);
3253  if (def == 0) return (false);
3254  return (def->m_priority_value);
3255}
3256
3257/**----------------------------------------------------------
3258   Return the vector of all existing strategy definitions
3259*/
3260StrategyDef::StrategyDefs& StrategyMgr::get_definitions ()
3261{
3262  static StrategyMgr& me = instance ();
3263
3264  return (me.m_defs);
3265}
3266
3267//-----------------------------------------------------------
3268Strategy::Strategy ()
3269{
3270  clear ();
3271}
3272
3273//-----------------------------------------------------------
3274void Strategy::clear ()
3275{
3276  m_definition = 0;
3277  m_specified = false;
3278  m_specified_value = false;
3279  m_value = false;
3280  m_on_tag = 0;
3281  m_off_tag = 0;
3282}
3283
3284/**----------------------------------------------------------
3285   Specify a new value for this strategy.
3286   This only happens when a strategy statement is met in a project file or in a requirements file.
3287*/
3288void Strategy::set (StrategyDef* definition, bool value, const cmt_string& project_name)
3289{
3290  //cerr << "Setting strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
3291
3292  m_definition = definition;
3293  m_specified = true;
3294  m_specified_value = value;
3295
3296  update (definition, value, project_name);
3297}
3298
3299/**----------------------------------------------------------
3300   Change the effective value for this strategy.
3301   This has no impact on to the specified value.
3302   This will adapt the tag settings
3303*/
3304void Strategy::update (StrategyDef* definition, bool value, const cmt_string& project_name)
3305{
3306  //cerr << "Updating strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
3307
3308  m_value = value;
3309  m_definition = definition;
3310
3311  cmt_string to_tag_name = project_name;
3312  cmt_string to_untag_name = project_name;
3313
3314  to_tag_name += "_";
3315  to_untag_name += "_";
3316
3317  if (m_value)
3318    {
3319      to_tag_name += m_definition->m_on_value;
3320      to_untag_name += m_definition->m_off_value;
3321    }
3322  else
3323    {
3324      to_tag_name += m_definition->m_off_value;
3325      to_untag_name += m_definition->m_on_value;
3326    }
3327
3328  m_on_tag = Tag::find (to_tag_name);
3329  m_off_tag = Tag::find (to_untag_name);
3330
3331  if (m_on_tag == 0 || m_off_tag == 0)
3332    {
3333      m_on_tag = Tag::add (to_tag_name, PriorityConfig, "PROJECT", 0);
3334      m_off_tag = Tag::add (to_untag_name, PriorityConfig, "PROJECT", 0);
3335
3336      m_on_tag->add_tag_exclude (m_off_tag);
3337      m_off_tag->add_tag_exclude (m_on_tag);
3338    }
3339
3340  m_off_tag->unmark ();
3341  m_on_tag->mark ();
3342}
3343
3344//-----------------------------------------------------------
3345const cmt_string& StrategyDef::get_default_value () const
3346{
3347  if (m_default_value)
3348    {
3349      return (m_on_value);
3350    }
3351  else
3352    {
3353      return (m_off_value);
3354    }
3355}
3356
3357//-----------------------------------------------------------
3358void Project::set_author (const cmt_string& name)
3359{
3360  // cerr << "set_author" << name << endl;     
3361  this->m_author = name;
3362}
3363
3364//-----------------------------------------------------------
3365const cmt_string& Project::get_author () const
3366{
3367  return (m_author);
3368}
3369
3370//-----------------------------------------------------------
3371void Project::project_author_action (const CmtSystem::cmt_string_vector& words)
3372{
3373  if (m_author != "") m_author += "\n";
3374
3375  for (int i = 1; i < words.size (); i++)
3376    {
3377      const cmt_string& w = words[i];
3378     
3379      if (i > 1) m_author += " ";
3380      m_author += w; 
3381    }
3382}
3383
3384//-----------------------------------------------------------
3385Use*  Project::get_use () const
3386{
3387  return m_use;   
3388} 
3389
3390//-----------------------------------------------------------
3391void  Project::set_use (Use* use)
3392{ 
3393  this->m_use = use;
3394}
3395
3396//-----------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.