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