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

Last change on this file since 654 was 24, checked in by arnault, 19 years ago

Fix project creation - CL 263

  • Property svn:eol-style set to native
File size: 42.9 KB
Line 
1//-----------------------------------------------------------
2// Copyright Christian Arnault LAL-Orsay CNRS
3// arnault@lal.in2p3.fr
4// See the complete license in cmt_license.txt "http://www.cecill.info".
5//-----------------------------------------------------------
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <ctype.h>
11
12#include "cmt_project.h"
13#include "cmt_database.h"
14#include "cmt_system.h"
15#include "cmt_awk.h"
16#include "cmt_syntax.h"
17#include "cmt_tag.h"
18#include "cmt_error.h"
19
20class ProjectReader : public Awk
21{
22public:
23
24  ProjectReader ()
25  {
26  }
27 
28  const cmt_string& get_project_name () const
29  {
30    return (m_project);
31  }
32 
33  void filter (const cmt_string& line)
34  {
35    CmtSystem::cmt_string_vector words;
36    CmtSystem::split (line, " \t", words);
37    if (words[0] == "project")
38      {
39        m_project = words[1];
40      }
41  }
42 
43private:
44  cmt_string m_project;
45};
46
47class ProjectPatcher : public Awk
48{
49public:
50
51  ProjectPatcher (const cmt_string& p) : m_project (p)
52  {
53  }
54
55  void commit ()
56  {
57    m_output.write (Project::get_project_file_name ());
58  }
59
60  void filter (const cmt_string& line)
61  {
62    if (m_output != "")
63      {
64        m_output += "\n";
65      }
66   
67    CmtSystem::cmt_string_vector words;
68    CmtSystem::split (line, " \t", words);
69    if (words[0] == "project")
70      {
71        m_output += "project ";
72        m_output += m_project;
73      }
74    else
75      {
76        m_output += line;
77      }
78  }
79 
80private:
81  cmt_string m_output;
82  const cmt_string& m_project;
83};
84
85IProjectFactory& ProjectFactory::instance ()
86{
87  static ProjectFactory me;
88 
89  return (me);
90}
91
92void ProjectFactory::reset ()
93{
94  Project::clear_all ();
95}
96
97static bool get_release_from_path (const cmt_string& path, const cmt_string& name, cmt_string& release)
98{
99  bool result = false;
100
101  release = "";
102
103  cmt_string p = path;
104
105  for (;;)
106    {
107      cmt_string n;
108
109      CmtSystem::basename (p, n);
110      CmtSystem::dirname (p, p);
111
112      if (n == name)
113        {
114          result = true;
115          break;
116        }
117
118      if (release == "")
119        {
120          release = n;
121        }
122      else
123        {
124          cmt_string r;
125
126          r = n;
127          r += CmtSystem::file_separator ();
128          r += release;
129          release = r;
130        }
131    }
132
133  //cerr << "$CMT> GRFP> path=" << path << " name=" << name << " rel=" << release << endl;
134
135  return (result);
136}
137 
138
139/*
140  Every new CMTPATH entry becomes associated with a dedicated PROJECT
141  This function will understand this new entry to CMTPATH and understand it:
142  - it can correspond to an existing project (ie already declared)
143  - it's a new project
144     - then it tries to read and parse its project file
145 */
146Project* ProjectFactory::create_project (const cmt_string& specified_name,
147                                         const cmt_string& path,
148                                         const cmt_string& source,
149                                         Project* parent)
150{
151  cmt_string compressed_path = path;
152  CmtSystem::compress_path (compressed_path);
153  bool specify_name = (specified_name != "");
154
155  //cerr << "Creating project " << path << " with parent " << ((parent==0)? "0" : parent->get_name ()) << endl;
156
157  static Project::ProjectVector& Projects = Project::projects ();
158 
159  for (int i = 0; i < Projects.size (); i++)
160    {
161      Project& p = Projects[i];
162     
163      if ((p.get_cmtpath () == compressed_path) ||
164          (p.get_cmtpath_pwd () == compressed_path) ||
165          (specify_name && (p.get_name () == specified_name)))
166        {
167          cmt_string r;
168
169          get_release_from_path (compressed_path, p.get_name (), r);
170
171          if (r != p.get_release ())
172            {
173              cerr << "#CMT> Project " << p.get_name () << " requested with conflicting releases " << p.get_release () << " and " << r << endl;
174              CmtError::set (CmtError::project_release_conflict, p.get_name ());
175            }
176 
177          if (parent != 0)
178            {
179              p.add_parent (parent);
180              parent->add_child (&p);
181
182              // Since p is a new parent, we should propagate the settings UP.
183
184              parent->update_strategies_from_children ();
185            }
186
187          return (&p);
188        }
189    }
190
191
192  Project* project = 0;
193  Project* cmt = 0;
194 
195  bool is_current = false;
196 
197  cmt_string here = CmtSystem::pwd ();
198  if (!CmtSystem::cd (compressed_path)) return (0);
199
200  cmt_string name = specified_name;
201  cmt_string release;
202
203  //
204  // Figure out if this is the current project
205  //
206  cmt_string pwd = CmtSystem::pwd ();
207  if (here.find (pwd) == 0) is_current = true;
208
209  cmt_string text;
210
211  /*
212    Now Figure out the project name from the project file
213       or does not specify the project name
214   */
215  if (CmtSystem::cd ("cmt") && CmtSystem::test_file (Project::get_project_file_name ()))
216    {
217      text.read (Project::get_project_file_name ());
218
219      ProjectReader reader;
220
221      reader.run (text);
222
223      name = reader.get_project_name ();
224      if (name == "")
225        {
226          if (!specify_name)
227            {
228              // The project is neither specified from the caller nor from the project file
229              // Send a warning?
230              // How can we guess it?
231              // For the moment, assume /name/release/ structure where release is one level only
232
233              /*
234              if (!Cmt::get_quiet ())
235                {
236                  cerr << "#CMT> Warning: project name unspecified in project file." << endl;
237                }
238              */
239
240              CmtSystem::basename (compressed_path, release);
241              CmtSystem::dirname (compressed_path, name);
242              CmtSystem::basename (name, name);
243            }
244          else
245            {
246              // The name is specified from the caller
247              // find this specified name in the path
248
249              cmt_string r;
250
251              if (get_release_from_path (compressed_path, specified_name, r))
252                {
253                  // The specified name has been found from the path.
254                  // We believe in the release spec.
255
256                  name = specified_name;
257                  release = r;
258                }
259              else
260                {
261                  // The specified name is not in the path.
262
263
264                  if (!Cmt::get_quiet ())
265                    {
266                      cerr << "#CMT> Warning: specified project name "
267                           << specified_name
268                           << " from project file does not match path." << endl;
269                    }
270
271                  CmtSystem::basename (compressed_path, release);
272                  CmtSystem::dirname (compressed_path, name);
273                  CmtSystem::basename (name, name);
274                }
275            }
276        }
277      else
278        {
279          if (specify_name)
280            {
281              // We have a double specification: from the caller and from the project file.
282              // check the consistency
283
284              if (name == specified_name)
285                {
286                  // Both specifications are consistent. 
287                  cmt_string r;
288
289                  if (get_release_from_path (compressed_path, specified_name, r))
290                    {
291                      // The specified name has been found from the path.
292                      // We believe in the release spec.
293
294                      name = specified_name;
295                      release = r;
296                    }
297                  else
298                    {
299                      // The specified name is not in the path.
300
301                      if (!Cmt::get_quiet ())
302                        {
303                          cerr << "#CMT> Warning: specified project name "
304                               << specified_name
305                               << " from project file does not match path." << endl;
306                        }
307
308                      CmtSystem::basename (compressed_path, release);
309                      CmtSystem::dirname (compressed_path, name);
310                      CmtSystem::basename (name, name);
311                    }
312                }
313              else
314                {
315                  // Specifications from the caller and from the project files are inconsistent!!
316
317                  if (!Cmt::get_quiet ())
318                    {
319                      cerr << "#CMT> Warning: specified project name "
320                           << specified_name
321                           << " inconsistent with name "
322                           << name
323                           << " from project file." << endl;
324                    }
325
326                  cmt_string r;
327
328                  if (get_release_from_path (compressed_path, specified_name, r))
329                    {
330                      // name from caller wins.
331                    }
332                  else if (get_release_from_path (compressed_path, specified_name, r))
333                    {
334                      // name from project file wins.
335                    }
336                  else
337                    {
338                      // The specified name is not in the path.
339
340                      if (!Cmt::get_quiet ())
341                        {
342                          cerr << "#CMT> Warning: none of specified project names "
343                               << name
344                               << " from graph and "
345                               << specified_name
346                               << " from project file match path." << endl;
347                        }
348
349                      CmtSystem::basename (compressed_path, release);
350                      CmtSystem::dirname (compressed_path, name);
351                      CmtSystem::basename (name, name);
352                    }
353                }
354            }
355        }
356    }
357  else
358    {
359      // There is no project file in this path.
360
361      if (source == "default path")
362        {
363          name = "CMT";
364        }
365      else
366        {
367          if (!specify_name)
368            {
369              // The project is not specified from the caller and there is no project file
370              // Send a warning?
371              // How can we guess it?
372              // For the moment, assume /name/release/ structure where release is one level only
373
374              /*
375              if (!Cmt::get_quiet ())
376                {
377                  cerr << "#CMT> Warning: project name is not specified "
378                       << " (no project file)." << endl;
379                }
380              */
381
382              CmtSystem::basename (compressed_path, release);
383              CmtSystem::dirname (compressed_path, name);
384              CmtSystem::basename (name, name);
385            }
386          else
387            {
388              // The name is specified from the caller
389              // find this specified name in the path
390
391              cmt_string r;
392
393              if (get_release_from_path (compressed_path, specified_name, r))
394                {
395                  // The specified name has been found from the path.
396                  // We believe in the release spec.
397
398                  release = r;
399                }
400              else
401                {
402                  // The specified name is not in the path.
403
404                  if (!Cmt::get_quiet ())
405                    {
406                      cerr << "#CMT> Warning: specified project name "
407                           << specified_name
408                           << " from project graph does not match path." << endl;
409                    }
410
411                  CmtSystem::basename (compressed_path, release);
412                  CmtSystem::dirname (compressed_path, name);
413                  CmtSystem::basename (name, name);
414                }
415            }
416        }
417    }
418
419  project = Project::add (name, release);
420
421  if (parent != 0)
422    {
423      project->add_parent (parent);
424      parent->add_child (project);
425
426      // Since p is a new parent, we should propagate the settings UP.
427
428      parent->update_strategies_from_children ();
429    }
430
431  if (source == "default path")
432    {
433      cmt = project;
434      is_current = false;
435    }
436
437  project->set_cmtpath (compressed_path);
438  project->set_cmtpath_pwd (pwd);
439  project->set_cmtpath_source (source);
440
441  if (is_current)
442    {
443      //
444      // The current project defines a tag with its name
445      //
446
447      Tag* tag;
448     
449      tag = Tag::add (project->get_name (), PriorityConfig, "PROJECT", 0);
450      tag->mark ();
451    }
452
453  if (text != "")
454    {
455      // Last step is to parse the project file
456
457      SyntaxParser::parse_project_file_text (text, 
458                                             Project::get_project_file_name (),
459                                             project);
460    }
461
462  CmtSystem::cd (here);
463
464  return (project);
465}
466
467/*----------------------------------------------------------*/
468/*                                                          */
469/*  Operations on Projects                                  */
470/*                                                          */
471/*----------------------------------------------------------*/
472
473//----------------------------------------------------------
474void Project::create (const cmt_string& name, 
475                      const cmt_string& release, 
476                      const cmt_string& path)
477{
478  cout << "------------------------------------------" << endl;
479  cout << "Configuring environment for project " << name << " " << release;
480
481  if (path != "")
482    {
483      cout << " in " << path;
484    }
485
486  cout << endl;
487  cout << "CMT version " << Cmt::get_cmt_version () << "." << endl;
488  cout << "------------------------------------------" << endl;
489
490  if (path != "")
491    {
492      if (!CmtSystem::mkdir (path))
493        {
494          cout << "Cannot create the " << path << " directory" << endl;
495          return;
496        }
497
498      if (!CmtSystem::cd (path))
499        {
500          cout << "Cannot access the " << path << " directory" << endl;
501          return;
502        }
503    }
504
505  if (!CmtSystem::mkdir (name))
506    {
507      cout << "Cannot create the " << name << " directory" << endl;
508      return;
509    }
510
511  if (!CmtSystem::cd (name))
512    {
513      cout << "Cannot access the " << name << " directory" << endl;
514      return;
515    }
516
517  if (release != "")
518    {
519      if (!CmtSystem::mkdir (release))
520        {
521          cout << "Cannot create the " << release << " directory" << endl;
522          return;
523        }
524     
525      if (!CmtSystem::cd (release))
526        {
527          cout << "Cannot access the " << release << " directory" << endl;
528          return;
529        }
530    }
531
532  if (!CmtSystem::test_directory ("cmt"))
533    {
534      if (!CmtSystem::mkdir ("cmt"))
535        {
536          cout << "Cannot create the cmt directory" << endl;
537          return;
538        }
539      else
540        {
541          cout << "Installing the cmt directory" << endl;
542        }
543    }
544
545  CmtSystem::cd ("cmt");
546
547  if (!CmtSystem::test_file (get_project_file_name ()))
548    {
549      cout << "Creating a new project file" << endl;
550
551      ofstream f (get_project_file_name ());
552      if (f)
553        {
554          f << "project " << name << endl;
555          f << endl;
556          f.close ();
557        }
558    }
559  else
560    {
561      cmt_string text;
562      text.read (get_project_file_name ());
563
564      ProjectPatcher p (name);
565
566      p.run (text);
567      p.commit ();
568
569      cout << "project file already there" << endl;
570    }
571}
572
573//----------------------------------------------------------
574Project* Project::find_by_name (const cmt_string& name)
575{
576  static ProjectVector& Projects = projects ();
577
578  for (int i = 0; i < Projects.size (); i++)
579    {
580      Project& p = Projects[i];
581
582      if (p.m_name == name) return (&p);
583    }
584
585  return (0);
586}
587
588//----------------------------------------------------------
589Project* Project::find_by_cmtpath (const cmt_string& cmtpath)
590{
591  cmt_string compressed_path = cmtpath;
592  CmtSystem::compress_path (compressed_path);
593
594  static ProjectVector& Projects = projects ();
595
596  for (int i = 0; i < Projects.size (); i++)
597    {
598      Project& p = Projects[i];
599
600      if (p.m_cmtpath == compressed_path) return (&p);
601      if (p.m_cmtpath_pwd == compressed_path) return (&p);
602    }
603
604  return (0);
605}
606
607//----------------------------------------------------------
608Project* Project::get_current ()
609{
610  cmt_string here = CmtSystem::pwd ();
611
612  static ProjectVector& Projects = projects ();
613
614  Project* result = 0;
615
616  for (int i = (Projects.size () - 1); i >= 0; i--)
617    {
618      Project& p = Projects[i];
619
620      if (here.find (p.m_cmtpath_pwd) == 0) 
621        {
622          result = &p;
623        }
624
625      if (here.find (p.m_cmtpath) == 0) 
626        {
627          result = &p;
628        }
629    }
630
631  return (result);
632}
633
634//----------------------------------------------------------
635Project* Project::add (const cmt_string& name,
636                       const cmt_string& release)
637{
638  static ProjectVector& Projects = projects ();
639
640  //cout << "Project::add> name=" << name << endl;
641
642  {
643    Project* project;
644
645    project = find_by_name (name);
646    if (project != 0) 
647      {
648        if (!Cmt::get_quiet ())
649          {
650            if (release != project->get_release ())
651              {
652                cerr << "#CMT> Project " << name << " requested with conflicting releases " << project->get_release () << " and " << release << endl;
653                CmtError::set (CmtError::project_release_conflict, name);
654              }
655          }
656
657        // Project objects are recreated here to follow the hierarchy
658        // This duplication is needed for properly applying the strategies
659        Project& p = Projects.add ();
660
661        p.set_name (name);
662        p.set_release (release);
663        p.configure ();
664
665        return (&p);
666
667        //return (project);
668      }
669  }
670
671  Project& project = Projects.add ();
672  project.clear ();
673  project.set_name (name);
674  project.set_release (release);
675  project.configure ();
676
677  return (&project);
678}
679
680//----------------------------------------------------------
681Project::ProjectVector& Project::projects ()
682{
683  static Database& db = Database::instance ();
684  static ProjectVector& Projects = db.projects ();
685
686  return (Projects);
687}
688
689/*----------------------------------------------------------*/
690void Project::clear_all ()
691{
692  static ProjectVector& Projects = projects ();
693
694  for (int i = 0; i < Projects.size (); i++)
695    {
696      Project& project = Projects[i];
697      project.clear ();
698    }
699
700  Projects.clear ();
701}
702
703/*----------------------------------------------------------*/
704void Project::show_all ()
705{
706  static Project::ProjectVector& Projects = Project::projects ();
707 
708  for (int i = 0; i < Projects.size (); i++)
709    {
710      Project& p = Projects[i];
711      p.m_visited = false;
712    }
713
714  Project* current = get_current ();
715
716  if (current != 0) current->show ();
717}
718
719/*----------------------------------------------------------*/
720void Project::show_specified_strategies_for_all ()
721{
722  static ProjectVector& Projects = projects ();
723
724  for (int i = 0; i < Projects.size (); i++)
725    {
726      const Project& project = Projects[i];
727      project.show_specified_strategies ();
728    }
729}
730
731/*----------------------------------------------------------*/
732class VisitorForShowPaths : public IProjectVisitor
733{
734public:
735  VisitorForShowPaths ()
736  {
737  }
738
739  void pre (Project* p)
740  {
741    const cmt_string& w = p->get_cmtpath_pwd ();
742    const cmt_string& s = p->get_cmtpath_source ();
743
744    if (s == "default path") return;
745
746    if (CmtSystem::test_directory (w))
747      {
748        cout << "# Add path " << w << " from " << s << endl;
749      }
750  }
751
752  void in (Project* p)
753  {
754    const cmt_string& w = p->get_cmtpath_pwd ();
755    const cmt_string& s = p->get_cmtpath_source ();
756
757    if (s == "default path") return;
758
759    if (CmtSystem::test_directory (w))
760      {
761        cout << "# Add path " << w << " from " << s << endl;
762      }
763  }
764
765  void post (Project* p)
766  {
767  }
768};
769
770/*----------------------------------------------------------*/
771void Project::show_paths ()
772{
773  VisitorForShowPaths visitor;
774
775  start_visit (visitor);
776}
777
778//----------------------------------------------------------
779const cmt_string& Project::get_project_file_name ()
780{
781  static const cmt_string name = "project.cmt";
782
783  return (name);
784}
785
786//----------------------------------------------------------
787void Project::fill_selection (int depth, CmtSystem::cmt_string_vector& path_selections)
788{
789  static ProjectVector& Projects = projects ();
790
791  for (int i = 0; i < Projects.size (); i++)
792    {
793      Project& project = Projects[i];
794
795      const cmt_string& p = project.get_cmtpath ();
796      const cmt_string& pwd = project.get_cmtpath_pwd ();
797      const cmt_string& src = project.get_cmtpath_source ();
798
799      if (src != "default path")
800        {
801          if (depth > 0)
802            {
803              cmt_string& s1 = path_selections.add ();
804              s1 = p;
805              cmt_string& s2 = path_selections.add ();
806              s2 = pwd;
807              depth--;
808
809              if (depth == 0) break;
810            }
811        }
812    }
813}
814
815//----------------------------------------------------------
816void Project::broadcast (IProjectAction& action)
817{
818  static ProjectVector& Projects = projects ();
819
820  for (int i = 0; i < Projects.size (); i++)
821    {
822      const Project& project = Projects[i];
823
824      if (!action.run (project)) break;
825    }
826}
827
828//----------------------------------------------------------
829void Project::reverse_broadcast (IProjectAction& action)
830{
831  static ProjectVector& Projects = projects ();
832
833  for (int i = (Projects.size () - 1); i >= 0; i--)
834    {
835      const Project& project = Projects[i];
836
837      if (!action.run (project)) break;
838    }
839}
840
841//----------------------------------------------------------
842void Project::scan_paths (PathScanner& scanner, PathScanner::actor& a)
843{
844  static ProjectVector& Projects = projects ();
845
846  for (int i = 0; i < Projects.size (); i++)
847    {
848      const Project& project = Projects[i];
849
850      const cmt_string& p = project.m_cmtpath;
851      scanner.scan_path (p, a);
852    }
853}
854
855//----------------------------------------------------------
856void Project::scan_paths_for_package (PathScanner& scanner, const cmt_string& name)
857{
858  static ProjectVector& Projects = projects ();
859
860  for (int i = 0; i < Projects.size (); i++)
861    {
862      const Project& project = Projects[i];
863
864      const cmt_string& p = project.m_cmtpath;
865      scanner.scan_package (p, name);
866    }
867}
868
869//----------------------------------------------------------
870cmt_string Project::find_in_cmt_paths (const cmt_string& path)
871{
872  const cmt_string pwd = CmtSystem::pwd ();
873
874  static ProjectVector& Projects = projects ();
875
876  for (int i = 0; i < Projects.size (); i++)
877    {
878      const Project& project = Projects[i];
879
880      const cmt_string& p = project.m_cmtpath;
881      const cmt_string& w = project.m_cmtpath_pwd;
882      const cmt_string& s = project.m_cmtpath_source;
883
884      if (s == "default path") continue;
885
886      if (CmtSystem::test_directory (p))
887        {
888          if (path.find (p) != cmt_string::npos)
889            {
890              return (p);
891            }
892
893          // To become the current area, a path must correspond to the current package
894          if (path.find (w) != cmt_string::npos)
895            {
896              return (p);
897            }
898        }
899
900      if (p == w) continue;
901
902      if (CmtSystem::test_directory (w))
903        {
904          if (path.find (w) != cmt_string::npos)
905            {
906              return (w);
907            }
908        }
909    }
910
911  return ("");
912}
913
914//----------------------------------------------------------
915void Project::visit (IProjectVisitor& visitor)
916{
917  if (m_visited) return;
918  m_visited = true;
919
920  int i;
921
922  for (i = 0; i < get_children_size (); i++)
923    {
924      Project* child = get_child (i);
925
926      if (child->visited ()) continue;
927
928      visitor.in (child);
929    }
930
931  for (i = 0; i < m_children.size (); i++)
932    {
933      Project* child = m_children[i];
934      child->visit (visitor);
935    }
936}
937
938//----------------------------------------------------------
939void Project::start_visit (IProjectVisitor& visitor)
940{
941  static Project::ProjectVector& Projects = Project::projects ();
942 
943  for (int i = 0; i < Projects.size (); i++)
944    {
945      Project& p = Projects[i];
946      p.m_visited = false;
947    }
948
949  Project* p = get_current ();
950
951  if (p == 0) return;
952
953  visitor.pre (p);
954  p->visit (visitor);
955  visitor.post (p);
956}
957
958//----------------------------------------------------------
959class VisitorForFillCMTPATH : public IProjectVisitor
960{
961public:
962  VisitorForFillCMTPATH (cmt_string& buffer) : m_buffer (buffer)
963  {
964  }
965
966  void pre (Project* p)
967  {
968    const cmt_string& w = p->get_cmtpath_pwd ();
969    const cmt_string& s = p->get_cmtpath_source ();
970
971    if (s == "default path") return;
972
973    if (CmtSystem::test_directory (w))
974      {
975        m_buffer += "path_append CMTPATH \"";
976        m_buffer += w;
977        m_buffer += "\" \n";
978      }
979  }
980
981  void in (Project* p)
982  {
983    const cmt_string& w = p->get_cmtpath_pwd ();
984    const cmt_string& s = p->get_cmtpath_source ();
985
986    if (s == "default path") return;
987
988    if (CmtSystem::test_directory (w))
989      {
990        m_buffer += "path_append CMTPATH \"";
991        m_buffer += w;
992        m_buffer += "\" \n";
993      }
994  }
995
996  void post (Project* p)
997  {
998    //cerr << "Buffer = " << m_buffer << endl;
999  }
1000
1001private:
1002  cmt_string& m_buffer;
1003
1004};
1005
1006//----------------------------------------------------------
1007void Project::fill_cmtpaths (cmt_string& buffer)
1008{
1009  /*
1010    Try to re-create all CMTPATH items from project definitions.
1011    The goal is to generate CMTPATH even if this EV was not pre-set
1012    which is the case when CMTPROJECTPATH is only used
1013   */
1014
1015  VisitorForFillCMTPATH visitor (buffer);
1016
1017  start_visit (visitor);
1018}
1019
1020//----------------------------------------------------------
1021Project::Project () : m_name ("")
1022{
1023  clear ();
1024}
1025
1026//----------------------------------------------------------
1027const cmt_string& Project::get_name () const
1028{
1029  return (m_name);
1030}
1031
1032//----------------------------------------------------------
1033const cmt_string& Project::get_release () const
1034{
1035  return (m_release);
1036}
1037
1038//----------------------------------------------------------
1039const cmt_string& Project::get_cmtpath () const
1040{
1041  return (m_cmtpath);
1042}
1043
1044//----------------------------------------------------------
1045const cmt_string& Project::get_cmtpath_pwd () const
1046{
1047  return (m_cmtpath_pwd);
1048}
1049
1050//----------------------------------------------------------
1051const cmt_string& Project::get_cmtpath_source () const
1052{
1053  return (m_cmtpath_source);
1054}
1055
1056//----------------------------------------------------------
1057int Project::get_children_size () const
1058{
1059  return (m_children.size ());
1060}
1061
1062//----------------------------------------------------------
1063Project* Project::get_child (int index) const
1064{
1065  if (index < 0) return (0);
1066  if (index >= m_children.size ()) return (0);
1067  return (m_children[index]);
1068}
1069
1070//----------------------------------------------------------
1071bool Project::visited () const
1072{
1073  return (m_visited);
1074}
1075
1076//----------------------------------------------------------
1077void Project::set_name (const cmt_string& name)
1078{
1079  m_name = name;
1080}
1081
1082//----------------------------------------------------------
1083void Project::set_release (const cmt_string& release)
1084{
1085  m_release = release;
1086}
1087
1088//----------------------------------------------------------
1089void Project::set_cmtpath (const cmt_string& path)
1090{
1091  m_cmtpath = path;
1092}
1093
1094//----------------------------------------------------------
1095void Project::set_cmtpath_pwd (const cmt_string& path)
1096{
1097  m_cmtpath_pwd = path;
1098}
1099
1100//----------------------------------------------------------
1101void Project::set_cmtpath_source (const cmt_string& source)
1102{
1103  m_cmtpath_source = source;
1104}
1105
1106//----------------------------------------------------------
1107void Project::clear ()
1108{
1109  m_name = "";
1110  m_release = "";
1111  m_cmtpath = "";
1112  m_cmtpath_pwd = "";
1113  m_cmtpath_source = "";
1114
1115  m_parents.clear ();
1116  m_children.clear ();
1117
1118  m_configured = false;
1119
1120  m_strategies.clear ();
1121}
1122
1123//----------------------------------------------------------
1124void Project::add_parent (Project* p)
1125{
1126  if (p == 0) return;
1127  if (p == this) return;
1128
1129  //cerr << "Adding parent " << p->get_name () << " to " << m_name << endl;
1130
1131  int i;
1132
1133  for (i = 0; i < m_children.size (); i++)
1134    {
1135      Project* child = m_children[i];
1136      if (child == 0) continue;
1137
1138      if (child->get_name () == p->get_name ())
1139        {
1140          // Already registered as a child (no cycle permitted!!)
1141          return;
1142        }
1143    }
1144
1145  for (i = 0; i < m_parents.size (); i++)
1146    {
1147      Project* parent = m_parents[i];
1148      if (parent == 0) continue;
1149
1150      if (parent->get_name () == p->get_name ())
1151        {
1152          // Already registered as a parent
1153          return;
1154        }
1155    }
1156
1157  m_parents.push_back (p);
1158}
1159
1160//----------------------------------------------------------
1161void Project::add_child (Project* p)
1162{
1163  if (p == 0) return;
1164  if (p == this) return;
1165
1166  int i;
1167
1168  for (i = 0; i < m_parents.size (); i++)
1169    {
1170      Project* parent = m_parents[i];
1171      if (parent == 0) continue;
1172
1173      if (parent->get_name () == p->get_name ())
1174        {
1175          // Already registered as a parent (no cycle permitted!!)
1176          return;
1177        }
1178    }
1179
1180  for (i = 0; i < m_children.size (); i++)
1181    {
1182      Project* child = m_children[i];
1183      if (child == 0) continue;
1184
1185      if (child->get_name () == p->get_name ())
1186        {
1187          // Already registered as a child
1188          return;
1189        }
1190    }
1191
1192  m_children.push_back (p);
1193}
1194
1195//----------------------------------------------------------
1196void Project::configure ()
1197{
1198  if (m_configured) return;
1199  m_configured = true;
1200
1201  set_default_strategy ("SetupConfig");
1202  set_default_strategy ("SetupRoot");
1203  set_default_strategy ("SetupCleanup");
1204  set_default_strategy ("BuildPrototypes");
1205  set_default_strategy ("InstallArea");
1206}
1207
1208/**---------------------------------------------------------
1209 A use statement is met in the project file
1210*/
1211void Project::use_action (const cmt_string& name, const cmt_string& release)
1212{
1213  //cerr << "Use action " << name << " " << release << endl;
1214
1215  // A project with its release is specified
1216  //
1217  // Is this project already visible?
1218  // If not: look for it
1219  //   + get CMTPROJECTPATH
1220  //   + search from all entries of CMTPROJECTPATH : p(i)/<name>/<release>
1221  //   + when found, this should become a new CMTPATH entry
1222  //   +             the new project is then parsed ... etc...
1223
1224  cmt_string cmtprojectpath = CmtSystem::getenv ("CMTPROJECTPATH");
1225  cmt_string sep;
1226  sep = CmtSystem::path_separator ();
1227
1228  //cerr << "cmtprojectpath = " << cmtprojectpath << endl;
1229  CmtSystem::cmt_string_vector items;
1230  CmtSystem::split (cmtprojectpath, sep, items);
1231
1232  bool found = false;
1233
1234  for (int i = 0; i < items.size (); i++)
1235    {
1236      const cmt_string& item = items[i];
1237      cmt_string p = item;
1238      p += CmtSystem::file_separator ();
1239      p += name;
1240      p += CmtSystem::file_separator ();
1241      p += release;
1242
1243      if (CmtSystem::test_directory (p))
1244        {
1245          //cerr << "Project directory " << p << " exists " << endl;
1246
1247          found = true;
1248
1249          IProjectFactory& factory = ProjectFactory::instance ();
1250
1251          factory.create_project (name, p, "ProjectPath", this);
1252
1253          break;
1254        }
1255    }
1256
1257  if (!found)
1258    {
1259      Project* p = Project::find_by_name (name);
1260
1261      if (p != 0)
1262        {
1263          found = true;
1264
1265          p->add_parent (this);
1266          add_child (p);
1267
1268          update_strategies_from_children ();
1269        }
1270    }
1271
1272  if (!found && (cmtprojectpath != ""))
1273    {
1274      cerr << "#CMT> Project " << name << " " << release << " requested by " << m_name << " not found in CMTPROJECTPATH" << endl;
1275    }
1276}
1277
1278
1279//----------------------------------------------------------
1280Project& Project::operator = (const Project& other)
1281{
1282  m_name = other.m_name;
1283  m_cmtpath = other.m_cmtpath;
1284  m_cmtpath_pwd = other.m_cmtpath_pwd;
1285  m_cmtpath_source = other.m_cmtpath_source;
1286
1287  return (*this);
1288}
1289
1290//----------------------------------------------------------
1291bool Project::operator == (const cmt_string& name) const
1292{
1293  return ((m_name == name));
1294}
1295
1296//----------------------------------------------------------
1297bool Project::operator != (const cmt_string& name) const
1298{
1299  return ((m_name != name));
1300}
1301
1302//----------------------------------------------------------
1303void Project::show ()
1304{
1305  static int level = 0;
1306
1307  bool is_current = false;
1308
1309  cmt_string here = CmtSystem::pwd ();
1310
1311  if (here.find (m_cmtpath) == 0) 
1312    {
1313      if (m_cmtpath_source != "default path")
1314        {
1315          is_current = true;
1316        }
1317    }
1318
1319  for (int tab = 0; tab < level; tab++) cout << "  ";
1320  cout << m_name << " " << m_release << " (in " << m_cmtpath << ")";
1321
1322  if (is_current) cout << " (current)";
1323
1324  int i;
1325
1326  /*
1327  for (i = 0; i < m_parents.size (); i++)
1328    {
1329      Project* p = m_parents[i];
1330      if (p == 0) continue;
1331      cout << " P=" << p->get_name ();
1332    }
1333
1334  for (i = 0; i < m_children.size (); i++)
1335    {
1336      Project* p = m_children[i];
1337      if (p == 0) continue;
1338      cout << " C=" << p->get_name ();
1339    }
1340  */
1341
1342  cout << endl;
1343
1344  if (m_visited) return;
1345
1346  m_visited = true;
1347
1348  for (i = 0; i < m_children.size (); i++)
1349    {
1350      Project* p = m_children[i];
1351      if (p == 0) continue;
1352      level++;
1353      p->show ();
1354      level--;
1355    }
1356}
1357
1358
1359//----------------------------------------------------------
1360void Project::show_specified_strategies () const
1361{
1362  int i;
1363
1364  for (i = 0; i < m_strategies.size (); i++)
1365    {
1366      const Strategy& s = m_strategies[i];
1367      if (s.m_specified)
1368        {
1369          const StrategyDef* def = s.m_definition;
1370 
1371          cout << "# Project " << m_name
1372               << " sets " << def->m_keyword
1373               << " strategy to " << ((s.m_value) ? def->m_on_value : def->m_off_value);
1374
1375          if (s.m_context != "")
1376            {
1377              cout << " (from package " << s.m_context << ")";
1378            }
1379
1380          cout << endl;
1381        }
1382    }
1383}
1384
1385//----------------------------------------------------------
1386bool Project::has_strategy (const StrategyDef* definition) const
1387{
1388  int i;
1389
1390  for (i = 0; i < m_strategies.size (); i++)
1391    {
1392      const Strategy& s = m_strategies[i];
1393      if (s.m_definition == definition)
1394        {
1395          return (true);
1396        }
1397    }
1398
1399  return (false);
1400}
1401
1402//----------------------------------------------------------
1403bool Project::get_strategy (const cmt_string& name) const
1404{
1405  static StrategyMgr& mgr = StrategyMgr::instance ();
1406
1407  StrategyDef* def = mgr.find_strategy (name);
1408  if (def == 0)
1409    {
1410      cerr << "#CMT> strategy " << name << " undefined" << endl;
1411      return (false);
1412    }
1413
1414  return (get_strategy (def));
1415}
1416
1417//----------------------------------------------------------
1418bool Project::is_specified (const StrategyDef* definition) const
1419{
1420  int i;
1421
1422  for (i = 0; i < m_strategies.size (); i++)
1423    {
1424      Strategy& s = m_strategies[i];
1425      if (s.m_definition == definition)
1426        {
1427          // This strategy is applied in this project
1428          return (s.m_specified);
1429        }
1430    }
1431
1432  // This strategy is not applied in this project
1433  return (false);
1434}
1435
1436//----------------------------------------------------------
1437bool Project::get_strategy (const StrategyDef* def) const
1438{
1439  int i;
1440
1441  for (i = 0; i < m_strategies.size (); i++)
1442    {
1443      Strategy& s = m_strategies[i];
1444      if (s.m_definition == def)
1445        {
1446          // This strategy is applied in this project
1447          if (s.m_specified)
1448            {
1449              return (s.m_specified_value);
1450            }
1451          return (s.m_value);
1452        }
1453    }
1454
1455  // This strategy is not applied in this project
1456  return (def->m_default_value);
1457}
1458
1459//----------------------------------------------------------
1460void Project::set_default_strategy (const cmt_string& name)
1461{
1462  static StrategyMgr& mgr = StrategyMgr::instance ();
1463
1464  StrategyDef* def = mgr.find_strategy (name);
1465  if (def == 0)
1466    {
1467      cerr << "#CMT> strategy " << name << " undefined" << endl;
1468      return;
1469    }
1470
1471  update_strategy (def, def->m_default_value);
1472}
1473
1474
1475//----------------------------------------------------------
1476void Project::set_strategy (const cmt_string& name, const cmt_string& value, const cmt_string& context)
1477{
1478  static StrategyMgr& mgr = StrategyMgr::instance ();
1479
1480  StrategyDef* def = mgr.find_strategy (name);
1481  if (def == 0)
1482    {
1483      cerr << "#CMT> strategy " << name << " undefined" << endl;
1484      return;
1485    }
1486
1487  bool b_value = false;
1488
1489  if (value == def->m_on_value)
1490    {
1491      b_value = true;
1492    }
1493  else if (value == def->m_off_value)
1494    {
1495      b_value = false;
1496    }
1497  else
1498    {
1499      cerr << "#CMT> requested strategy value " << value << " undefined in strategy " << name << endl;
1500      return;
1501    }
1502
1503  set_strategy (def, b_value, context);
1504}
1505
1506//----------------------------------------------------------
1507void Project::set_strategy (StrategyDef* definition, bool b_value, const cmt_string& context)
1508{
1509  bool need_strategy = true;
1510
1511  int i;
1512
1513  for (i = 0; i < m_strategies.size (); i++)
1514    {
1515      Strategy& s = m_strategies[i];
1516      if (s.m_definition == definition)
1517        {
1518          // This strategy is already applied in this project. Let's change it's value
1519          s.set (definition, b_value, get_name ());
1520          if (context != "")
1521            {
1522              if (s.m_context != "") s.m_context += " ";
1523              s.m_context += context;
1524            }
1525          need_strategy = false;
1526          break;
1527        }
1528    }
1529
1530  if (need_strategy)
1531    {
1532      // This strategy is not yet applied in this project.
1533
1534      Strategy& s = m_strategies.add ();
1535      s.clear ();
1536      s.set (definition, b_value, get_name ());
1537      s.m_context = context;
1538    }
1539 
1540  for (i = 0; i < m_parents.size (); i++)
1541    {
1542      Project* project = m_parents[i];
1543
1544      project->update_strategy (definition, b_value);
1545    }
1546}
1547
1548/**----------------------------------------------------------
1549   The strategy value is changed because of indirect influences
1550   - default strategy at initialization time
1551   - change in the children
1552   - change in the children list
1553
1554   (This is not a specification : see the set_strategy method)
1555 */
1556void Project::update_strategy (StrategyDef* definition, bool b_value)
1557{
1558  bool need_strategy = true;
1559  bool specified = false;
1560
1561  int i;
1562
1563  for (i = 0; i < m_strategies.size (); i++)
1564    {
1565      Strategy& s = m_strategies[i];
1566      if (s.m_definition == definition)
1567        {
1568          need_strategy = false;
1569
1570          if (!s.m_specified)
1571            {
1572              // This strategy is already applied in this project. Let's change it's value
1573              s.update (definition, b_value, get_name ());
1574            }
1575          else
1576            {
1577              specified = true;
1578            }
1579          break;
1580        }
1581    }
1582
1583  if (need_strategy)
1584    {
1585      // This strategy is not yet applied in this project.
1586
1587      Strategy& s = m_strategies.add ();
1588      s.clear ();
1589      s.update (definition, b_value, get_name ());
1590    }
1591
1592  if (!specified)
1593    {
1594      for (i = 0; i < m_parents.size (); i++)
1595        {
1596          Project* project = m_parents[i];
1597
1598          project->update_strategy (definition, b_value);
1599        }
1600    }
1601}
1602
1603/**----------------------------------------------------------
1604   At least one of the children has changed this strategy
1605   Or the list of children has changed.
1606   We need to update the strategy value accordingly
1607   This will not change the specified value for this strategy
1608 */
1609void Project::update_strategy_from_children (StrategyDef* definition)
1610{
1611  // If this strategy is specified we don't care what happens from the children
1612
1613  //cerr << "Updating strategy " << definition->m_name << " from children for project " << m_name << endl;
1614
1615  int i;
1616
1617  for (i = 0; i < m_strategies.size (); i++)
1618    {
1619      Strategy& s = m_strategies[i];
1620      if (s.m_definition == definition)
1621        {
1622          // This strategy is applied in this project.
1623
1624          if (s.m_specified)
1625            {
1626              // There will be no impact since the strategy is specified
1627
1628              //cerr << "This strategy is specified in this project" << endl;
1629              return;
1630            }
1631
1632          break;
1633        }
1634    }
1635
1636  // The strategy is not specified locally so we will now figure out
1637  // which strategy has to be considered from the mixture of specifications
1638  // from all children.
1639
1640  // Algorithm:
1641  // - We consider children by pairs
1642  // - a child that specifies its strategy wins over a child that does not
1643  // - when the two children have the same level of priority we consider the priority value
1644
1645  Project* selected = 0;
1646  bool selected_is_specified = false;
1647  bool selected_value = definition->m_default_value;
1648
1649  for (i = 0; i < m_children.size (); i++)
1650    {
1651      Project* p = m_children[i];
1652
1653      //cerr << "Checking strategy for child " << p->get_name () << endl;
1654
1655      bool is_specified = p->is_specified (definition);
1656      bool value = p->get_strategy (definition);
1657
1658      if (selected == 0)
1659        {
1660          selected = p;
1661          selected_is_specified = is_specified;
1662          selected_value = value;
1663          continue;
1664        }
1665
1666      if (is_specified == selected_is_specified)
1667        {
1668          if (selected_value != value)
1669            {
1670              // same level of priority but different values -> we must decide
1671              bool priority_value = definition->m_priority_value;
1672              if (value == priority_value)
1673                {
1674                  selected = p;
1675                  selected_is_specified = is_specified;
1676                  selected_value = value;
1677                }
1678            }
1679        }
1680      else
1681        {
1682          if (is_specified)
1683            {
1684              selected = p;
1685              selected_is_specified = is_specified;
1686              selected_value = value;
1687            }
1688        }
1689    }
1690
1691  update_strategy (definition, selected_value); 
1692}
1693
1694/**----------------------------------------------------------
1695   At least one of the children has changed its strategies
1696   Or the list of children has changed.
1697   We need to update the strategy values accordingly
1698   This will not change the specified values
1699 */
1700void Project::update_strategies_from_children ()
1701{
1702  StrategyDef::StrategyDefs& defs = StrategyMgr::get_definitions ();
1703
1704  //cerr << "Updating strategies from children for project " << m_name << endl;
1705
1706  int i;
1707
1708  for (i = 0; i < defs.size (); i++)
1709    {
1710      StrategyDef* def = defs[i];
1711     
1712      update_strategy_from_children (def);
1713    }
1714
1715  for (i = 0; i < m_parents.size (); i++)
1716    {
1717      Project* p = m_parents[i];
1718      p->update_strategies_from_children ();
1719    }
1720}
1721
1722/**----------------------------------------------------------
1723   The StrategyMgr singleton
1724 */
1725StrategyMgr& StrategyMgr::instance ()
1726{
1727  static StrategyMgr me;
1728  return (me);
1729}
1730
1731/**----------------------------------------------------------
1732   The StrategyMgr constructor
1733   Here are primarily constructed all strategy definitions
1734 */
1735StrategyMgr::StrategyMgr ()
1736{
1737  m_defs.clear ();
1738
1739  StrategyDef* s;
1740
1741  s = new StrategyDef;
1742  s->m_keyword = "build";
1743  s->m_name = "BuildPrototypes";
1744  s->m_on_value = "prototypes";
1745  s->m_off_value = "no_prototypes";
1746  s->m_default_value = true;
1747  s->m_priority_value = false;
1748
1749  m_defs.push_back (s);
1750
1751  s = new StrategyDef;
1752  s->m_keyword = "build";
1753  s->m_name = "InstallArea";
1754  s->m_on_value = "with_installarea";
1755  s->m_off_value = "without_installarea";
1756  s->m_default_value = false;
1757  s->m_priority_value = true;
1758
1759  m_defs.push_back (s);
1760
1761  s = new StrategyDef;
1762  s->m_keyword = "setup";
1763  s->m_name = "SetupConfig";
1764  s->m_on_value = "config";
1765  s->m_off_value = "no_config";
1766  s->m_default_value = true;
1767  s->m_priority_value = false;
1768
1769  m_defs.push_back (s);
1770
1771  s = new StrategyDef;
1772  s->m_keyword = "setup";
1773  s->m_name = "SetupRoot";
1774  s->m_on_value = "root";
1775  s->m_off_value = "no_root";
1776  s->m_default_value = true;
1777  s->m_priority_value = false;
1778
1779  m_defs.push_back (s);
1780
1781  s = new StrategyDef;
1782  s->m_keyword = "setup";
1783  s->m_name = "SetupCleanup";
1784  s->m_on_value = "cleanup";
1785  s->m_off_value = "no_cleanup";
1786  s->m_default_value = true;
1787  s->m_priority_value = false;
1788
1789  m_defs.push_back (s);
1790}
1791
1792/**----------------------------------------------------------
1793   Find a strategy definition by its name
1794 */
1795StrategyDef* StrategyMgr::find_strategy (const cmt_string& name)
1796{
1797  static StrategyMgr& me = instance ();
1798
1799  int i;
1800
1801  for (i = 0; i < me.m_defs.size (); i++)
1802    {
1803      StrategyDef* def = me.m_defs[i];
1804      if (def->m_name == name)
1805        {
1806          return (def);
1807        }
1808    }
1809
1810  return (0);
1811}
1812
1813/**----------------------------------------------------------
1814   Retreive the default value defined for a given strategy
1815 */
1816bool StrategyMgr::get_default_strategy (const cmt_string& name)
1817{
1818  StrategyDef* def = find_strategy (name);
1819  if (def == 0) return (false);
1820  return (def->m_default_value);
1821}
1822
1823/**----------------------------------------------------------
1824   Retreive the priority value defined for a given strategy
1825   This value is used when two children of a project request two conflicting strategy values
1826 */
1827bool StrategyMgr::get_priority_strategy (const cmt_string& name)
1828{
1829  StrategyDef* def = find_strategy (name);
1830  if (def == 0) return (false);
1831  return (def->m_priority_value);
1832}
1833
1834/**----------------------------------------------------------
1835   Return the vector of all existing strategy definitions
1836 */
1837StrategyDef::StrategyDefs& StrategyMgr::get_definitions ()
1838{
1839  static StrategyMgr& me = instance ();
1840
1841  return (me.m_defs);
1842}
1843
1844//-----------------------------------------------------------
1845Strategy::Strategy ()
1846{
1847  clear ();
1848}
1849
1850//-----------------------------------------------------------
1851void Strategy::clear ()
1852{
1853  m_definition = 0;
1854  m_specified = false;
1855  m_specified_value = false;
1856  m_value = false;
1857  m_on_tag = 0;
1858  m_off_tag = 0;
1859}
1860
1861/**----------------------------------------------------------
1862   Specify a new value for this strategy.
1863   This only happens when a strategy statement is met in a project file or in a requirements file.
1864 */
1865void Strategy::set (StrategyDef* definition, bool value, const cmt_string& project_name)
1866{
1867  //cerr << "Setting strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
1868
1869  m_definition = definition;
1870  m_specified = true;
1871  m_specified_value = value;
1872
1873  update (definition, value, project_name);
1874}
1875
1876/**----------------------------------------------------------
1877   Change the effective value for this strategy.
1878   This has no impact on to the specified value.
1879   This will adapt the tag settings
1880 */
1881void Strategy::update (StrategyDef* definition, bool value, const cmt_string& project_name)
1882{
1883  //cerr << "Updating strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
1884
1885  m_value = value;
1886  m_definition = definition;
1887
1888  cmt_string to_tag_name = project_name;
1889  cmt_string to_untag_name = project_name;
1890
1891  to_tag_name += "_";
1892  to_untag_name += "_";
1893
1894  if (m_value)
1895    {
1896      to_tag_name += m_definition->m_on_value;
1897      to_untag_name += m_definition->m_off_value;
1898    }
1899  else
1900    {
1901      to_tag_name += m_definition->m_off_value;
1902      to_untag_name += m_definition->m_on_value;
1903    }
1904
1905  m_on_tag = Tag::find (to_tag_name);
1906  m_off_tag = Tag::find (to_untag_name);
1907
1908  if (m_on_tag == 0) 
1909    {
1910      m_on_tag = Tag::add (to_tag_name, PriorityConfig, "PROJECT", 0);
1911      m_off_tag = Tag::add (to_untag_name, PriorityConfig, "PROJECT", 0);
1912
1913      m_on_tag->add_tag_exclude (m_off_tag);
1914      m_off_tag->add_tag_exclude (m_on_tag);
1915    }
1916
1917  m_off_tag->unmark ();
1918  m_on_tag->mark ();
1919}
1920
1921const cmt_string& StrategyDef::get_default_value () const
1922{
1923  if (m_default_value)
1924    {
1925      return (m_on_value);
1926    }
1927  else
1928    {
1929      return (m_off_value);
1930    }
1931}
1932
Note: See TracBrowser for help on using the repository browser.