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

Last change on this file since 669 was 667, checked in by rybkin, 10 years ago

See C.L. 524

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