source: CMT/v1r20p20090520/source/cmt_project.cxx @ 615

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

See C.L. 396

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