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

Last change on this file since 523 was 523, checked in by rybkin, 15 years ago

See C.L. 410

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