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

Last change on this file since 607 was 607, checked in by rybkin, 12 years ago

See C.L. 482

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