source: CMT/v1rbeta20p20061025/source/cmt_cvs.cxx@ 295

Last change on this file since 295 was 295, checked in by garonne, 19 years ago

beta development 1

  • Property svn:eol-style set to native
File size: 63.7 KB
Line 
1//-----------------------------------------------------------
2// Copyright Christian Arnault LAL-Orsay CNRS
3// arnault@lal.in2p3.fr
4// Modified by: garonne@lal.in2p3.fr
5// See the complete license in cmt_license.txt "http://www.cecill.info".
6//-----------------------------------------------------------
7
8#include <stdlib.h>
9#include <stdio.h>
10
11#include "cmt.h"
12#include "cmt_cvs.h"
13#include "cmt_awk.h"
14#include "cmt_symbol.h"
15#include "cmt_project.h"
16
17/**
18
19 Grep : perform a grep like operation onto a cmt_string
20
21 o All lines of the input string are collected when they contain
22 the specified pattern.
23 o The input string and the selector pattern are specified in
24 the constructor:
25
26 Grep (input_string, pattern)
27
28 o All selected lines are accumulated (appended) into the internal
29 variable m_result . 'space' is the separator.
30
31 o The accumulator is retrieved by the result () method.
32
33 */
34class Grep : public Awk
35{
36public:
37
38 void begin ();
39 void filter (const cmt_string& line);
40 const cmt_string& result () const;
41
42private:
43 cmt_string m_result;
44};
45
46/**
47
48 Cut : perform a cut-like operation :
49
50 o collect the <field>'th field of every line into the m_result
51 internal variable
52
53 o the field number is given in the constructor and starts at zero.
54
55 o selected fields are accumulated with a space as separator.
56
57 */
58class Cut : public Awk
59{
60public:
61 Cut (int field);
62 void begin ();
63 void filter (const cmt_string& line);
64 const cmt_string& result () const;
65
66private:
67 cmt_string m_result;
68 int m_field;
69};
70
71/**
72
73 History : maintains the history of checkouts during a
74 recursive checkout, so as to avoid double checkouts.
75
76 */
77class History
78{
79public:
80 static History& instance ();
81 void clear ();
82 void install (const cmt_string& line);
83 bool is_installed (const cmt_string& line);
84
85private:
86 History ();
87
88 cmt_string m_installed;
89};
90
91/**
92
93 RecursivePass1 : simply validate use statements in a requirements file
94 and echo those that really need to be handled.
95
96 */
97class RecursivePass1 : public Awk
98{
99public:
100
101 void begin ();
102 void filter (const cmt_string& line);
103 const cmt_string& result () const;
104
105private:
106 cmt_string m_result;
107 bool m_first;
108};
109
110/**
111
112 RecursivePass2 : after filtering the use statements really perform the
113 checkouts.
114
115 */
116class CvsImplementation;
117class RecursivePass2 : public Awk
118{
119public:
120 RecursivePass2 (CvsImplementation& cvs);
121 void begin ();
122 void filter (const cmt_string& line);
123
124private:
125 CvsImplementation& m_cvs;
126};
127
128/**
129
130 RecursivePass3 : simply validate use statements in a project file
131 and echo those that really need to be handled.
132
133 */
134class RecursivePass3 : public Awk
135{
136public:
137
138 void begin ();
139 void filter (const cmt_string& line);
140 const cmt_string& result () const;
141
142private:
143 cmt_string m_result;
144 bool m_first;
145};
146
147/**
148
149 RecursivePass4 : after filtering the use statements really perform the
150 project checkouts.
151
152 */
153class CvsImplementation;
154class RecursivePass4 : public Awk
155{
156public:
157 RecursivePass4 (CvsImplementation& cvs);
158 void begin ();
159 void filter (const cmt_string& line);
160
161private:
162 CvsImplementation& m_cvs;
163};
164
165/**
166
167 Internal implementation of CVS to CMT operations.
168 The Cvs class only provides abstract interface.
169
170 */
171class CvsImplementation
172{
173public:
174
175 CvsImplementation ()
176 {
177 clear ();
178 }
179
180 void clear ()
181 {
182 m_recursive = false;
183 m_head = false;
184 m_verbose = false;
185 m_simulation = false;
186 no_config = false;
187
188 m_home_dir = "";
189 m_checkout_dir = "";
190 m_version_dir = "";
191 m_cvs_offset = "";
192
193 m_last_module = "";
194 m_last_cvs_infos = "";
195 structure_info = "";
196 error_info = "";
197 tags_top_info = "";
198 tags_info = "";
199 cvsversions_top_info = "";
200 cvsversions_info = "";
201 branches_info = "";
202 subpackages_info = "";
203 subprojects_info = "";
204
205 m_protocol_level = "";
206
207 Symbol* symbol = Symbol::find ("cmt_cvs_protocol_level");
208 if (symbol != 0)
209 {
210 m_protocol_level = symbol->build_macro_value ();
211 Symbol::expand (m_protocol_level);
212 }
213 }
214
215 CvsImplementation& operator = (const CvsImplementation& other)
216 {
217 m_recursive = other.m_recursive;
218 m_head = other.m_head;
219 m_verbose = other.m_verbose;
220 m_simulation = other.m_simulation;
221 no_config = other.no_config;
222
223 m_home_dir = other.m_home_dir;
224 m_checkout_dir = other.m_checkout_dir;
225 m_version_dir = other.m_version_dir;
226 m_cvs_offset = other.m_cvs_offset;
227 m_protocol_level = other.m_protocol_level;
228 m_last_module = other.m_last_module;
229 m_last_cvs_infos = other.m_last_cvs_infos;
230
231 structure_info = other.structure_info;
232 error_info = other.error_info;
233 tags_top_info = other.tags_top_info;
234 tags_info = other.tags_info;
235 cvsversions_top_info = other.cvsversions_top_info;
236 cvsversions_info = other.cvsversions_info;
237 branches_info = other.branches_info;
238 subpackages_info = other.subpackages_info;
239 subprojects_info = other.subprojects_info;
240
241 return (*this);
242 }
243
244 /**
245 Filter out the space-separated words of a text that don't match a regexp.
246 */
247 void filter_list (cmt_string& text, const cmt_regexp& exp)
248 {
249 CmtSystem::cmt_string_vector list;
250
251 CmtSystem::split (text, " ", list);
252
253 int i;
254
255 text = "";
256
257 for (i = 0; i < list.size (); i++)
258 {
259 const cmt_string& s = list[i];
260 if (exp.match (s))
261 {
262 if (i > 0) text += " ";
263 text += s;
264 }
265 }
266 }
267
268 int execute (const cmt_string& command)
269 {
270 int status = 0;
271
272 if (m_verbose || m_simulation)
273 {
274 cout << "#CMT> Executing [" << command << "]" << endl;
275 }
276
277 if (!m_simulation)
278 {
279 status = CmtSystem::execute (command);
280 }
281
282 return (status);
283 }
284
285 void execute_and_retry (const cmt_string& command, const cmt_string& message)
286 {
287 int status;
288 int retry = 0;
289
290 for (;;)
291 {
292 status = execute (command);
293
294 if (status != 0)
295 {
296 retry++;
297
298 cout << "# " << message << ": status=" << status << endl;
299 cout << "#---------------------------------------------------------" << endl;
300
301 if (retry > 5) exit(0);
302 }
303 else
304 {
305 break;
306 }
307 }
308 }
309
310 int execute (const cmt_string& command, cmt_string& out)
311 {
312 int status = 0;
313
314 if (m_verbose || m_simulation)
315 {
316 cout << "#CMT> Executing [" << command << "]" << endl;
317 }
318
319 if (!m_simulation)
320 {
321 status = CmtSystem::execute (command, out);
322
323 }
324
325 //if (m_verbose || m_simulation)
326 // {
327 // cout << out << endl;
328 // }
329 return (status);
330 }
331
332
333 /**
334 This function will check the protocol level with the CVS pluggin.
335 The expected level is defined in a macro (in the requirements file of CMT)
336 The protocol level characterizes the structure of the message received from the CVS pluggin
337 and depends on its version.
338
339 In order to know if the pluggin is installed AND if the support for this version is
340 installed, we checkout CVSROOT/loginfo which should contain entries with selection patterns
341
342 .cmtcvsinfos/<protocol_level>
343
344 However old versions only offer as pattern:
345
346 .cmtcvsinfos
347
348 In this function we'll detect if the effective protocol level satisifies the
349 level expected for this release of CMT
350
351 In simulation mode we suppose the expected protocol has been found.
352 */
353 bool check_protocol ()
354 {
355 static bool done = false;
356 static bool found = true;
357
358 if (done) return (found);
359 done = true;
360
361 cmt_string cvsroot;
362
363 CmtSystem::get_cvsroot (cvsroot);
364
365 cmt_string command;
366
367 command = "cvs";
368 if (cvsroot != "")
369 {
370 command += " -d ";
371 command += cvsroot;
372 }
373 command += " -Q co -p CVSROOT/loginfo ";
374
375 found = false;
376
377 cmt_string pattern = ".cmtcvsinfos";
378
379 if (m_protocol_level != "")
380 {
381 pattern += "/";
382 pattern += m_protocol_level;
383 }
384
385 cmt_string loginfo;
386
387 if (m_simulation)
388 {
389 loginfo = pattern;
390 }
391
392 execute (command, loginfo);
393
394 int pos = loginfo.find (pattern);
395
396 if (pos != cmt_string::npos)
397 {
398 found = true;
399 }
400
401 if (m_verbose)
402 {
403 if (found)
404 {
405 cout << "#CMT> Protocol level " << m_protocol_level << endl;
406 }
407 else
408 {
409 cout << "#CMT> The CVS pluggin is not installed or is not at protocol level " << m_protocol_level << endl;
410 }
411 }
412
413 return (found);
414 }
415
416 /**
417 Execute the CVS command that activates the CVS pluggin, ie this is a cvs import
418 using the conventional module .cmtcvsinfos/<protocol-level>/<module>
419
420 We create a temporary directory just to lauch the command. However nothing
421 should change in this temporary directory since the pluggin returns an error status.
422 */
423 void retreive_cvs_infos (const cmt_string& module)
424 {
425 static const cmt_string cmtcvsinfos = ".cmtcvsinfos";
426
427 cmt_string home_dir = CmtSystem::pwd ();
428
429 //
430 // Activities related with .cmtcvsinfos will occur in a temporary directory
431 //
432 cmt_string tmp_dir = CmtSystem::getenv ("TMPDIR");
433 if (tmp_dir == "")
434 {
435 tmp_dir = CmtSystem::file_separator ();
436 tmp_dir += "tmp";
437 }
438
439 if (!CmtSystem::cd (tmp_dir))
440 {
441 tmp_dir = home_dir;
442 }
443
444 tmp_dir += CmtSystem::file_separator ();
445 tmp_dir += "cmtcvs";
446 {
447 cmt_string temp = CmtSystem::get_temporary_name ();
448 CmtSystem::basename (temp, temp);
449 // Suppress dots for Windows
450 temp.replace_all (".", "");
451 tmp_dir += temp;
452 }
453
454 if (!CmtSystem::test_directory (tmp_dir))
455 {
456 if (!CmtSystem::mkdir (tmp_dir))
457 {
458 cout << "#CMT> Cannot create the temporary directory [" << tmp_dir << "]" << endl;
459 return;
460 }
461 }
462
463 //trap "rm -rf ${tmp_dir}" 0 1 2 15
464
465 if (!CmtSystem::cd (tmp_dir))
466 {
467 cout << "#CMT> Cannot move to the temporary directory " << tmp_dir << endl;
468
469 if (m_verbose)
470 {
471 cout << "#CMT> now removing tmp_dir " << tmp_dir << " home=" << home_dir << endl;
472 }
473
474 CmtSystem::remove_directory (tmp_dir);
475
476 return;
477 }
478
479 if (m_verbose)
480 {
481 cout << "#CMT> cvs infos are now obtained from the temporary directory " << CmtSystem::pwd () << endl;
482 }
483
484 /**
485 The script associated to such entries is supposed to :
486 1) extract the set of <infos> from ${module}/cmt/requirements
487 or ${module}/cmt/project.cmt
488 2) build an output of the form :
489 <infos>=info1 info2 info3 ...
490
491 Currently this script can be found in
492
493 ${CMTROOT}/cmt/cmt_buildcvsinfos2.sh
494 %CMTROOT%/cmt/cmt_buildcvsinfos.py
495 There is a C++ implementation as cmtcvs.exe
496
497 */
498
499 if (!CmtSystem::test_directory (cmtcvsinfos))
500 {
501 CmtSystem::mkdir (cmtcvsinfos);
502 }
503
504 CmtSystem::cd (cmtcvsinfos);
505
506 cmt_string cvsroot;
507
508 CmtSystem::get_cvsroot (cvsroot);
509
510 cmt_string command;
511
512 command = "cvs";
513 if (cvsroot != "")
514 {
515 command += " -d ";
516 command += cvsroot;
517 }
518 command += " -Q import -m cmt ";
519
520 command += cmtcvsinfos;
521
522 if (m_protocol_level != "")
523 {
524 command += "/";
525 command += m_protocol_level;
526 }
527 command += "/";
528 command += module;
529 command += " CMT v1";
530
531 m_last_cvs_infos = "";
532
533 execute (command, m_last_cvs_infos);
534
535 if (m_verbose)
536 {
537 cout << "#CMT> now removing tmp_dir " << tmp_dir << " home=" << home_dir << endl;
538 }
539
540 CmtSystem::cd (home_dir);
541 CmtSystem::remove_directory (tmp_dir);
542 }
543
544 /**
545 This method exploits the hook installed into the loginfo script.
546 A communication is setup with a dummy CVS module named .cmtcvsinfos/<module>
547
548 At import time, the contents of the file will be used to parameterize
549 the script named cmt_buildcvsinfos2.sh (referenced in the loginfo script)
550
551 This script performs a scan in the CVS repository for the following types of
552 information :
553
554 the recognized structure below this module (none, project, package)
555 all top symbolic tags installed for the module
556 all symbolic tags installed for the module
557 all branches available below this module
558 all subpackages installed below the module.
559 all subprojects installed below the module.
560
561 In principle, only modules corresponding to true CMT products (packages or projects) are considered.
562 o tags are obtained from the requirements or the project file
563 o branches are sub-directories which are not themselves packages
564 o subpackages are sub-directories which are CMT packages
565 (a subdirectory is always either a branch or a subpackage)
566 */
567 void get_cvs_infos_with_offset (const cmt_string& module)
568 {
569 if (!check_protocol ())
570 {
571 cout << "#CMT> The CVS pluggin is not installed or is not at protocol level " << m_protocol_level << endl;
572 return;
573 }
574
575 if (module == "")
576 {
577 cout << "#CMT> cmt cvs needs a module name" << endl;
578 return;
579 }
580
581 if (module == m_last_module)
582 {
583 if (m_verbose)
584 {
585 cout << "#CMT> cvs infos for module " << module << " already there" << endl;
586 }
587 }
588 else
589 {
590 m_last_module = module;
591
592 retreive_cvs_infos (module);
593 }
594
595 /**
596 Now retrieve all info fields :
597 */
598
599 Grep grep;
600
601 grep.run (m_last_cvs_infos, "structure=");
602
603 if (grep.result () != "")
604 {
605 structure_info = grep.result ();
606 structure_info.replace ("structure=", "");
607 }
608 else
609 {
610 // This may happen for old protocol level < v1r1
611 structure_info = "package";
612 }
613
614 grep.run (m_last_cvs_infos, "error=");
615
616 if (grep.result () != "")
617 {
618 error_info = grep.result ();
619 error_info.replace ("error=", "");
620 }
621 else
622 {
623 error_info = "";
624 }
625
626 grep.run (m_last_cvs_infos, "tags_top=");
627
628 if (grep.result () != "")
629 {
630 tags_top_info = grep.result ();
631 tags_top_info.replace ("tags_top=", "");
632 }
633 else
634 {
635 tags_top_info = "";
636 }
637
638 grep.run (m_last_cvs_infos, "tags=");
639
640 if (grep.result () != "")
641 {
642 tags_info = grep.result ();
643 tags_info.replace ("tags=", "");
644 }
645 else
646 {
647 tags_info = "";
648 }
649
650 grep.run (m_last_cvs_infos, "cvsversions_top=");
651
652 if (grep.result () != "")
653 {
654 cvsversions_top_info = grep.result ();
655 cvsversions_top_info.replace ("cvsversions_top=", "");
656 }
657 else
658 {
659 cvsversions_top_info = "";
660 }
661
662 grep.run (m_last_cvs_infos, "cvsversions=");
663
664 if (grep.result () != "")
665 {
666 cvsversions_info = grep.result ();
667 cvsversions_info.replace ("cvsversions=", "");
668 }
669 else
670 {
671 cvsversions_info = "";
672 }
673
674 grep.run (m_last_cvs_infos, "branches=");
675
676 if (grep.result () != "")
677 {
678 branches_info = grep.result ();
679 branches_info.replace ("branches=", "");
680 }
681 else
682 {
683 branches_info = "";
684 }
685
686 grep.run (m_last_cvs_infos, "subpackages=");
687
688 if (grep.result () != "")
689 {
690 subpackages_info = grep.result ();
691 subpackages_info.replace ("subpackages=", "");
692 }
693 else
694 {
695 subpackages_info = "";
696 }
697
698 grep.run (m_last_cvs_infos, "subprojects=");
699
700 if (grep.result () != "")
701 {
702 subprojects_info = grep.result ();
703 subprojects_info.replace ("subprojects=", "");
704 }
705 else
706 {
707 subprojects_info = "";
708 }
709
710 /**
711 The CMTCVSTAGFILTER env. var. may contain a regexp that will exclude some tags
712 from the answr of the CVS pluggin.
713 The pattern is a regexp but it may also contain the <package> template
714 */
715 cmt_string tag_filter = CmtSystem::getenv ("CMTCVSTAGFILTER");
716
717 if (tag_filter != "")
718 {
719 cmt_string package;
720 CmtSystem::basename (module, package);
721
722 cmt_string pattern = "<package>";
723
724 tag_filter.replace_all (pattern, package);
725
726 cmt_regexp exp (tag_filter);
727
728 cmt_string text;
729
730 filter_list (tags_top_info, exp);
731 filter_list (tags_info, exp);
732 filter_list (cvsversions_top_info, exp);
733 filter_list (cvsversions_info, exp);
734 }
735 }
736
737 void get_cvs_infos (const cmt_string& cvs_offset, const cmt_string& module)
738 {
739 cmt_string full_name;
740
741 if (cvs_offset != "")
742 {
743 full_name = cvs_offset;
744 full_name += "/";
745 while (full_name.find ("//") != cmt_string::npos)
746 {
747 full_name.replace_all ("//", "/");
748 }
749 }
750
751 full_name += module;
752
753 get_cvs_infos_with_offset (full_name);
754 }
755
756 /**
757 From a space-separated list of version tags, try to find one tag
758 matching a given regular expression.
759
760 o The first matching tag is returned into 'version'
761 o Success is returned as function value.
762
763 */
764 bool match_version_request (const cmt_string& text,
765 const cmt_regexp& version_exp,
766 cmt_string& version)
767 {
768 CmtSystem::cmt_string_vector vs;
769
770 CmtSystem::split (text, " \t", vs);
771
772 version = "";
773
774 for (int i = 0; i < vs.size (); i++)
775 {
776 const cmt_string& vv = "^"+ vs[i] + "$";
777
778 if (version_exp.match (vv))
779 {
780 version = vv;
781 return (true);
782 }
783 }
784
785 return (false);
786 }
787
788 void get_module (const cmt_string& offset,
789 const cmt_string& product,
790 cmt_string& module)
791 {
792 module = "";
793
794 if (offset != "")
795 {
796 module = offset;
797 module += "/"; // This is for CVS only thus we don't use the real separator.
798 while (module.find ("//") != cmt_string::npos)
799 {
800 module.replace_all ("//", "/");
801 }
802 }
803
804 module += product;
805 }
806
807 bool get_version (const cmt_string& offset,
808 const cmt_string& product,
809 const cmt_string& version_request,
810 const cmt_string& module,
811 cmt_string& version,
812 bool& at_head)
813 {
814 Grep grep;
815 cmt_string topversions;
816 cmt_string versions;
817 cmt_string requested_version = version_request;
818
819 at_head = false;
820
821 /**
822 * Try to figure out what is the effective version tag available
823 * for the requested version expressions (which may contain
824 * wild card)
825 *
826 * the requested version may either be in the top tags (ie those
827 * corresponding to the same most recent CVS version number before
828 * the HEAD) or not. The returned at_head flag will show this.
829 *
830 * then the requested product may either be located in the CVS repository
831 * under the offset or not, the returned module will contain the effective
832 * location where the requested version has been found.
833 */
834
835 if (m_verbose)
836 {
837 cout << "#CMT> requesting cvs infos onto module " << module << endl;
838 }
839
840 get_cvs_infos_with_offset (module);
841
842 if (error_info != "")
843 {
844 versions = "";
845 cout << "#CMT> Product " << product << " not found in ${CVSROOT}" << endl;
846 return (false);
847 }
848
849 versions = tags_top_info;
850
851 cmt_string v = version_request;
852
853 if (version_request.find ("*") != cmt_string::npos)
854 {
855 v.replace_all ("*", ".*");
856 }
857 else
858 {
859 // this is an exact match to the end of the word since there is no wild card
860 v += "$";
861 }
862
863 cmt_regexp version_exp (v);
864
865 if (!match_version_request (versions, version_exp, version))
866 {
867 // We try on non-top versions
868
869 versions = tags_info;
870
871 if (!match_version_request (versions, version_exp, version))
872 {
873 version = requested_version;
874 int pos = 0;
875 if ((pos = version.find ("*")) != cmt_string::npos)
876 {
877 //
878 // There was a wild card but the expression does not match
879 // any of the existing tags in CVS.
880 // Things will be retreived from HEAD but we have to build
881 // a reasonable version tag from the wild card expression.
882 // If the letter before the * was a digit, then simply remove
883 // the * (v5* -> v5) otherwise add a zero (v5r* -> v5r0)
884 //
885 if (pos > 0)
886 {
887 char letter = version[pos-1];
888
889 static const cmt_string digits = "0123456789";
890
891 if (digits.find (letter) == cmt_string::npos)
892 {
893 // "v5r*" -> "v5r0"
894 version.replace ("*", "0");
895 }
896 else
897 {
898 // "v5*" -> "v5"
899 version.replace ("*", "");
900 }
901 }
902 else
903 {
904 // The expression was simply "*" !!!
905 version = "v0";
906 }
907 }
908 at_head = true;
909 }
910 else
911 {
912 at_head = false;
913 }
914 }
915 else
916 {
917 at_head = true;
918 }
919
920 /**
921 * Here we have at least one version matching the requested expression.
922 */
923
924 return (true);
925 }
926
927 bool do_need_version ()
928 {
929 bool need_version = false;
930
931 if (structure_info == "project")
932 {
933 need_version = true;
934 //CmtStructuringStyle style = Cmt::get_current_structuring_style ();
935 //if (style == default_structuring_style)
936 //{
937 // Use& current_use = Use::current ();
938 // if (current_use.get_strategy ("VersionDirectory"))
939 // need_version = true;
940 //}
941 //else if (style == with_version_directory)
942 // need_version = true;
943 // cout<<"need version"<<need_version<<endl;
944 }
945 else
946 {
947 CmtStructuringStyle style = Cmt::get_current_structuring_style ();
948 if (style == default_structuring_style)
949 {
950 Use& current_use = Use::current ();
951 if (current_use.get_strategy ("VersionDirectory"))
952 need_version = true;
953 }
954 else if (style == with_version_directory)
955 need_version = true;
956 }
957
958 return (need_version);
959 }
960
961 /**
962 Take care of structuring style for packages and of project vs package conventions
963 */
964 cmt_string build_version_directory (const cmt_string& offset,
965 const cmt_string& product,
966 const cmt_string& version)
967 {
968 cmt_string dir = m_home_dir;
969
970 if (m_checkout_dir != "")
971 {
972 // consider the usual -d option
973
974 dir += CmtSystem::file_separator ();
975 dir += m_checkout_dir;
976 }
977
978 dir += CmtSystem::file_separator ();
979 dir += offset;
980 dir += CmtSystem::file_separator ();
981 dir += product;
982
983 if (do_need_version ())
984 {
985 dir += CmtSystem::file_separator ();
986 dir += version;
987 }
988
989 CmtSystem::reduce_file_separators (dir);
990
991 return (dir);
992 }
993
994 /**
995 Wrapper to mkdir handling simulation and verbose options.
996 */
997 bool mkdir (const cmt_string& dir)
998 {
999 if (m_simulation)
1000 {
1001 cout << "#CMT> Would create the " << dir << " directory" << endl;
1002 }
1003 else
1004 {
1005 if (!CmtSystem::cd (dir))
1006 {
1007 if (m_verbose)
1008 {
1009 cout << "#CMT> About to mkdir " << dir << endl;
1010 }
1011
1012 CmtSystem::mkdir (dir);
1013 if (!CmtSystem::cd (dir))
1014 {
1015 cout << "# Error creating the directory :" << dir << endl;
1016 cout << "#---------------------------------------------------------" << endl;
1017 return (false);
1018 }
1019 }
1020 }
1021 return (true);
1022 }
1023
1024 /**
1025 When running cmt cvs commands, we stand by definition outside of any existing
1026 package context. Thus it's likely that CMTPATH are not completely defined.
1027 This function manually prepends CMTPATH entries to the environment variable.
1028 */
1029 void add_cmtpath (const cmt_string& dir)
1030 {
1031 static cmt_string CMTPATH;
1032
1033 cmt_string cmtpath = Symbol::get_env_value ("CMTPATH");
1034
1035 if (cmtpath.find (dir) == cmt_string::npos)
1036 {
1037 CMTPATH = dir;
1038 CMTPATH += ":";
1039 CMTPATH += cmtpath;
1040
1041 CmtSystem::putenv ("CMTPATH", CMTPATH);
1042 }
1043
1044 if (m_verbose)
1045 {
1046 cout << "#CMT> CMTPATH=" << CmtSystem::getenv ("CMTPATH") << endl;
1047 }
1048 }
1049
1050 /**
1051 Specific checkout of one project
1052 */
1053 bool really_checkout_project_contents (const cmt_string& offset,
1054 const cmt_string& project,
1055 const cmt_string& version,
1056 const cmt_string& tag,
1057 const cmt_string& module,
1058 const cmt_string& basedir,
1059 bool at_head,
1060 const cmt_string& currentdir)
1061 {
1062 cmt_string dir = currentdir;
1063
1064 cout << " # get project files into " << dir << endl;
1065
1066
1067 cmt_string version_dir = version;
1068 if (!mkdir (version_dir)) return (false);
1069
1070 dir += CmtSystem::file_separator ();
1071 dir += version_dir;
1072
1073 cmt_string command = "cvs -f -Q co -P ";
1074 if (!at_head)
1075 {
1076 command += "-r ";
1077 command += (tag != "") ? tag : version;
1078 }
1079
1080 command += " -d cmt ";
1081
1082 command += " ";
1083 command += module;
1084 command += "/cmt";
1085
1086 command += CmtSystem::command_separator ();
1087
1088 command += " cvs -f update -l .";
1089
1090 execute_and_retry (command, "Error getting project CMT contents");
1091
1092 return (true);
1093 }
1094 /**
1095 Construct CVS management files in the top directory. This is needed
1096 if the top directory of a product is empty. (In this case the
1097 co -l results in nothing)
1098 */
1099 void make_management_files (const cmt_string& module,
1100 const cmt_string& entries_text)
1101 {
1102 if (!CmtSystem::test_directory ("CVS"))
1103 {
1104 /**
1105 * The CVS repository had not been created (this is generally
1106 * due to the lack of top files)
1107 */
1108
1109 if (!mkdir ("CVS")) return;
1110
1111 CmtSystem::cd ("..");
1112
1113 cmt_string s;
1114
1115 // Let's create first the CVS/Root file.
1116
1117 CmtSystem::get_cvsroot (s);
1118 s += "\n";
1119
1120 cmt_string f;
1121
1122 f = "CVS";
1123 f += CmtSystem::file_separator ();
1124 f += "Root";
1125
1126 if (m_simulation)
1127 {
1128 cout << "#CMT> Would fill in the CVS/Root file with " << endl;
1129 cout << s << endl;
1130 }
1131 else
1132 {
1133 if (m_verbose)
1134 {
1135 cout << "#CMT> Fill in the CVS/Root file with " << endl;
1136 cout << s << endl;
1137 }
1138 s.write (f);
1139 }
1140
1141 // Now we create the CVS/Repository file
1142
1143 f = "CVS";
1144 f += CmtSystem::file_separator ();
1145 f += "Repository";
1146
1147 CmtSystem::get_cvsroot (s);
1148 if (s[0] == ':')
1149 {
1150 int pos = s.find (1, ":");
1151 s.erase (0, pos+1);
1152 pos = s.find (0, ":");
1153 s.erase (0, pos+1);
1154 }
1155 s += "/";
1156 s += module;
1157 s += "\n";
1158
1159 if (m_simulation)
1160 {
1161 cout << "#CMT> Would fill in the CVS/Repository file with " << endl;
1162 cout << s << endl;
1163 }
1164 else
1165 {
1166 if (m_verbose)
1167 {
1168 cout << "#CMT> Fill in the CVS/Repository file with " << endl;
1169 cout << s << endl;
1170 }
1171 s.write (f);
1172 }
1173 }
1174
1175 if (m_simulation)
1176 {
1177 cout << "#CMT> Would write the top CVS/Entries file with " << endl;
1178 cout << entries_text << endl;
1179 }
1180 else
1181 {
1182 cmt_string entries_file_name;
1183
1184 entries_file_name = "CVS";
1185 entries_file_name += CmtSystem::file_separator ();
1186 entries_file_name += "Entries";
1187
1188 cmt_string text;
1189
1190 if (!text.read (entries_file_name))
1191 {
1192 // This happens when there were no top files
1193 }
1194
1195 text += entries_text;
1196
1197 // Now the CVS/Entries is ready to be created.
1198 if (m_verbose)
1199 {
1200 cout << "#CMT> Fill in the top CVS/Entries file with " << endl;
1201 cout << text << endl;
1202 }
1203
1204 text.write (entries_file_name);
1205 }
1206 }
1207
1208
1209 /**
1210 Specific checkout of one package
1211
1212 1) get top files (no directories)
1213 2) construct the directory structure (with or without version directory)
1214 3) build the CVS/Entries file for subdirs and co individual subdirs
1215 4) write the CVS management files if CVS did not do it.
1216 */
1217 bool really_checkout_package_contents (const cmt_string& offset,
1218 const cmt_string& package,
1219 const cmt_string& version,
1220 const cmt_string& module,
1221 const cmt_string& basedir,
1222 bool at_head,
1223 const cmt_string& currentdir)
1224 {
1225 cmt_string dir = currentdir;
1226
1227 cout << " # get top files " << endl;
1228
1229 cmt_string command = "cvs -f -Q co -l ";
1230 if (!at_head)
1231 {
1232 command += "-r ";
1233 command += version;
1234 }
1235
1236 bool need_version = do_need_version ();
1237
1238 if (need_version)
1239 {
1240 command += " -d ";
1241 command += version;
1242 }
1243 else
1244 {
1245 command += " -d ";
1246 command += package;
1247
1248 // Must stand just above the package directory
1249 CmtSystem::cd ("..");
1250 CmtSystem::dirname (dir, dir);
1251 }
1252
1253 command += " ";
1254 command += module;
1255
1256 execute_and_retry (command, "Error getting package CMT contents");
1257
1258 if (need_version)
1259 {
1260 if (!mkdir (version)) return (false);
1261 dir += CmtSystem::file_separator ();
1262 dir += version;
1263 }
1264 else
1265 {
1266 if (!mkdir (package)) return (false);
1267
1268 dir += CmtSystem::file_separator ();
1269 dir += package;
1270 }
1271
1272 if (m_verbose)
1273 {
1274 cout << "#CMT> Now getting subdirectories pwd=" << CmtSystem::pwd () << " dir=" << dir << endl;
1275 }
1276
1277 cmt_string branches = CmtSystem::getenv ("CMTCVSBRANCHES");
1278
1279 if (branches == "")
1280 {
1281 branches = branches_info;
1282 }
1283
1284 CmtSystem::cmt_string_vector branch_vector;
1285
1286 CmtSystem::split (branches, " \t", branch_vector);
1287
1288 cmt_string text = "";
1289
1290 command = "";
1291
1292 if (!CmtSystem::test_directory ("CVS"))
1293 {
1294 int i;
1295 for (i = 0; i < branch_vector.size (); i++)
1296 {
1297 cmt_string& branch = branch_vector[i];
1298 if (i > 0)
1299 {
1300 command += CmtSystem::command_separator ();
1301 }
1302
1303 command += "cvs -f -Q co ";
1304
1305 if (!at_head)
1306 {
1307 command += "-r ";
1308 command += version;
1309 }
1310
1311 command += " -d ";
1312 command += branch;
1313 command += " ";
1314 command += module;
1315 command += "/"; // CVS uses the '/' notation on all platforms!!
1316 command += branch;
1317
1318 text += "D/";
1319 text += branch;
1320 text += "////\n";
1321 }
1322 execute_and_retry (command, "Error getting package contents");
1323
1324 make_management_files (module, text);
1325
1326 if (need_touch_files)
1327 {
1328
1329 cout << "# --> udapte the file timestamps" << endl;
1330 for (i = 0; i < branch_vector.size (); i++)
1331 {
1332 cmt_string& branch = branch_vector[i];
1333 CmtSystem::cmt_string_vector& list = CmtSystem::scan_dir (branch);
1334 int j;
1335 for (j = 0; j < list.size (); j++)
1336 if (CmtSystem::test_file(list[j]))
1337 CmtSystem::touch_file (list[j]);
1338 }
1339 }
1340 return (true);
1341 }
1342
1343 command += "cvs -Q update -d ";
1344
1345 if (!at_head)
1346 {
1347 command += "-r ";
1348 command += version;
1349 }
1350
1351 int i;
1352
1353 for (i = 0; i < branch_vector.size (); i++)
1354 {
1355 cmt_string& branch = branch_vector[i];
1356 if (branch != "CVS")
1357 {
1358 command += " ";
1359 command += branch;
1360 }
1361 }
1362
1363 command += CmtSystem::command_separator ();
1364
1365 command += "cvs update -l .";
1366
1367 execute_and_retry (command, "Error getting package contents");
1368
1369 if (need_touch_files)
1370 {
1371
1372 cout << "# --> udapte the file timestamps" << endl;
1373 for (i = 0; i < branch_vector.size (); i++)
1374 {
1375 cmt_string& branch = branch_vector[i];
1376 CmtSystem::cmt_string_vector& list = CmtSystem::scan_dir (branch);
1377 int j;
1378 for (j = 0; j < list.size (); j++)
1379 if (CmtSystem::test_file(list[j]))
1380 CmtSystem::touch_file (list[j]);
1381 }
1382 }
1383 return (true);
1384 }
1385
1386 /**
1387 Effective checkout of a package or a project
1388 */
1389 bool really_checkout (const cmt_string& offset,
1390 const cmt_string& product,
1391 const cmt_string& version,
1392 const cmt_string& tag,
1393 const cmt_string& module,
1394 const cmt_string& basedir,
1395 bool at_head)
1396 {
1397 cmt_string dir = basedir;
1398 cmt_string out;
1399
1400 cout << "# ================= working on " << structure_info << " " << product
1401 << " version " << version;
1402
1403 if (at_head) cout << " (At head) ";
1404
1405 cmt_string full_offset;
1406
1407 full_offset = m_cvs_offset;
1408 full_offset += offset;
1409
1410 cmt_string echo_ppath;
1411
1412 if (offset != "")
1413 {
1414 echo_ppath = " path ";
1415 echo_ppath += offset;
1416 }
1417
1418 cout << echo_ppath << " in " << dir << endl;
1419
1420 if (do_need_version ())
1421 {
1422 // Move back to the product name.
1423 CmtSystem::dirname (dir, dir);
1424 }
1425
1426 if (!mkdir (dir)) return (false);
1427
1428 if (structure_info == "package")
1429 {
1430 really_checkout_package_contents (offset,
1431 product,
1432 version,
1433 module,
1434 basedir,
1435 at_head,
1436 dir);
1437 }
1438 else if (structure_info == "project")
1439 {
1440 really_checkout_project_contents (offset,
1441 product,
1442 version,
1443 tag,
1444 module,
1445 basedir,
1446 at_head,
1447 dir);
1448 }
1449
1450 return (true);
1451 }
1452
1453 /**
1454 Find the most appropriate effective version directory corresponding to the
1455 specified version expression.
1456 The specified expression may contain wildcards (in the file manager sense). This
1457 FME is first converted into a RE then a directory search is performed.
1458 An empty string is returned if no match is found.
1459 */
1460 cmt_string find_matching_version (const cmt_string& expression)
1461 {
1462
1463 cmt_string result;
1464
1465 //
1466 // Here expression takes the form
1467 // <some path>/<expression with wild-card>
1468 //
1469
1470 cmt_string dir;
1471 CmtSystem::dirname (expression, dir);
1472 dir += CmtSystem::file_separator ();
1473
1474 cmt_string version;
1475 CmtSystem::basename (expression, version);
1476
1477 if (version.find ("*") == cmt_string::npos)
1478 {
1479 // there is no wildcarding here. A simple test is enough.
1480 if (CmtSystem::test_directory (expression))
1481 {
1482 result = version;
1483 }
1484 }
1485 else
1486 {
1487 version.replace ("*", ".*");
1488
1489 cmt_regexp exp (version);
1490
1491 CmtSystem::cmt_string_vector list;
1492
1493 CmtSystem::scan_dir (dir, exp, list);
1494
1495 if (list.size () > 0)
1496 {
1497 result = list[0];
1498
1499 CmtSystem::basename (result, result);
1500 }
1501 }
1502
1503 return (result);
1504 }
1505
1506 /**
1507 * We provide a path to a requirements file. From it we read the use
1508 * statements, and we try to checkout the corresponding packages.
1509 *
1510 * A boolean return tells if any recursion occurred.
1511 */
1512 bool checkout_from_requirements (const cmt_string& requirements_path)
1513 {
1514 static cmt_regexp expression ("^[ \t]*use[ \t]");
1515
1516 cmt_string text;
1517
1518 text.read (requirements_path);
1519
1520 RecursivePass1 p1;
1521 p1.run (text, expression);
1522
1523 bool result = (p1.result () != "");
1524 RecursivePass2 p2 (*this);
1525 p2.run (p1.result ());
1526
1527 return (result);
1528 }
1529
1530 /**
1531 * We provide a path to a project file. From it we read the use
1532 * statements, and we try to checkout the corresponding projects.
1533 */
1534 void checkout_from_project_file (const cmt_string& file_name)
1535 {
1536 static cmt_regexp expression ("^[ \t]*use[ \t]");
1537
1538 cmt_string text;
1539
1540 text.read (file_name);
1541
1542 CvsImplementation& me = *this;
1543 CvsImplementation saved;
1544 saved = me;
1545 cmt_string here = CmtSystem::pwd ();
1546
1547 RecursivePass3 p3;
1548 p3.run (text, expression);
1549
1550 RecursivePass4 p4 (*this);
1551 p4.run (p3.result ());
1552
1553 Grep grep;
1554
1555 grep.run (text, "container");
1556 cmt_string container = grep.result ();
1557
1558 if (container != "")
1559 {
1560 static cmt_regexp container_expression ("^[ \t]*container[ \t]");
1561
1562 add_cmtpath (here);
1563
1564 cout << " # --> now getting project packages from the " << container << " " << here << endl;
1565
1566 CmtSystem::cd (here);
1567
1568 RecursivePass1 p1;
1569 p1.run (text, container_expression);
1570
1571 RecursivePass2 p2 (*this);
1572
1573 m_home_dir = CmtSystem::pwd ();
1574 p2.run (p1.result ());
1575 }
1576
1577 CmtSystem::cd (here);
1578 me = saved;
1579 }
1580
1581 /**
1582 Check whether a given directory structure matches an expected product structure
1583 given by the structure info obtained from the most recent request to the CVS pluggin
1584 */
1585 bool check_structure (const cmt_string& dir, const cmt_string& version)
1586 {
1587 bool result = false;
1588 if (!CmtSystem::test_directory (dir))
1589 {
1590 return (false);
1591 }
1592
1593 if (structure_info == "package")
1594 {
1595 // Check if it is a true CMT package.
1596 cmt_string file_name;
1597
1598 file_name = dir;
1599 file_name += CmtSystem::file_separator ();
1600 file_name += "cmt";
1601 file_name += CmtSystem::file_separator ();
1602 file_name += "requirements";
1603
1604 if (CmtSystem::test_file (file_name))
1605 {
1606 if (!do_need_version ())
1607 {
1608 // open the version.cmt file and compare the version
1609 cmt_string current_version;
1610 cmt_string version_file = dir;
1611 version_file += CmtSystem::file_separator ();
1612 version_file += "CVS";
1613 version_file += CmtSystem::file_separator ();
1614 version_file += "Tag";
1615 current_version.read (version_file);
1616 //cout <<version_file<<", "<<current_version<<", "<<"N"+version+"\n"<<endl;
1617 return current_version=="N"+version+"\n";
1618 }
1619 else
1620 result = true;
1621 }
1622 else
1623 {
1624
1625 file_name = dir;
1626 file_name += CmtSystem::file_separator ();
1627 file_name += "mgr";
1628 file_name += CmtSystem::file_separator ();
1629 file_name += "requirements";
1630
1631 if (CmtSystem::test_file (file_name))
1632 {
1633 if (!do_need_version ())
1634 {
1635 // open the version.cmt file and compare the version
1636 cmt_string current_version;
1637 cmt_string version_file = dir;
1638 version_file += CmtSystem::file_separator ();
1639 version_file += "CVS";
1640 version_file += CmtSystem::file_separator ();
1641 version_file += "Tag";
1642 current_version.read (version_file);
1643 //cout <<version_file<<", "<<current_version<<", "<<"N"+version+"\n"<<endl;
1644 return current_version=="N"+version+"\n";
1645 }
1646 else
1647 result = true;
1648 }
1649 }
1650 }
1651 else if (structure_info == "project")
1652 {
1653 cmt_string file_name;
1654
1655 file_name = dir;
1656 file_name += CmtSystem::file_separator ();
1657 file_name += "cmt";
1658 file_name += CmtSystem::file_separator ();
1659 file_name += "project.cmt";
1660
1661 if (CmtSystem::test_file (file_name))
1662 {
1663 result = true;
1664 }
1665 }
1666
1667 return (result);
1668 }
1669
1670 /**
1671 Internal call from the initial do_checkout or from recursive passes
1672 Prepare the directory structure for the checkout
1673 Do the checkout
1674 Check if everything was done properly, if a package or a project has been created
1675 If needed recurse from the requirements or project file
1676
1677 For projects there may be two different specifications for
1678 - the version directory
1679 - the CVS tag
1680 */
1681 void do_checkout_phase2 (const cmt_string& offset,
1682 const cmt_string& product,
1683 const cmt_string& specified_version,
1684 const cmt_string& tag)
1685 {
1686 if (m_verbose)
1687 {
1688 cout << "#CMT> do_checkout_phase2> offset=" << offset
1689 << " " << structure_info << "=" << product
1690 << " specified_version=" << specified_version
1691 << " tag=" << tag
1692 << " pwd=" << CmtSystem::pwd ()
1693 << endl;
1694 }
1695
1696 cmt_string version = specified_version;
1697 cmt_string empty;
1698 cmt_string full_offset;
1699
1700 full_offset = m_cvs_offset;
1701 full_offset += offset;
1702
1703 cmt_string echo_ppath;
1704
1705 if (offset != "")
1706 {
1707 echo_ppath = " path ";
1708 echo_ppath += offset;
1709 }
1710
1711 if (version == "")
1712 {
1713 cout << "# ================= No version specified for " << structure_info << " " << product << endl;
1714 return;
1715 }
1716
1717 //
1718 // First make an attempt to locate the specified version of
1719 // this product "as-it-is" in the work area.
1720 // Since 'version' may contain wild-card, it's likely that
1721 // we should not simply use CmtSystem::test_directory but
1722 // use the wild-card search.
1723 //
1724
1725 cmt_string dir;
1726
1727 dir = build_version_directory (offset, product, version);
1728
1729 bool recursive = m_recursive;
1730
1731 cmt_string effective_version = "";
1732 if (do_need_version ())
1733 {
1734 /* Important this part should be enhanced ASAP
1735 and deal with many other cases.... arghhhh !!
1736 */
1737 effective_version = find_matching_version (dir);
1738 }
1739
1740
1741
1742 cmt_string module;
1743 get_module (full_offset, product, module);
1744
1745 cmt_string cvs_tag = (tag != "") ? tag : version;
1746 bool at_head = false;
1747
1748 if (effective_version != "")
1749 {
1750 version = effective_version;
1751 }
1752 else
1753 {
1754 //
1755 // get_version attempts to find the most appropriate version
1756 // tag matching the specification FROM the repository. However,
1757 // we should take into account situations where some versions have
1758 // already been checked out, in which case they might be sufficient
1759 // (or preferred?)
1760 //
1761
1762 if (cvs_tag.find ("*") != cmt_string::npos)
1763 {
1764 cout << "# ================= " << structure_info << " " << product
1765 << " version " << cvs_tag << echo_ppath
1766 << " has wild cards and will not be considered." << endl;
1767 return;
1768 }
1769
1770 if (!get_version (full_offset, product, cvs_tag, module,
1771 cvs_tag, at_head))
1772 {
1773 return;
1774 }
1775
1776 if (m_head)
1777 {
1778 m_head = false;
1779
1780 at_head = true;
1781 }
1782 else
1783 {
1784 at_head = false;
1785 }
1786
1787 //
1788 // Make a second try after having selected a CVS tag from all the
1789 // available tags compatible with the specified version
1790 //
1791
1792 if (tag == "")
1793 {
1794 // If tag was not specified, then the version directory has to match the CVS tag
1795 // Otherwise the original version specification is kept for the directory.
1796 version = cvs_tag;
1797 dir = build_version_directory (offset, product, version);
1798 }
1799 }
1800
1801 if (check_structure (dir, version))
1802 {
1803 cout << "# ================= " << structure_info << " " << product
1804 << " version " << version << echo_ppath
1805 << " already installed." << endl;
1806 recursive = false;
1807 }
1808 else
1809 {
1810 //
1811 // Now we can say that we have to perform the real checkout.
1812 //
1813
1814 if (!really_checkout (offset, product, version, cvs_tag, module, dir, at_head))
1815 {
1816 cout << "# bad return from really_checkout_product" << endl;
1817 return;
1818 }
1819 }
1820
1821 //
1822 // Now reach the newly checked out product.
1823 //
1824
1825 if (m_simulation)
1826 {
1827 cout << "#CMT> " << structure_info << " directory not really created " << dir << endl;
1828 }
1829 else if (structure_info == "package")
1830 {
1831 if (!CmtSystem::cd (dir))
1832 {
1833 cout << "#CMT> Package directory not created " << dir << endl;
1834 return;
1835 }
1836
1837 // Check if it is a true CMT package.
1838
1839 cmt_string file_name;
1840
1841 file_name = "cmt";
1842 file_name += CmtSystem::file_separator ();
1843 file_name += "requirements";
1844
1845 if (CmtSystem::test_file (file_name))
1846 {
1847 dir += CmtSystem::file_separator ();
1848 dir += "cmt";
1849 CmtSystem::cd ("cmt");
1850
1851 if (!do_need_version ())
1852 {
1853 cmt_string text = version;
1854 text += "\n";
1855 text.write ("version.cmt");
1856 }
1857 }
1858 else
1859 {
1860 file_name = "mgr";
1861 file_name += CmtSystem::file_separator ();
1862 file_name += "requirements";
1863
1864 if (CmtSystem::test_file (file_name))
1865 {
1866 dir += CmtSystem::file_separator ();
1867 dir += "mgr";
1868 CmtSystem::cd ("mgr");
1869 }
1870 else
1871 {
1872 cout << "# " << product << " not a CMT package" << endl;
1873 return;
1874 }
1875 }
1876
1877 if (recursive)
1878 {
1879 cmt_string here = CmtSystem::pwd ();
1880
1881 bool did_recurse = checkout_from_requirements ("requirements");
1882
1883 CmtSystem::cd (here);
1884
1885 if (did_recurse)
1886 {
1887 if (no_config==false)
1888 execute ("cmt -quiet broadcast cmt -quiet config");
1889
1890 }
1891 else
1892 {
1893 if (no_config==false)
1894 execute ("cmt -quiet config");
1895 }
1896 }
1897 else
1898 {
1899 if (no_config==false)
1900 execute ("cmt -quiet config");
1901 }
1902 }
1903 else if (structure_info == "project")
1904 {
1905
1906 if (m_verbose)
1907 {
1908 cout << "#CMT> dir=" << dir << endl;
1909 }
1910
1911 if (!CmtSystem::cd (dir))
1912 {
1913 cout << "#CMT> Project directory not created " << dir << endl;
1914 return;
1915 }
1916
1917 cmt_string file_name;
1918
1919 file_name = "cmt";
1920 file_name += CmtSystem::file_separator ();
1921 file_name += "project.cmt";
1922
1923 if (!CmtSystem::test_file (file_name))
1924 {
1925 cout << "# " << product << " not a CMT project" << endl;
1926 return;
1927 }
1928
1929 if (recursive)
1930 {
1931 checkout_from_project_file (file_name);
1932 }
1933
1934 cout << "# ================= Project " << product << " completed" << endl;
1935
1936 }
1937 }
1938
1939 /**
1940 Top level of the checkout operation, initiated from the command line arguments
1941
1942 Construct an history of the checkouts to avoid duplicating the
1943 checkouts during the recursivity
1944
1945 Eventually
1946 o perform the cmt config for packages.
1947
1948 */
1949 void do_checkout_phase1 (const cmt_string& module,
1950 const cmt_string& version_dir,
1951 const cmt_string& version_tag)
1952 {
1953 add_cmtpath (m_home_dir);
1954
1955 History& h = History::instance ();
1956
1957 h.clear ();
1958
1959 if (module == "")
1960 {
1961 if (m_verbose)
1962 {
1963 cout << "#CMT> Missing module name" << endl;
1964 }
1965 return;
1966 }
1967
1968 cmt_string offset;
1969 cmt_string product;
1970 cmt_string version;
1971 cmt_string tag;
1972
1973 {
1974 cmt_string m;
1975 m = m_cvs_offset;
1976 m += module;
1977
1978 get_cvs_infos_with_offset (m);
1979
1980 if (error_info != "")
1981 {
1982 cout << error_info << endl;
1983 return;
1984 }
1985 }
1986
1987 if (version_tag == "")
1988 {
1989 Cut cut (0);
1990
1991 if (tags_top_info != "") tag = tags_top_info;
1992 else tag = tags_info;
1993
1994 cut.run (tag);
1995
1996 tag = cut.result ();
1997 }
1998 else
1999 {
2000 tag = version_tag;
2001 }
2002
2003 version = (version_dir == "") ? tag : version_dir;
2004
2005 CmtSystem::dirname (module, offset);
2006 CmtSystem::basename (module, product);
2007
2008 cmt_string top_dir;
2009
2010 top_dir = m_home_dir;
2011 top_dir += CmtSystem::file_separator ();
2012 top_dir += m_checkout_dir;
2013 top_dir += CmtSystem::file_separator ();
2014 top_dir += offset;
2015 top_dir += CmtSystem::file_separator ();
2016 top_dir += product;
2017 top_dir += CmtSystem::file_separator ();
2018 top_dir += version;
2019
2020 CmtSystem::reduce_file_separators (top_dir);
2021
2022 if (m_verbose)
2023 {
2024 cout << "#CMT> about to checkout " << structure_info
2025 << " " << product << " version " << version << " into " << top_dir << endl;
2026 }
2027
2028 static const cmt_string empty;
2029 do_checkout_phase2 (offset, product, version, tag);
2030
2031 if (m_simulation) return;
2032
2033 if (!CmtSystem::cd (top_dir)) return;
2034
2035 if (structure_info == "project")
2036 {
2037 cmt_string file_name;
2038
2039 file_name = "cmt";
2040 file_name += CmtSystem::file_separator ();
2041 file_name += "project.cmt";
2042
2043 if (!CmtSystem::test_file (file_name))
2044 {
2045 cout << "# " << product << " was not properly checked out and is missing its cmt/project.cmt file" << endl;
2046 return;
2047 }
2048 }
2049 else
2050 {
2051 cmt_string file_name;
2052
2053 file_name = "cmt";
2054 file_name += CmtSystem::file_separator ();
2055 file_name += "requirements";
2056
2057 if (CmtSystem::test_file (file_name))
2058 {
2059 top_dir += CmtSystem::file_separator ();
2060 top_dir += "cmt";
2061 CmtSystem::cd ("cmt");
2062 }
2063 else
2064 {
2065 file_name = "mgr";
2066 file_name += CmtSystem::file_separator ();
2067 file_name += "requirements";
2068
2069 if (CmtSystem::test_file (file_name))
2070 {
2071 top_dir += CmtSystem::file_separator ();
2072 top_dir += "mgr";
2073 CmtSystem::cd ("mgr");
2074 }
2075 else
2076 {
2077 cout << "# " << product << " was not properly checked out and is missing its cmt/requirements file" << endl;
2078 return;
2079 }
2080 }
2081
2082 if (m_verbose)
2083 {
2084 cout << "#CMT> product " << product << " has been checked out" << endl;
2085 }
2086
2087 if (!m_recursive)
2088 {
2089 if (no_config==false)
2090 execute ("cmt -quiet config");
2091 }
2092 }
2093 }
2094
2095 void help ()
2096 {
2097 cout << "> cd <some work area>" << endl;
2098 cout << "> cmt checkout [modifier ...] <package|project>" << endl;
2099 cout << "" << endl;
2100 cout << " modifier :" << endl;
2101 cout << " -l Do not process used packages (default)." << endl;
2102 cout << " -R Process used products recursively." << endl;
2103 cout << " -r rev Check out version tag. (is sticky)" << endl;
2104 cout << " -vd dir Use this version directory instead of CVS tag." << endl;
2105 cout << " -d dir Check out into dir instead of module name." << endl;
2106 cout << " -o offset Offset in the CVS repository" << endl;
2107 cout << " -requirements <requirements file path> Check out packages referenced in this requirements file" << endl;
2108 cout << " -t Change file timestamps to the date of checkout" << endl;
2109 cout << " -n simulation mode on" << endl;
2110 cout << " -no_config Disable config step after checkout" << endl;
2111 cout << " -v verbose mode on" << endl;
2112 cout << " --help print this help" << endl;
2113 cout << "" << endl;
2114 cout << "> cmt cvstags <package|project>" << endl;
2115 cout << "> cmt cvssubpackages <directory>" << endl;
2116 cout << "> cmt cvssubprojects <directory>" << endl;
2117 cout << "" << endl;
2118 }
2119
2120 /**
2121 Implementation of the cmt cvstags
2122 Get the CVS tags of a module
2123 */
2124 void tags (const CmtSystem::cmt_string_vector& arguments)
2125 {
2126 if (arguments.size () < 1)
2127 {
2128 help ();
2129 return;
2130 }
2131
2132 if (CmtSystem::getenv ("CVSROOT") == "")
2133 {
2134 cout << "# Please set CVSROOT first !" << endl;
2135 return;
2136 }
2137
2138 m_cvs_offset = CmtSystem::getenv ("CMTCVSOFFSET");
2139 if (m_cvs_offset != "")
2140 {
2141 m_cvs_offset += "/";
2142 m_cvs_offset.replace_all ("//", "/");
2143 }
2144
2145 bool all = false;
2146
2147 for (int arg = 0; arg < arguments.size (); arg++)
2148 {
2149 const cmt_string& option = arguments[arg];
2150
2151 if (option == "-all")
2152 {
2153 all = true;
2154 }
2155 else
2156 {
2157 get_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), option);
2158
2159 if (error_info != "")
2160 {
2161 cout << error_info << endl;
2162 }
2163 else
2164 {
2165 cmt_string tags;
2166
2167 if (all)
2168 {
2169 tags = cvsversions_top_info;
2170 tags += " ";
2171 tags += cvsversions_info;
2172 }
2173 else
2174 {
2175 tags = tags_top_info;
2176 tags += " ";
2177 tags += tags_info;
2178 }
2179
2180 CmtSystem::cmt_string_vector v;
2181
2182 CmtSystem::split (tags, " \t", v);
2183 for (int i = 0; i < v.size (); i++)
2184 {
2185 const cmt_string& s = v[i];
2186 cout << s << endl;
2187 }
2188 }
2189 }
2190 }
2191 }
2192
2193 /**
2194 Implementation of the cmt cvsbranches
2195 Get the subdirs of a module that are not subackages
2196 */
2197 void branches (const cmt_string& module)
2198 {
2199 cmt_string out;
2200
2201 get_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), module);
2202
2203 if (error_info != "")
2204 {
2205 cout << error_info << endl;
2206 }
2207 else
2208 {
2209 cout << branches_info << endl;
2210 }
2211 }
2212
2213 /**
2214 Implementation of the cmt cvssubpackages
2215 Get the subdirs of a module that ARE CMT subpackages
2216 */
2217 void subpackages (const cmt_string& module)
2218 {
2219 cmt_string out;
2220
2221 get_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), (module == "") ? "." : module);
2222
2223 if (error_info != "")
2224 {
2225 cout << error_info << endl;
2226 }
2227 else
2228 {
2229 cout << subpackages_info << endl;
2230 }
2231 }
2232
2233 /**
2234 Implementation of the cmt cvssubrojects
2235 Get the subdirs of a module that ARE CMT projects
2236 */
2237 void subprojects (const cmt_string& module)
2238 {
2239 cmt_string out;
2240
2241 get_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), (module == "") ? "." : module);
2242
2243 if (error_info != "")
2244 {
2245 cout << error_info << endl;
2246 }
2247 else
2248 {
2249 cout << subprojects_info << endl;
2250 }
2251 }
2252
2253 /**
2254 Implementation of the cmt checkout
2255 Parse the arguments
2256 Then call do_checkout for each argument
2257 */
2258 void checkout (const CmtSystem::cmt_string_vector& arguments)
2259 {
2260 if (arguments.size () < 1)
2261 {
2262 help ();
2263 return;
2264 }
2265
2266 if (CmtSystem::getenv ("CVSROOT") == "")
2267 {
2268 cout << "# Please set CVSROOT first !" << endl;
2269 return;
2270 }
2271
2272 m_home_dir = CmtSystem::pwd ();
2273 m_checkout_dir = "";
2274 m_version_dir = "";
2275 m_cvs_offset = "";
2276
2277 cmt_string module;
2278
2279 m_recursive = false;
2280 need_touch_files = false;
2281 no_config = false;
2282
2283 bool need_version_tag = false;
2284 cmt_string version_tag;
2285
2286
2287 bool need_checkout_dir = false;
2288 bool need_cvs_offset = false;
2289 bool need_requirements_file = false;
2290 bool need_version_dir = false;
2291
2292 m_simulation = false;
2293 //m_verbose = true;
2294 m_verbose = false;
2295
2296 m_head = true;
2297
2298 m_cvs_offset = CmtSystem::getenv ("CMTCVSOFFSET");
2299 if (m_cvs_offset != "")
2300 {
2301 m_cvs_offset += "/";
2302 m_cvs_offset.replace_all ("//", "/");
2303 }
2304
2305 for (int arg = 0; arg < arguments.size (); arg++)
2306 {
2307 const cmt_string& option = arguments[arg];
2308
2309 if (need_version_tag)
2310 {
2311 need_version_tag = false;
2312
2313 if (option == "HEAD")
2314 {
2315 m_head = true;
2316 }
2317 else
2318 {
2319 version_tag = option;
2320 }
2321 }
2322 else if (need_checkout_dir)
2323 {
2324 need_checkout_dir = false;
2325 m_checkout_dir = option;
2326 }
2327 else if (need_version_dir)
2328 {
2329 need_version_dir = false;
2330 m_version_dir = option;
2331 }
2332 else if (need_cvs_offset)
2333 {
2334 need_cvs_offset = false;
2335 m_cvs_offset = option;
2336 m_cvs_offset += '/';
2337 m_cvs_offset.replace_all ("//", "/");
2338 }
2339 else if (need_requirements_file)
2340 {
2341 need_requirements_file = false;
2342 m_head = false;
2343 checkout_from_requirements (option);
2344 }
2345 else
2346 {
2347 if (option == "-R")
2348 {
2349 m_recursive = true;
2350 }
2351 else if (option == "-t")
2352 {
2353 need_touch_files = true;
2354 }
2355 else if (option == "-l")
2356 {
2357 m_recursive = false;
2358 }
2359 else if (option == "-r")
2360 {
2361 need_version_tag = true;
2362 m_head = false;
2363 }
2364 else if (option == "-d")
2365 {
2366 need_checkout_dir = true;
2367 }
2368 else if (option == "-o")
2369 {
2370 need_cvs_offset = true;
2371 }
2372 else if (option == "-n")
2373 {
2374 m_simulation = true;
2375 }
2376 else if (option == "-no_config")
2377 {
2378 no_config = true;
2379 }
2380 else if (option == "-v")
2381 {
2382 m_verbose = true;
2383 }
2384 else if (option == "-vd")
2385 {
2386 need_version_dir = true;
2387 }
2388 else if (option == "-requirements")
2389 {
2390 need_requirements_file = true;
2391 }
2392 else if (option == "--help")
2393 {
2394 help ();
2395 return;
2396 }
2397 else if (option[0] == '-')
2398 {
2399 help ();
2400 return;
2401 }
2402 else
2403 {
2404 do_checkout_phase1 (option, m_version_dir, version_tag);
2405 }
2406 }
2407 }
2408 }
2409
2410private:
2411
2412 bool m_recursive;
2413 bool need_touch_files;
2414 bool m_head;
2415 bool m_verbose;
2416 bool m_simulation;
2417 bool no_config;
2418
2419 cmt_string m_home_dir;
2420 cmt_string m_checkout_dir;
2421 cmt_string m_version_dir;
2422 cmt_string m_cvs_offset;
2423
2424 cmt_string m_protocol_level;
2425 cmt_string m_last_module;
2426 cmt_string m_last_cvs_infos;
2427 cmt_string structure_info;
2428 cmt_string error_info;
2429 cmt_string tags_top_info;
2430 cmt_string tags_info;
2431 cmt_string cvsversions_top_info;
2432 cmt_string cvsversions_info;
2433 cmt_string branches_info;
2434 cmt_string subpackages_info;
2435 cmt_string subprojects_info;
2436};
2437
2438//--------------------------------------------------------------------
2439
2440void Grep::begin ()
2441{
2442 m_result = "";
2443}
2444
2445void Grep::filter (const cmt_string& line)
2446{
2447 //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "Grep::filter" << endl;
2448
2449 if (m_result != "") m_result += " ";
2450 m_result += line;
2451}
2452
2453const cmt_string& Grep::result () const
2454{
2455 return (m_result);
2456}
2457
2458//--------------------------------------------------------------------
2459
2460Cut::Cut (int field)
2461{
2462 m_field = field;
2463}
2464
2465void Cut::begin ()
2466{
2467 //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "Cut::begin" << endl;
2468 m_result = "";
2469}
2470
2471void Cut::filter (const cmt_string& line)
2472{
2473 //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "Cut::filter" << endl;
2474
2475 static CmtSystem::cmt_string_vector words;
2476
2477 CmtSystem::split (line, " \t", words);
2478
2479 if (words.size () <= m_field) return;
2480
2481 if (m_result != "") m_result += " ";
2482 m_result += words[m_field];
2483}
2484
2485const cmt_string& Cut::result () const
2486{
2487 return (m_result);
2488}
2489
2490//--------------------------------------------------------------------
2491//--------------------------------------------------------------------
2492
2493History& History::instance ()
2494{
2495 static History h;
2496 return (h);
2497}
2498
2499void History::clear ()
2500{
2501 m_installed = "";
2502}
2503
2504void History::install (const cmt_string& line)
2505{
2506 m_installed += "|";
2507 m_installed += line;
2508 m_installed += "|";
2509}
2510
2511bool History::is_installed (const cmt_string& line)
2512{
2513 if (m_installed.find (line) != cmt_string::npos)
2514 {
2515 return (true);
2516 }
2517
2518 return (false);
2519}
2520
2521History::History ()
2522{
2523}
2524
2525
2526//--------------------------------------------------------------------
2527
2528void RecursivePass1::begin ()
2529{
2530 m_first = true;
2531 m_result = "";
2532}
2533
2534void RecursivePass1::filter (const cmt_string& line)
2535{
2536 //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "RecursivePass1::filter> "
2537 // << "line=[" << line << "]" << endl;
2538
2539 if (line.find ("use CMT") != cmt_string::npos) return;
2540 if (line.find ("use cmt") != cmt_string::npos) return;
2541
2542 History& h = History::instance ();
2543
2544 if (h.is_installed (line)) return;
2545
2546 CmtSystem::cmt_string_vector words;
2547
2548 CmtSystem::split (line, " \t", words);
2549
2550 enum
2551 {
2552 need_package,
2553 need_version,
2554 need_path,
2555 no_need
2556 } state = need_package;
2557
2558 cmt_string package;
2559 cmt_string version;
2560 cmt_string path;
2561
2562 for (int i = 1; i < words.size (); i++)
2563 {
2564 const cmt_string& s = words[i];
2565
2566 if (s[0] == '-') continue;
2567
2568 switch (state)
2569 {
2570 case need_package:
2571 package = s;
2572 state = need_version;
2573 break;
2574 case need_version:
2575 version = s;
2576 state = need_path;
2577 break;
2578 case need_path:
2579 path = s;
2580 state = no_need;
2581 break;
2582 }
2583 }
2584
2585 if (version.find ("*") != cmt_string::npos)
2586 {
2587 /*
2588 cout << "# ================= Package " << package
2589 << " version " << version << " " << path
2590 << " has wild cards and will not be considered." << endl;
2591 */
2592 return;
2593 }
2594
2595 /**
2596 * At the first pass, we simply accumulate the not-yet handled
2597 * use statements.
2598 */
2599
2600 m_result += line;
2601 m_result += "\n";
2602
2603 if (m_first)
2604 {
2605 m_first = false;
2606 cout << " # --> now propagate cmt checkout to :" << endl;
2607 }
2608
2609 cout << " # " << package << " " << version << " " << path << endl;
2610}
2611
2612const cmt_string& RecursivePass1::result () const
2613{
2614 return (m_result);
2615}
2616
2617//--------------------------------------------------------------------
2618
2619RecursivePass2::RecursivePass2 (CvsImplementation& cvs) : m_cvs (cvs)
2620{
2621}
2622
2623void RecursivePass2::begin ()
2624{
2625}
2626
2627void RecursivePass2::filter (const cmt_string& line)
2628{
2629 //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "RecursivePass2::filter> "
2630 // << "line=[" << line << "]" << endl;
2631
2632 /**
2633 * At the second pass, the lines are really handled. Thus
2634 * the lines are stored into m_installed so as to avoid
2635 * later on re-installation.
2636 */
2637
2638 History& h = History::instance ();
2639
2640 if (h.is_installed (line)) return;
2641
2642 h.install (line);
2643
2644 CmtSystem::cmt_string_vector words;
2645
2646 CmtSystem::split (line, " \t", words);
2647
2648 enum
2649 {
2650 need_package,
2651 need_version,
2652 need_path,
2653 no_need
2654 } state = need_package;
2655
2656 cmt_string package;
2657 cmt_string version;
2658 cmt_string path;
2659
2660 for (int i = 1; i < words.size (); i++)
2661 {
2662 const cmt_string& s = words[i];
2663
2664 if (s[0] == '-') continue;
2665
2666 switch (state)
2667 {
2668 case need_package:
2669 package = s;
2670 state = need_version;
2671 break;
2672 case need_version:
2673 version = s;
2674 state = need_path;
2675 break;
2676 case need_path:
2677 path = s;
2678 state = no_need;
2679 break;
2680 }
2681 }
2682
2683 if (version.find ("*") != cmt_string::npos)
2684 {
2685 /*
2686 cout << "# ================= Package " << package
2687 << " version " << version << " " << path
2688 << " has wild cards and will not be considered." << endl;
2689 */
2690 }
2691 else
2692 {
2693 static const cmt_string empty;
2694 m_cvs.do_checkout_phase2 (path, package, version, empty);
2695 }
2696}
2697
2698//--------------------------------------------------------------------
2699
2700void RecursivePass3::begin ()
2701{
2702 m_first = true;
2703 m_result = "";
2704}
2705
2706void RecursivePass3::filter (const cmt_string& line)
2707{
2708 History& h = History::instance ();
2709
2710 if (h.is_installed (line)) return;
2711
2712 CmtSystem::cmt_string_vector words;
2713
2714 CmtSystem::split (line, " \t", words);
2715
2716 enum
2717 {
2718 need_project,
2719 need_version,
2720 need_tag,
2721 no_need
2722 } state = need_project;
2723
2724 cmt_string project;
2725 cmt_string version;
2726 cmt_string tag;
2727
2728 for (int i = 1; i < words.size (); i++)
2729 {
2730 const cmt_string& s = words[i];
2731
2732 switch (state)
2733 {
2734 case need_project:
2735 project = s;
2736 state = need_version;
2737 break;
2738 case need_version:
2739 version = s;
2740 state = need_tag;
2741 break;
2742 case need_tag:
2743 tag = s;
2744 state = no_need;
2745 break;
2746 }
2747 }
2748
2749 if (version.find ("*") != cmt_string::npos)
2750 {
2751 /*
2752 cout << "# ================= Project " << project
2753 << " version " << version << " " << path
2754 << " has wild cards and will not be considered." << endl;
2755 */
2756 return;
2757 }
2758
2759 /**
2760 * At the first pass, we simply accumulate the not-yet handled
2761 * use statements.
2762 */
2763
2764 m_result += line;
2765 m_result += "\n";
2766
2767 if (m_first)
2768 {
2769 m_first = false;
2770 cout << " # --> now propagate cmt checkout to :" << endl;
2771 }
2772
2773 cout << " # " << project << " " << version << " " << tag << endl;
2774}
2775
2776const cmt_string& RecursivePass3::result () const
2777{
2778 return (m_result);
2779}
2780
2781//--------------------------------------------------------------------
2782
2783RecursivePass4::RecursivePass4 (CvsImplementation& cvs) : m_cvs (cvs)
2784{
2785}
2786
2787void RecursivePass4::begin ()
2788{
2789}
2790
2791void RecursivePass4::filter (const cmt_string& line)
2792{
2793 //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "RecursivePass4::filter> "
2794 // << "line=[" << line << "]" << endl;
2795
2796 /**
2797 * At the second pass, the lines are really handled. Thus
2798 * the lines are stored into m_installed so as to avoid
2799 * later on re-installation.
2800 */
2801
2802 History& h = History::instance ();
2803
2804 if (h.is_installed (line)) return;
2805
2806 h.install (line);
2807
2808 CmtSystem::cmt_string_vector words;
2809
2810 CmtSystem::split (line, " \t", words);
2811
2812 enum
2813 {
2814 need_project,
2815 need_version,
2816 need_tag,
2817 no_need
2818 } state = need_project;
2819
2820 cmt_string project;
2821 cmt_string version;
2822 cmt_string tag;
2823
2824 for (int i = 1; i < words.size (); i++)
2825 {
2826 const cmt_string& s = words[i];
2827
2828 switch (state)
2829 {
2830 case need_project:
2831 project = s;
2832 state = need_version;
2833 break;
2834 case need_version:
2835 version = s;
2836 state = need_tag;
2837 break;
2838 case need_tag:
2839 tag = s;
2840 state = no_need;
2841 break;
2842 }
2843 }
2844
2845 if (version.find ("*") != cmt_string::npos)
2846 {
2847 /*
2848 cout << "# ================= Project " << project
2849 << " version " << version
2850 << " has wild cards and will not be considered." << endl;
2851 */
2852 }
2853 else
2854 {
2855 static const cmt_string empty;
2856 m_cvs.do_checkout_phase2 (empty, project, version, tag);
2857 }
2858}
2859
2860//--------------------------------------------------------------------
2861
2862void Cvs::tags (const CmtSystem::cmt_string_vector& arguments)
2863{
2864 CvsImplementation cvs;
2865
2866 cvs.tags (arguments);
2867}
2868
2869void Cvs::branches (const cmt_string& module)
2870{
2871 CvsImplementation cvs;
2872
2873 cvs.branches (module);
2874}
2875
2876void Cvs::subpackages (const cmt_string& module)
2877{
2878 CvsImplementation cvs;
2879
2880 cvs.subpackages (module);
2881}
2882
2883void Cvs::subprojects (const cmt_string& module)
2884{
2885 CvsImplementation cvs;
2886
2887 cvs.subprojects (module);
2888}
2889
2890void Cvs::checkout (const CmtSystem::cmt_string_vector& arguments)
2891{
2892 CvsImplementation cvs;
2893
2894 cvs.checkout (arguments);
2895}
2896
Note: See TracBrowser for help on using the repository browser.