source: CMT/v1r14p20031120/src/cmt_cvs.cxx @ 1

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

Import all tags

File size: 50.6 KB
Line 
1#include <stdlib.h>
2#include <stdio.h>
3
4#include "cmt.h"
5#include "cmt_cvs.h"
6#include "cmt_awk.h"
7
8/**
9
10    Grep : perform a grep like operation onto a cmt_string
11
12    o All lines of the input string are collected when they contain
13      the specified pattern.
14    o The input string and the selector pattern are specified in
15      the constructor:
16
17         Grep (input_string, pattern)
18
19    o All selected lines are accumulated (appended) into the internal
20      variable m_result . 'space' is the separator.
21
22    o The accumulator is retrieved by the result () method.
23
24 */
25class Grep : public Awk
26{
27public:
28
29  void begin ();
30  void filter (const cmt_string& line);
31  const cmt_string& result () const;
32
33private:
34  cmt_string m_result;
35};
36
37/**
38
39     Cut : perform a cut-like operation :
40
41     o collect the <field>'th field of every line into the m_result
42       internal variable
43
44     o the field number is given in the constructor and starts at zero.
45
46     o selected fields are accumulated with a space as separator.
47
48 */
49class Cut : public Awk
50{
51public:
52  Cut (int field);
53  void begin ();
54  void filter (const cmt_string& line);
55  const cmt_string& result () const;
56
57private:
58  cmt_string m_result;
59  int m_field;
60};
61
62/**
63
64      History : maintains the history of checkout packages during a
65                recursive checkout, so as to avoid double checkouts.
66
67 */
68class History
69{
70public:
71  static History& instance ();
72  void clear ();
73  void install (const cmt_string& line);
74  bool is_installed (const cmt_string& line);
75
76private:
77  History ();
78
79  cmt_string m_installed;
80};
81
82/**
83
84     RecursivePass1 : simply validate use statements in a requirements file
85                      and echo those that really need to be handled.
86
87 */
88class RecursivePass1 : public Awk
89{
90public:
91
92  void begin ();
93  void filter (const cmt_string& line);
94  const cmt_string& result () const;
95
96private:
97  cmt_string m_result;
98  bool m_first;
99};
100
101/**
102
103     RecursivePass2 : after filtering the use statements really perform the
104                      checkouts.
105
106 */
107class CvsImplementation;
108class RecursivePass2 : public Awk
109{
110public:
111  RecursivePass2 (CvsImplementation& cvs);
112  void begin ();
113  void filter (const cmt_string& line);
114
115private:
116  CvsImplementation& m_cvs;
117};
118
119/**
120
121   Internal implementation of CVS to CMT operations.
122   The Cvs class only provides abstract interface.
123
124 */
125class CvsImplementation
126{
127public:
128
129  void filter_list (cmt_string& text, const cmt_regexp& exp)
130      {
131        CmtSystem::cmt_string_vector list;
132
133        CmtSystem::split (text, " ", list);
134
135        int i;
136
137        text = "";
138
139        for (i = 0; i < list.size (); i++)
140          {
141            const cmt_string& s = list[i];
142            if (exp.match (s))
143              {
144                if (i > 0) text += " ";
145                text += s;
146              }
147          }
148      }
149
150    //
151    // This method exploits the hook installed into the loginfo script.
152    // A communication is setup with a dummy CVS module named .cmtcvsinfos/<module>
153    //
154    //  At import time, the contents of the file will be used to parameterize
155    // the script named cmt_buildcvsinfos2.sh (referenced in the loginfo script)
156    //
157    //  This script performs a scan in the CVS repository for currently 4 types of
158    // information :
159    //
160    //   all top symbolic tags installed for the module
161    //   all symbolic tags installed for the module
162    //   all branches available below this module
163    //   all subpackages installed below the module.
164    //
165    //    In principle, only modules corresponding to true CMT packages are considered.
166    //      o tags are obtained from the requirements file
167    //      o branches are sub-directories which are not themselves packages
168    //      o subpackages are sub-directories which are CMT packages
169    //        (a subdirectory is always either a branch or a subpackage)
170    //
171  void show_cvs_infos (const cmt_string& module)
172      {
173        cmt_string out;
174
175        if (module == "")
176          {
177            cout << "# cmt cvs needs a module name" << endl;
178            return;
179          }
180       
181        cmt_string home_dir = CmtSystem::pwd ();
182
183          //
184          // Activities related with .cmtcvsinfos will occur in a temporary directory
185          //
186        cmt_string tmp_dir = CmtSystem::getenv ("TMPDIR");
187        if (tmp_dir == "")
188          {
189            tmp_dir = CmtSystem::file_separator ();
190            tmp_dir += "tmp";
191          }
192       
193        if (!CmtSystem::cd (tmp_dir))
194          {
195            tmp_dir = home_dir;
196          }
197
198        tmp_dir += CmtSystem::file_separator ();
199        tmp_dir += "cmtcvs";
200        {
201          cmt_string temp = CmtSystem::get_temporary_name ();
202          CmtSystem::basename (temp, temp);
203          tmp_dir += temp;
204        }
205       
206        if (!CmtSystem::test_directory (tmp_dir))
207          {
208            if (!CmtSystem::mkdir (tmp_dir))
209              {
210                cout << "# Cannot create the temporary directory [" 
211                     << tmp_dir << "]" << endl;
212                return;
213              }
214          }
215       
216          //trap "rm -rf ${tmp_dir}" 0 1 2 15
217       
218        if (!CmtSystem::cd (tmp_dir))
219          {
220            cout << "# Cannot move to the temporary directory " << tmp_dir << endl;
221            return;
222          }
223       
224          /*
225            #
226            # The script associated to such entries is supposed to :
227            #  1) extract the set of <infos> from the ${module}/cmt/requirements file
228            #  2) build an output of the form :
229            #      <infos>=info1 info2 info3 ...
230            #
231            # Currently this script can be found in
232            #
233            # ${CMTROOT}/cmt/cmt_buildcvsinfos2.sh
234            # %CMTROOT%/cmt/cmt_buildcvsinfos.py
235            #
236          */
237
238        if (!CmtSystem::test_directory (".cmtcvsinfos"))
239          {
240            CmtSystem::mkdir (".cmtcvsinfos");
241          }
242
243        CmtSystem::cd (".cmtcvsinfos");
244
245        cmt_string cvsroot;
246
247        CmtSystem::get_cvsroot (cvsroot);
248
249        cmt_string command;
250
251        command = "cvs";
252        if (cvsroot != "") 
253          {
254            command += " -d ";
255            command += cvsroot;
256          }
257        command += " -Q import -m cmt ";
258        if (m_cmtcvstest)
259          {
260            command += ".cmtcvsinfos/cmtcvstest";
261          }
262        else
263          {
264            command += ".cmtcvsinfos";
265          }
266        command += "/";
267        command += module;
268        command += " CMT v1";
269       
270        CmtSystem::execute (command, out);
271
272          //cout << "# after cvsinfos out=[" << out << "]" << endl;
273
274        /**
275           Now retrieve all info fields :
276
277             error=
278             tags_top=
279             tags=
280             branches=
281             subpackages=
282
283         */
284
285        Grep grep;
286
287        grep.run (out, "error=");
288
289        if (grep.result () != "")
290          {
291            error_info = grep.result ();
292            error_info.replace ("error=", "");
293          }
294        else
295          {
296            error_info = "";
297          }
298
299        grep.run (out, "tags_top=");
300
301        if (grep.result () != "")
302          {
303            tags_top_info = grep.result ();
304            tags_top_info.replace ("tags_top=", "");
305          }
306        else
307          {
308            tags_top_info = "";
309          }
310
311        grep.run (out, "tags=");
312
313        if (grep.result () != "")
314          {
315            tags_info = grep.result ();
316            tags_info.replace ("tags=", "");
317          }
318        else
319          {
320            tags_info = "";
321          }
322
323        grep.run (out, "cvsversions_top=");
324
325        if (grep.result () != "")
326          {
327            cvsversions_top_info = grep.result ();
328            cvsversions_top_info.replace ("cvsversions_top=", "");
329          }
330        else
331          {
332            cvsversions_top_info = "";
333          }
334
335        grep.run (out, "cvsversions=");
336
337        if (grep.result () != "")
338          {
339            cvsversions_info = grep.result ();
340            cvsversions_info.replace ("cvsversions=", "");
341          }
342        else
343          {
344            cvsversions_info = "";
345          }
346
347        cmt_string tag_filter = CmtSystem::getenv ("CMTCVSTAGFILTER");
348
349        if (tag_filter != "")
350          {
351            cmt_string package;
352            CmtSystem::basename (module, package);
353           
354            cmt_string pattern = "<package>";
355           
356            tag_filter.replace_all (pattern, package);
357           
358            cmt_regexp exp (tag_filter);
359           
360            cmt_string text;
361           
362            filter_list (tags_top_info, exp);
363            filter_list (tags_info, exp);
364            filter_list (cvsversions_top_info, exp);
365            filter_list (cvsversions_info, exp);
366          }
367
368        if (m_cmtcvstest)
369          {
370            cout << "## tags_top_info=" << tags_top_info << endl;
371            cout << "## tags_info=" << tags_info << endl;
372            cout << "## cvsversions_top_info=" << cvsversions_top_info << endl;
373            cout << "## cvsversions_info=" << cvsversions_info << endl;
374          }
375
376        grep.run (out, "branches=");
377
378        if (grep.result () != "")
379          {
380            branches_info = grep.result ();
381            branches_info.replace ("branches=", "");
382          }
383        else
384          {
385            branches_info = "";
386          }
387
388        grep.run (out, "subpackages=");
389
390        if (grep.result () != "")
391          {
392            subpackages_info = grep.result ();
393            subpackages_info.replace ("subpackages=", "");
394          }
395        else
396          {
397            subpackages_info = "";
398          }
399
400        CmtSystem::cd (home_dir);
401          //cout << "# (removing tmp_dir= " << tmp_dir << " home=" << home_dir<< ")" << endl;
402        CmtSystem::remove_directory (tmp_dir);
403      }
404
405  void show_cvs_infos (const cmt_string& offset,
406                       const cmt_string& module)
407  {
408    cmt_string full_name;
409
410    if (offset != "") 
411      {
412        full_name = offset;
413        full_name += "/";
414        full_name.replace_all ("//", "/");
415      }
416
417    full_name += module;
418
419    show_cvs_infos (full_name);
420  }
421
422    //
423    // Resolve all possible "aaa/bbb/../ccc/ddd" patterns into "aaa/ccc/ddd"
424    //
425  void filter_dir (cmt_string& d)
426      {
427        while (true)
428          {
429            int pos = d.find ("/../");
430            if (pos == cmt_string::npos) break;
431           
432            int slash = d.find ("/");
433            if (slash < pos)
434              {
435                  //
436                  // xxxxx/yyy/../zzzz -> xxxxx/zzzz
437                  // 01234567890123456
438                  //       1234567
439                  //  pos   = 9
440                  //  slash = 5
441                  //  length = 9+3-5
442                  //
443                d.erase (slash + 1, pos + 3 - slash);
444              }
445            else
446              {
447                  //
448                  // yyy/../zzzz -> zzzz
449                  // 01234567890
450                  // 1234567
451                  //  pos   = 3
452                  //  length = 3+1+3
453                  //
454                d.erase (0, pos + 1 + 3);
455              }
456          }
457      }
458
459  /**
460     From a space-separated list of version tags, try to find one tag
461     matching a given regular expression.
462
463       o The first matching tag is returned into 'version'
464       o Success is returned as function value.
465
466   */
467  bool match_version_request (const cmt_string& text, 
468                              const cmt_regexp& version_exp,
469                              cmt_string& version)
470      {
471        CmtSystem::cmt_string_vector vs;
472     
473        CmtSystem::split (text, " \t", vs);
474
475        version = "";
476
477        for (int i = 0; i < vs.size (); i++)
478          {
479            const cmt_string& vv = vs[i];
480       
481            if (version_exp.match (vv))
482              {
483                version = vv;
484                return (true);
485              }
486          }
487
488        return (false);
489      }
490
491  bool get_version (const cmt_string& prefix,
492                    const cmt_string& package,
493                    const cmt_string& version_request,
494                    cmt_string& module,
495                    cmt_string& version,
496                    bool& at_head)
497      {
498        Grep grep;
499        cmt_string topversions;
500        cmt_string versions;
501        cmt_string requested_version = version_request;
502   
503        at_head = false;
504           
505        module = "";
506
507        if (prefix != "")
508          {
509            module = prefix;
510            module += "/"; // This is for CVS only
511            module.replace_all ("//", "/");
512          }
513
514        module += package;
515
516          /**
517           *   Try to figure out what is the effective version tag available
518           *   for the requested version expressions (which may contain
519           *   wild card)
520           *
521           *     the requested version may either be in the top tags (ie those
522           *     corresponding to the same most recent CVS version number before
523           *     the HEAD) or not. The returned at_head flag will show this.
524           *
525           *     then the requested package may either be located in the CVS repository
526           *     under the prefix or not, the returned module will contain the effective
527           *     location where the requested version has been found.
528           */
529
530          //cout << " in get version : module=[" << module << "]" << endl;
531
532        show_cvs_infos (module);
533
534        if (error_info != "")
535          {
536            versions = "";
537            cout << "# Package " << package << " not found in ${CVSROOT}" << endl;
538            return (false);
539          }
540
541        versions = tags_top_info;
542
543        cmt_string v = version_request;
544
545        if (version_request.find ("*") != cmt_string::npos)
546          {
547            v.replace_all ("*", ".*");
548          }
549        else
550          {
551            v += "$";
552          }
553
554        if (m_cmtcvstest) cout << "##    (version expression is " << v << ")" << endl;
555
556        cmt_regexp version_exp (v);
557   
558        if (!match_version_request (versions, version_exp, version))
559          {
560            if (m_cmtcvstest) cout << "##    (no match in " << versions << ")" << endl;
561
562              // We try on non-top versions
563
564            versions = tags_info;
565
566            if (!match_version_request (versions, version_exp, version))
567              {
568                if (m_cmtcvstest) cout << "##    (no match in " << versions << ")" << endl;
569
570                version = requested_version;
571                int pos = 0;
572                if ((pos = version.find ("*")) != cmt_string::npos)
573                  {
574                      //
575                      //  There was a wild card but the expression does not match
576                      // any of the existing tags in CVS.
577                      //  Things will be retreived from HEAD but we have to build
578                      // a reasonable version tag from the wild card expression.
579                      //  If the letter before the * was a digit, then simply remove
580                      // the * (v5* -> v5) otherwise add a zero (v5r* -> v5r0)
581                      //
582                    if (pos > 0)
583                      {
584                        char letter = version[pos-1];
585
586                        static const cmt_string digits = "0123456789";
587
588                        if (digits.find (letter) == cmt_string::npos)
589                          {
590                              // "v5r*" -> "v5r0"
591                            version.replace ("*", "0");
592                          }
593                        else
594                          {
595                              // "v5*" -> "v5"
596                            version.replace ("*", "");
597                          }
598                      }
599                    else
600                      {
601                          // The expression was simply "*" !!!
602                        version = "v0";
603                      }
604                  }
605                at_head = true;
606              }
607            else
608              {
609                if (m_cmtcvstest) cout << "##    (match in non head " << versions << ")" << endl;
610
611                at_head = false;
612              }
613          }
614        else
615          {
616            if (m_cmtcvstest) cout << "##    (match in head " << versions << ")" << endl;
617
618            at_head = true;
619          }
620   
621          /**
622           *   Here we have at least one version matching the requested expression.
623           */
624   
625        return (true);
626      }
627
628  cmt_string build_version_directory (const cmt_string& prefix,
629                                      const cmt_string& package,
630                                      const cmt_string& version)
631      {
632        cmt_string dir = m_home_dir;
633
634        if (m_checkout_dir != "")
635          {
636            dir += CmtSystem::file_separator ();
637            dir += m_checkout_dir;
638          }
639
640        dir += CmtSystem::file_separator ();
641        dir += prefix;
642        dir += CmtSystem::file_separator ();
643        dir += package;
644
645        if (Cmt::get_current_structuring_style () == with_version_directory)
646          {
647            dir += CmtSystem::file_separator ();
648            dir += version;
649          }
650
651        {
652          cmt_string fs = CmtSystem::file_separator ();
653          cmt_string dfs = fs;
654          dfs += fs;
655
656          dir.replace_all (dfs, fs);
657        }
658
659        return (dir);
660      }
661
662  bool really_checkout_package (const cmt_string& prefix,
663                                const cmt_string& package,
664                                const cmt_string& version,
665                                const cmt_string& module,
666                                const cmt_string& basedir,
667                                bool at_head)
668      {
669        cmt_string dir = basedir;
670        cmt_string out;
671
672        cout << "# ================= working on package " << package
673             << " version " << version;
674
675        if (at_head) cout << " (At head) ";
676
677        {
678          cmt_string full_prefix;
679
680          full_prefix = m_offset;
681          full_prefix += prefix;
682
683          cmt_string echo_ppath;
684       
685          if (full_prefix != "")
686            {
687              echo_ppath = " path ";
688              echo_ppath += prefix;
689            }
690
691          cout << echo_ppath << endl;
692        }
693
694        CmtSystem::dirname (dir, dir);
695
696          //cout << "  #1> dir=" << dir << " pwd=" << CmtSystem::pwd () << endl;
697
698          //if (Cmt::get_current_structuring_style () == with_version_directory)
699          {
700            if (!CmtSystem::mkdir (dir))
701              {
702                cout << "# Error creating the base directory :" << dir << endl;
703                cout << "#---------------------------------------------------------" << endl;
704                return (false);
705              }
706
707            CmtSystem::cd (dir);
708          }
709
710            /*
711        cout << "  #2> pwd=" << CmtSystem::pwd ()
712             << " module=" << module
713             << endl;
714            */
715
716        cout << "  # get top files " << endl;
717           
718        cmt_string command = "cvs -Q co -P -l ";
719        if (!at_head)
720          {
721            command += "-r ";
722            command += version;
723          }
724
725        if (Cmt::get_current_structuring_style () == with_version_directory)
726          {
727            command += " -d ";
728            command += version;
729          }
730        else
731          {
732            command += " -d ";
733            command += package;
734          }
735
736        command += " ";
737        command += module;
738               
739        if (m_cmtcvstest)
740          {
741            cmt_string cvsroot;
742           
743            CmtSystem::get_cvsroot (cvsroot);
744           
745            cout << "## cvsroot=" << cvsroot << " command[" << command << "]" << endl;
746          }
747       
748        int status = CmtSystem::execute (command, out);
749       
750          //cout << "-> status = " << status << " out=[" << out << "]" << endl;
751       
752        if (Cmt::get_current_structuring_style () == with_version_directory)
753          {
754            if (!CmtSystem::cd (version))
755              {
756                CmtSystem::mkdir (version);
757                if (!CmtSystem::cd (version))
758                  {
759                    cout << "# Error creating the version directory :" << version << endl;
760                    cout << "#---------------------------------------------------------" << endl;
761                    return (false);
762                  }
763              }
764
765            dir += CmtSystem::file_separator ();
766            dir += version;
767          }
768        else
769          {
770            if (!CmtSystem::cd (package))
771              {
772                CmtSystem::mkdir (package);
773                if (!CmtSystem::cd (package))
774                  {
775                    cout << "# Error creating the package directory :" << package << endl;
776                    cout << "#---------------------------------------------------------" << endl;
777                    return (false);
778                  }
779              }
780
781            dir += CmtSystem::file_separator ();
782            dir += package;
783          }
784               
785        cmt_string file_name;
786        cmt_string text;
787       
788        cmt_string branches = CmtSystem::getenv ("CMTCVSBRANCHES");
789       
790        if (branches == "")
791          {
792            branches = branches_info;
793          }
794       
795        CmtSystem::cmt_string_vector branch_vector;
796       
797        CmtSystem::split (branches, " \t", branch_vector);
798       
799        int i;
800       
801        cout << "  # get branches " << branches << endl;
802       
803        command = "";
804       
805        file_name = "CVS";
806        file_name += CmtSystem::file_separator ();
807        file_name += "Entries";
808       
809        if (!text.read (file_name))
810          {
811              // This happens when there were no top files
812          }
813       
814        for (i = 0; i < branch_vector.size (); i++)
815          {
816            cmt_string& branch = branch_vector[i];
817           
818              //command += "cvs -Q co -P ";
819            command += "cvs -Q co ";
820           
821//            if (branch != "cmt")
822//              {
823            if (!at_head)
824              {
825                command += "-r ";
826                command += version;
827              }
828//              }
829           
830            command += " -d ";
831            command += branch;
832            command += " ";
833            command += module;
834            command += "/";    // CVS uses the '/' notation on all platforms!!
835            command += branch;
836            //command += "\n";
837            command += CmtSystem::command_separator ();
838           
839            text += "D/";
840            text += branch;
841            text += "////\n";
842          }
843       
844        if (m_cmtcvstest)
845          {
846            cmt_string cvsroot;
847           
848            CmtSystem::get_cvsroot (cvsroot);
849           
850            cout << " cvsroot=" << cvsroot << " command[" << command << "]" << endl;
851          }
852       
853        if (CmtSystem::execute (command, out) == 0)
854          {
855            cout << "# Error getting package contents:" << endl;
856            cout << out << endl;
857            cout << "#---------------------------------------------------------" << endl;
858          }
859        else
860          {
861            if (!CmtSystem::test_directory ("CVS"))
862              {
863                  /**
864                   * The CVS repository had not been created (this is generally
865                   * due to the lack of top files)
866                   */
867               
868                  //cout << "file_name=" << file_name << endl;
869               
870                CmtSystem::mkdir ("CVS");
871                cmt_string s;
872               
873                  // Let's create first the CVS/Root file.
874               
875                CmtSystem::get_cvsroot (s);
876                s += "\n";
877               
878                cmt_string f;
879               
880                f = "CVS";
881                f += CmtSystem::file_separator ();
882                f += "Root";
883               
884                  //cout << "f=" << f << " s=[" << s << "]" << endl;
885                s.write (f);
886               
887                  // Now we create the CVS/Repository file
888               
889                f = "CVS";
890                f += CmtSystem::file_separator ();
891                f += "Repository";
892               
893                CmtSystem::get_cvsroot (s);
894                if (s[0] == ':')
895                  {
896                    int pos = s.find (1, ":");
897                    s.erase (0, pos+1);
898                    pos = s.find (0, ":");
899                    s.erase (0, pos+1);
900                  }
901                s += "/";
902                s += module;
903                s += "\n";
904               
905                  //cout << "f=" << f << " s=[" << s << "]" << endl;
906                s.write (f);
907              }
908           
909              // Now the CVS/Entries is ready to be created.
910            text.write (file_name);
911          }
912
913        return (true);
914      }
915
916  cmt_string find_matching_version (const cmt_string& expression)
917      {
918        cmt_string result;
919
920          //
921          // Here expression takes the form
922          //   <some path>/<expression with wild-card>
923          //
924
925        cmt_string dir;
926        CmtSystem::dirname (expression, dir);
927        dir += CmtSystem::file_separator ();
928
929        cmt_string version;
930        CmtSystem::basename (expression, version);
931
932        if (version.find ("*") == cmt_string::npos)
933          {
934              // there is no wildcarding here. A simple test is enough.
935            if (CmtSystem::test_directory (expression))
936              {
937                if (m_cmtcvstest) cout << "## Found direct match with " << version << endl;
938                result = version;
939              }
940            else
941              {
942                if (m_cmtcvstest) cout << "## Explicit version " << version
943                                       << " has no direct match" << endl;
944              }
945          }
946        else
947          {
948            version.replace ("*", ".*");
949
950            cmt_regexp exp (version);
951
952            CmtSystem::cmt_string_vector list;
953
954            if (m_cmtcvstest) cout << "## Trying scan_dir dir=" << dir
955                                   << " exp=" << version << endl;
956
957            CmtSystem::scan_dir (dir, exp, list);
958
959            if (list.size () > 0)
960              {
961                result = list[0];
962
963                if (m_cmtcvstest) cout << "## At least one version is matching " << version
964                                       << "(" << list.size () << " matches) " << result << endl;
965
966                CmtSystem::basename (result, result);
967              }
968            else
969              {
970                if (m_cmtcvstest) cout << "## There is no version matching " << version << endl;
971              }
972          }
973
974        return (result);
975      }
976 
977  void checkout_package (const cmt_string& prefix,
978                         const cmt_string& package,
979                         const cmt_string& specified_version)
980      {
981          //cout << "checkout_package> prefix=" << prefix
982          //    << " package=" << package
983          //   << " specified_version=" << specified_version
984          //   << endl;
985
986        cmt_string version = specified_version;
987        cmt_string empty;
988        cmt_string full_prefix;
989
990        full_prefix = m_offset;
991        full_prefix += prefix;
992
993        cmt_string echo_ppath;
994       
995        if (full_prefix != "")
996          {
997            echo_ppath = " path ";
998            echo_ppath += prefix;
999          }
1000       
1001        if (version == "")
1002          {
1003            cout << "# ================= No version specified for package " << package << endl;
1004            return;
1005          }
1006
1007          //
1008          //  First make an attempt to locate the specified version of
1009          //  this package "as-it-is" in the work area.
1010          //   Since 'version' may contain wild-card, it's likely that
1011          //  we should not simply use CmtSystem::test_directory but
1012          //  use the wild-card search.
1013          //
1014
1015        cmt_string dir;
1016       
1017        dir = build_version_directory (prefix, package, version);
1018             
1019        if (m_cmtcvstest) 
1020          cout << "## (testing dir= " << dir << ")" << endl;
1021
1022        bool recursive = m_recursive;
1023
1024          /*
1025        if (m_cmtcvstest)
1026          {
1027            cmt_string v = find_matching_version (dir);
1028
1029            cout << "---> v=" << v << endl;
1030          }
1031          */
1032
1033          //if (CmtSystem::test_directory (dir))
1034
1035        cmt_string effective_version = find_matching_version (dir);
1036
1037        if (effective_version != "")
1038          {
1039            version = effective_version;
1040
1041            dir = build_version_directory (prefix, package, version);
1042
1043            cout << "# ================= Package " << package
1044                 << " version " << version << echo_ppath
1045                 << " already installed." << endl;
1046
1047            recursive = false;
1048          }
1049        else
1050          {
1051            bool at_head = false;
1052            cmt_string module;
1053
1054              //
1055              // get_version attempts to find the most appropriate version
1056              // tag matching the specification FROM the repository. However,
1057              // we should take into account situations where some versions have
1058              // already been checked out, in which case they might be sufficient
1059              // (or preferred?)
1060              //
1061
1062            if (version.find ("*") != cmt_string::npos)
1063              {
1064                cout << "# ================= Package " << package
1065                     << " version " << version << echo_ppath
1066                     << " has wild cards and will not be considered." << endl;
1067                return;
1068              }
1069
1070            if (!get_version (full_prefix, package, version, 
1071                              module, version, at_head))
1072              {
1073                return;
1074              }
1075
1076              //cout << " full_prefix=[" << full_prefix << "] module=[" << module << "]" << endl;
1077
1078            if (m_cmtcvstest) cout << "## after get_version at_head=" << at_head << " m_head=" << m_head << endl;
1079
1080            if (m_head)
1081              {
1082                m_head = false;
1083
1084                at_head = true;
1085              }
1086            else
1087              {
1088                at_head = false;
1089              }
1090
1091              //
1092              // Make a second try after having selected a version from all the
1093              // available versions compatible with the specified version
1094              //
1095
1096            dir = build_version_directory (prefix, package, version);
1097
1098            if (CmtSystem::test_directory (dir))
1099              {
1100                cout << "# ================= Package " << package
1101                     << " version " << version << echo_ppath
1102                     << " already installed." << endl;
1103
1104                recursive = false;
1105              }
1106            else
1107              {
1108                  //
1109                  // Now we can say that we have to perform the real checkout.
1110                  //
1111
1112                if (!really_checkout_package (prefix, package, version, module, dir, at_head))
1113                  {
1114                    cout << "# bad return from really_checkout_package" << endl;
1115                    return;
1116                  }
1117              }
1118          }
1119
1120          //
1121          //  Now reach the newly checked out package.
1122          //
1123
1124        CmtSystem::cd (dir);
1125
1126          // Check if it is a true CMT package.
1127
1128        cmt_string file_name;
1129
1130        file_name = "cmt";
1131        file_name += CmtSystem::file_separator ();
1132        file_name += "requirements";
1133
1134        if (CmtSystem::test_file (file_name))
1135          {
1136            dir += CmtSystem::file_separator ();
1137            dir += "cmt";
1138            CmtSystem::cd ("cmt");
1139
1140            if (Cmt::get_current_structuring_style () == without_version_directory)
1141              {
1142                cmt_string text = version;
1143                text += "\n";
1144                text.write ("version.cmt");
1145              }
1146          }
1147        else
1148          {
1149            file_name = "mgr";
1150            file_name += CmtSystem::file_separator ();
1151            file_name += "requirements";
1152           
1153            if (CmtSystem::test_file (file_name))
1154              {
1155                dir += CmtSystem::file_separator ();
1156                dir += "mgr";
1157                CmtSystem::cd ("mgr");
1158              }
1159            else
1160              {
1161                cout << "# " << package << " not a CMT package" << endl;
1162                return;
1163              }
1164          }
1165
1166          //cout << "#   (recursive is " << recursive << ")" << endl;
1167
1168        if (recursive)
1169          {
1170            checkout_from_requirements ("requirements");
1171          }
1172      }
1173
1174  /**
1175   *   We provide a path to a requirements file. From it we read the use
1176   *  statements, and we try to checkout the corresponding packages.
1177   */
1178  void checkout_from_requirements (const cmt_string& requirements_path)
1179  {
1180    static cmt_regexp expression ("^[ \t]*use[ \t]");
1181
1182    cmt_string text;
1183
1184    text.read (requirements_path);
1185
1186    RecursivePass1 p1;
1187    p1.run (text, expression);
1188
1189    RecursivePass2 p2 (*this);
1190    p2.run (p1.result ());
1191  }
1192
1193  void tags (const CmtSystem::cmt_string_vector& arguments)
1194      {
1195        if (arguments.size () < 1)
1196          {
1197            help ();
1198            return;
1199          }
1200       
1201        if (CmtSystem::getenv ("CVSROOT") == "")
1202          {
1203            cout << "# Please set CVSROOT first !" << endl;
1204            return;
1205          }
1206             
1207        if (CmtSystem::getenv ("CMTCVSTEST") != "")
1208          {
1209            m_cmtcvstest = true;
1210          }
1211        else
1212          {
1213            m_cmtcvstest = false;
1214          }
1215
1216        m_offset = CmtSystem::getenv ("CMTCVSOFFSET");
1217        if (m_offset != "") 
1218          {
1219            m_offset += "/";
1220            m_offset.replace_all ("//", "/");
1221          }
1222
1223        bool all = false;
1224       
1225        for (int arg = 0; arg < arguments.size (); arg++)
1226          {
1227            const cmt_string& option = arguments[arg];
1228
1229            if (option == "-all")
1230              {
1231                all = true;
1232              }
1233            else
1234              {
1235                show_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), option);
1236
1237                if (error_info != "")
1238                  {
1239                    cout << error_info << endl;
1240                  }
1241                else
1242                  {
1243                    cmt_string tags;
1244
1245                    if (all)
1246                      {
1247                        tags = cvsversions_top_info;
1248                        tags += " ";
1249                        tags += cvsversions_info;
1250                      }
1251                    else
1252                      {
1253                        tags = tags_top_info;
1254                        tags += " ";
1255                        tags += tags_info;
1256                      }
1257
1258                    CmtSystem::cmt_string_vector v;
1259
1260                    CmtSystem::split (tags, " \t", v);
1261                    for (int i = 0; i < v.size (); i++)
1262                      {
1263                        const cmt_string& s = v[i];
1264                        cout << s << endl;
1265                      }
1266                  }
1267              }
1268          }
1269      }
1270
1271  void branches (const cmt_string& module)
1272      {
1273        cmt_string out;
1274
1275        show_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), module);
1276
1277        if (error_info != "")
1278          {
1279            cout << error_info << endl;
1280          }
1281        else
1282          {
1283            cout << branches_info << endl;
1284          }
1285      }
1286
1287  void subpackages (const cmt_string& module)
1288      {
1289        cmt_string out;
1290
1291        show_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), module);
1292
1293        if (error_info != "")
1294          {
1295            cout << error_info << endl;
1296          }
1297        else
1298          {
1299            cout << subpackages_info << endl;
1300          }
1301      }
1302
1303  void help ()
1304      {
1305        cout << "> cd <some work area>" << endl;
1306        cout << "> cmt checkout [modifier ...] <package>" << endl;
1307        cout << "" << endl;
1308        cout << "   modifier :" << endl;
1309        cout << "   -l        Do not process used packages (default)." << endl;
1310        cout << "   -R        Process used packages recursively." << endl;
1311        cout << "   -r rev    Check out version tag. (is sticky)" << endl;
1312        cout << "   -d dir    Check out into dir instead of module name." << endl;
1313        cout << "   -o offset Offset in the CVS repository" << endl;
1314        cout << "   -requirements <requirements file path>  Check out packages referenced in this requirements file" << endl;
1315          //cout << "   -n        simulation mode on" << endl;
1316          //cout << "   -v        verbose mode on" << endl;
1317        cout << "   --help    print this help" << endl;
1318        cout << "" << endl;
1319      }
1320
1321  void do_checkout (const cmt_string& module, const cmt_string& version_tag)
1322  {
1323    //CMTPATH=${CMTPATH}:${m_home_dir}; export CMTPATH
1324
1325    History& h = History::instance ();
1326
1327    h.clear ();
1328
1329    if (module == "") return;
1330
1331    cmt_string prefix;
1332    cmt_string package;
1333    cmt_string version;
1334   
1335    if (version_tag == "")
1336      {
1337        Cut cut (0);
1338       
1339        cmt_string m;
1340        m = m_offset;
1341        m += module;
1342       
1343        show_cvs_infos (m);
1344       
1345        if (error_info != "")
1346          {
1347            cout << error_info << endl;
1348            return;
1349          }
1350
1351        if (tags_top_info != "") version = tags_top_info;
1352        else version = tags_info;
1353       
1354          //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "version=" << version << endl;
1355
1356        cut.run (version);
1357       
1358        version = cut.result ();
1359
1360          //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "version=" << version << endl;
1361      }
1362    else
1363      {
1364        version = version_tag;
1365      }
1366   
1367    CmtSystem::dirname (module, prefix);
1368    CmtSystem::basename (module, package);
1369   
1370    cmt_string top_dir;
1371       
1372    top_dir = m_home_dir;
1373    top_dir += CmtSystem::file_separator ();
1374    top_dir += m_checkout_dir;
1375    top_dir += CmtSystem::file_separator ();
1376    top_dir += prefix;
1377    top_dir += CmtSystem::file_separator ();
1378    top_dir += package;
1379    top_dir += CmtSystem::file_separator ();
1380    top_dir += version;
1381   
1382    checkout_package (prefix, package, version);
1383   
1384    //cout << "after checkout_package pwd=[" << CmtSystem::pwd () << "] top_dir=[" << top_dir << "]" << endl;
1385   
1386    if (!CmtSystem::cd (top_dir)) return;
1387   
1388    cmt_string file_name;
1389   
1390    file_name = "cmt";
1391    file_name += CmtSystem::file_separator ();
1392    file_name += "requirements";
1393   
1394    if (CmtSystem::test_file (file_name))
1395      {
1396        top_dir += CmtSystem::file_separator ();
1397        top_dir += "cmt";
1398        CmtSystem::cd ("cmt");
1399      }
1400    else
1401      {
1402        file_name = "mgr";
1403        file_name += CmtSystem::file_separator ();
1404        file_name += "requirements";
1405       
1406        if (CmtSystem::test_file (file_name))
1407          {
1408            top_dir += CmtSystem::file_separator ();
1409            top_dir += "mgr";
1410            CmtSystem::cd ("mgr");
1411          }
1412        else
1413          {
1414            cout << "# " << package << "not a CMT package" << endl;
1415            return;
1416          }
1417      }
1418   
1419    //cout << "end of checkout pwd=[" << CmtSystem::pwd () << "]" << endl;
1420   
1421    if (m_recursive)
1422      {
1423        CmtSystem::execute ("cmt broadcast cmt config");
1424      }
1425    else
1426      {
1427        CmtSystem::execute ("cmt config");
1428      }
1429  }
1430
1431  void checkout (const CmtSystem::cmt_string_vector& arguments)
1432      {
1433        if (arguments.size () < 1)
1434          {
1435            help ();
1436            return;
1437          }
1438       
1439        if (CmtSystem::getenv ("CVSROOT") == "")
1440          {
1441            cout << "# Please set CVSROOT first !" << endl;
1442            return;
1443          }
1444             
1445        if (CmtSystem::getenv ("CMTCVSTEST") != "")
1446          {
1447            m_cmtcvstest = true;
1448          }
1449        else
1450          {
1451            m_cmtcvstest = false;
1452          }
1453
1454        m_home_dir = CmtSystem::pwd ();
1455        m_checkout_dir = "";
1456        m_offset = "";
1457        m_branch_suffix = "";
1458
1459        cmt_string module;
1460             
1461        m_recursive = false;
1462
1463        bool need_version_tag = false;
1464        cmt_string version_tag;
1465
1466        bool need_checkout_dir = false;
1467        bool need_offset = false;
1468        bool need_requirements_file = false;
1469
1470        bool simulation = false;
1471        bool verbose = false;
1472
1473        bool need_branch_suffix = false;
1474
1475        m_head = true;
1476
1477        m_offset = CmtSystem::getenv ("CMTCVSOFFSET");
1478        if (m_offset != "") 
1479          {
1480            m_offset += "/";
1481            m_offset.replace_all ("//", "/");
1482          }
1483
1484        for (int arg = 0; arg < arguments.size (); arg++)
1485          {
1486            const cmt_string& option = arguments[arg];
1487
1488            if (need_version_tag)
1489              {
1490                need_version_tag = false;
1491
1492                if (option == "HEAD")
1493                  {
1494                    m_head = true;
1495                  }
1496                else
1497                  {
1498                    version_tag = option;
1499                  }
1500              }
1501            else if (need_checkout_dir)
1502              {
1503                need_checkout_dir = false;
1504                m_checkout_dir = option;
1505              }
1506            else if (need_offset)
1507              {
1508                need_offset = false;
1509                m_offset = option;
1510                m_offset += '/';
1511                m_offset.replace_all ("//", "/");
1512              }
1513            else if (need_branch_suffix)
1514              {
1515                need_branch_suffix = false;
1516                m_branch_suffix = "-";
1517                m_branch_suffix += option;
1518              }
1519            else if (need_requirements_file)
1520              {
1521                need_requirements_file = false;
1522                m_head = false;
1523                checkout_from_requirements (option);
1524              }
1525            else
1526              {
1527                if (option == "-R")
1528                  {
1529                    m_recursive = true;
1530                  }
1531                else if (option == "-l")
1532                  {
1533                    m_recursive = false;
1534                  }
1535                else if (option == "-r")
1536                  {
1537                    need_version_tag = true;
1538                    m_head = false;
1539                  }
1540                else if (option == "-d")
1541                  {
1542                    need_checkout_dir = true;
1543                  }
1544                else if (option == "-o")
1545                  {
1546                    need_offset = true;
1547                  }
1548                else if (option == "-n")
1549                  {
1550                    simulation = true;
1551                    verbose = true;
1552                  }
1553                else if (option == "-v")
1554                  {
1555                    verbose = true;
1556                  }
1557                else if (option == "-branch")
1558                  {
1559                    need_branch_suffix = true;
1560                  }
1561                else if (option == "-requirements")
1562                  {
1563                    need_requirements_file = true;
1564                  }
1565                else if (option == "--help")
1566                  {
1567                    help ();
1568                    return;
1569                  }
1570                else if (option[0] == '-')
1571                  {
1572                    help ();
1573                    return;
1574                  }
1575                else
1576                  {
1577                    do_checkout (option, version_tag);
1578                  }
1579              }
1580          }
1581
1582      }
1583
1584private:
1585
1586  bool m_recursive;
1587  bool m_head;
1588  bool m_cmtcvstest;
1589
1590  cmt_string m_home_dir;
1591  cmt_string m_checkout_dir;
1592  cmt_string m_offset;
1593  cmt_string m_branch_suffix;
1594
1595  cmt_string error_info;
1596  cmt_string tags_top_info;
1597  cmt_string tags_info;
1598  cmt_string cvsversions_top_info;
1599  cmt_string cvsversions_info;
1600  cmt_string branches_info;
1601  cmt_string subpackages_info;
1602};
1603
1604//--------------------------------------------------------------------
1605
1606void Grep::begin ()
1607{
1608  m_result = "";
1609}
1610
1611void Grep::filter (const cmt_string& line)
1612{
1613    //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "Grep::filter" << endl;
1614
1615  if (m_result != "") m_result += " ";
1616  m_result += line;
1617}
1618
1619const cmt_string& Grep::result () const
1620{
1621  return (m_result);
1622}
1623
1624//--------------------------------------------------------------------
1625
1626Cut::Cut (int field)
1627{
1628  m_field = field;
1629}
1630
1631void Cut::begin ()
1632{
1633    //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "Cut::begin" << endl;
1634  m_result = "";
1635}
1636
1637void Cut::filter (const cmt_string& line)
1638{
1639    //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "Cut::filter" << endl;
1640
1641  static CmtSystem::cmt_string_vector words;
1642 
1643  CmtSystem::split (line, " \t", words);
1644 
1645  if (words.size () <= m_field) return;
1646 
1647  if (m_result != "") m_result += " ";
1648  m_result += words[m_field];
1649}
1650
1651const cmt_string& Cut::result () const
1652{
1653  return (m_result);
1654}
1655
1656//--------------------------------------------------------------------
1657//--------------------------------------------------------------------
1658
1659History& History::instance ()
1660{
1661  static History h;
1662  return (h);
1663}
1664
1665void History::clear ()
1666{
1667  m_installed = "";
1668}
1669
1670void History::install (const cmt_string& line)
1671{
1672  m_installed += "|";
1673  m_installed += line;
1674  m_installed += "|";
1675}
1676
1677bool History::is_installed (const cmt_string& line)
1678{
1679  if (m_installed.find (line) != cmt_string::npos)
1680    {
1681      return (true);
1682    }
1683 
1684  return (false);
1685}
1686
1687History::History ()
1688{
1689}
1690
1691
1692//--------------------------------------------------------------------
1693
1694void RecursivePass1::begin ()
1695{
1696  m_first = true;
1697  m_result = "";
1698}
1699
1700void RecursivePass1::filter (const cmt_string& line)
1701{
1702    //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "RecursivePass1::filter> "
1703    //                                          << "line=[" << line << "]" << endl;
1704
1705  if (line.find ("use CMT") != cmt_string::npos) return;
1706  if (line.find ("use cmt") != cmt_string::npos) return;
1707 
1708  History& h = History::instance ();
1709 
1710  if (h.is_installed (line)) return;
1711 
1712  CmtSystem::cmt_string_vector words;
1713 
1714  CmtSystem::split (line, " \t", words);
1715
1716  enum
1717  {
1718    need_package,
1719    need_version,
1720    need_path,
1721    no_need
1722  } state = need_package;
1723
1724  cmt_string package;
1725  cmt_string version;
1726  cmt_string path;
1727
1728  for (int i = 1; i < words.size (); i++)
1729    {
1730      const cmt_string& s = words[i];
1731
1732      if (s[0] == '-') continue;
1733
1734      switch (state)
1735        {
1736          case need_package:
1737            package = s;
1738            state = need_version;
1739            break;
1740          case need_version:
1741            version = s;
1742            state = need_path;
1743            break;
1744          case need_path:
1745            path = s;
1746            state = no_need;
1747            break;
1748        }
1749    }
1750 
1751  if (version.find ("*") != cmt_string::npos)
1752    {
1753        /*
1754      cout << "# ================= Package " << package
1755           << " version " << version << " " << path
1756           << " has wild cards and will not be considered." << endl;
1757        */
1758      return;
1759    }
1760
1761  /**
1762   *  At the first pass, we simply accumulate the not-yet handled
1763   *  use statements.
1764   */
1765 
1766  m_result += line;
1767  m_result += "\n";
1768 
1769  if (m_first)
1770    {
1771      m_first = false;
1772      cout << "  # --> now propagate cmt checkout to :" << endl;
1773    }
1774 
1775  cout << "  #     " << package << " " << version << " " << path << endl;
1776}
1777
1778const cmt_string& RecursivePass1::result () const
1779{
1780  return (m_result);
1781}
1782
1783//--------------------------------------------------------------------
1784
1785RecursivePass2::RecursivePass2 (CvsImplementation& cvs) : m_cvs (cvs)
1786{
1787}
1788
1789void RecursivePass2::begin ()
1790{
1791}
1792
1793void RecursivePass2::filter (const cmt_string& line)
1794{
1795    //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "RecursivePass2::filter> "
1796    //                                          << "line=[" << line << "]" << endl;
1797
1798  /**
1799   *   At the second pass, the lines are really handled. Thus
1800   *   the lines are stored into m_installed so as to avoid
1801   *   later on re-installation.
1802   */
1803 
1804  History& h = History::instance ();
1805 
1806  if (h.is_installed (line)) return;
1807 
1808  h.install (line);
1809 
1810  CmtSystem::cmt_string_vector words;
1811 
1812  CmtSystem::split (line, " \t", words);
1813
1814  enum
1815  {
1816    need_package,
1817    need_version,
1818    need_path,
1819    no_need
1820  } state = need_package;
1821
1822  cmt_string package;
1823  cmt_string version;
1824  cmt_string path;
1825
1826  for (int i = 1; i < words.size (); i++)
1827    {
1828      const cmt_string& s = words[i];
1829
1830      if (s[0] == '-') continue;
1831
1832      switch (state)
1833        {
1834          case need_package:
1835            package = s;
1836            state = need_version;
1837            break;
1838          case need_version:
1839            version = s;
1840            state = need_path;
1841            break;
1842          case need_path:
1843            path = s;
1844            state = no_need;
1845            break;
1846        }
1847    }
1848
1849  if (version.find ("*") != cmt_string::npos)
1850    {
1851        /*
1852      cout << "# ================= Package " << package
1853           << " version " << version << " " << path
1854           << " has wild cards and will not be considered." << endl;
1855        */
1856    }
1857  else
1858    {
1859      m_cvs.checkout_package (path, package, version);
1860    }
1861}
1862
1863//--------------------------------------------------------------------
1864
1865void Cvs::tags (const CmtSystem::cmt_string_vector& arguments)
1866{
1867  CvsImplementation cvs;
1868
1869  cvs.tags (arguments);
1870}
1871
1872void Cvs::branches (const cmt_string& module)
1873{
1874  CvsImplementation cvs;
1875
1876  cvs.branches (module);
1877}
1878
1879void Cvs::subpackages (const cmt_string& module)
1880{
1881  CvsImplementation cvs;
1882
1883  cvs.subpackages (module);
1884}
1885
1886void Cvs::checkout (const CmtSystem::cmt_string_vector& arguments)
1887{
1888  CvsImplementation cvs;
1889
1890  cvs.checkout (arguments);
1891}
1892
Note: See TracBrowser for help on using the repository browser.