source: CMT/v1r20p20081118/source/cmt_project.cxx @ 654

Last change on this file since 654 was 471, checked in by rybkin, 16 years ago

See C.L. 372

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