source: CMT/v1r25/source/cmt_project.cxx

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

See C.L. 485

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