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

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

See C.L. 377

  • Property svn:eol-style set to native
File size: 63.7 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 (const CmtSystem::cmt_string_vector& arguments)
1060//void Project::show_paths ()
1061{
1062  if (arguments.size () == 0)
1063    {
1064      const ProjectPtrVector Ordered = Project::ordered_projects ();
1065      for (int i = 0; i < Ordered.size (); i++)
1066        {
1067          const Project* p = Ordered[i];
1068          const cmt_string& w = p->get_cmtpath_pwd ();
1069          const cmt_string& s = p->get_cmtpath_source ();
1070         
1071          if (s == "default path") continue;
1072         
1073          if (CmtSystem::test_directory (w))
1074            {
1075              cout << "# Add path " << w << " from " << s << endl;
1076            }
1077        }
1078    }
1079  else if (arguments.size () == 1 && cmt_string (arguments[0]) == "-d")
1080    {
1081      VisitorForShowPaths visitor;
1082      start_visit (visitor);
1083    }
1084  else
1085    CmtMessage::error ("show_paths: unexpected argument(s)");
1086}
1087
1088//----------------------------------------------------------
1089const cmt_string& Project::get_project_file_name ()
1090{
1091  static const cmt_string name = "project.cmt";
1092
1093  return (name);
1094}
1095
1096//----------------------------------------------------------
1097void Project::fill_selection (int depth, CmtSystem::cmt_string_vector& path_selections)
1098{
1099  static ProjectVector& Projects = projects ();
1100
1101  for (int i = 0; i < Projects.size (); i++)
1102    {
1103      Project& project = Projects[i];
1104
1105      const cmt_string& p = project.get_cmtpath ();
1106      const cmt_string& pwd = project.get_cmtpath_pwd ();
1107      const cmt_string& p_real = project.get_cmtpath_real ();
1108      const cmt_string& src = project.get_cmtpath_source ();
1109
1110      if (src != "default path")
1111        {
1112          if (depth > 0)
1113            {
1114              cmt_string& s1 = path_selections.add ();
1115              s1 = p;
1116              if (pwd != p)
1117                {
1118                  cmt_string& s2 = path_selections.add ();
1119                  s2 = pwd;
1120                }
1121              if (p_real != p && p_real != pwd)
1122                {
1123                  cmt_string& s3 = path_selections.add ();
1124                  s3 = p_real;
1125                }
1126              if (src != "CMTHOME" && src != "CMTUSERCONTEXT")
1127                depth--;
1128
1129              if (depth == 0) break;
1130            }
1131        }
1132    }
1133}
1134
1135//----------------------------------------------------------
1136void Project::broadcast (IProjectAction& action)
1137{
1138  static ProjectPtrVector Projects = Project::ordered_projects ();
1139
1140  for (int i = 0; i < Projects.size (); i++)
1141    {
1142      const Project* project = Projects[i];
1143
1144      if (!action.run (*project)) break;
1145    }
1146  /*
1147  static ProjectVector& Projects = projects ();
1148
1149  for (int i = 0; i < Projects.size (); i++)
1150    {
1151      const Project& project = Projects[i];
1152
1153      if (!action.run (project)) break;
1154    }
1155  */
1156}
1157
1158//----------------------------------------------------------
1159void Project::reverse_broadcast (IProjectAction& action)
1160{
1161  static ProjectPtrVector Projects = Project::ordered_projects ();
1162
1163  for (int i = (Projects.size () - 1); i >= 0; i--)
1164    {
1165      const Project* project = Projects[i];
1166
1167      if (!action.run (*project)) break;
1168    }
1169  /*
1170  static ProjectVector& Projects = projects ();
1171
1172  for (int i = (Projects.size () - 1); i >= 0; i--)
1173    {
1174      const Project& project = Projects[i];
1175
1176      if (!action.run (project)) break;
1177    }
1178  */
1179}
1180
1181//----------------------------------------------------------
1182void Project::scan_paths (PathScanner& scanner, PathScanner::actor& a)
1183{
1184  static ProjectVector& Projects = projects ();
1185
1186  int i;
1187
1188  for (i = 0; i < Projects.size (); i++)
1189    {
1190      Project& p  = Projects[i];
1191      p.m_visited = false;
1192    }
1193
1194  for (i = 0; i < Projects.size (); i++)
1195    {
1196      const Project& project = Projects[i];
1197       
1198      const cmt_string& p = project.m_cmtpath;
1199      scanner.scan_path (p, a);
1200    }
1201}
1202
1203//----------------------------------------------------------
1204void Project::scan_paths_for_package (PathScanner& scanner, const cmt_string& name)
1205{
1206  static ProjectVector& Projects = projects ();
1207
1208  for (int i = 0; i < Projects.size (); i++)
1209    {
1210      const Project& project = Projects[i];
1211
1212      const cmt_string& p = project.m_cmtpath;
1213      scanner.scan_package (p, name);
1214    }
1215}
1216
1217//----------------------------------------------------------
1218cmt_string Project::find_in_cmt_paths (const cmt_string& path)
1219{
1220  const cmt_string pwd = CmtSystem::pwd ();
1221
1222  // In case there are symlinks
1223  cmt_string path_real;
1224  //cerr << "realpath_: find_in_cmt_paths" << endl;
1225  CmtSystem::realpath_ (path, path_real);
1226
1227  static ProjectVector& Projects = projects ();
1228
1229  for (int i = 0; i < Projects.size (); i++)
1230    {
1231      const Project& project = Projects[i];
1232
1233      const cmt_string& p = project.m_cmtpath;
1234      const cmt_string& p_real = project.m_cmtpath_real;
1235      const cmt_string& w = project.m_cmtpath_pwd;
1236      const cmt_string& s = project.m_cmtpath_source;
1237
1238      if (s == "default path") continue;
1239
1240      if (CmtSystem::test_directory (p))
1241        {
1242//        if (path.find (p) != cmt_string::npos)
1243//          {
1244//            return (p);
1245//          }
1246
1247          if (path_real.find (p_real) != cmt_string::npos)
1248            {
1249              return (p);
1250            }
1251
1252          // To become the current area, a path must correspond to the current package
1253          if (path.find (w) != cmt_string::npos)
1254            {
1255              return (p);
1256            }
1257        }
1258
1259      if (p == w) continue;
1260
1261      if (CmtSystem::test_directory (w))
1262        {
1263          if (path.find (w) != cmt_string::npos)
1264            {
1265              return (w);
1266            }
1267        }
1268    }
1269
1270  return ("");
1271}
1272
1273//----------------------------------------------------------
1274void Project::visit (IProjectVisitor& visitor)
1275{
1276  if (m_visited) return;
1277  m_visited = true;
1278
1279  int i;
1280
1281  for (i = 0; i < get_children_size (); i++)
1282    {
1283      Project* child = get_child (i);
1284
1285      if (child->visited ()) continue;
1286
1287      visitor.in (child);
1288    }
1289
1290  for (i = 0; i < m_children.size (); i++)
1291    {
1292      Project* child = m_children[i];
1293      child->visit (visitor);
1294    }
1295}
1296
1297//----------------------------------------------------------
1298void Project::visit (IProjectVisitor& visitor, ProjectPtrVector& projects)
1299{
1300  int size = projects.size ();
1301  if (0 == size) return;
1302
1303  ProjectPtrVector children;
1304  for (int j = 0; j < size; j++)
1305    {
1306      Project* p = projects[j];
1307      if (20 == p->m_visits)
1308        continue;
1309      for (int i = 0; i < p->get_children_size (); i++)
1310        {
1311          Project* child = p->get_child (i);
1312          if (0 == child->m_visits)       
1313            visitor.in (child);
1314          else
1315            visitor.in_again (child);
1316          child->m_visits++;
1317          children.push_back (child);
1318        }
1319    }
1320
1321  visit (visitor, children);
1322}
1323
1324//----------------------------------------------------------
1325/**
1326 *  Visit the projects tree and order the projects.
1327 *  Order is the projects upon which the project depends directly,
1328 *  then the direct dependencies of the of the first dependency, of the second
1329 *  dependency and so on. That is first left to right, then downwards.
1330 *  @param order the order of the last project visited
1331 *  @param projs vector of projects to visit and order
1332 */
1333void Project::visit (int& order, ProjectPtrVector& projs)
1334{
1335  int size = projs.size ();
1336  if (0 == size) return;
1337  static ProjectVector& all = Project::projects ();
1338
1339  ProjectPtrVector children;
1340  for (int j = 0; j < size; j++)
1341    {
1342      Project* p = projs[j];
1343      // Avoid looping in case of circular project dependencies
1344      if (100 <= p->m_visits)
1345        continue;
1346      for (int i = 0; i < p->get_children_size (); i++)
1347        {
1348          Project* child = p->get_child (i);
1349          const int chorder = child->m_order;
1350          if (-1 == chorder) // not ordered yet, i.e. visited for the first time
1351            child->m_order = ++order;
1352          else
1353            { // ordered already, want to put it last in the order
1354              for (int k = 0; k < all.size (); k++)
1355                {
1356                  Project& q = all[k];
1357                  if (q.m_order == chorder)
1358                    q.m_order = order;
1359                  else if (q.m_order > chorder)
1360                    q.m_order--;
1361                }
1362            }
1363          child->m_visits++;
1364          children.push_back (child);
1365        }
1366    }
1367
1368  visit (order, children);
1369}
1370
1371//----------------------------------------------------------
1372void Project::start_visit (IProjectVisitor& visitor)
1373{
1374  static Project::ProjectVector& Projects = Project::projects ();
1375 
1376  for (int i = 0; i < Projects.size (); i++)
1377    {
1378      Project& p = Projects[i];
1379      p.m_visited = false;
1380      p.m_visits = 0;
1381    }
1382
1383  Project* p = get_current ();
1384
1385  if (p == 0)
1386    {
1387      if (Projects.size () == 0) return;
1388
1389      p = &(Projects[0]);
1390    }
1391
1392  //  visitor.pre (p);
1393  //p->visit (visitor);
1394  //  visitor.post (p);
1395  visitor.in (p);
1396  p->m_visits++;
1397  ProjectPtrVector projs;
1398  projs.push_back (p);
1399  visit (visitor, projs);
1400}
1401
1402//----------------------------------------------------------
1403class VisitorForFillCMTPATH : public IProjectVisitor
1404{
1405public:
1406  VisitorForFillCMTPATH (cmt_string& buffer) : m_buffer (buffer)
1407  {
1408    buffer = "path CMTPATH \"\" \n";
1409  }
1410
1411  void pre (Project* p)
1412  {
1413    const cmt_string& w = p->get_cmtpath_pwd ();
1414    const cmt_string& s = p->get_cmtpath_source ();
1415
1416    if (s == "default path") return;
1417
1418    if (CmtSystem::test_directory (w))
1419      {
1420        m_buffer += "path_append CMTPATH \"";
1421        m_buffer += w;
1422        m_buffer += "\" \n";
1423      }
1424  }
1425
1426  void in (Project* p)
1427  {
1428    const cmt_string& w = p->get_cmtpath_pwd ();
1429    const cmt_string& s = p->get_cmtpath_source ();
1430
1431    if (s == "default path") return;
1432
1433    if (CmtSystem::test_directory (w))
1434      {
1435        m_buffer += "path_append CMTPATH \"";
1436        m_buffer += w;
1437        m_buffer += "\" \n";
1438      }
1439  }
1440
1441  void in_again (Project* p)
1442  {
1443    const cmt_string& w = p->get_cmtpath_pwd ();
1444    const cmt_string& s = p->get_cmtpath_source ();
1445
1446    if (s == "default path") return;
1447
1448    if (CmtSystem::test_directory (w))
1449      {
1450        m_buffer += "path_remove CMTPATH \"";
1451        m_buffer += w;
1452        m_buffer += "\" \n";
1453        m_buffer += "path_append CMTPATH \"";
1454        m_buffer += w;
1455        m_buffer += "\" \n";
1456      }
1457  }
1458
1459  void post (Project* p)
1460  {
1461    //cerr << "Buffer = " << m_buffer << endl;
1462  }
1463
1464private:
1465  cmt_string& m_buffer;
1466
1467};
1468
1469//----------------------------------------------------------
1470void Project::fill_cmtpaths (cmt_string& buffer)
1471{
1472  /*
1473    Try to re-create all CMTPATH items from project definitions.
1474    The goal is to generate CMTPATH even if this EV was not pre-set
1475    which is the case when CMTPROJECTPATH is only used
1476  */
1477
1478  /*
1479  VisitorForFillCMTPATH visitor (buffer);
1480
1481  start_visit (visitor);
1482  */
1483  const ProjectPtrVector Ordered = Project::ordered_projects ();
1484
1485  buffer = "path CMTPATH \"\" \n";
1486  for (int i = 0; i < Ordered.size (); i++)
1487    {
1488      const Project* p = Ordered[i];
1489      const cmt_string& w = p->get_cmtpath_pwd ();
1490      const cmt_string& s = p->get_cmtpath_source ();
1491     
1492      if (s == "default path") continue;
1493     
1494      if (CmtSystem::test_directory (w))
1495        {
1496          buffer += "path_append CMTPATH \"";
1497          buffer += w;
1498          buffer += "\" \n";
1499        }
1500    }
1501}
1502
1503//----------------------------------------------------------
1504Project::Project () : m_name (""), m_author("")
1505{
1506  clear ();
1507}
1508
1509//----------------------------------------------------------
1510const cmt_string& Project::get_name () const
1511{
1512  return (m_name);
1513}
1514
1515//----------------------------------------------------------
1516const cmt_string& Project::get_release () const
1517{
1518  return (m_release);
1519}
1520
1521//----------------------------------------------------------
1522const cmt_string& Project::get_container () const
1523{
1524  return (m_container);
1525}
1526
1527//----------------------------------------------------------
1528const cmt_string& Project::get_container_version () const
1529{
1530  return (m_container_version);
1531}
1532
1533//----------------------------------------------------------
1534const cmt_string& Project::get_cmtpath () const
1535{
1536  return (m_cmtpath);
1537}
1538
1539//----------------------------------------------------------
1540const cmt_string& Project::get_cmtpath_real () const
1541{
1542  return (m_cmtpath_real);
1543}
1544
1545//----------------------------------------------------------
1546const cmt_string& Project::get_cmtpath_pwd () const
1547{
1548  return (m_cmtpath_pwd);
1549}
1550
1551//----------------------------------------------------------
1552const cmt_string& Project::get_cmtpath_source () const
1553{
1554  return (m_cmtpath_source);
1555}
1556
1557//----------------------------------------------------------
1558int Project::get_children_size () const
1559{
1560  return (m_children.size ());
1561}
1562
1563//----------------------------------------------------------
1564Project* Project::get_child (int index) const
1565{
1566  if (index < 0) return (0);
1567  if (index >= m_children.size ()) return (0);
1568  return (m_children[index]);
1569}
1570
1571//----------------------------------------------------------
1572bool Project::visited () const
1573{
1574  return (m_visited);
1575}
1576
1577//----------------------------------------------------------
1578void Project::set_name (const cmt_string& name)
1579{
1580  m_name = name;
1581}
1582
1583//----------------------------------------------------------
1584void Project::set_release (const cmt_string& release)
1585{
1586  m_release = release;
1587}
1588
1589//----------------------------------------------------------
1590void Project::set_container (const cmt_string& container)
1591{
1592  m_container = container;
1593}
1594
1595//----------------------------------------------------------
1596void Project::set_container_version (const cmt_string& container_version)
1597{
1598  m_container_version = container_version;
1599}
1600
1601//----------------------------------------------------------
1602void Project::set_cmtpath (const cmt_string& path)
1603{
1604  m_cmtpath = path;
1605}
1606
1607//----------------------------------------------------------
1608void Project::set_cmtpath_real (const cmt_string& path)
1609{
1610  m_cmtpath_real = path;
1611}
1612
1613//----------------------------------------------------------
1614void Project::set_cmtpath_pwd (const cmt_string& path)
1615{
1616  m_cmtpath_pwd = path;
1617}
1618
1619//----------------------------------------------------------
1620void Project::set_cmtpath_source (const cmt_string& source)
1621{
1622  m_cmtpath_source = source;
1623}
1624
1625//----------------------------------------------------------
1626void Project::clear ()
1627{
1628  m_name    = "";
1629  m_release = "";
1630  m_cmtpath = "";
1631  m_cmtpath_real = "";
1632  m_cmtpath_pwd    = "";
1633  m_cmtpath_source = "";
1634  m_use            = 0;
1635
1636  m_parents.clear ();
1637  m_children.clear ();
1638
1639  m_configured = false;
1640
1641  m_strategies.clear ();
1642}
1643
1644//----------------------------------------------------------
1645bool Project::has_parents () const
1646{
1647  return ((m_parents.size () > 0));
1648}
1649
1650//----------------------------------------------------------
1651bool Project::has_parent (Project* p) const
1652{
1653  if (p == 0) return (false);
1654  if (p == this) return (false);
1655
1656  const cmt_string& name = p->get_name ();
1657
1658  int i;
1659
1660  for (i = 0; i < m_parents.size (); i++)
1661    {
1662      const Project* parent = m_parents[i];
1663      if (parent == 0) continue;
1664
1665      if (parent->get_name () == name)
1666        {
1667          // registered as a parent
1668          return (true);
1669        }
1670
1671      if (parent->has_parent (p))
1672        {
1673          // recurse
1674          return (true);
1675        }
1676    }
1677
1678  return (false);
1679}
1680
1681//----------------------------------------------------------
1682bool Project::has_child (Project* p) const
1683{
1684  if (p == 0) return (false);
1685  if (p == this) return (false);
1686
1687  const cmt_string& name = p->get_name ();
1688
1689  int i;
1690
1691  for (i = 0; i < m_children.size (); i++)
1692    {
1693      const Project* child = m_children[i];
1694      if (child == 0) continue;
1695
1696      if (child->get_name () == name)
1697        {
1698          // registered as a child
1699          return (true);
1700        }
1701
1702      if (child->has_child (p))
1703        {
1704          // recurse
1705          return (true);
1706        }
1707    }
1708
1709  return (false);
1710}
1711
1712//----------------------------------------------------------
1713void Project::add_parent (Project* p)
1714{
1715  if (p == 0) return;
1716  if (p == this) return;
1717
1718  //cerr << "Adding parent " << p->get_name () << " to " << m_name << endl;
1719
1720  if (has_child (p)) return;
1721  if (has_parent (p)) return;
1722
1723  m_parents.push_back (p);
1724}
1725
1726//----------------------------------------------------------
1727void Project::add_child (Project* p)
1728{
1729  if (p == 0) return;
1730  if (p == this) return;
1731
1732  if (has_child (p)) return;
1733  if (has_parent (p)) return;
1734
1735  m_children.push_back (p);
1736}
1737
1738//----------------------------------------------------------
1739void Project::configure ()
1740{
1741  if (m_configured) return;
1742  m_configured = true;
1743
1744  set_default_strategy ("SetupConfig");
1745  set_default_strategy ("SetupRoot");
1746  set_default_strategy ("SetupCleanup");
1747  set_default_strategy ("BuildPrototypes");
1748  set_default_strategy ("InstallArea");
1749  set_default_strategy ("VersionDirectory");
1750}
1751
1752/**---------------------------------------------------------
1753   A container statement is met in the project file
1754*/
1755void Project::container_action (const cmt_string& name, const cmt_string& version)
1756{
1757  //cerr << "Container action " << name << " " << version << endl;
1758
1759  set_container (name);
1760  set_container_version (version);
1761}
1762
1763/**---------------------------------------------------------
1764   A use statement is met in the project file
1765*/
1766void Project::use_action (const cmt_string& name, const cmt_string& release)
1767{
1768  if (Cmt::get_debug ())
1769    {
1770      cout << "Use action " << name << " " << release << endl;
1771    }
1772
1773  // A project with its release is specified
1774  //
1775  // Is this project already visible?
1776  // If not: look for it
1777  //   + get CMTPROJECTPATH
1778  //   + search from all entries of CMTPROJECTPATH : p(i)/<name>/<release>
1779  //   + when found, this should become a new CMTPATH entry
1780  //   +             the new project is then parsed ... etc...
1781
1782  // First test it wilcard is used
1783  int v = -1;
1784  int r = -1;
1785  int p = -1;
1786  cmt_string new_release = release;
1787  CmtSystem::is_version_directory (new_release, v, r, p); 
1788  bool use_has_wild_card = (v == -1) || (r == -1) || (p == -1);
1789  if (use_has_wild_card)
1790    {
1791      cmt_string selected_release = "";
1792
1793      if (select_release(name, new_release,selected_release))
1794        {
1795          // cerr <<"selected_release: "<<selected_release<<endl;   
1796          new_release = selected_release;
1797        }         
1798    }
1799
1800  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
1801  cmt_string sep;
1802  sep = CmtSystem::path_separator ();
1803
1804  CmtSystem::cmt_string_vector items;
1805  CmtSystem::split (cmtprojectpath, sep, items);
1806
1807  bool found = false;
1808
1809  for (int i = 0; i < items.size (); i++)
1810    {
1811      const cmt_string& item = items[i];
1812      cmt_string p = item;
1813      p += CmtSystem::file_separator ();
1814      p += name;
1815      if (new_release != "")
1816        {
1817          p += CmtSystem::file_separator ();
1818          p += new_release;
1819        }
1820
1821      if (CmtSystem::test_directory (p))
1822        {
1823          //cerr << "Project directory " << p << " exists " << endl;
1824
1825          found = true;
1826
1827          IProjectFactory& factory = ProjectFactory::instance ();
1828
1829          factory.create_project (name, p, "ProjectPath", this);
1830
1831          break;
1832        }
1833    }
1834
1835  if (!found)
1836    {
1837      Project* p = Project::find_by_name (name);
1838
1839      if (p != 0)
1840        {
1841          found = true;
1842          p->add_parent (this);
1843          add_child (p);
1844
1845          update_strategies_from_children ();
1846        }
1847    }
1848   
1849  if (!found && (cmtprojectpath != ""))
1850    {
1851      CmtMessage::warning ("Project " + name + " " + release + " requested by " + m_name + " not found in CMTPROJECTPATH");
1852      //      cerr << "#CMT> Project " << name << " " << release << " requested by " << m_name << " not found in CMTPROJECTPATH" << endl;
1853    }
1854}
1855
1856//---------------------------------------------------------
1857bool Project::select_release(const cmt_string& name, const cmt_string& release, cmt_string& result)
1858{
1859  cmt_string selected_release = "";
1860
1861  int v = -1;
1862  int r = -1;
1863  int p = -1;
1864  CmtSystem::is_version_directory (release, v, r, p); 
1865
1866  int selected_v = -1;
1867  int selected_r = -1;
1868  int selected_p = -1;
1869  CmtSystem::cmt_string_vector releases = get_project_releases(name);
1870  for (int j = 0; j < releases.size (); j++)
1871    {
1872      int new_v = -1;
1873      int new_r = -1;
1874      int new_p = -1;
1875      CmtSystem::is_version_directory (releases[j], new_v, new_r, new_p);
1876      if (v == -1)
1877        {
1878          if (selected_v < new_v)
1879            {
1880              selected_v = new_v;
1881              selected_r = -1;
1882              selected_p = -1;
1883              selected_release = releases[j];
1884            }
1885          else if (selected_v == new_v)
1886            {
1887              // We compare the r
1888              if (selected_r < new_r)
1889                {
1890                  selected_r = new_r;
1891                  selected_p = -1;
1892                  selected_release = releases[j];                               
1893                }
1894              else if (selected_r == new_r)
1895                {
1896                  // We compare the p
1897                  if (selected_p < new_p)
1898                    {
1899                      selected_p = new_p;
1900                      selected_release = releases[j];                               
1901                    }
1902                  // else if ? not possible                                                           
1903                }                               
1904            }
1905        }
1906      else if (r == -1)
1907        {
1908          if (v == new_v)
1909            {
1910              // We compare the r                                                     
1911              if (selected_r < new_r)
1912                {
1913                  selected_r = new_r;
1914                  selected_p = -1;
1915                  selected_release = releases[j];                               
1916                }
1917              else if (selected_r == new_r)
1918                { 
1919                  // We compare the p
1920                  if (selected_p < new_p)
1921                    {
1922                      selected_p = new_p;
1923                      selected_release = releases[j];                               
1924                    }
1925                  // else if ? not possible
1926                }
1927            }
1928        }
1929      else if (p == -1)
1930        {
1931          if ((v == new_v) && (r == new_r))
1932            { 
1933              // We compare the p
1934              if (selected_p < new_p)
1935                {
1936                  selected_p = new_p;
1937                  selected_release = releases[j];                               
1938                }
1939              // else if ? not possible
1940            }       
1941        }       
1942
1943      //cerr << "v:" << new_v << ", r:" << new_r << ", p:" << new_p << endl;             
1944      //cerr << "req v:" << v << ", req r:" << r << ", req p:" << p << endl;       
1945
1946    }
1947
1948  // cerr << "selected release: " << selected_release << endl; 
1949
1950  if (selected_release == "") return false;
1951
1952  result = selected_release;   
1953
1954  return (true);
1955}
1956
1957//---------------------------------------------------------
1958const CmtSystem::cmt_string_vector Project::get_project_releases (const cmt_string& name) const
1959{
1960  CmtSystem::cmt_string_vector releases;
1961  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
1962
1963  static cmt_string sep = CmtSystem::path_separator ();
1964
1965  CmtSystem::cmt_string_vector items;
1966  CmtSystem::split (cmtprojectpath, sep, items);   
1967
1968  for (int i = 0; i < items.size (); i++)
1969    {
1970      const cmt_string& item = items[i];
1971      cmt_string p = item;
1972      p += CmtSystem::file_separator ();
1973      p += name;
1974
1975      if (CmtSystem::test_directory (p))
1976        { 
1977          CmtSystem::cmt_string_vector directories;
1978          CmtSystem::scan_dir (p, directories);
1979
1980          for (int j = 0; j < directories.size (); j++)
1981            {
1982              if  (CmtSystem::test_directory(directories[j]))
1983                {
1984                  cmt_string release;
1985                  CmtSystem:: basename(directories[j], release);
1986
1987                  if (CmtSystem::is_version_directory(release))
1988                    {                             
1989                      cmt_string& name_entry = releases.add ();
1990                      name_entry = release; 
1991                    }             
1992                }                           
1993            }                           
1994        }
1995    }
1996  return (releases);
1997}
1998
1999//----------------------------------------------------------
2000Project& Project::operator = (const Project& other)
2001{
2002  m_name = other.m_name;
2003  m_cmtpath = other.m_cmtpath;
2004  m_cmtpath_real = other.m_cmtpath_real;
2005  m_cmtpath_pwd = other.m_cmtpath_pwd;
2006  m_cmtpath_source = other.m_cmtpath_source;
2007
2008  return (*this);
2009}
2010
2011//----------------------------------------------------------
2012bool Project::operator == (const cmt_string& name) const
2013{
2014  return ((m_name == name));
2015}
2016
2017//----------------------------------------------------------
2018bool Project::operator != (const cmt_string& name) const
2019{
2020  return ((m_name != name));
2021}
2022
2023//----------------------------------------------------------
2024void Project::show ()
2025{
2026  static int level = 0;
2027
2028  bool is_current = false;
2029
2030  //  cmt_string here = CmtSystem::pwd ();
2031  // In case there are symlinks
2032  cmt_string here_real;
2033  CmtSystem::realpath_ (CmtSystem::pwd (), here_real);
2034
2035  //  if (here.find (m_cmtpath) == 0)
2036  if (here_real.find (m_cmtpath_real) == 0) 
2037    {
2038      if (m_cmtpath_source != "default path")
2039        {
2040          is_current = true;
2041        }
2042    }
2043
2044  for (int tab = 0; tab < level; tab++) cout << "  ";
2045  cout << m_name << " " << m_release << " (in " << m_cmtpath << ")";
2046
2047  if (is_current) cout << " (current)";
2048
2049  int i;
2050
2051  for (i = 0; i < m_parents.size (); i++)
2052    {
2053      Project* p = m_parents[i];
2054      if (p == 0) continue;
2055      cout << " P=" << p->get_name ();
2056    }
2057
2058  for (i = 0; i < m_children.size (); i++)
2059    {
2060      Project* p = m_children[i];
2061      if (p == 0) continue;
2062      cout << " C=" << p->get_name ();
2063    }
2064
2065  cout << endl;
2066
2067  if (m_visited) return;
2068
2069  m_visited = true;
2070
2071  for (i = 0; i < m_children.size (); i++)
2072    {
2073      Project* p = m_children[i];
2074      if (p == 0) continue;
2075      level++;
2076      p->show ();
2077      level--;
2078    }
2079}
2080
2081
2082//----------------------------------------------------------
2083void Project::show_specified_strategies () const
2084{
2085  int i;
2086
2087  for (i = 0; i < m_strategies.size (); i++)
2088    {
2089      const Strategy& s = m_strategies[i];
2090      if (s.m_specified)
2091        {
2092          const StrategyDef* def = s.m_definition;
2093 
2094          cout << "# Project " << m_name
2095               << " sets " << def->m_keyword
2096               << " strategy to " << ((s.m_value) ? def->m_on_value : def->m_off_value);
2097
2098          if (s.m_context != "")
2099            {
2100              cout << " (from package " << s.m_context << ")";
2101            }
2102
2103          cout << endl;
2104        }
2105    }
2106}
2107
2108//----------------------------------------------------------
2109bool Project::has_strategy (const StrategyDef* definition) const
2110{
2111  int i;
2112
2113  for (i = 0; i < m_strategies.size (); i++)
2114    {
2115      const Strategy& s = m_strategies[i];
2116      if (s.m_definition == definition)
2117        {
2118          return (true);
2119        }
2120    }
2121
2122  return (false);
2123}
2124
2125//----------------------------------------------------------
2126bool Project::get_strategy (const cmt_string& name) const
2127{
2128  static StrategyMgr& mgr = StrategyMgr::instance ();
2129
2130  StrategyDef* def = mgr.find_strategy (name);
2131  if (def == 0)
2132    {
2133      CmtMessage::warning ("strategy " + name + " undefined");
2134      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2135      return (false);
2136    }
2137
2138  return (get_strategy (def));
2139}
2140
2141//----------------------------------------------------------
2142bool Project::is_specified (const StrategyDef* definition) const
2143{
2144  int i;
2145
2146  for (i = 0; i < m_strategies.size (); i++)
2147    {
2148      Strategy& s = m_strategies[i];
2149      if (s.m_definition == definition)
2150        {
2151          // This strategy is applied in this project
2152          return (s.m_specified);
2153        }
2154    }
2155
2156  // This strategy is not applied in this project
2157  return (false);
2158}
2159
2160//----------------------------------------------------------
2161bool Project::get_strategy (const StrategyDef* def) const
2162{
2163  int i;
2164
2165  for (i = 0; i < m_strategies.size (); i++)
2166    {
2167      Strategy& s = m_strategies[i];
2168      if (s.m_definition == def)
2169        {
2170          // This strategy is applied in this project
2171          if (s.m_specified)
2172            {
2173              return (s.m_specified_value);
2174            }
2175          return (s.m_value);
2176        }
2177    }
2178
2179  // This strategy is not applied in this project
2180  return (def->m_default_value);
2181}
2182
2183//----------------------------------------------------------
2184void Project::set_default_strategy (const cmt_string& name)
2185{
2186  static StrategyMgr& mgr = StrategyMgr::instance ();
2187
2188  StrategyDef* def = mgr.find_strategy (name);
2189  if (def == 0)
2190    {
2191      CmtMessage::warning ("strategy " + name + " undefined");
2192      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2193      return;
2194    }
2195
2196  update_strategy (def, def->m_default_value);
2197}
2198
2199
2200//----------------------------------------------------------
2201void Project::set_strategy (const cmt_string& name, const cmt_string& value, const cmt_string& context)
2202{
2203  static StrategyMgr& mgr = StrategyMgr::instance ();
2204
2205  StrategyDef* def = mgr.find_strategy (name);
2206  if (def == 0)
2207    {
2208      CmtMessage::warning ("strategy " + name + " undefined");
2209      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2210      return;
2211    }
2212
2213  bool b_value = false;
2214
2215  if (value == def->m_on_value)
2216    {
2217      b_value = true;
2218    }
2219  else if (value == def->m_off_value)
2220    {
2221      b_value = false;
2222    }
2223  else
2224    {
2225      CmtMessage::warning ("requested strategy value " + value + " undefined in strategy " + name);
2226      //      cerr << "#CMT> requested strategy value " << value << " undefined in strategy " << name << endl;
2227      return;
2228    }
2229
2230  set_strategy (def, b_value, context);
2231}
2232
2233//----------------------------------------------------------
2234void Project::set_strategy (StrategyDef* definition, bool b_value, const cmt_string& context)
2235{
2236  bool need_strategy = true;
2237
2238  int i;
2239
2240  for (i = 0; i < m_strategies.size (); i++)
2241    {
2242      Strategy& s = m_strategies[i];
2243      if (s.m_definition == definition)
2244        {
2245          // This strategy is already applied in this project. Let's change it's value
2246          s.set (definition, b_value, get_name ());
2247          if (context != "")
2248            {
2249              if (s.m_context != "") s.m_context += " ";
2250              s.m_context += context;
2251            }
2252          need_strategy = false;
2253          break;
2254        }
2255    }
2256
2257  if (need_strategy)
2258    {
2259      // This strategy is not yet applied in this project.
2260
2261      Strategy& s = m_strategies.add ();
2262      s.clear ();
2263      s.set (definition, b_value, get_name ());
2264      s.m_context = context;
2265    }
2266 
2267  for (i = 0; i < m_parents.size (); i++)
2268    {
2269      Project* project = m_parents[i];
2270
2271      project->update_strategy (definition, b_value);
2272    }
2273}
2274
2275/**----------------------------------------------------------
2276   The strategy value is changed because of indirect influences
2277   - default strategy at initialization time
2278   - change in the children
2279   - change in the children list
2280
2281   (This is not a specification : see the set_strategy method)
2282*/
2283void Project::update_strategy (StrategyDef* definition, bool b_value)
2284{
2285  bool need_strategy = true;
2286  bool specified = false;
2287
2288  int i;
2289
2290  for (i = 0; i < m_strategies.size (); i++)
2291    {
2292      Strategy& s = m_strategies[i];
2293      if (s.m_definition == definition)
2294        {
2295          need_strategy = false;
2296
2297          if (!s.m_specified)
2298            {
2299              // This strategy is already applied in this project. Let's change it's value
2300              s.update (definition, b_value, get_name ());
2301            }
2302          else
2303            {
2304              specified = true;
2305            }
2306          break;
2307        }
2308    }
2309
2310  if (need_strategy)
2311    {
2312      // This strategy is not yet applied in this project.
2313
2314      Strategy& s = m_strategies.add ();
2315      s.clear ();
2316      s.update (definition, b_value, get_name ());
2317    }
2318
2319  if (!specified)
2320    {
2321      for (i = 0; i < m_parents.size (); i++)
2322        {
2323          Project* project = m_parents[i];
2324
2325          project->update_strategy (definition, b_value);
2326        }
2327    }
2328}
2329
2330/**----------------------------------------------------------
2331   At least one of the children has changed this strategy
2332   Or the list of children has changed.
2333   We need to update the strategy value accordingly
2334   This will not change the specified value for this strategy
2335*/
2336void Project::update_strategy_from_children (StrategyDef* definition)
2337{
2338  // If this strategy is specified we don't care what happens from the children
2339
2340  //cerr << "Updating strategy " << definition->m_name << " from children for project " << m_name << endl;
2341
2342  int i;
2343
2344  for (i = 0; i < m_strategies.size (); i++)
2345    {
2346      Strategy& s = m_strategies[i];
2347      if (s.m_definition == definition)
2348        {
2349          // This strategy is applied in this project.
2350
2351          if (s.m_specified)
2352            {
2353              // There will be no impact since the strategy is specified
2354
2355              //cerr << "This strategy is specified in this project" << endl;
2356              return;
2357            }
2358
2359          break;
2360        }
2361    }
2362
2363  // The strategy is not specified locally so we will now figure out
2364  // which strategy has to be considered from the mixture of specifications
2365  // from all children.
2366
2367  // Algorithm:
2368  // - We consider children by pairs
2369  // - a child that specifies its strategy wins over a child that does not
2370  // - when the two children have the same level of priority we consider the priority value
2371
2372  Project* selected = 0;
2373  bool selected_is_specified = false;
2374  bool selected_value = definition->m_default_value;
2375
2376  for (i = 0; i < m_children.size (); i++)
2377    {
2378      Project* p = m_children[i];
2379
2380      //cerr << "Checking strategy for child " << p->get_name () << endl;
2381
2382      bool is_specified = p->is_specified (definition);
2383      bool value = p->get_strategy (definition);
2384
2385      if (selected == 0)
2386        {
2387          selected = p;
2388          selected_is_specified = is_specified;
2389          selected_value = value;
2390          continue;
2391        }
2392
2393      if (is_specified == selected_is_specified)
2394        {
2395          if (selected_value != value)
2396            {
2397              // same level of priority but different values -> we must decide
2398              bool priority_value = definition->m_priority_value;
2399              if (value == priority_value)
2400                {
2401                  selected = p;
2402                  selected_is_specified = is_specified;
2403                  selected_value = value;
2404                }
2405            }
2406        }
2407      else
2408        {
2409          if (is_specified)
2410            {
2411              selected = p;
2412              selected_is_specified = is_specified;
2413              selected_value = value;
2414            }
2415        }
2416    }
2417
2418  update_strategy (definition, selected_value); 
2419}
2420
2421/**----------------------------------------------------------
2422   At least one of the children has changed its strategies
2423   Or the list of children has changed.
2424   We need to update the strategy values accordingly
2425   This will not change the specified values
2426*/
2427void Project::update_strategies_from_children ()
2428{
2429  StrategyDef::StrategyDefs& defs = StrategyMgr::get_definitions ();
2430
2431  //cerr << "Updating strategies from children for project " << m_name << endl;
2432
2433  int i;
2434
2435  for (i = 0; i < defs.size (); i++)
2436    {
2437      StrategyDef* def = defs[i];
2438     
2439      update_strategy_from_children (def);
2440    }
2441
2442  for (i = 0; i < m_parents.size (); i++)
2443    {
2444      Project* p = m_parents[i];
2445      p->update_strategies_from_children ();
2446    }
2447}
2448
2449/**----------------------------------------------------------
2450   The StrategyMgr singleton
2451*/
2452StrategyMgr& StrategyMgr::instance ()
2453{
2454  static StrategyMgr me;
2455  return (me);
2456}
2457
2458/**----------------------------------------------------------
2459   The StrategyMgr constructor
2460   Here are primarily constructed all strategy definitions
2461*/
2462StrategyMgr::StrategyMgr ()
2463{
2464  m_defs.clear ();
2465
2466  StrategyDef* s;
2467
2468  s = new StrategyDef;
2469  s->m_keyword = "build";
2470  s->m_name = "BuildPrototypes";
2471  s->m_on_value = "prototypes";
2472  s->m_off_value = "no_prototypes";
2473  s->m_default_value = true;
2474  s->m_priority_value = false;
2475
2476  m_defs.push_back (s);
2477
2478  s = new StrategyDef;
2479  s->m_keyword = "build";
2480  s->m_name = "InstallArea";
2481  s->m_on_value = "with_installarea";
2482  s->m_off_value = "without_installarea";
2483  s->m_default_value = false;
2484  s->m_priority_value = true;
2485
2486  m_defs.push_back (s);
2487
2488  s = new StrategyDef;
2489  s->m_keyword = "setup";
2490  s->m_name = "SetupConfig";
2491  s->m_on_value = "config";
2492  s->m_off_value = "no_config";
2493  s->m_default_value = true;
2494  s->m_priority_value = false;
2495
2496  m_defs.push_back (s);
2497
2498  s = new StrategyDef;
2499  s->m_keyword = "setup";
2500  s->m_name = "SetupRoot";
2501  s->m_on_value = "root";
2502  s->m_off_value = "no_root";
2503  s->m_default_value = true;
2504  s->m_priority_value = false;
2505
2506  m_defs.push_back (s);
2507
2508  s = new StrategyDef;
2509  s->m_keyword = "setup";
2510  s->m_name = "SetupCleanup";
2511  s->m_on_value = "cleanup";
2512  s->m_off_value = "no_cleanup";
2513  s->m_default_value = true;
2514  s->m_priority_value = false;
2515
2516  m_defs.push_back (s);
2517
2518  s = new StrategyDef;
2519  s->m_keyword = "structure";
2520  s->m_name = "VersionDirectory";
2521  s->m_on_value = "with_version_directory";
2522  s->m_off_value = "without_version_directory";
2523  if (Cmt::get_current_structuring_style () != without_version_directory)
2524    {
2525      s->m_default_value = true;
2526      s->m_priority_value = false;
2527    }
2528  else
2529    {
2530      s->m_default_value = false;
2531      s->m_priority_value = true;
2532    }
2533
2534  m_defs.push_back (s);
2535}
2536
2537/**----------------------------------------------------------
2538   Find a strategy definition by its name
2539*/
2540StrategyDef* StrategyMgr::find_strategy (const cmt_string& name)
2541{
2542  static StrategyMgr& me = instance ();
2543
2544  int i;
2545
2546  for (i = 0; i < me.m_defs.size (); i++)
2547    {
2548      StrategyDef* def = me.m_defs[i];
2549      if (def->m_name == name)
2550        {
2551          return (def);
2552        }
2553    }
2554
2555  return (0);
2556}
2557
2558/**----------------------------------------------------------
2559   Retreive the default value defined for a given strategy
2560*/
2561bool StrategyMgr::get_default_strategy (const cmt_string& name)
2562{
2563  StrategyDef* def = find_strategy (name);
2564  if (def == 0) return (false);
2565  return (def->m_default_value);
2566}
2567
2568/**----------------------------------------------------------
2569   Retreive the priority value defined for a given strategy
2570   This value is used when two children of a project request two conflicting strategy values
2571*/
2572bool StrategyMgr::get_priority_strategy (const cmt_string& name)
2573{
2574  StrategyDef* def = find_strategy (name);
2575  if (def == 0) return (false);
2576  return (def->m_priority_value);
2577}
2578
2579/**----------------------------------------------------------
2580   Return the vector of all existing strategy definitions
2581*/
2582StrategyDef::StrategyDefs& StrategyMgr::get_definitions ()
2583{
2584  static StrategyMgr& me = instance ();
2585
2586  return (me.m_defs);
2587}
2588
2589//-----------------------------------------------------------
2590Strategy::Strategy ()
2591{
2592  clear ();
2593}
2594
2595//-----------------------------------------------------------
2596void Strategy::clear ()
2597{
2598  m_definition = 0;
2599  m_specified = false;
2600  m_specified_value = false;
2601  m_value = false;
2602  m_on_tag = 0;
2603  m_off_tag = 0;
2604}
2605
2606/**----------------------------------------------------------
2607   Specify a new value for this strategy.
2608   This only happens when a strategy statement is met in a project file or in a requirements file.
2609*/
2610void Strategy::set (StrategyDef* definition, bool value, const cmt_string& project_name)
2611{
2612  //cerr << "Setting strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
2613
2614  m_definition = definition;
2615  m_specified = true;
2616  m_specified_value = value;
2617
2618  update (definition, value, project_name);
2619}
2620
2621/**----------------------------------------------------------
2622   Change the effective value for this strategy.
2623   This has no impact on to the specified value.
2624   This will adapt the tag settings
2625*/
2626void Strategy::update (StrategyDef* definition, bool value, const cmt_string& project_name)
2627{
2628  //cerr << "Updating strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
2629
2630  m_value = value;
2631  m_definition = definition;
2632
2633  cmt_string to_tag_name = project_name;
2634  cmt_string to_untag_name = project_name;
2635
2636  to_tag_name += "_";
2637  to_untag_name += "_";
2638
2639  if (m_value)
2640    {
2641      to_tag_name += m_definition->m_on_value;
2642      to_untag_name += m_definition->m_off_value;
2643    }
2644  else
2645    {
2646      to_tag_name += m_definition->m_off_value;
2647      to_untag_name += m_definition->m_on_value;
2648    }
2649
2650  m_on_tag = Tag::find (to_tag_name);
2651  m_off_tag = Tag::find (to_untag_name);
2652
2653  if (m_on_tag == 0) 
2654    {
2655      m_on_tag = Tag::add (to_tag_name, PriorityConfig, "PROJECT", 0);
2656      m_off_tag = Tag::add (to_untag_name, PriorityConfig, "PROJECT", 0);
2657
2658      m_on_tag->add_tag_exclude (m_off_tag);
2659      m_off_tag->add_tag_exclude (m_on_tag);
2660    }
2661
2662  m_off_tag->unmark ();
2663  m_on_tag->mark ();
2664}
2665
2666//-----------------------------------------------------------
2667const cmt_string& StrategyDef::get_default_value () const
2668{
2669  if (m_default_value)
2670    {
2671      return (m_on_value);
2672    }
2673  else
2674    {
2675      return (m_off_value);
2676    }
2677}
2678
2679//-----------------------------------------------------------
2680void Project::set_author (const cmt_string& name)
2681{
2682  // cerr << "set_author" << name << endl;     
2683  this->m_author = name;
2684}
2685
2686//-----------------------------------------------------------
2687const cmt_string& Project::get_author () const
2688{
2689  return (m_author);
2690}
2691
2692//-----------------------------------------------------------
2693void Project::project_author_action (const CmtSystem::cmt_string_vector& words)
2694{
2695  if (m_author != "") m_author += "\n";
2696
2697  for (int i = 1; i < words.size (); i++)
2698    {
2699      const cmt_string& w = words[i];
2700     
2701      if (i > 1) m_author += " ";
2702      m_author += w; 
2703    }
2704}
2705
2706//-----------------------------------------------------------
2707Use*  Project::get_use () const
2708{
2709  return m_use;   
2710} 
2711
2712//-----------------------------------------------------------
2713void  Project::set_use (Use* use)
2714{ 
2715  this->m_use = use;
2716}
2717
2718//-----------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.