source: CMT/v1r19/source/cmt_project.cxx @ 22

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

create project improvements - see CL261

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