source: CMT/v1r25-branch/source/cmt_project.cxx @ 646

Last change on this file since 646 was 646, checked in by rybkin, 11 years ago

merge -r 635:645 HEAD

File size: 82.6 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  const ProjectPtrVector& OrderedProjects = Project::ordered_projects ();
2962  for (int i = OrderedProjects.size () - 2; i >= 0; i--)
2963    {
2964      if (this != OrderedProjects[i + 1]) continue;
2965      if (!OrderedProjects[i]->has_parents () &&
2966          OrderedProjects[i]->get_children_size () == 0)
2967        {
2968          OrderedProjects[i]->update_strategy (definition, b_value);
2969        }
2970      break;
2971    }
2972}
2973
2974/**----------------------------------------------------------
2975   The strategy value is changed because of indirect influences
2976   - default strategy at initialization time
2977   - change in the children
2978   - change in the children list
2979
2980   (This is not a specification : see the set_strategy method)
2981*/
2982void Project::update_strategy (StrategyDef* definition, bool b_value)
2983{
2984  bool need_strategy = true;
2985  bool specified = false;
2986
2987  int i;
2988
2989  for (i = 0; i < m_strategies.size (); i++)
2990    {
2991      Strategy& s = m_strategies[i];
2992      if (s.m_definition == definition)
2993        {
2994          need_strategy = false;
2995
2996          if (!s.m_specified)
2997            {
2998              // This strategy is already applied in this project. Let's change it's value
2999              s.update (definition, b_value, get_name ());
3000            }
3001          else
3002            {
3003              specified = true;
3004            }
3005          break;
3006        }
3007    }
3008
3009  if (need_strategy)
3010    {
3011      // This strategy is not yet applied in this project.
3012
3013      Strategy& s = m_strategies.add ();
3014      s.clear ();
3015      s.update (definition, b_value, get_name ());
3016    }
3017
3018  if (!specified)
3019    {
3020      for (i = 0; i < m_parents.size (); i++)
3021        {
3022          Project* project = m_parents[i];
3023
3024          project->update_strategy (definition, b_value);
3025        }
3026
3027      const ProjectPtrVector& OrderedProjects = Project::ordered_projects ();
3028      for (int i = OrderedProjects.size () - 2; i >= 0; i--)
3029        {
3030          if (this != OrderedProjects[i + 1]) continue;
3031          if (!OrderedProjects[i]->has_parents () &&
3032              OrderedProjects[i]->get_children_size () == 0)
3033            {
3034              OrderedProjects[i]->update_strategy (definition, b_value);
3035            }
3036          break;
3037        }
3038    }
3039}
3040
3041/**----------------------------------------------------------
3042   At least one of the children has changed this strategy
3043   Or the list of children has changed.
3044   We need to update the strategy value accordingly
3045   This will not change the specified value for this strategy
3046*/
3047void Project::update_strategy_from_children (StrategyDef* definition)
3048{
3049  // If this strategy is specified we don't care what happens from the children
3050
3051  //cerr << "Updating strategy " << definition->m_name << " from children for project " << m_name << endl;
3052
3053  int i;
3054
3055  for (i = 0; i < m_strategies.size (); i++)
3056    {
3057      Strategy& s = m_strategies[i];
3058      if (s.m_definition == definition)
3059        {
3060          // This strategy is applied in this project.
3061
3062          if (s.m_specified)
3063            {
3064              // There will be no impact since the strategy is specified
3065
3066              //cerr << "This strategy is specified in this project" << endl;
3067              return;
3068            }
3069
3070          break;
3071        }
3072    }
3073
3074  // The strategy is not specified locally so we will now figure out
3075  // which strategy has to be considered from the mixture of specifications
3076  // from all children.
3077
3078  // Algorithm:
3079  // - We consider children by pairs
3080  // - a child that specifies its strategy wins over a child that does not
3081  // - when the two children have the same level of priority we consider the priority value
3082
3083  Project* selected = 0;
3084  bool selected_is_specified = false;
3085  bool selected_value = definition->m_default_value;
3086
3087  for (i = 0; i < m_children.size (); i++)
3088    {
3089      Project* p = m_children[i];
3090
3091      //cerr << "Checking strategy for child " << p->get_name () << endl;
3092
3093      bool is_specified = p->is_specified (definition);
3094      bool value = p->get_strategy (definition);
3095
3096      if (selected == 0)
3097        {
3098          selected = p;
3099          selected_is_specified = is_specified;
3100          selected_value = value;
3101          continue;
3102        }
3103
3104      if (is_specified == selected_is_specified)
3105        {
3106          if (selected_value != value)
3107            {
3108              // same level of priority but different values -> we must decide
3109              bool priority_value = definition->m_priority_value;
3110              if (value == priority_value)
3111                {
3112                  selected = p;
3113                  selected_is_specified = is_specified;
3114                  selected_value = value;
3115                }
3116            }
3117        }
3118      else
3119        {
3120          if (is_specified)
3121            {
3122              selected = p;
3123              selected_is_specified = is_specified;
3124              selected_value = value;
3125            }
3126        }
3127    }
3128
3129  update_strategy (definition, selected_value); 
3130}
3131
3132/**----------------------------------------------------------
3133   At least one of the children has changed its strategies
3134   Or the list of children has changed.
3135   We need to update the strategy values accordingly
3136   This will not change the specified values
3137*/
3138void Project::update_strategies_from_children ()
3139{
3140  StrategyDef::StrategyDefs& defs = StrategyMgr::get_definitions ();
3141
3142  //cerr << "Updating strategies from children for project " << m_name << endl;
3143
3144  int i;
3145
3146  for (i = 0; i < defs.size (); i++)
3147    {
3148      StrategyDef* def = defs[i];
3149     
3150      update_strategy_from_children (def);
3151    }
3152
3153  for (i = 0; i < m_parents.size (); i++)
3154    {
3155      Project* p = m_parents[i];
3156      p->update_strategies_from_children ();
3157    }
3158}
3159
3160/**----------------------------------------------------------
3161   The StrategyMgr singleton
3162*/
3163StrategyMgr& StrategyMgr::instance ()
3164{
3165  static StrategyMgr me;
3166  return (me);
3167}
3168
3169/**----------------------------------------------------------
3170   The StrategyMgr constructor
3171   Here are primarily constructed all strategy definitions
3172*/
3173StrategyMgr::StrategyMgr ()
3174{
3175  m_defs.clear ();
3176
3177  StrategyDef* s;
3178
3179  s = new StrategyDef;
3180  s->m_keyword = "build";
3181  s->m_name = "BuildPrototypes";
3182  s->m_on_value = "prototypes";
3183  s->m_off_value = "no_prototypes";
3184  s->m_default_value = true;
3185  s->m_priority_value = false;
3186
3187  m_defs.push_back (s);
3188
3189  s = new StrategyDef;
3190  s->m_keyword = "build";
3191  s->m_name = "InstallArea";
3192  s->m_on_value = "with_installarea";
3193  s->m_off_value = "without_installarea";
3194  s->m_default_value = false;
3195  s->m_priority_value = true;
3196
3197  m_defs.push_back (s);
3198
3199  s = new StrategyDef;
3200  s->m_keyword = "setup";
3201  s->m_name = "SetupConfig";
3202  s->m_on_value = "config";
3203  s->m_off_value = "no_config";
3204  s->m_default_value = true;
3205  s->m_priority_value = false;
3206
3207  m_defs.push_back (s);
3208
3209  s = new StrategyDef;
3210  s->m_keyword = "setup";
3211  s->m_name = "SetupRoot";
3212  s->m_on_value = "root";
3213  s->m_off_value = "no_root";
3214  s->m_default_value = true;
3215  s->m_priority_value = false;
3216
3217  m_defs.push_back (s);
3218
3219  s = new StrategyDef;
3220  s->m_keyword = "setup";
3221  s->m_name = "SetupCleanup";
3222  s->m_on_value = "cleanup";
3223  s->m_off_value = "no_cleanup";
3224  s->m_default_value = true;
3225  s->m_priority_value = false;
3226
3227  m_defs.push_back (s);
3228
3229  s = new StrategyDef;
3230  s->m_keyword = "setup";
3231  s->m_name = "SetupScripts";
3232  s->m_on_value = "scripts";
3233  s->m_off_value = "no_scripts";
3234  s->m_default_value = true;
3235  s->m_priority_value = false;
3236
3237  m_defs.push_back (s);
3238
3239  s = new StrategyDef;
3240  s->m_keyword = "structure";
3241  s->m_name = "VersionDirectory";
3242  s->m_on_value = "with_version_directory";
3243  s->m_off_value = "without_version_directory";
3244  if (Cmt::get_current_structuring_style () != without_version_directory)
3245    {
3246      s->m_default_value = true;
3247      s->m_priority_value = false;
3248    }
3249  else
3250    {
3251      s->m_default_value = false;
3252      s->m_priority_value = true;
3253    }
3254
3255  m_defs.push_back (s);
3256}
3257
3258/**----------------------------------------------------------
3259   Find a strategy definition by its name
3260*/
3261StrategyDef* StrategyMgr::find_strategy (const cmt_string& name)
3262{
3263  static StrategyMgr& me = instance ();
3264
3265  int i;
3266
3267  for (i = 0; i < me.m_defs.size (); i++)
3268    {
3269      StrategyDef* def = me.m_defs[i];
3270      if (def->m_name == name)
3271        {
3272          return (def);
3273        }
3274    }
3275
3276  return (0);
3277}
3278
3279/**----------------------------------------------------------
3280   Retreive the default value defined for a given strategy
3281*/
3282bool StrategyMgr::get_default_strategy (const cmt_string& name)
3283{
3284  StrategyDef* def = find_strategy (name);
3285  if (def == 0) return (false);
3286  return (def->m_default_value);
3287}
3288
3289/**----------------------------------------------------------
3290   Retreive the priority value defined for a given strategy
3291   This value is used when two children of a project request two conflicting strategy values
3292*/
3293bool StrategyMgr::get_priority_strategy (const cmt_string& name)
3294{
3295  StrategyDef* def = find_strategy (name);
3296  if (def == 0) return (false);
3297  return (def->m_priority_value);
3298}
3299
3300/**----------------------------------------------------------
3301   Return the vector of all existing strategy definitions
3302*/
3303StrategyDef::StrategyDefs& StrategyMgr::get_definitions ()
3304{
3305  static StrategyMgr& me = instance ();
3306
3307  return (me.m_defs);
3308}
3309
3310//-----------------------------------------------------------
3311Strategy::Strategy ()
3312{
3313  clear ();
3314}
3315
3316//-----------------------------------------------------------
3317void Strategy::clear ()
3318{
3319  m_definition = 0;
3320  m_specified = false;
3321  m_specified_value = false;
3322  m_value = false;
3323  m_on_tag = 0;
3324  m_off_tag = 0;
3325}
3326
3327/**----------------------------------------------------------
3328   Specify a new value for this strategy.
3329   This only happens when a strategy statement is met in a project file or in a requirements file.
3330*/
3331void Strategy::set (StrategyDef* definition, bool value, const cmt_string& project_name)
3332{
3333  //cerr << "Setting strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
3334
3335  m_definition = definition;
3336  m_specified = true;
3337  m_specified_value = value;
3338
3339  update (definition, value, project_name);
3340}
3341
3342/**----------------------------------------------------------
3343   Change the effective value for this strategy.
3344   This has no impact on to the specified value.
3345   This will adapt the tag settings
3346*/
3347void Strategy::update (StrategyDef* definition, bool value, const cmt_string& project_name)
3348{
3349  //cerr << "Updating strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
3350
3351  m_value = value;
3352  m_definition = definition;
3353
3354  cmt_string to_tag_name = project_name;
3355  cmt_string to_untag_name = project_name;
3356
3357  to_tag_name += "_";
3358  to_untag_name += "_";
3359
3360  if (m_value)
3361    {
3362      to_tag_name += m_definition->m_on_value;
3363      to_untag_name += m_definition->m_off_value;
3364    }
3365  else
3366    {
3367      to_tag_name += m_definition->m_off_value;
3368      to_untag_name += m_definition->m_on_value;
3369    }
3370
3371  m_on_tag = Tag::find (to_tag_name);
3372  m_off_tag = Tag::find (to_untag_name);
3373
3374  if (m_on_tag == 0 || m_off_tag == 0)
3375    {
3376      m_on_tag = Tag::add (to_tag_name, PriorityConfig, "PROJECT", 0);
3377      m_off_tag = Tag::add (to_untag_name, PriorityConfig, "PROJECT", 0);
3378
3379      m_on_tag->add_tag_exclude (m_off_tag);
3380      m_off_tag->add_tag_exclude (m_on_tag);
3381    }
3382
3383  m_off_tag->unmark ();
3384  m_on_tag->mark ("PROJECT");
3385}
3386
3387//-----------------------------------------------------------
3388const cmt_string& StrategyDef::get_default_value () const
3389{
3390  if (m_default_value)
3391    {
3392      return (m_on_value);
3393    }
3394  else
3395    {
3396      return (m_off_value);
3397    }
3398}
3399
3400//-----------------------------------------------------------
3401void Project::set_author (const cmt_string& name)
3402{
3403  // cerr << "set_author" << name << endl;     
3404  this->m_author = name;
3405}
3406
3407//-----------------------------------------------------------
3408const cmt_string& Project::get_author () const
3409{
3410  return (m_author);
3411}
3412
3413//-----------------------------------------------------------
3414void Project::project_author_action (const CmtSystem::cmt_string_vector& words)
3415{
3416  if (m_author != "") m_author += "\n";
3417
3418  for (int i = 1; i < words.size (); i++)
3419    {
3420      const cmt_string& w = words[i];
3421     
3422      if (i > 1) m_author += " ";
3423      m_author += w; 
3424    }
3425}
3426
3427//-----------------------------------------------------------
3428Use*  Project::get_use () const
3429{
3430  return m_use;   
3431} 
3432
3433//-----------------------------------------------------------
3434void  Project::set_use (Use* use)
3435{ 
3436  this->m_use = use;
3437}
3438
3439//-----------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.