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

Last change on this file since 639 was 629, checked in by rybkin, 13 years ago

See C.L. 500

  • Property svn:eol-style set to native
File size: 82.6 KB
Line 
1
2//-----------------------------------------------------------
3// Copyright Christian Arnault LAL-Orsay CNRS
4// arnault@lal.in2p3.fr
5// Modified by garonne@lal.in2p3.fr
6// See the complete license in cmt_license.txt "http://www.cecill.info".
7//-----------------------------------------------------------
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <ctype.h>
13
14#include "cmt_project.h"
15#include "cmt_database.h"
16#include "cmt_system.h"
17#include "cmt_awk.h"
18#include "cmt_syntax.h"
19#include "cmt_tag.h"
20#include "cmt_error.h"
21#include "cmt_log.h"
22
23class ProjectReader : public Awk
24{
25public:
26
27 ProjectReader ()
28 {
29 }
30
31 const cmt_string& get_project_name () const
32 {
33 return (m_project);
34 }
35
36 void filter (const cmt_string& line)
37 {
38 if (0 == line.size () ||
39 line[0] == '#') return;
40 CmtSystem::cmt_string_vector words;
41 CmtSystem::split (line, " \t", words);
42 if (words[0] == "project")
43 {
44 m_project = words[1];
45 }
46 }
47
48private:
49 cmt_string m_project;
50};
51
52class ProjectPatcher : public Awk
53{
54public:
55
56 ProjectPatcher (const cmt_string& p) : m_project (p)
57 {
58 }
59
60 void commit ()
61 {
62 m_output.write (Project::get_project_file_name ());
63 }
64
65 void filter (const cmt_string& line)
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 m_output += "\n";
80 }
81
82private:
83 cmt_string m_output;
84 const cmt_string& m_project;
85};
86
87IProjectFactory& ProjectFactory::instance ()
88{
89 static ProjectFactory me;
90
91 return (me);
92}
93
94void ProjectFactory::reset ()
95{
96 Project::clear_all ();
97}
98
99static bool get_release_from_path (const CmtSystem::cmt_string_vector& items,
100 const cmt_string& path,
101 const cmt_string& name,
102 cmt_string& real_name,
103 cmt_string& release)
104{
105 bool result = false;
106
107 release = "";
108 real_name = "";
109
110 cmt_string p = path;
111
112 if ((items.size () == 0) && (name == ""))
113 {
114 // There is no CMTPROJECTPATH and no expected project name.
115 // We have no way to find a project structure
116 // So we only expect a 2-level structure.
117
118 CmtSystem::basename (p, release);
119 CmtSystem::dirname (p, p);
120 CmtSystem::basename (p, real_name);
121
122 return (false);
123 }
124
125 for (;;)
126 {
127 if (p == "")
128 {
129 // Protection: we found no matching project name
130 // and path was outside any CMTPROJECTPATH
131
132 p = path;
133
134 CmtSystem::basename (p, release);
135 CmtSystem::dirname (p, p);
136 CmtSystem::basename (p, real_name);
137
138 return (false);
139 }
140
141 cmt_string n;
142
143 CmtSystem::basename (p, n);
144 CmtSystem::dirname (p, p);
145
146 if (n == name)
147 {
148 real_name = name;
149 result = true;
150 break;
151 }
152
153 CmtSystem::basename (p, real_name);
154
155 for (int i = 0; i < items.size (); i++)
156 {
157 const cmt_string& item = items[i];
158 if (p == item)
159 {
160 // We have reached an item of CMTPROJECTPATH, no need to continue
161 return (false);
162 }
163 }
164
165 if (release == "")
166 {
167 release = n;
168 }
169 else
170 {
171 cmt_string r;
172
173 r = n;
174 r += CmtSystem::file_separator ();
175 r += release;
176 release = r;
177 }
178 }
179
180 //cerr << "$CMT> GRFP> path=" << path << " name=" << name << " rel=" << release << endl;
181
182 return (result);
183}
184
185
186/*
187 Every new CMTPATH entry becomes associated with a dedicated PROJECT
188 This function will understand this new entry to CMTPATH and understand it:
189 - it can correspond to an existing project (ie already declared)
190 - it's a new project
191 - then it tries to read and parse its project file
192*/
193Project* ProjectFactory::create_project (const cmt_string& specified_name,
194 const cmt_string& path,
195 const cmt_string& source,
196 Project* parent)
197{
198 cmt_string compressed_path = path;
199 CmtSystem::compress_path (compressed_path);
200 bool specify_name = (specified_name != "");
201
202 if (Cmt::get_debug ())
203 {
204 cout << "Creating project " << specified_name << " in " << path << " from " << source << " with parent " << ((parent==0)? "0" : parent->get_name ()) << endl;
205 Project::show_all ();
206 }
207
208 cmt_string sep;
209 sep = CmtSystem::path_separator ();
210
211 cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
212 CmtSystem::cmt_string_vector items;
213 CmtSystem::split (cmtprojectpath, sep, items);
214
215 cmt_string here = CmtSystem::pwd ();
216 if (!CmtSystem::cd (compressed_path)) return (0);
217 cmt_string pwd = CmtSystem::pwd ();
218
219 static Project::ProjectVector& Projects = Project::projects ();
220
221 int i;
222
223 for (i = 0; i < Projects.size (); i++)
224 {
225 Project& p = Projects[i];
226
227 if ((p.get_cmtpath () == compressed_path) ||
228 (p.get_cmtpath_pwd () == pwd) ||
229 (specify_name && (p.get_name () == specified_name)))
230 {
231 cmt_string r;
232 cmt_string n;
233
234 get_release_from_path (items, compressed_path, p.get_name (), n, r);
235
236 if (r != p.get_release ())
237 {
238 CmtMessage::warning ("Project " + p.get_name ()
239 + " requested with conflicting releases "
240 + p.get_release () + " and " + r
241 + ", latter (in " + compressed_path + ") ignored");
242 /*
243 CmtMessage::error ("Project " + p.get_name ()
244 + " requested with conflicting releases "
245 + p.get_release () + " and " + r);
246 */
247 /*
248 if (!Cmt::get_quiet ())
249 {
250 cerr << "#CMT> Project " << p.get_name ()
251 << " requested with conflicting releases " << p.get_release () << " and " << r << endl;
252 }
253 */
254 //CmtError::set (CmtError::project_release_conflict, p.get_name ());
255 }
256
257 bool updated (false);
258 if (parent != 0)
259 {
260 if (!p.has_parent (parent) || !parent->has_child (&p))
261 {
262 p.add_parent (parent);
263 parent->add_child (&p);
264
265 // Since p is a new parent, we should propagate the settings UP.
266
267 parent->update_strategies_from_children ();
268 updated = true;
269 }
270
271 }
272
273 CmtSystem::cd (here);
274 if (updated) Project::order_all ();
275 return (&p);
276 }
277 }
278
279
280 Project* project = 0;
281 Project* cmt = 0;
282
283 bool is_current = false;
284
285 cmt_string name = specified_name;
286 cmt_string project_name;
287 cmt_string release;
288
289 //
290 // Figure out if this is the current project
291 //
292 // if (here.find (pwd) == 0) is_current = true;
293
294 // In case there are symlinks
295
296 // cmt_string here_real, pwd_real;
297 //cerr << "realpath_: create_project" << endl;
298 /*
299 if (CmtSystem::realpath_ (here, here_real) && CmtSystem::realpath_ (pwd, pwd_real))
300 {
301 if (here_real.find (pwd_real) == 0) is_current = true;
302 }
303 */
304 cmt_string pwd_real;
305 if (!CmtSystem::realpath_ (pwd, pwd_real))
306 {
307 CmtError::set (CmtError::file_access_error, "Cannot compute real path `" +
308 pwd + "'");
309 CmtError::print ();
310 return 0;
311 // if (Cmt::get_current_dir_real ().find (pwd_real) == 0) is_current = true;
312 }
313
314 cmt_string text;
315
316 /*
317 Now Figure out the project name from the project file
318 or does not specify the project name
319 */
320 bool has_project_file = false;
321
322 if (CmtSystem::cd ("cmt") && CmtSystem::test_file (Project::get_project_file_name ()))
323 {
324 has_project_file = true;
325 text.read (Project::get_project_file_name ());
326
327 ProjectReader reader;
328
329 reader.run (text);
330
331 project_name = reader.get_project_name ();
332 }
333
334 enum
335 {
336 without_project_file = 0x01,
337 with_project_file = 0x02,
338 without_project_name = 0x04,
339 with_project_name = 0x08,
340 without_specified_name = 0x10,
341 with_specified_name = 0x20,
342 names_mismatch = 0x40,
343 names_match = 0x80
344 };
345
346 int status = ((has_project_file) ? with_project_file : without_project_file) |
347 ((has_project_file && (project_name != "")) ? with_project_name : without_project_name) |
348 ((specify_name) ? with_specified_name : without_specified_name) |
349 ((specify_name && has_project_file && (project_name == specified_name)) ? names_match : names_mismatch);
350
351 if (source == "default path")
352 {
353 name = "CMT";
354 }
355 else
356 {
357 cmt_string n;
358
359 switch (status)
360 {
361 case with_project_file | without_project_name | without_specified_name | names_mismatch:
362
363 // The project is neither specified from the caller nor from the project file
364
365 /*
366 if (!Cmt::get_quiet ())
367 {
368 cerr << "#CMT> Warning: project name unspecified in project file." << endl;
369 }
370 */
371
372 get_release_from_path (items, compressed_path, "", name, release);
373
374 break;
375
376 case with_project_file | without_project_name | with_specified_name | names_mismatch:
377
378 // The name is only specified from the caller
379 // find this specified name in the path
380
381 if (get_release_from_path (items, compressed_path, specified_name, name, release))
382 {
383 // The specified name has been found from the path.
384 // We believe in the release spec.
385 }
386 else
387 {
388 // The specified name is not in the path.
389 /*
390 if (!Cmt::get_quiet ())
391 {
392 cerr << "#CMT> Warning: specified project name "
393 << specified_name
394 << " from the caller does not match path." << endl;
395 }
396 */
397 name = specified_name;
398 }
399
400 break;
401
402 case with_project_file | with_project_name | with_specified_name | names_match:
403
404 // We have a double specification: from the caller and from the project file.
405 // And both specifications are consistent.
406
407 if (get_release_from_path (items, compressed_path, specified_name, name, release))
408 {
409 // The specified name has been found from the path.
410 // We believe in the release spec.
411 }
412 else
413 {
414 // The specified name is not in the path.
415 /*
416 if (!Cmt::get_quiet ())
417 {
418 cerr << "#CMT> Warning: specified project name "
419 << specified_name
420 << " from project file and from caller does not match path." << endl;
421 }
422 */
423 name = specified_name;
424 }
425
426 break;
427
428 case with_project_file | with_project_name | with_specified_name | names_mismatch:
429
430 // We have a double specification: from the caller and from the project file.
431 // Specifications are inconsistent!!
432
433 /*
434 if (!Cmt::get_quiet ())
435 {
436 cerr << "#CMT> Warning: specified project name "
437 << specified_name
438 << " inconsistent with name "
439 << project_name
440 << " from project file." << endl;
441 }
442 */
443
444 if (get_release_from_path (items, compressed_path, specified_name, n, release))
445 {
446 // name from caller wins.
447 }
448 else if (get_release_from_path (items, compressed_path, project_name, name, release))
449 {
450 // name from project file wins.
451 }
452 else
453 {
454 // The specified name is not in the path.
455
456 CmtMessage::warning ("none of specified project names "
457 + specified_name + " from graph and "
458 + project_name + " from project file match path.");
459 /*
460 if (!Cmt::get_quiet ())
461 {
462 cerr << "#CMT> Warning: none of specified project names "
463 << specified_name
464 << " from graph and "
465 << project_name
466 << " from project file match path." << endl;
467 }
468 */
469
470 name = specified_name;
471 }
472
473 break;
474
475 case with_project_file | with_project_name | without_specified_name | names_mismatch:
476
477 // Project name is specified in the project file but not from the caller.
478
479 if (get_release_from_path (items, compressed_path, project_name, name, release))
480 {
481 // The specified name has been found from the path.
482 // We believe in the release spec.
483
484 }
485 else
486 {
487 // The specified name is not in the path.
488
489 /*
490 if (!Cmt::get_quiet ())
491 {
492 cerr << "#CMT> Warning: specified project name "
493 << project_name
494 << " from project file does not match path." << endl;
495 }
496 */
497
498 name = project_name;
499 }
500
501 break;
502
503 case without_project_file | without_project_name | without_specified_name | names_mismatch:
504
505 // The project is not specified from the caller and there is no project file
506 // This corresponds to the backward compatibility
507 // For the moment, assume /name/release/ structure where release is one level only
508
509 /*
510 if (!Cmt::get_quiet ())
511 {
512 cerr << "#CMT> Warning: project name is not specified "
513 << " (no project file)." << endl;
514 }
515 */
516
517 CmtSystem::basename (compressed_path, release);
518 CmtSystem::dirname (compressed_path, name);
519 CmtSystem::basename (name, name);
520
521 if (name == "")
522 {
523 name = release;
524 release = "";
525 }
526
527 break;
528
529 case without_project_file | without_project_name | with_specified_name | names_mismatch:
530
531 // The name is only specified from the caller
532 // find this specified name in the path
533
534 if (get_release_from_path (items, compressed_path, specified_name, name, release))
535 {
536 // The specified name has been found from the path.
537 // We believe in the release spec.
538 }
539 else
540 {
541 // The specified name is not in the path.
542 /*
543 if (!Cmt::get_quiet ())
544 {
545 cerr << "#CMT> Warning: specified project name "
546 << specified_name
547 << " from project graph does not match path." << endl;
548 }
549 */
550 name = specified_name;
551 }
552
553 break;
554 }
555 }
556
557 if (name == "")
558 {
559 name = "Project";
560 }
561
562 project = Project::add (name, release);
563
564 if (parent != 0)
565 {
566 project->add_parent (parent);
567 parent->add_child (project);
568
569 // Since project is a new child, we should propagate the settings UP.
570
571 parent->update_strategies_from_children ();
572 }
573 /*
574 else if ((name != "CMTUSERCONTEXT") && (name != "CMTHOME"))
575 // else
576 {
577 // this project has no parent thus it should become the top project.
578 // Let's look for all projects without parent.
579 // they will become children of this project.
580
581 for (i = 0; i < Projects.size (); i++)
582 {
583 Project* p = &(Projects[i]);
584 const cmt_string& n = p->get_name ();
585 if (n == name) continue;
586 // if (p->get_name () == name) continue;
587 if ((n == "CMTUSERCONTEXT") || (n == "CMTHOME")) continue;
588 if (!p->has_parents ())
589 {
590 project->add_child (p);
591 p->add_parent (project);
592 }
593 }
594
595 // Since project is a new parent, we should upgrade its settings
596
597 project->update_strategies_from_children ();
598 }
599 */
600 if (source == "default path")
601 {
602 cmt = project;
603 is_current = false;
604 }
605
606 project->set_cmtpath (compressed_path);
607 project->set_cmtpath_real (pwd_real);
608 project->set_cmtpath_pwd (pwd);
609 project->set_cmtpath_source (source);
610
611 // project->set_is_current (is_current);
612 /*
613 if (is_current)
614 {
615 // cerr << "current: " << project->get_name () << endl;
616 //
617 // The current project defines a tag with its name
618 //
619
620 Tag* tag;
621
622 tag = Tag::add (project->get_name (), PriorityConfig, "PROJECT", 0);
623 tag->mark ();
624 }
625 */
626
627 // Project::order_all ();
628
629 if (text != "")
630 {
631 // Last step is to parse the project file
632
633 if (Cmt::get_debug ())
634 {
635 cout << "About to parse project file [" << text << "]" << endl;
636 }
637
638 // First create the Project.m_use for the policy
639
640 Use* project_use = Use::create (project->get_cmtpath(),
641 "package_policy_for_project_" + project->get_name(),
642 project->get_release (), "", "");
643
644 project_use->done = true;
645 project_use->discarded = false;
646 project_use->m_hidden = true;
647 project_use->selected = true;
648 project_use->m_located = true;
649 cmt_map <Use*, bool> visited;
650 project_use->set_auto_imports(Unspecified, Off, visited);
651 //project_use->set_auto_imports(Off);
652 project_use->initial_scope = ScopePublic;
653 project->set_use(project_use);
654
655
656 // add at the uses level ?????
657 /*static Use::UsePtrVector& uses = Use::get_ordered_uses ();
658 bool found = false;
659 int size = uses.size ();
660 cerr << "\n size:"<<size<< ":" << endl;
661 for (int n = 0; n < size; n++)
662 {
663 Use* tuse = uses[n];
664 cerr << "\tpackage file [" << tuse->get_package_name() << "]" <<project_use->get_package_name()<< endl;
665 if (tuse->get_package_name()==project_use->get_package_name())
666 found=true;
667
668 }
669
670 if (not found)
671 {
672 uses.push_back (project_use);
673 project_use->m_index = uses.size () - 1;
674 }
675 */
676
677 SyntaxParser::parse_project_file_text (text,
678 Project::get_project_file_name (),
679 project);
680 }
681
682
683
684 CmtSystem::cd (here);
685 Project::order_all ();
686
687 return (project);
688}
689
690/*----------------------------------------------------------*/
691/* */
692/* Operations on Projects */
693/* */
694/*----------------------------------------------------------*/
695
696//----------------------------------------------------------
697bool Project::create (const cmt_string& name,
698 const cmt_string& release,
699 const cmt_string& path)
700{
701 cmt_string pwd = CmtSystem::pwd ();
702
703 if (CmtMessage::active (Error))
704 {
705 cerr << "------------------------------------------" << endl;
706 cerr << "Configuring environment for project " << name << " " << release << " (from " << pwd << ") ";
707
708 if (path != "")
709 {
710 cerr << " in " << path;
711 }
712
713 cerr << endl;
714 cerr << "CMT version " << Cmt::get_cmt_version () << "." << endl;
715 cerr << "------------------------------------------" << endl;
716 }
717
718 if (path != "")
719 {
720 if (!CmtSystem::mkdir (path))
721 {
722 CmtMessage::error ("Cannot create the " + path + " directory");
723 // cerr << "Cannot create the " << path << " directory" << endl;
724 return (false);
725 }
726
727 if (!CmtSystem::cd (path))
728 {
729 CmtMessage::error ("Cannot access the " + path + " directory");
730 // cerr << "Cannot access the " << path << " directory" << endl;
731 return (false);
732 }
733 }
734
735 if (!CmtSystem::mkdir (name))
736 {
737 CmtMessage::error ("Cannot create the " + name + " directory");
738 // cerr << "Cannot create the " << name << " directory" << endl;
739 return (false);
740 }
741
742 if (!CmtSystem::cd (name))
743 {
744 CmtMessage::error ("Cannot access the " + name + " directory");
745 // cerr << "Cannot access the " << name << " directory" << endl;
746 return (false);
747 }
748
749 if (release != "")
750 {
751 if (!CmtSystem::mkdir (release))
752 {
753 CmtMessage::error ("Cannot create the " + release + " directory");
754 // cerr << "Cannot create the " << release << " directory" << endl;
755 return (false);
756 }
757
758 if (!CmtSystem::cd (release))
759 {
760 CmtMessage::error ("Cannot access the " + release + " directory");
761 // cerr << "Cannot access the " << release << " directory" << endl;
762 return (false);
763 }
764 }
765
766 if (!CmtSystem::test_directory ("cmt"))
767 {
768 if (!CmtSystem::mkdir ("cmt"))
769 {
770 CmtMessage::error ("Cannot create the cmt directory");
771 // cerr << "Cannot create the cmt directory" << endl;
772 return (false);
773 }
774 else
775 {
776 if (CmtMessage::active (Info))
777 cerr << "Installing the cmt directory" << endl;
778 }
779 }
780
781 CmtSystem::cd ("cmt");
782
783 if (!CmtSystem::test_file (get_project_file_name ()))
784 {
785 if (CmtMessage::active (Info))
786 cerr << "Creating a new project file" << endl;
787
788 ofstream f (get_project_file_name ());
789 if (f)
790 {
791 f << "project " << name << endl;
792 f << endl;
793 f.close ();
794 }
795 else
796 {
797 CmtMessage::error ("Cannot create the project file");
798 // cerr << "Cannot create the project file" << endl;
799 return (false);
800 }
801 }
802 else
803 {
804 cmt_string text;
805 text.read (get_project_file_name ());
806
807 ProjectPatcher p (name);
808
809 p.run (text);
810 p.commit ();
811
812 if (CmtMessage::active (Info))
813 cerr << "project file already there" << endl;
814 }
815
816 return (true);
817}
818
819//----------------------------------------------------------
820Project* Project::find_by_name (const cmt_string& name)
821{
822 static ProjectVector& Projects = projects ();
823
824 for (int i = 0; i < Projects.size (); i++)
825 {
826 Project& p = Projects[i];
827 if (p.m_name == name) return (&p);
828
829 }
830
831 return (0);
832}
833
834//----------------------------------------------------------
835Project* Project::find_by_cmtpath (const cmt_string& cmtpath)
836{
837 cmt_string compressed_path = cmtpath;
838 CmtSystem::compress_path (compressed_path);
839
840 static ProjectVector& Projects = projects ();
841
842 for (int i = 0; i < Projects.size (); i++)
843 {
844 Project& p = Projects[i];
845
846 if (p.m_cmtpath == compressed_path) return (&p);
847 if (p.m_cmtpath_real == compressed_path) return (&p);
848 if (p.m_cmtpath_pwd == compressed_path) return (&p);
849 }
850
851 return (0);
852}
853
854//----------------------------------------------------------
855Project* Project::get_current ()
856{
857 /*
858 cmt_string here = CmtSystem::pwd ();
859
860 // In case there are symlinks
861 cmt_string here_real;
862 CmtSystem::realpath_ (here, here_real);
863 */
864 static ProjectVector& Projects = projects ();
865
866 Project* result = 0;
867
868 for (int i = (Projects.size () - 1); i >= 0; i--)
869 {
870 Project& p = Projects[i];
871
872// if (here.find (p.m_cmtpath_pwd) == 0)
873// {
874// result = &p;
875// }
876
877// if (here.find (p.m_cmtpath) == 0)
878 if (p.is_current ())
879 // if (here_real.find (p.m_cmtpath_real) == 0)
880 {
881 result = &p;
882 }
883 }
884
885 return (result);
886}
887
888//----------------------------------------------------------
889Project* Project::add (const cmt_string& name,
890 const cmt_string& release)
891{
892 static ProjectVector& Projects = projects ();
893
894 {
895 Project* project;
896
897 project = find_by_name (name);
898 if (project != 0)
899 {
900 // if (!Cmt::get_quiet ())
901 // {
902 if (release != project->get_release ())
903 {
904 //if (CmtMessage::active (Verbose))
905 CmtMessage::error ("Project " + name
906 + " requested with conflicting releases "
907 + project->get_release () + " and " + release);
908 // cerr << "#CMT> Project " << name << " requested with conflicting releases " << project->get_release () << " and " << release << endl;
909 CmtError::set (CmtError::project_release_conflict, name);
910 }
911 // }
912
913 // Project objects are recreated here to follow the hierarchy
914 // This duplication is needed for properly applying the strategies
915 Project& p = Projects.add ();
916
917 p.set_name (name);
918 p.set_release (release);
919 p.configure ();
920
921 return (&p);
922
923 //return (project);
924 }
925 }
926
927 Project& project = Projects.add ();
928 project.clear ();
929 project.set_name (name);
930 project.set_release (release);
931 project.configure ();
932
933 return (&project);
934}
935
936//----------------------------------------------------------
937Project::ProjectVector& Project::projects ()
938{
939 static Database& db = Database::instance ();
940 static ProjectVector& Projects = db.projects ();
941
942 return (Projects);
943}
944
945//----------------------------------------------------------
946Project::ProjectPtrVector& Project::ordered_projects ()
947{
948 static Database& db = Database::instance ();
949 static ProjectPtrVector& Projects = db.ordered_projects ();
950
951 return (Projects);
952}
953
954//----------------------------------------------------------
955void Project::order_all ()
956//Project::ProjectPtrVector Project::ordered_projects ()
957{
958 ProjectPtrVector OrderedProjects;
959 // static ProjectPtrVector OrderedProjects;
960 static Project::ProjectPtrVector& orderedProjects = Project::ordered_projects ();
961
962 static Project::ProjectVector& Projects = Project::projects ();
963 const int size = Projects.size ();
964
965 int offset (0);
966 int iuser (-1);
967 int ihome (-1);
968 for (int i = 0; i < 2; i++)
969 {
970 if (offset < size)
971 {
972 const cmt_string& name = Projects[offset].get_name ();
973 if (name == "CMTUSERCONTEXT")
974 {
975 iuser = offset;
976 ++offset;
977 }
978 else if (name == "CMTHOME")
979 {
980 ihome = offset;
981 ++offset;
982 }
983 else
984 break;
985 }
986 }
987
988 OrderedProjects.resize (size);
989
990 Use& use = Use::current();
991 cmt_string current_path;
992 cmt_string current_path_real;
993 if (use.located ())
994 {
995 current_path_real = use.get_realpath ();
996 if (current_path_real.size ())
997 CmtMessage::verbose ("Using current use realpath `" + current_path_real + "'");
998 else
999 {
1000 current_path = use.real_path;
1001 CmtMessage::verbose ("Using current use real_path `" + current_path + "'");
1002 }
1003 }
1004 else
1005 current_path = Cmt::get_current_dir ();
1006
1007 if (0 == current_path_real.size () &&
1008 !CmtSystem::realpath_ (current_path, current_path_real))
1009 {
1010 CmtError::set (CmtError::file_access_error, "Cannot compute real path `" +
1011 current_path + "'");
1012 CmtError::print ();
1013 return;
1014 //CmtMessage::error ("Cannot compute real path `" + Use::current().real_path + "'");
1015 }
1016
1017 Project* p_cur (0);
1018 for (int i = 0; i < size; i++)
1019 {
1020 Project& p = Projects[i];
1021 if (i >= offset)
1022 p.m_order = -1;
1023 else
1024 p.m_order = -2;
1025 p.m_visits = 0;
1026 //
1027 // The current project specification
1028 //
1029 if (current_path_real.find (p.get_cmtpath_real ()) == 0)
1030 {
1031 p_cur = &p;
1032 if (p.is_current ()) continue;
1033
1034 p.set_is_current (true);
1035 //
1036 // The current project defines a tag with its name
1037 //
1038
1039 Tag* tag;
1040
1041 tag = Tag::add (p.get_name (), PriorityConfig, "PROJECT", 0);
1042 tag->mark ("PROJECT");
1043 }
1044 else if (p.is_current ())
1045 {
1046 //
1047 // Unset the tag with its name
1048 //
1049 Tag* tag = Tag::find (p.get_name ());
1050 if (tag != 0)
1051 tag->unmark ();
1052
1053 p.set_is_current (false);
1054 }
1055 }
1056
1057 if (size == offset)
1058 {
1059 for (int i = 0; i < offset; i++)
1060 {
1061 Project* p = &(Projects[i]);
1062 OrderedProjects[i] = p;
1063 }
1064 /*
1065 if (2 == offset)
1066 {
1067 OrderedProjects[0]->add_child (OrderedProjects[1]);
1068 OrderedProjects[1]->add_parent (OrderedProjects[0]);
1069 OrderedProjects[0]->update_strategies_from_children ();
1070 }
1071 */
1072 for (int i = OrderedProjects.size () - 2; i >= 0; i--)
1073 {
1074 if (!OrderedProjects[i]->has_parents () &&
1075 OrderedProjects[i]->get_children_size () == 0)
1076 {
1077 OrderedProjects[i]->add_child (OrderedProjects[i + 1]);
1078 OrderedProjects[i]->update_strategies_from_children ();
1079 OrderedProjects[i]->erase_child (OrderedProjects[i + 1]);
1080 }
1081 }
1082
1083 orderedProjects = OrderedProjects;
1084 // return OrderedProjects;
1085 return;
1086 }
1087
1088 Project* p (p_cur);
1089 // Project* p = get_current ();
1090
1091 // cerr << "get_current: " << p << " offset: " << offset << endl;
1092 /*
1093 if (p == 0)
1094 {
1095 p = &(Projects[offset]);
1096 // p = &(Projects[0]);
1097 }
1098 */
1099 // cerr << "p: " << p << " offset: " << offset << " name: " << p->get_name () << endl;
1100
1101 int order (-1);
1102 /*
1103 if ((p->get_name () != "CMTUSERCONTEXT") && (p->get_name () != "CMTHOME"))
1104 {
1105 ProjectPtrVector projs;
1106 p->m_order = ++order;
1107 // p->m_visits++;
1108 projs.push_back (p);
1109
1110 visit (offset, order, projs);
1111 // visit (order, projs);
1112 }
1113 // cerr << "order: " << order << endl;
1114 // int unordered = size - offset - (order + 1);
1115 */
1116 ProjectPtrVector projs;
1117
1118 if (p != 0 && (p->get_name () != "CMTUSERCONTEXT") && (p->get_name () != "CMTHOME"))
1119 {
1120 p->m_order = ++order;
1121 projs.push_back (p);
1122 }
1123
1124 if (p == 0 ||
1125 !p->has_parents ())
1126 // may come from CMTPATH entry
1127 /*
1128 (!p->has_parents () && p->get_children_size () == 0)
1129 // comes from CMTPATH entry
1130 )
1131 */
1132 {
1133 for (int i = offset; i < size; i++)
1134 {
1135 Project* q = &(Projects[i]);
1136 if (q != p && !q->has_parents ())
1137 { // may come from CMTPATH entry
1138 q->m_order = ++order;
1139 projs.push_back (q);
1140 }
1141 }
1142 }
1143
1144 visit (offset, order, projs);
1145
1146 int beg (0);
1147 if (-1 != iuser)
1148 {
1149 OrderedProjects[0] = &(Projects[iuser]);
1150 // cerr << "OrderedProjects[0]: " << (OrderedProjects[0])->get_name () << endl;
1151 ++beg;
1152 }
1153
1154 int noorder (0);
1155 for (int i = offset; i < size; i++)
1156 // for (int i = 0; i < size; i++)
1157 {
1158 Project* p = &(Projects[i]);
1159 int j = p->m_order;
1160 if (-1 == j)
1161 {
1162 OrderedProjects[beg + order + 1 + noorder++] = p;
1163 // cerr << "no: OrderedProjects[" << beg + order + noorder << "]: " << (OrderedProjects[beg + order + noorder])->get_name () << endl;
1164 // OrderedProjects[order + 1 + noorder++] = p;
1165 /*
1166 if (CmtMessage::active (Verbose))
1167 CmtMessage::warning ("Not ordered project " + p->get_name () +
1168 " in path " + p->get_cmtpath_pwd () +
1169 " from " + p->get_cmtpath_source ());
1170 continue;
1171 */
1172 }
1173 else if (-2 != j)
1174 {
1175 OrderedProjects[beg + j] = p;
1176 }
1177 /*
1178 else if (-2 == j)
1179 {
1180 }
1181 else
1182 {
1183 OrderedProjects[beg + j] = p;
1184 // OrderedProjects[j] = p;
1185 // cerr << "OrderedProjects[" << beg + j << "]: " << (OrderedProjects[beg + j])->get_name () << endl;
1186 }
1187 */
1188 }
1189
1190 if (p != 0)
1191 {
1192 for (int i = 0; i < noorder; i++)
1193 OrderedProjects.pop_back ();
1194 }
1195 if (-1 != ihome)
1196 {
1197 OrderedProjects[OrderedProjects.size () - 1] = &(Projects[ihome]);
1198 }
1199 /*
1200 if (p)
1201 {
1202 if (-1 != ihome)
1203 {
1204 OrderedProjects[beg + order + 1] = &(Projects[ihome]);
1205 }
1206 for (int i = 0; i < noorder; i++)
1207 OrderedProjects.pop_back ();
1208 }
1209 else
1210 {
1211 if (-1 != ihome)
1212 {
1213 OrderedProjects[size - 1] = &(Projects[ihome]);
1214 }
1215 }
1216 */
1217 /*
1218 if (-1 != iuser)
1219 {
1220 OrderedProjects[0]->add_child (OrderedProjects[1]);
1221 OrderedProjects[1]->add_parent (OrderedProjects[0]);
1222 OrderedProjects[0]->update_strategies_from_children ();
1223 }
1224 */
1225
1226// if (-1 != ihome)
1227// {
1228 /*
1229 cerr << "beg: " << beg << " order: " << order << endl;
1230 cerr << "noorder: " << noorder << " size - offset: " << size - offset << endl;
1231 */
1232 /*
1233 if (noorder != size - offset)
1234 { // the last ordered project
1235 OrderedProjects[beg + order]->add_child (OrderedProjects[size - 1]);
1236 OrderedProjects[size - 1]->add_parent (OrderedProjects[beg + order]);
1237 OrderedProjects[beg + order]->update_strategies_from_children ();
1238 }
1239 else
1240 {
1241 OrderedProjects[size - 2]->add_child (OrderedProjects[size - 1]);
1242 OrderedProjects[size - 1]->add_parent (OrderedProjects[size - 2]);
1243 OrderedProjects[size - 2]->update_strategies_from_children ();
1244 }
1245 */
1246// }
1247
1248 for (int i = OrderedProjects.size () - 2; i >= 0; i--)
1249 {
1250 if (!OrderedProjects[i]->has_parents () &&
1251 OrderedProjects[i]->get_children_size () == 0)
1252 {
1253 OrderedProjects[i]->add_child (OrderedProjects[i + 1]);
1254 OrderedProjects[i]->update_strategies_from_children ();
1255 OrderedProjects[i]->erase_child (OrderedProjects[i + 1]);
1256 }
1257 }
1258
1259 orderedProjects = OrderedProjects;
1260 // return OrderedProjects;
1261 return;
1262}
1263
1264/*----------------------------------------------------------*/
1265void Project::clear_all ()
1266{
1267 static ProjectVector& Projects = projects ();
1268
1269 for (int i = 0; i < Projects.size (); i++)
1270 {
1271 Project& project = Projects[i];
1272 project.clear ();
1273 }
1274
1275 Projects.clear ();
1276}
1277
1278/*----------------------------------------------------------*/
1279void Project::show_all (PrintMode mode)
1280//void Project::show_all ()
1281{
1282 static const Project::ProjectPtrVector& Ordered = Project::ordered_projects ();
1283 static Project::ProjectVector& Projects = Project::projects ();
1284
1285 for (int i = 0; i < Projects.size (); i++)
1286 {
1287 Project& p = Projects[i];
1288 p.m_visited = false;
1289 }
1290
1291 switch (mode)
1292 {
1293 case Xml :
1294 Cmt::print_xml_prolog ("projects");
1295 cout << "<projects>";
1296 break;
1297 }
1298
1299 for (int i = 0; i < Ordered.size (); i++)
1300 Ordered[i]->show (mode);
1301 // Ordered[i]->show ();
1302
1303 for (int i = 0; i < Projects.size (); i++)
1304 Projects[i].show (mode);
1305 // Projects[i].show ();
1306
1307 switch (mode)
1308 {
1309 case Xml :
1310 cout << "</projects>" << endl;
1311 break;
1312 }
1313 /*
1314 Project* p = get_current ();
1315
1316 if (p == 0)
1317 {
1318 if (Ordered.size () == 0) return;
1319
1320 p = Ordered[0];
1321 }
1322 */
1323 // p->show ();
1324}
1325
1326/*----------------------------------------------------------*/
1327void Project::show_container (const cmt_string& path)
1328//void Project::show_container ()
1329{
1330 Project* p (0);
1331 if (path == "")
1332 {
1333 p = get_current ();
1334 }
1335 else
1336 {
1337 p = find_by_cmtpath (find_in_cmt_paths (path));
1338 }
1339
1340 if (p == 0)
1341 {
1342 cmt_string msg ("No project found for path "
1343 + (path != "" ? path : (Use::current()).real_path)
1344 );
1345 CmtMessage::warning (msg);
1346 CmtError::set (CmtError::warning, msg);
1347 return;
1348 }
1349 Use* use = &(p->m_container);
1350 if (use->get_package_name () == "")
1351 {
1352 cmt_string msg ("No container specified for project " + p->get_name ()
1353 + " (" + p->get_cmtpath () + ")");
1354 CmtMessage::warning (msg);
1355 CmtError::set (CmtError::warning, msg);
1356 return;
1357 }
1358
1359 if (!use->located ())
1360 {
1361 CmtMessage::warning ("container " + use->get_info ()
1362 + " not found");
1363 CmtError::set (CmtError::package_not_found, use->get_package_name ());
1364 }
1365 else
1366 {
1367 static const cmt_string empty;
1368 cmt_string p = use->real_path;
1369 if (use->path != "")
1370 {
1371 int pos = p.find_last_of (use->path);
1372 if (pos != cmt_string::npos)
1373 {
1374 p.erase (pos);
1375 }
1376 }
1377
1378 cout << "container " << use->get_package_name ()
1379 << " " << use->version;
1380
1381 if (CmtSystem::absolute_path (use->path))
1382 {
1383 if (!Cmt::get_quiet ())
1384 {
1385 cout << " (" << use->path << ")";
1386 }
1387 }
1388 else
1389 {
1390 cout << " " << use->path;
1391 }
1392
1393 if (!Cmt::get_quiet ())
1394 {
1395 if (p != "") cout << " (" << p << ")";
1396 if (use->auto_imports == Off) cout << " (no_auto_imports)";
1397 }
1398
1399 cout << endl;
1400 }
1401}
1402
1403/*----------------------------------------------------------*/
1404void Project::show_specified_strategies_for_all ()
1405{
1406 static ProjectVector& Projects = projects ();
1407
1408 for (int i = 0; i < Projects.size (); i++)
1409 {
1410 const Project& project = Projects[i];
1411 project.show_specified_strategies ();
1412 }
1413}
1414
1415/*----------------------------------------------------------*/
1416class VisitorForShowPaths : public IProjectVisitor
1417{
1418public:
1419 VisitorForShowPaths ()
1420 {
1421 }
1422
1423 void pre (Project* p)
1424 {
1425 const cmt_string& w = p->get_cmtpath_pwd ();
1426 const cmt_string& s = p->get_cmtpath_source ();
1427
1428 if (s == "default path") return;
1429
1430 if (CmtSystem::test_directory (w))
1431 {
1432 cout << "# Add path " << w << " from " << s << endl;
1433 }
1434 }
1435
1436 void in (Project* p)
1437 {
1438 const cmt_string& w = p->get_cmtpath_pwd ();
1439 const cmt_string& s = p->get_cmtpath_source ();
1440
1441 if (s == "default path") return;
1442
1443 if (CmtSystem::test_directory (w))
1444 {
1445 cout << "# Add path " << w << " from " << s << endl;
1446 }
1447 }
1448
1449 void in_again (Project* p)
1450 {
1451 const cmt_string& w = p->get_cmtpath_pwd ();
1452 const cmt_string& s = p->get_cmtpath_source ();
1453
1454 if (s == "default path") return;
1455
1456 if (CmtSystem::test_directory (w))
1457 {
1458 cout << "# Remove path " << w << " from " << s << endl;
1459 cout << "# Add path " << w << " from " << s << endl;
1460 }
1461 }
1462
1463 void post (Project* p)
1464 {
1465 }
1466};
1467
1468/*----------------------------------------------------------*/
1469void Project::show_paths (const CmtSystem::cmt_string_vector& arguments,
1470 ostream& out)
1471//void Project::show_paths ()
1472{
1473 if (arguments.size () == 0 ||
1474 Cmt::get_action () != action_show_path)
1475 {
1476 const ProjectPtrVector& Ordered = Project::ordered_projects ();
1477 for (int i = 0; i < Ordered.size (); i++)
1478 {
1479 const Project* p = Ordered[i];
1480 const cmt_string& w = p->get_cmtpath_pwd ();
1481 const cmt_string& s = p->get_cmtpath_source ();
1482
1483 if (s == "default path") continue;
1484
1485 if (CmtSystem::test_directory (w))
1486 {
1487 out << "# Add path " << w << " from " << s << endl;
1488 }
1489 }
1490 }
1491 else if (arguments.size () == 1 && cmt_string (arguments[0]) == "-d")
1492 {
1493 const ProjectVector& Projects = projects ();
1494 for (int i = 0; i < Projects.size (); i++)
1495 {
1496 Project& p = Projects[i];
1497 const cmt_string& w = p.get_cmtpath_pwd ();
1498 const cmt_string& s = p.get_cmtpath_source ();
1499
1500 if (s == "default path") continue;
1501
1502 if (CmtSystem::test_directory (w))
1503 {
1504 out << "# Create path " << w << " from " << s << endl;
1505 }
1506 }
1507 /*
1508 VisitorForShowPaths visitor;
1509 start_visit (visitor);
1510 */
1511 }
1512 else
1513 CmtMessage::error ("show_paths: unexpected argument(s)");
1514}
1515
1516//----------------------------------------------------------
1517const cmt_string& Project::get_project_file_name ()
1518{
1519 static const cmt_string name = "project.cmt";
1520
1521 return (name);
1522}
1523
1524//----------------------------------------------------------
1525void Project::fill_selection (int depth, CmtSystem::cmt_string_vector& path_selections)
1526{
1527 static ProjectPtrVector& Ordered = Project::ordered_projects ();
1528 for (int i = 0; i < Ordered.size (); i++)
1529 {
1530 const Project* project = Ordered[i];
1531
1532 const cmt_string& p = project->get_cmtpath ();
1533 const cmt_string& pwd = project->get_cmtpath_pwd ();
1534 const cmt_string& p_real = project->get_cmtpath_real ();
1535 const cmt_string& src = project->get_cmtpath_source ();
1536 /*
1537 static ProjectVector& Projects = projects ();
1538
1539 for (int i = 0; i < Projects.size (); i++)
1540 {
1541 Project& project = Projects[i];
1542
1543 const cmt_string& p = project.get_cmtpath ();
1544 const cmt_string& pwd = project.get_cmtpath_pwd ();
1545 const cmt_string& p_real = project.get_cmtpath_real ();
1546 const cmt_string& src = project.get_cmtpath_source ();
1547 */
1548 if (src != "default path")
1549 {
1550 if (depth > 0)
1551 {
1552 cmt_string& s1 = path_selections.add ();
1553 s1 = p;
1554 if (pwd != p)
1555 {
1556 cmt_string& s2 = path_selections.add ();
1557 s2 = pwd;
1558 }
1559 if (p_real != p && p_real != pwd)
1560 {
1561 cmt_string& s3 = path_selections.add ();
1562 s3 = p_real;
1563 }
1564 if (src != "CMTHOME" && src != "CMTUSERCONTEXT")
1565 depth--;
1566
1567 if (depth == 0) break;
1568 }
1569 }
1570 }
1571}
1572
1573//----------------------------------------------------------
1574void Project::broadcast (IProjectAction& action)
1575{
1576 // const ProjectPtrVector Projects = Project::ordered_projects ();
1577 static ProjectPtrVector& Projects = Project::ordered_projects ();
1578
1579 for (int i = 0; i < Projects.size (); i++)
1580 {
1581 const Project* project = Projects[i];
1582
1583 if (!action.run (*project)) break;
1584 }
1585 /*
1586 static ProjectVector& Projects = projects ();
1587
1588 for (int i = 0; i < Projects.size (); i++)
1589 {
1590 const Project& project = Projects[i];
1591
1592 if (!action.run (project)) break;
1593 }
1594 */
1595}
1596
1597//----------------------------------------------------------
1598void Project::reverse_broadcast (IProjectAction& action)
1599{
1600 // const ProjectPtrVector Projects = Project::ordered_projects ();
1601 static ProjectPtrVector& Projects = Project::ordered_projects ();
1602
1603 for (int i = (Projects.size () - 1); i >= 0; i--)
1604 {
1605 const Project* project = Projects[i];
1606
1607 if (!action.run (*project)) break;
1608 }
1609 /*
1610 static ProjectVector& Projects = projects ();
1611
1612 for (int i = (Projects.size () - 1); i >= 0; i--)
1613 {
1614 const Project& project = Projects[i];
1615
1616 if (!action.run (project)) break;
1617 }
1618 */
1619}
1620
1621//----------------------------------------------------------
1622void Project::scan_paths (PathScanner& scanner, PathScanner::actor& a)
1623{
1624 static ProjectVector& Projects = projects ();
1625
1626 int i;
1627
1628 for (i = 0; i < Projects.size (); i++)
1629 {
1630 Project& p = Projects[i];
1631 p.m_visited = false;
1632 }
1633
1634 for (i = 0; i < Projects.size (); i++)
1635 {
1636 const Project& project = Projects[i];
1637
1638 const cmt_string& p = project.m_cmtpath;
1639 scanner.scan_path (p, a);
1640 }
1641}
1642
1643//----------------------------------------------------------
1644void Project::scan_paths_for_package (PathScanner& scanner, const cmt_string& name)
1645{
1646 static ProjectVector& Projects = projects ();
1647
1648 bool found (false);
1649 for (int i = 0; i < Projects.size (); i++)
1650 {
1651 const Project& project = Projects[i];
1652
1653 const cmt_string& p = project.m_cmtpath;
1654 if (scanner.scan_package (p, name))
1655 found = true;
1656 }
1657
1658 if (!found)
1659 CmtError::set (CmtError::package_not_found, name);
1660}
1661
1662//----------------------------------------------------------
1663cmt_string Project::find_in_cmt_paths (const cmt_string& path, bool realpath)
1664{
1665 //const cmt_string pwd = CmtSystem::pwd ();
1666
1667 // In case there are symlinks
1668 cmt_string path_real;
1669 //cerr << "realpath_: find_in_cmt_paths" << endl;
1670 if (realpath)
1671 path_real = path;
1672 else if (!CmtSystem::realpath_ (path, path_real))
1673 return ("");
1674
1675 static ProjectVector& Projects = projects ();
1676
1677 for (int i = 0; i < Projects.size (); i++)
1678 {
1679 const Project& project = Projects[i];
1680
1681 const cmt_string& p = project.m_cmtpath;
1682 const cmt_string& p_real = project.m_cmtpath_real;
1683 const cmt_string& w = project.m_cmtpath_pwd;
1684 const cmt_string& s = project.m_cmtpath_source;
1685
1686 if (s == "default path") continue;
1687
1688 // MUST be directory if project added
1689 // if (CmtSystem::test_directory (p))
1690 {
1691// if (path.find (p) != cmt_string::npos)
1692// {
1693// return (p);
1694// }
1695
1696 if (path_real.find (p_real) != cmt_string::npos)
1697 {
1698 return (p);
1699 }
1700
1701 // To become the current area, a path must correspond to the current package
1702 if (path.find (w) != cmt_string::npos)
1703 {
1704 return (p);
1705 }
1706 }
1707
1708 if (p == w) continue;
1709
1710 // MUST be directory if project added
1711 // if (CmtSystem::test_directory (w))
1712 {
1713 if (path.find (w) != cmt_string::npos)
1714 {
1715 return (w);
1716 }
1717 }
1718 }
1719
1720 return ("");
1721}
1722
1723//----------------------------------------------------------
1724void Project::visit (IProjectVisitor& visitor)
1725{
1726 if (m_visited) return;
1727 m_visited = true;
1728
1729 int i;
1730
1731 for (i = 0; i < get_children_size (); i++)
1732 {
1733 Project* child = get_child (i);
1734
1735 if (child->visited ()) continue;
1736
1737 visitor.in (child);
1738 }
1739
1740 for (i = 0; i < m_children.size (); i++)
1741 {
1742 Project* child = m_children[i];
1743 child->visit (visitor);
1744 }
1745}
1746
1747//----------------------------------------------------------
1748void Project::visit (IProjectVisitor& visitor, ProjectPtrVector& projects)
1749{
1750 int size = projects.size ();
1751 if (0 == size) return;
1752
1753 ProjectPtrVector children;
1754 for (int j = 0; j < size; j++)
1755 {
1756 Project* p = projects[j];
1757 if (20 == p->m_visits)
1758 continue;
1759 for (int i = 0; i < p->get_children_size (); i++)
1760 {
1761 Project* child = p->get_child (i);
1762 if (0 == child->m_visits)
1763 visitor.in (child);
1764 else
1765 visitor.in_again (child);
1766 child->m_visits++;
1767 children.push_back (child);
1768 }
1769 }
1770
1771 visit (visitor, children);
1772}
1773
1774//----------------------------------------------------------
1775/**
1776 * Visit the projects tree and order the projects.
1777 * Order is the projects upon which the project depends directly,
1778 * then the direct dependencies of the of the first dependency, of the second
1779 * dependency and so on. That is first left to right, then downwards.
1780 * @param offset the offset from which to use all the projects
1781 * @param order the order of the last project visited
1782 * @param projs vector of projects to visit and order
1783 */
1784void Project::visit (const int offset, int& order, ProjectPtrVector& projs)
1785{
1786 int size = projs.size ();
1787 // cerr << "visit: " << offset << " " << order << " " << size << endl;
1788 if (0 == size) return;
1789 static ProjectVector& all = Project::projects ();
1790 /*
1791 cerr << "@ visit: " << order;
1792 for (int j = 0; j < size; j++)
1793 {
1794 Project* p = projs[j];
1795 cerr << " " << p->get_name ();
1796 }
1797 cerr << " @" << endl;
1798 */
1799 ProjectPtrVector children;
1800 for (int j = 0; j < size; j++)
1801 {
1802 Project* p = projs[j];
1803 p->m_visits++;
1804 // Avoid looping in case of circular project dependencies
1805 if (500 <= p->m_visits)
1806 // if (100 <= p->m_visits)
1807 continue;
1808 for (int i = 0; i < p->get_children_size (); i++)
1809 {
1810 Project* child = p->get_child (i);
1811 const int chorder = child->m_order;
1812 const int porder = p->m_order;
1813 /*
1814 cerr << ">>> " << p->get_name () << " child: " << i << endl;
1815 cerr << child->get_name () << " in: " << chorder << endl;
1816 */
1817 if (-2 == chorder)
1818 continue;
1819 else if (-1 == chorder)
1820 { // not ordered yet, i.e. visited for the first time
1821 child->m_order = ++order;
1822 }
1823 else if (child->is_current ())
1824 // else if (0 == chorder)
1825 { // the project we started with, i. e. the current project:
1826 // o circular dependency
1827 // o do want to keep it first no matter what
1828 if (CmtMessage::active (Verbose))
1829 CmtMessage::warning ("Circular dependency on project: "
1830 + child->get_name ()
1831 + " " + child->get_release ()
1832 + " " + child->get_cmtpath ());
1833 }
1834 else if ((0 <= chorder) && (chorder < porder))
1835 // else if ((0 < chorder) && (chorder < porder))
1836 { // ordered already, want to put it after the parent in the order
1837 for (int k = offset; k < all.size (); k++)
1838 {
1839 Project& q = all[k];
1840 if (&q == child)
1841 {// the child we are putting after the parent in the order
1842 q.m_order = porder;
1843 // cerr << "Moved back: " << q.get_name () << " order: " << q.m_order << endl;
1844 }
1845 else if ((chorder < q.m_order) && (q.m_order <= porder))
1846 q.m_order--;
1847 }
1848 }
1849 // cerr << child->get_name () << " out: " << child->m_order << endl;
1850 // child->m_visits++;
1851 bool unknown (true);
1852 for (int j = 0; j < children.size (); j++)
1853 {
1854 if (children[j] == child)
1855 {
1856 unknown = false;
1857 break;
1858 }
1859 }
1860 if (unknown)
1861 {
1862 children.push_back (child);
1863 }
1864 }
1865 }
1866
1867 visit (offset, order, children);
1868}
1869
1870//----------------------------------------------------------
1871void Project::start_visit (IProjectVisitor& visitor)
1872{
1873 static Project::ProjectVector& Projects = Project::projects ();
1874
1875 for (int i = 0; i < Projects.size (); i++)
1876 {
1877 Project& p = Projects[i];
1878 p.m_visited = false;
1879 p.m_visits = 0;
1880 }
1881
1882 Project* p = get_current ();
1883
1884 if (p == 0)
1885 {
1886 if (Projects.size () == 0) return;
1887
1888 p = &(Projects[0]);
1889 }
1890
1891 // visitor.pre (p);
1892 //p->visit (visitor);
1893 // visitor.post (p);
1894 visitor.in (p);
1895 p->m_visits++;
1896 ProjectPtrVector projs;
1897 projs.push_back (p);
1898 visit (visitor, projs);
1899}
1900
1901//----------------------------------------------------------
1902class VisitorForFillCMTPATH : public IProjectVisitor
1903{
1904public:
1905 VisitorForFillCMTPATH (cmt_string& buffer) : m_buffer (buffer)
1906 {
1907 buffer = "path CMTPATH \"\" \n";
1908 }
1909
1910 void pre (Project* p)
1911 {
1912 const cmt_string& w = p->get_cmtpath_pwd ();
1913 const cmt_string& s = p->get_cmtpath_source ();
1914
1915 if (s == "default path") return;
1916
1917 if (CmtSystem::test_directory (w))
1918 {
1919 m_buffer += "path_append CMTPATH \"";
1920 m_buffer += w;
1921 m_buffer += "\" \n";
1922 }
1923 }
1924
1925 void in (Project* p)
1926 {
1927 const cmt_string& w = p->get_cmtpath_pwd ();
1928 const cmt_string& s = p->get_cmtpath_source ();
1929
1930 if (s == "default path") return;
1931
1932 if (CmtSystem::test_directory (w))
1933 {
1934 m_buffer += "path_append CMTPATH \"";
1935 m_buffer += w;
1936 m_buffer += "\" \n";
1937 }
1938 }
1939
1940 void in_again (Project* p)
1941 {
1942 const cmt_string& w = p->get_cmtpath_pwd ();
1943 const cmt_string& s = p->get_cmtpath_source ();
1944
1945 if (s == "default path") return;
1946
1947 if (CmtSystem::test_directory (w))
1948 {
1949 m_buffer += "path_remove CMTPATH \"";
1950 m_buffer += w;
1951 m_buffer += "\" \n";
1952 m_buffer += "path_append CMTPATH \"";
1953 m_buffer += w;
1954 m_buffer += "\" \n";
1955 }
1956 }
1957
1958 void post (Project* p)
1959 {
1960 //cerr << "Buffer = " << m_buffer << endl;
1961 }
1962
1963private:
1964 cmt_string& m_buffer;
1965
1966};
1967
1968//----------------------------------------------------------
1969void Project::fill_cmtpaths (cmt_string& buffer)
1970{
1971 /*
1972 Try to re-create all CMTPATH items from project definitions.
1973 The goal is to generate CMTPATH even if this EV was not pre-set
1974 which is the case when CMTPROJECTPATH is only used
1975 */
1976
1977 /*
1978 VisitorForFillCMTPATH visitor (buffer);
1979
1980 start_visit (visitor);
1981 */
1982 const ProjectPtrVector& Ordered = Project::ordered_projects ();
1983
1984 buffer = "path CMTPATH \"\" \n";
1985 for (int i = 0; i < Ordered.size (); i++)
1986 {
1987 const Project* p = Ordered[i];
1988 const cmt_string& w = p->get_cmtpath_pwd ();
1989 const cmt_string& s = p->get_cmtpath_source ();
1990
1991 if (s == "default path") continue;
1992
1993 if (CmtSystem::test_directory (w))
1994 {
1995 buffer += "path_append CMTPATH \"";
1996 buffer += w;
1997 buffer += "\" \n";
1998 }
1999 }
2000}
2001
2002//----------------------------------------------------------
2003Project::Project () : m_name (""), m_author("")
2004{
2005 clear ();
2006}
2007
2008//----------------------------------------------------------
2009const cmt_string& Project::get_name () const
2010{
2011 return (m_name);
2012}
2013
2014//----------------------------------------------------------
2015const cmt_string& Project::get_release () const
2016{
2017 return (m_release);
2018}
2019
2020//----------------------------------------------------------
2021const cmt_string& Project::get_container_name () const
2022{
2023 return (m_container_name);
2024}
2025
2026//----------------------------------------------------------
2027const cmt_string& Project::get_container_version () const
2028{
2029 return (m_container_version);
2030}
2031
2032//----------------------------------------------------------
2033const cmt_string& Project::get_container_path () const
2034{
2035 return (m_container_path);
2036}
2037
2038//----------------------------------------------------------
2039const Use& Project::get_container () const
2040{
2041 return (m_container);
2042}
2043
2044//----------------------------------------------------------
2045const cmt_string& Project::get_cmtpath () const
2046{
2047 return (m_cmtpath);
2048}
2049
2050//----------------------------------------------------------
2051const cmt_string& Project::get_cmtpath_real () const
2052{
2053 return (m_cmtpath_real);
2054}
2055
2056//----------------------------------------------------------
2057const cmt_string& Project::get_cmtpath_pwd () const
2058{
2059 return (m_cmtpath_pwd);
2060}
2061
2062//----------------------------------------------------------
2063const cmt_string& Project::get_cmtpath_source () const
2064{
2065 return (m_cmtpath_source);
2066}
2067
2068//----------------------------------------------------------
2069int Project::get_children_size () const
2070{
2071 return (m_children.size ());
2072}
2073
2074//----------------------------------------------------------
2075Project* Project::get_child (int index) const
2076{
2077 if (index < 0) return (0);
2078 if (index >= m_children.size ()) return (0);
2079 return (m_children[index]);
2080}
2081
2082//----------------------------------------------------------
2083bool Project::visited () const
2084{
2085 return (m_visited);
2086}
2087
2088//----------------------------------------------------------
2089void Project::set_name (const cmt_string& name)
2090{
2091 m_name = name;
2092}
2093
2094//----------------------------------------------------------
2095void Project::set_release (const cmt_string& release)
2096{
2097 m_release = release;
2098}
2099
2100//----------------------------------------------------------
2101void Project::set_container_name (const cmt_string& name)
2102{
2103 m_container_name = name;
2104}
2105
2106//----------------------------------------------------------
2107void Project::set_container_version (const cmt_string& container_version)
2108{
2109 m_container_version = container_version;
2110}
2111
2112//----------------------------------------------------------
2113void Project::set_container_path (const cmt_string& container_path)
2114{
2115 m_container_path = container_path;
2116}
2117
2118//----------------------------------------------------------
2119void Project::set_cmtpath (const cmt_string& path)
2120{
2121 m_cmtpath = path;
2122}
2123
2124//----------------------------------------------------------
2125void Project::set_cmtpath_real (const cmt_string& path)
2126{
2127 m_cmtpath_real = path;
2128}
2129
2130//----------------------------------------------------------
2131void Project::set_cmtpath_pwd (const cmt_string& path)
2132{
2133 m_cmtpath_pwd = path;
2134}
2135
2136//----------------------------------------------------------
2137void Project::set_cmtpath_source (const cmt_string& source)
2138{
2139 m_cmtpath_source = source;
2140}
2141
2142//----------------------------------------------------------
2143void Project::set_is_current (bool is_current)
2144{
2145 m_is_current = is_current;
2146}
2147
2148//----------------------------------------------------------
2149bool Project::is_current () const
2150{
2151 return m_is_current;
2152}
2153
2154//----------------------------------------------------------
2155void Project::clear ()
2156{
2157 m_name = "";
2158 m_release = "";
2159 m_cmtpath = "";
2160 m_cmtpath_real = "";
2161 m_cmtpath_pwd = "";
2162 m_cmtpath_source = "";
2163 m_use = 0;
2164
2165 m_parents.clear ();
2166 m_children.clear ();
2167
2168 m_configured = false;
2169
2170 m_strategies.clear ();
2171 m_is_current = false;
2172}
2173
2174//----------------------------------------------------------
2175bool Project::has_parents () const
2176{
2177 return ((m_parents.size () > 0));
2178}
2179
2180//----------------------------------------------------------
2181bool Project::has_parent (Project* p) const
2182{
2183 if (p == 0) return (false);
2184 if (p == this) return (false);
2185
2186 const cmt_string& name = p->get_name ();
2187
2188 int i;
2189
2190 for (i = 0; i < m_parents.size (); i++)
2191 {
2192 const Project* parent = m_parents[i];
2193 if (parent == 0) continue;
2194
2195 if (parent->get_name () == name)
2196 {
2197 // registered as a parent
2198 return (true);
2199 }
2200
2201 if (parent->has_parent (p))
2202 {
2203 // recurse
2204 return (true);
2205 }
2206 }
2207
2208 return (false);
2209}
2210
2211//----------------------------------------------------------
2212bool Project::has_child (Project* p) const
2213{
2214 if (p == 0) return (false);
2215 if (p == this) return (false);
2216
2217 const cmt_string& name = p->get_name ();
2218
2219 int i;
2220
2221 for (i = 0; i < m_children.size (); i++)
2222 {
2223 const Project* child = m_children[i];
2224 if (child == 0) continue;
2225
2226 if (child->get_name () == name)
2227 {
2228 // registered as a child
2229 return (true);
2230 }
2231
2232 if (child->has_child (p))
2233 {
2234 // recurse
2235 return (true);
2236 }
2237 }
2238
2239 return (false);
2240}
2241
2242//----------------------------------------------------------
2243void Project::add_parent (Project* p)
2244{
2245 if (p == 0) return;
2246 if (p == this) return;
2247
2248 //cerr << "Adding parent " << p->get_name () << " to " << m_name << endl;
2249
2250 if (has_child (p)) return;
2251 if (has_parent (p)) return;
2252
2253 m_parents.push_back (p);
2254}
2255
2256//----------------------------------------------------------
2257void Project::add_child (Project* p)
2258{
2259 if (p == 0) return;
2260 if (p == this) return;
2261
2262 if (has_child (p)) return;
2263 if (has_parent (p)) return;
2264
2265 m_children.push_back (p);
2266}
2267
2268//----------------------------------------------------------
2269void Project::erase_child (Project* p)
2270{
2271 if (p == 0) return;
2272 if (p == this) return;
2273
2274 if (!has_child (p)) return;
2275
2276 const cmt_string& name = p->get_name ();
2277
2278 for (int i = 0; i < m_children.size (); i++)
2279 {
2280 const Project* child = m_children[i];
2281 if (child == 0) continue;
2282
2283 if (child->get_name () == name)
2284 {
2285 // registered as a child
2286 m_children.erase (i);
2287 break;
2288 }
2289 }
2290}
2291
2292//----------------------------------------------------------
2293void Project::configure ()
2294{
2295 if (m_configured) return;
2296 m_configured = true;
2297
2298 set_default_strategy ("SetupConfig");
2299 set_default_strategy ("SetupRoot");
2300 set_default_strategy ("SetupCleanup");
2301 set_default_strategy ("SetupScripts");
2302 set_default_strategy ("BuildPrototypes");
2303 set_default_strategy ("InstallArea");
2304 set_default_strategy ("VersionDirectory");
2305}
2306
2307/**---------------------------------------------------------
2308 A container statement is met in the project file
2309*/
2310void Project::container_action (const CmtSystem::cmt_string_vector& words)
2311//void Project::container_action (const cmt_string& name, const cmt_string& version)
2312{
2313 //
2314 // complete syntax : "container <package> <version> <path>"
2315 // minimal syntax : "container <package>"
2316 //
2317 // o if <version> is omitted then take any version available
2318 // o <version> can be specified using "v*" or "v<n>r*" or "v<n>r<m>p*"
2319 //
2320 // o the notation "v*" is preferred to omission (particularly since
2321 // omission does not permit <path>)
2322 //
2323 if (words.size () < 2) return;
2324
2325 CmtSystem::cmt_string_vector ewords;
2326 for (int i = 1; i < words.size (); i++)
2327 {
2328 const cmt_string& w = words[i];
2329 cmt_string ew = w;
2330
2331 Symbol::expand (ew);
2332 if (ew != w)
2333 {
2334 CmtSystem::cmt_string_vector ws;
2335 CmtSystem::split (ew, " ", ws);
2336
2337 for (int j = 0; j < ws.size (); ++j)
2338 {
2339 ewords.push_back (ws[j]);
2340 }
2341 }
2342 else
2343 {
2344 ewords.push_back (w);
2345 }
2346 }
2347
2348 cmt_string name, version, path;
2349 if (ewords.size () > 0) name = ewords[0];
2350 if (ewords.size () > 1) version = ewords[1];
2351 if (ewords.size () > 2) path = ewords[2];
2352
2353 Use* use = &m_container;
2354 if (name == "")
2355 {
2356 use->clear ();
2357 return;
2358 }
2359 if (version == "") version = "*";
2360
2361 use->set (name, version, path);
2362 use->get_package ()->remove_use (use);
2363 CmtSystem::cd (m_cmtpath_pwd);
2364 if (use->move_to ("", true) &&
2365 !CmtSystem::absolute_path (use->real_path))
2366 {
2367 use->change_path (m_cmtpath_pwd);
2368 }
2369 CmtSystem::cd (m_cmtpath_pwd + CmtSystem::file_separator () + "cmt");
2370
2371 set_container_name (name);
2372 set_container_version (version);
2373 set_container_path (path);
2374}
2375
2376/**---------------------------------------------------------
2377 A use statement is met in the project file
2378*/
2379void Project::use_action (const cmt_string& name, const cmt_string& release)
2380{
2381 if (Cmt::get_debug ())
2382 {
2383 cout << "Use action " << name << " " << release << endl;
2384 }
2385
2386 // A project with its release is specified
2387 //
2388 // Is this project already visible?
2389 // If not: look for it
2390 // + get CMTPROJECTPATH
2391 // + search from all entries of CMTPROJECTPATH : p(i)/<name>/<release>
2392 // + when found, this should become a new CMTPATH entry
2393 // + the new project is then parsed ... etc...
2394
2395 // First test it wilcard is used
2396 int v = -1;
2397 int r = -1;
2398 int p = -1;
2399 cmt_string new_release = release;
2400 CmtSystem::is_version_directory (new_release, v, r, p);
2401 bool use_has_wild_card = (v == -1) || (r == -1) || (p == -1);
2402 if (use_has_wild_card)
2403 {
2404 cmt_string selected_release = "";
2405
2406 if (select_release(name, new_release,selected_release))
2407 {
2408 // cerr <<"selected_release: "<<selected_release<<endl;
2409 new_release = selected_release;
2410 }
2411 }
2412
2413 cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2414 cmt_string sep;
2415 sep = CmtSystem::path_separator ();
2416
2417 CmtSystem::cmt_string_vector items;
2418 CmtSystem::split (cmtprojectpath, sep, items);
2419
2420 bool found = false;
2421
2422 for (int i = 0; i < items.size (); i++)
2423 {
2424 const cmt_string& item = items[i];
2425 cmt_string p = item;
2426 p += CmtSystem::file_separator ();
2427 p += name;
2428 if (new_release != "")
2429 {
2430 p += CmtSystem::file_separator ();
2431 p += new_release;
2432 }
2433
2434 if (CmtSystem::test_directory (p))
2435 {
2436 //cerr << "Project directory " << p << " exists " << endl;
2437
2438 found = true;
2439
2440 IProjectFactory& factory = ProjectFactory::instance ();
2441
2442 factory.create_project (name, p, "ProjectPath", this);
2443
2444 break;
2445 }
2446 }
2447
2448 if (!found)
2449 {
2450 Project* p = Project::find_by_name (name);
2451
2452 if (p != 0)
2453 {
2454 found = true;
2455 p->add_parent (this);
2456 add_child (p);
2457
2458 update_strategies_from_children ();
2459 }
2460 }
2461
2462 if (!found && (cmtprojectpath != ""))
2463 {
2464 CmtMessage::warning ("Project " + name + " " + release + " requested by " + m_name + " not found in CMTPROJECTPATH");
2465 // cerr << "#CMT> Project " << name << " " << release << " requested by " << m_name << " not found in CMTPROJECTPATH" << endl;
2466 }
2467}
2468
2469//---------------------------------------------------------
2470bool Project::select_release(const cmt_string& name, const cmt_string& release, cmt_string& result)
2471{
2472 cmt_string selected_release = "";
2473
2474 int v = -1;
2475 int r = -1;
2476 int p = -1;
2477 CmtSystem::is_version_directory (release, v, r, p);
2478
2479 int selected_v = -1;
2480 int selected_r = -1;
2481 int selected_p = -1;
2482 CmtSystem::cmt_string_vector releases = get_project_releases(name);
2483 for (int j = 0; j < releases.size (); j++)
2484 {
2485 int new_v = -1;
2486 int new_r = -1;
2487 int new_p = -1;
2488 CmtSystem::is_version_directory (releases[j], new_v, new_r, new_p);
2489 if (v == -1)
2490 {
2491 if (selected_v < new_v)
2492 {
2493 selected_v = new_v;
2494 selected_r = -1;
2495 selected_p = -1;
2496 selected_release = releases[j];
2497 }
2498 else if (selected_v == new_v)
2499 {
2500 // We compare the r
2501 if (selected_r < new_r)
2502 {
2503 selected_r = new_r;
2504 selected_p = -1;
2505 selected_release = releases[j];
2506 }
2507 else if (selected_r == new_r)
2508 {
2509 // We compare the p
2510 if (selected_p < new_p)
2511 {
2512 selected_p = new_p;
2513 selected_release = releases[j];
2514 }
2515 // else if ? not possible
2516 }
2517 }
2518 }
2519 else if (r == -1)
2520 {
2521 if (v == new_v)
2522 {
2523 // We compare the r
2524 if (selected_r < new_r)
2525 {
2526 selected_r = new_r;
2527 selected_p = -1;
2528 selected_release = releases[j];
2529 }
2530 else if (selected_r == new_r)
2531 {
2532 // We compare the p
2533 if (selected_p < new_p)
2534 {
2535 selected_p = new_p;
2536 selected_release = releases[j];
2537 }
2538 // else if ? not possible
2539 }
2540 }
2541 }
2542 else if (p == -1)
2543 {
2544 if ((v == new_v) && (r == new_r))
2545 {
2546 // We compare the p
2547 if (selected_p < new_p)
2548 {
2549 selected_p = new_p;
2550 selected_release = releases[j];
2551 }
2552 // else if ? not possible
2553 }
2554 }
2555
2556 //cerr << "v:" << new_v << ", r:" << new_r << ", p:" << new_p << endl;
2557 //cerr << "req v:" << v << ", req r:" << r << ", req p:" << p << endl;
2558
2559 }
2560
2561 // cerr << "selected release: " << selected_release << endl;
2562
2563 if (selected_release == "") return false;
2564
2565 result = selected_release;
2566
2567 return (true);
2568}
2569
2570//---------------------------------------------------------
2571const CmtSystem::cmt_string_vector Project::get_project_releases (const cmt_string& name) const
2572{
2573 CmtSystem::cmt_string_vector releases;
2574 cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2575
2576 static cmt_string sep = CmtSystem::path_separator ();
2577
2578 CmtSystem::cmt_string_vector items;
2579 CmtSystem::split (cmtprojectpath, sep, items);
2580
2581 for (int i = 0; i < items.size (); i++)
2582 {
2583 const cmt_string& item = items[i];
2584 cmt_string p = item;
2585 p += CmtSystem::file_separator ();
2586 p += name;
2587
2588 if (CmtSystem::test_directory (p))
2589 {
2590 CmtSystem::cmt_string_vector directories;
2591 CmtSystem::scan_dir (p, directories);
2592
2593 for (int j = 0; j < directories.size (); j++)
2594 {
2595 if (CmtSystem::test_directory(directories[j]))
2596 {
2597 cmt_string release;
2598 CmtSystem:: basename(directories[j], release);
2599
2600 if (CmtSystem::is_version_directory(release))
2601 {
2602 cmt_string& name_entry = releases.add ();
2603 name_entry = release;
2604 }
2605 }
2606 }
2607 }
2608 }
2609 return (releases);
2610}
2611
2612//----------------------------------------------------------
2613Project& Project::operator = (const Project& other)
2614{
2615 m_name = other.m_name;
2616 m_cmtpath = other.m_cmtpath;
2617 m_cmtpath_real = other.m_cmtpath_real;
2618 m_cmtpath_pwd = other.m_cmtpath_pwd;
2619 m_cmtpath_source = other.m_cmtpath_source;
2620
2621 return (*this);
2622}
2623
2624//----------------------------------------------------------
2625bool Project::operator == (const cmt_string& name) const
2626{
2627 return ((m_name == name));
2628}
2629
2630//----------------------------------------------------------
2631bool Project::operator != (const cmt_string& name) const
2632{
2633 return ((m_name != name));
2634}
2635
2636//----------------------------------------------------------
2637void Project::show (PrintMode mode)
2638//void Project::show ()
2639{
2640 if (m_visited) return;
2641 m_visited = true;
2642
2643 static int level = 0;
2644
2645 // bool is_current = false;
2646
2647 // cmt_string here = CmtSystem::pwd ();
2648 // In case there are symlinks
2649 /*
2650 cmt_string here_real;
2651 CmtSystem::realpath_ (CmtSystem::pwd (), here_real);
2652
2653 // if (here.find (m_cmtpath) == 0)
2654 if (here_real.find (m_cmtpath_real) == 0)
2655 {
2656 if (m_cmtpath_source != "default path")
2657 {
2658 is_current = true;
2659 }
2660 }
2661 */
2662 switch (mode)
2663 {
2664 case Xml :
2665 cout << "<project" << (m_is_current ? " current=\"yes\"" : "") << ">";
2666 // if (m_order >= 0)
2667 cout << "<order>" << m_order << "</order>";
2668 cout << "<name>" << m_name << "</name><version>" << (m_name != "CMTUSERCONTEXT" && m_name != "CMTHOME" ? m_release : "v0") << "</version><cmtpath>" << m_cmtpath << "</cmtpath>";
2669 break;
2670 default :
2671 for (int tab = 0; tab < level; tab++) cout << " ";
2672 cout << m_name << " " << (m_name != "CMTUSERCONTEXT" && m_name != "CMTHOME" ? m_release : "v0") << " (in " << m_cmtpath << ")";
2673 // cout << m_name << " " << m_release << " (in " << m_cmtpath << ")";
2674
2675 if (m_is_current) cout << " (current)";
2676 // if (is_current) cout << " (current)";
2677 break;
2678 }
2679
2680 int i;
2681
2682 switch (mode)
2683 {
2684 case Xml :
2685 cout << "<clients>";
2686 break;
2687 }
2688 for (i = 0; i < m_parents.size (); i++)
2689 {
2690 Project* p = m_parents[i];
2691 if (p == 0) continue;
2692 switch (mode)
2693 {
2694 case Xml :
2695 // cout << "<name>" << p->get_name () << "</name>";
2696 cout << "<project" << (p->is_current () ? " current=\"yes\"" : "") << ">";
2697 // if (p->m_order >= 0)
2698 cout << "<order>" << p->m_order << "</order>";
2699 cout << "<name>" << p->get_name () << "</name><version>" << (p->get_name () != "CMTUSERCONTEXT" && p->get_name () != "CMTHOME" ? p->get_release () : "v0") << "</version><cmtpath>" << p->get_cmtpath () << "</cmtpath>";
2700 cout << "</project>";
2701 break;
2702 default :
2703 cout << " P=" << p->get_name ();
2704 break;
2705 }
2706 }
2707 switch (mode)
2708 {
2709 case Xml :
2710 cout << "</clients>";
2711 break;
2712 }
2713
2714 switch (mode)
2715 {
2716 case Xml :
2717 cout << "<uses>";
2718 break;
2719 }
2720 for (i = 0; i < m_children.size (); i++)
2721 {
2722 Project* p = m_children[i];
2723 if (p == 0) continue;
2724 switch (mode)
2725 {
2726 case Xml :
2727 // cout << "<name>" << p->get_name () << "</name>";
2728 cout << "<project" << (p->is_current () ? " current=\"yes\"" : "") << ">";
2729 // if (p->m_order >= 0)
2730 cout << "<order>" << p->m_order << "</order>";
2731 cout << "<name>" << p->get_name () << "</name><version>" << (p->get_name () != "CMTUSERCONTEXT" && p->get_name () != "CMTHOME" ? p->get_release () : "v0") << "</version><cmtpath>" << p->get_cmtpath () << "</cmtpath>";
2732 cout << "</project>";
2733 break;
2734 default :
2735 cout << " C=" << p->get_name ();
2736 break;
2737 }
2738 }
2739 switch (mode)
2740 {
2741 case Xml :
2742 cout << "</uses>";
2743 cout << "</project>";
2744 break;
2745 default :
2746 cout << endl;
2747 break;
2748 }
2749
2750
2751/*
2752 if (m_visited) return;
2753
2754 m_visited = true;
2755*/
2756
2757 for (i = 0; i < m_children.size (); i++)
2758 {
2759 Project* p = m_children[i];
2760 if (p == 0) continue;
2761 level++;
2762 p->show (mode);
2763 // p->show ();
2764 level--;
2765 }
2766}
2767
2768
2769//----------------------------------------------------------
2770void Project::show_specified_strategies () const
2771{
2772 int i;
2773
2774 for (i = 0; i < m_strategies.size (); i++)
2775 {
2776 const Strategy& s = m_strategies[i];
2777 if (s.m_specified)
2778 {
2779 const StrategyDef* def = s.m_definition;
2780
2781 cout << "# Project " << m_name
2782 << " sets " << def->m_keyword
2783 << " strategy to " << ((s.m_value) ? def->m_on_value : def->m_off_value);
2784
2785 if (s.m_context != "")
2786 {
2787 cout << " (from package " << s.m_context << ")";
2788 }
2789
2790 cout << endl;
2791 }
2792 }
2793}
2794
2795//----------------------------------------------------------
2796bool Project::has_strategy (const StrategyDef* definition) const
2797{
2798 int i;
2799
2800 for (i = 0; i < m_strategies.size (); i++)
2801 {
2802 const Strategy& s = m_strategies[i];
2803 if (s.m_definition == definition)
2804 {
2805 return (true);
2806 }
2807 }
2808
2809 return (false);
2810}
2811
2812//----------------------------------------------------------
2813bool Project::get_strategy (const cmt_string& name) const
2814{
2815 static StrategyMgr& mgr = StrategyMgr::instance ();
2816
2817 StrategyDef* def = mgr.find_strategy (name);
2818 if (def == 0)
2819 {
2820 CmtMessage::warning ("strategy " + name + " undefined");
2821 // cerr << "#CMT> strategy " << name << " undefined" << endl;
2822 return (false);
2823 }
2824
2825 return (get_strategy (def));
2826}
2827
2828//----------------------------------------------------------
2829bool Project::is_specified (const StrategyDef* definition) const
2830{
2831 int i;
2832
2833 for (i = 0; i < m_strategies.size (); i++)
2834 {
2835 Strategy& s = m_strategies[i];
2836 if (s.m_definition == definition)
2837 {
2838 // This strategy is applied in this project
2839 return (s.m_specified);
2840 }
2841 }
2842
2843 // This strategy is not applied in this project
2844 return (false);
2845}
2846
2847//----------------------------------------------------------
2848bool Project::get_strategy (const StrategyDef* def) const
2849{
2850 int i;
2851
2852 for (i = 0; i < m_strategies.size (); i++)
2853 {
2854 Strategy& s = m_strategies[i];
2855 if (s.m_definition == def)
2856 {
2857 // This strategy is applied in this project
2858 if (s.m_specified)
2859 {
2860 return (s.m_specified_value);
2861 }
2862 return (s.m_value);
2863 }
2864 }
2865
2866 // This strategy is not applied in this project
2867 return (def->m_default_value);
2868}
2869
2870//----------------------------------------------------------
2871void Project::set_default_strategy (const cmt_string& name)
2872{
2873 static StrategyMgr& mgr = StrategyMgr::instance ();
2874
2875 StrategyDef* def = mgr.find_strategy (name);
2876 if (def == 0)
2877 {
2878 CmtMessage::warning ("strategy " + name + " undefined");
2879 // cerr << "#CMT> strategy " << name << " undefined" << endl;
2880 return;
2881 }
2882
2883 update_strategy (def, def->m_default_value);
2884}
2885
2886
2887//----------------------------------------------------------
2888void Project::set_strategy (const cmt_string& name, const cmt_string& value, const cmt_string& context)
2889{
2890 static StrategyMgr& mgr = StrategyMgr::instance ();
2891
2892 StrategyDef* def = mgr.find_strategy (name);
2893 if (def == 0)
2894 {
2895 CmtMessage::warning ("strategy " + name + " undefined");
2896 // cerr << "#CMT> strategy " << name << " undefined" << endl;
2897 return;
2898 }
2899
2900 bool b_value = false;
2901
2902 if (value == def->m_on_value)
2903 {
2904 b_value = true;
2905 }
2906 else if (value == def->m_off_value)
2907 {
2908 b_value = false;
2909 }
2910 else
2911 {
2912 CmtMessage::warning ("requested strategy value " + value + " undefined in strategy " + name);
2913 // cerr << "#CMT> requested strategy value " << value << " undefined in strategy " << name << endl;
2914 return;
2915 }
2916
2917 set_strategy (def, b_value, context);
2918}
2919
2920//----------------------------------------------------------
2921void Project::set_strategy (StrategyDef* definition, bool b_value, const cmt_string& context)
2922{
2923 bool need_strategy = true;
2924
2925 int i;
2926
2927 for (i = 0; i < m_strategies.size (); i++)
2928 {
2929 Strategy& s = m_strategies[i];
2930 if (s.m_definition == definition)
2931 {
2932 // This strategy is already applied in this project. Let's change it's value
2933 s.set (definition, b_value, get_name ());
2934 if (context != "")
2935 {
2936 if (s.m_context != "") s.m_context += " ";
2937 s.m_context += context;
2938 }
2939 need_strategy = false;
2940 break;
2941 }
2942 }
2943
2944 if (need_strategy)
2945 {
2946 // This strategy is not yet applied in this project.
2947
2948 Strategy& s = m_strategies.add ();
2949 s.clear ();
2950 s.set (definition, b_value, get_name ());
2951 s.m_context = context;
2952 }
2953
2954 for (i = 0; i < m_parents.size (); i++)
2955 {
2956 Project* project = m_parents[i];
2957
2958 project->update_strategy (definition, b_value);
2959 }
2960
2961 const ProjectPtrVector& OrderedProjects = Project::ordered_projects ();
2962 for (int i = OrderedProjects.size () - 2; i >= 0; i--)
2963 {
2964 if (this != OrderedProjects[i + 1]) continue;
2965 if (!OrderedProjects[i]->has_parents () &&
2966 OrderedProjects[i]->get_children_size () == 0)
2967 {
2968 OrderedProjects[i]->update_strategy (definition, b_value);
2969 }
2970 break;
2971 }
2972}
2973
2974/**----------------------------------------------------------
2975 The strategy value is changed because of indirect influences
2976 - default strategy at initialization time
2977 - change in the children
2978 - change in the children list
2979
2980 (This is not a specification : see the set_strategy method)
2981*/
2982void Project::update_strategy (StrategyDef* definition, bool b_value)
2983{
2984 bool need_strategy = true;
2985 bool specified = false;
2986
2987 int i;
2988
2989 for (i = 0; i < m_strategies.size (); i++)
2990 {
2991 Strategy& s = m_strategies[i];
2992 if (s.m_definition == definition)
2993 {
2994 need_strategy = false;
2995
2996 if (!s.m_specified)
2997 {
2998 // This strategy is already applied in this project. Let's change it's value
2999 s.update (definition, b_value, get_name ());
3000 }
3001 else
3002 {
3003 specified = true;
3004 }
3005 break;
3006 }
3007 }
3008
3009 if (need_strategy)
3010 {
3011 // This strategy is not yet applied in this project.
3012
3013 Strategy& s = m_strategies.add ();
3014 s.clear ();
3015 s.update (definition, b_value, get_name ());
3016 }
3017
3018 if (!specified)
3019 {
3020 for (i = 0; i < m_parents.size (); i++)
3021 {
3022 Project* project = m_parents[i];
3023
3024 project->update_strategy (definition, b_value);
3025 }
3026
3027 const ProjectPtrVector& OrderedProjects = Project::ordered_projects ();
3028 for (int i = OrderedProjects.size () - 2; i >= 0; i--)
3029 {
3030 if (this != OrderedProjects[i + 1]) continue;
3031 if (!OrderedProjects[i]->has_parents () &&
3032 OrderedProjects[i]->get_children_size () == 0)
3033 {
3034 OrderedProjects[i]->update_strategy (definition, b_value);
3035 }
3036 break;
3037 }
3038 }
3039}
3040
3041/**----------------------------------------------------------
3042 At least one of the children has changed this strategy
3043 Or the list of children has changed.
3044 We need to update the strategy value accordingly
3045 This will not change the specified value for this strategy
3046*/
3047void Project::update_strategy_from_children (StrategyDef* definition)
3048{
3049 // If this strategy is specified we don't care what happens from the children
3050
3051 //cerr << "Updating strategy " << definition->m_name << " from children for project " << m_name << endl;
3052
3053 int i;
3054
3055 for (i = 0; i < m_strategies.size (); i++)
3056 {
3057 Strategy& s = m_strategies[i];
3058 if (s.m_definition == definition)
3059 {
3060 // This strategy is applied in this project.
3061
3062 if (s.m_specified)
3063 {
3064 // There will be no impact since the strategy is specified
3065
3066 //cerr << "This strategy is specified in this project" << endl;
3067 return;
3068 }
3069
3070 break;
3071 }
3072 }
3073
3074 // The strategy is not specified locally so we will now figure out
3075 // which strategy has to be considered from the mixture of specifications
3076 // from all children.
3077
3078 // Algorithm:
3079 // - We consider children by pairs
3080 // - a child that specifies its strategy wins over a child that does not
3081 // - when the two children have the same level of priority we consider the priority value
3082
3083 Project* selected = 0;
3084 bool selected_is_specified = false;
3085 bool selected_value = definition->m_default_value;
3086
3087 for (i = 0; i < m_children.size (); i++)
3088 {
3089 Project* p = m_children[i];
3090
3091 //cerr << "Checking strategy for child " << p->get_name () << endl;
3092
3093 bool is_specified = p->is_specified (definition);
3094 bool value = p->get_strategy (definition);
3095
3096 if (selected == 0)
3097 {
3098 selected = p;
3099 selected_is_specified = is_specified;
3100 selected_value = value;
3101 continue;
3102 }
3103
3104 if (is_specified == selected_is_specified)
3105 {
3106 if (selected_value != value)
3107 {
3108 // same level of priority but different values -> we must decide
3109 bool priority_value = definition->m_priority_value;
3110 if (value == priority_value)
3111 {
3112 selected = p;
3113 selected_is_specified = is_specified;
3114 selected_value = value;
3115 }
3116 }
3117 }
3118 else
3119 {
3120 if (is_specified)
3121 {
3122 selected = p;
3123 selected_is_specified = is_specified;
3124 selected_value = value;
3125 }
3126 }
3127 }
3128
3129 update_strategy (definition, selected_value);
3130}
3131
3132/**----------------------------------------------------------
3133 At least one of the children has changed its strategies
3134 Or the list of children has changed.
3135 We need to update the strategy values accordingly
3136 This will not change the specified values
3137*/
3138void Project::update_strategies_from_children ()
3139{
3140 StrategyDef::StrategyDefs& defs = StrategyMgr::get_definitions ();
3141
3142 //cerr << "Updating strategies from children for project " << m_name << endl;
3143
3144 int i;
3145
3146 for (i = 0; i < defs.size (); i++)
3147 {
3148 StrategyDef* def = defs[i];
3149
3150 update_strategy_from_children (def);
3151 }
3152
3153 for (i = 0; i < m_parents.size (); i++)
3154 {
3155 Project* p = m_parents[i];
3156 p->update_strategies_from_children ();
3157 }
3158}
3159
3160/**----------------------------------------------------------
3161 The StrategyMgr singleton
3162*/
3163StrategyMgr& StrategyMgr::instance ()
3164{
3165 static StrategyMgr me;
3166 return (me);
3167}
3168
3169/**----------------------------------------------------------
3170 The StrategyMgr constructor
3171 Here are primarily constructed all strategy definitions
3172*/
3173StrategyMgr::StrategyMgr ()
3174{
3175 m_defs.clear ();
3176
3177 StrategyDef* s;
3178
3179 s = new StrategyDef;
3180 s->m_keyword = "build";
3181 s->m_name = "BuildPrototypes";
3182 s->m_on_value = "prototypes";
3183 s->m_off_value = "no_prototypes";
3184 s->m_default_value = true;
3185 s->m_priority_value = false;
3186
3187 m_defs.push_back (s);
3188
3189 s = new StrategyDef;
3190 s->m_keyword = "build";
3191 s->m_name = "InstallArea";
3192 s->m_on_value = "with_installarea";
3193 s->m_off_value = "without_installarea";
3194 s->m_default_value = false;
3195 s->m_priority_value = true;
3196
3197 m_defs.push_back (s);
3198
3199 s = new StrategyDef;
3200 s->m_keyword = "setup";
3201 s->m_name = "SetupConfig";
3202 s->m_on_value = "config";
3203 s->m_off_value = "no_config";
3204 s->m_default_value = true;
3205 s->m_priority_value = false;
3206
3207 m_defs.push_back (s);
3208
3209 s = new StrategyDef;
3210 s->m_keyword = "setup";
3211 s->m_name = "SetupRoot";
3212 s->m_on_value = "root";
3213 s->m_off_value = "no_root";
3214 s->m_default_value = true;
3215 s->m_priority_value = false;
3216
3217 m_defs.push_back (s);
3218
3219 s = new StrategyDef;
3220 s->m_keyword = "setup";
3221 s->m_name = "SetupCleanup";
3222 s->m_on_value = "cleanup";
3223 s->m_off_value = "no_cleanup";
3224 s->m_default_value = true;
3225 s->m_priority_value = false;
3226
3227 m_defs.push_back (s);
3228
3229 s = new StrategyDef;
3230 s->m_keyword = "setup";
3231 s->m_name = "SetupScripts";
3232 s->m_on_value = "scripts";
3233 s->m_off_value = "no_scripts";
3234 s->m_default_value = true;
3235 s->m_priority_value = false;
3236
3237 m_defs.push_back (s);
3238
3239 s = new StrategyDef;
3240 s->m_keyword = "structure";
3241 s->m_name = "VersionDirectory";
3242 s->m_on_value = "with_version_directory";
3243 s->m_off_value = "without_version_directory";
3244 if (Cmt::get_current_structuring_style () != without_version_directory)
3245 {
3246 s->m_default_value = true;
3247 s->m_priority_value = false;
3248 }
3249 else
3250 {
3251 s->m_default_value = false;
3252 s->m_priority_value = true;
3253 }
3254
3255 m_defs.push_back (s);
3256}
3257
3258/**----------------------------------------------------------
3259 Find a strategy definition by its name
3260*/
3261StrategyDef* StrategyMgr::find_strategy (const cmt_string& name)
3262{
3263 static StrategyMgr& me = instance ();
3264
3265 int i;
3266
3267 for (i = 0; i < me.m_defs.size (); i++)
3268 {
3269 StrategyDef* def = me.m_defs[i];
3270 if (def->m_name == name)
3271 {
3272 return (def);
3273 }
3274 }
3275
3276 return (0);
3277}
3278
3279/**----------------------------------------------------------
3280 Retreive the default value defined for a given strategy
3281*/
3282bool StrategyMgr::get_default_strategy (const cmt_string& name)
3283{
3284 StrategyDef* def = find_strategy (name);
3285 if (def == 0) return (false);
3286 return (def->m_default_value);
3287}
3288
3289/**----------------------------------------------------------
3290 Retreive the priority value defined for a given strategy
3291 This value is used when two children of a project request two conflicting strategy values
3292*/
3293bool StrategyMgr::get_priority_strategy (const cmt_string& name)
3294{
3295 StrategyDef* def = find_strategy (name);
3296 if (def == 0) return (false);
3297 return (def->m_priority_value);
3298}
3299
3300/**----------------------------------------------------------
3301 Return the vector of all existing strategy definitions
3302*/
3303StrategyDef::StrategyDefs& StrategyMgr::get_definitions ()
3304{
3305 static StrategyMgr& me = instance ();
3306
3307 return (me.m_defs);
3308}
3309
3310//-----------------------------------------------------------
3311Strategy::Strategy ()
3312{
3313 clear ();
3314}
3315
3316//-----------------------------------------------------------
3317void Strategy::clear ()
3318{
3319 m_definition = 0;
3320 m_specified = false;
3321 m_specified_value = false;
3322 m_value = false;
3323 m_on_tag = 0;
3324 m_off_tag = 0;
3325}
3326
3327/**----------------------------------------------------------
3328 Specify a new value for this strategy.
3329 This only happens when a strategy statement is met in a project file or in a requirements file.
3330*/
3331void Strategy::set (StrategyDef* definition, bool value, const cmt_string& project_name)
3332{
3333 //cerr << "Setting strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
3334
3335 m_definition = definition;
3336 m_specified = true;
3337 m_specified_value = value;
3338
3339 update (definition, value, project_name);
3340}
3341
3342/**----------------------------------------------------------
3343 Change the effective value for this strategy.
3344 This has no impact on to the specified value.
3345 This will adapt the tag settings
3346*/
3347void Strategy::update (StrategyDef* definition, bool value, const cmt_string& project_name)
3348{
3349 //cerr << "Updating strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
3350
3351 m_value = value;
3352 m_definition = definition;
3353
3354 cmt_string to_tag_name = project_name;
3355 cmt_string to_untag_name = project_name;
3356
3357 to_tag_name += "_";
3358 to_untag_name += "_";
3359
3360 if (m_value)
3361 {
3362 to_tag_name += m_definition->m_on_value;
3363 to_untag_name += m_definition->m_off_value;
3364 }
3365 else
3366 {
3367 to_tag_name += m_definition->m_off_value;
3368 to_untag_name += m_definition->m_on_value;
3369 }
3370
3371 m_on_tag = Tag::find (to_tag_name);
3372 m_off_tag = Tag::find (to_untag_name);
3373
3374 if (m_on_tag == 0 || m_off_tag == 0)
3375 {
3376 m_on_tag = Tag::add (to_tag_name, PriorityConfig, "PROJECT", 0);
3377 m_off_tag = Tag::add (to_untag_name, PriorityConfig, "PROJECT", 0);
3378
3379 m_on_tag->add_tag_exclude (m_off_tag);
3380 m_off_tag->add_tag_exclude (m_on_tag);
3381 }
3382
3383 m_off_tag->unmark ();
3384 m_on_tag->mark ("PROJECT");
3385}
3386
3387//-----------------------------------------------------------
3388const cmt_string& StrategyDef::get_default_value () const
3389{
3390 if (m_default_value)
3391 {
3392 return (m_on_value);
3393 }
3394 else
3395 {
3396 return (m_off_value);
3397 }
3398}
3399
3400//-----------------------------------------------------------
3401void Project::set_author (const cmt_string& name)
3402{
3403 // cerr << "set_author" << name << endl;
3404 this->m_author = name;
3405}
3406
3407//-----------------------------------------------------------
3408const cmt_string& Project::get_author () const
3409{
3410 return (m_author);
3411}
3412
3413//-----------------------------------------------------------
3414void Project::project_author_action (const CmtSystem::cmt_string_vector& words)
3415{
3416 if (m_author != "") m_author += "\n";
3417
3418 for (int i = 1; i < words.size (); i++)
3419 {
3420 const cmt_string& w = words[i];
3421
3422 if (i > 1) m_author += " ";
3423 m_author += w;
3424 }
3425}
3426
3427//-----------------------------------------------------------
3428Use* Project::get_use () const
3429{
3430 return m_use;
3431}
3432
3433//-----------------------------------------------------------
3434void Project::set_use (Use* use)
3435{
3436 this->m_use = use;
3437}
3438
3439//-----------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.