//----------------------------------------------------------- // Copyright Christian Arnault LAL-Orsay CNRS // arnault@lal.in2p3.fr // See the complete license in cmt_license.txt "http://www.cecill.info". //----------------------------------------------------------- #include #include #include "cmt.h" #include "cmt_cvs.h" #include "cmt_awk.h" /** Grep : perform a grep like operation onto a cmt_string o All lines of the input string are collected when they contain the specified pattern. o The input string and the selector pattern are specified in the constructor: Grep (input_string, pattern) o All selected lines are accumulated (appended) into the internal variable m_result . 'space' is the separator. o The accumulator is retrieved by the result () method. */ class Grep : public Awk { public: void begin (); void filter (const cmt_string& line); const cmt_string& result () const; private: cmt_string m_result; }; /** Cut : perform a cut-like operation : o collect the 'th field of every line into the m_result internal variable o the field number is given in the constructor and starts at zero. o selected fields are accumulated with a space as separator. */ class Cut : public Awk { public: Cut (int field); void begin (); void filter (const cmt_string& line); const cmt_string& result () const; private: cmt_string m_result; int m_field; }; /** History : maintains the history of checkout packages during a recursive checkout, so as to avoid double checkouts. */ class History { public: static History& instance (); void clear (); void install (const cmt_string& line); bool is_installed (const cmt_string& line); private: History (); cmt_string m_installed; }; /** RecursivePass1 : simply validate use statements in a requirements file and echo those that really need to be handled. */ class RecursivePass1 : public Awk { public: void begin (); void filter (const cmt_string& line); const cmt_string& result () const; private: cmt_string m_result; bool m_first; }; /** RecursivePass2 : after filtering the use statements really perform the checkouts. */ class CvsImplementation; class RecursivePass2 : public Awk { public: RecursivePass2 (CvsImplementation& cvs); void begin (); void filter (const cmt_string& line); private: CvsImplementation& m_cvs; }; /** Internal implementation of CVS to CMT operations. The Cvs class only provides abstract interface. */ class CvsImplementation { public: CvsImplementation () { m_recursive = false; m_head = false; m_cmtcvstest = false; m_verbose = false; m_simulation = false; m_home_dir = ""; m_checkout_dir = ""; m_offset = ""; m_branch_suffix = ""; m_last_module = ""; m_last_cvs_infos = ""; error_info = ""; tags_top_info = ""; tags_info = ""; cvsversions_top_info = ""; cvsversions_info = ""; branches_info = ""; subpackages_info = ""; } void filter_list (cmt_string& text, const cmt_regexp& exp) { CmtSystem::cmt_string_vector list; CmtSystem::split (text, " ", list); int i; text = ""; for (i = 0; i < list.size (); i++) { const cmt_string& s = list[i]; if (exp.match (s)) { if (i > 0) text += " "; text += s; } } } // // This method exploits the hook installed into the loginfo script. // A communication is setup with a dummy CVS module named .cmtcvsinfos/ // // At import time, the contents of the file will be used to parameterize // the script named cmt_buildcvsinfos2.sh (referenced in the loginfo script) // // This script performs a scan in the CVS repository for currently 4 types of // information : // // all top symbolic tags installed for the module // all symbolic tags installed for the module // all branches available below this module // all subpackages installed below the module. // // In principle, only modules corresponding to true CMT packages are considered. // o tags are obtained from the requirements file // o branches are sub-directories which are not themselves packages // o subpackages are sub-directories which are CMT packages // (a subdirectory is always either a branch or a subpackage) // void show_cvs_infos (const cmt_string& module) { if (module == "") { cout << "#CMT> cmt cvs needs a module name" << endl; return; } if (module == m_last_module) { if (m_verbose) { cout << "#CMT> cvs infos for module " << module << " already there" << endl; } } else { m_last_module = module; cmt_string home_dir = CmtSystem::pwd (); // // Activities related with .cmtcvsinfos will occur in a temporary directory // cmt_string tmp_dir = CmtSystem::getenv ("TMPDIR"); if (tmp_dir == "") { tmp_dir = CmtSystem::file_separator (); tmp_dir += "tmp"; } if (!CmtSystem::cd (tmp_dir)) { tmp_dir = home_dir; } tmp_dir += CmtSystem::file_separator (); tmp_dir += "cmtcvs"; { cmt_string temp = CmtSystem::get_temporary_name (); CmtSystem::basename (temp, temp); tmp_dir += temp; } if (!CmtSystem::test_directory (tmp_dir)) { if (!CmtSystem::mkdir (tmp_dir)) { cout << "#CMT> Cannot create the temporary directory [" << tmp_dir << "]" << endl; return; } } //trap "rm -rf ${tmp_dir}" 0 1 2 15 if (!CmtSystem::cd (tmp_dir)) { cout << "#CMT> Cannot move to the temporary directory " << tmp_dir << endl; if (m_verbose) { cout << "#CMT> now removing tmp_dir " << tmp_dir << " home=" << home_dir << endl; } CmtSystem::remove_directory (tmp_dir); return; } if (m_verbose) { cout << "#CMT> cvs infos are now obtained from the temporary directory " << CmtSystem::pwd () << endl; } /* # # The script associated to such entries is supposed to : # 1) extract the set of from the ${module}/cmt/requirements file # 2) build an output of the form : # =info1 info2 info3 ... # # Currently this script can be found in # # ${CMTROOT}/cmt/cmt_buildcvsinfos2.sh # %CMTROOT%/cmt/cmt_buildcvsinfos.py # */ if (!CmtSystem::test_directory (".cmtcvsinfos")) { CmtSystem::mkdir (".cmtcvsinfos"); } CmtSystem::cd (".cmtcvsinfos"); cmt_string cvsroot; CmtSystem::get_cvsroot (cvsroot); cmt_string command; command = "cvs"; if (cvsroot != "") { command += " -d "; command += cvsroot; } command += " -Q import -m cmt "; if (m_cmtcvstest) { command += ".cmtcvsinfos/cmtcvstest"; } else { command += ".cmtcvsinfos"; } command += "/"; command += module; command += " CMT v1"; if (m_verbose || m_simulation) { cout << "#CMT> Executing [" << command << "]" << endl; } m_last_cvs_infos = ""; CmtSystem::execute (command, m_last_cvs_infos); if (m_verbose) { cout << "#CMT> now removing tmp_dir " << tmp_dir << " home=" << home_dir << endl; } CmtSystem::remove_directory (tmp_dir); CmtSystem::cd (home_dir); } /** Now retrieve all info fields : error= tags_top= tags= branches= subpackages= */ Grep grep; grep.run (m_last_cvs_infos, "error="); if (grep.result () != "") { error_info = grep.result (); error_info.replace ("error=", ""); } else { error_info = ""; } grep.run (m_last_cvs_infos, "tags_top="); if (grep.result () != "") { tags_top_info = grep.result (); tags_top_info.replace ("tags_top=", ""); } else { tags_top_info = ""; } grep.run (m_last_cvs_infos, "tags="); if (grep.result () != "") { tags_info = grep.result (); tags_info.replace ("tags=", ""); } else { tags_info = ""; } grep.run (m_last_cvs_infos, "cvsversions_top="); if (grep.result () != "") { cvsversions_top_info = grep.result (); cvsversions_top_info.replace ("cvsversions_top=", ""); } else { cvsversions_top_info = ""; } grep.run (m_last_cvs_infos, "cvsversions="); if (grep.result () != "") { cvsversions_info = grep.result (); cvsversions_info.replace ("cvsversions=", ""); } else { cvsversions_info = ""; } cmt_string tag_filter = CmtSystem::getenv ("CMTCVSTAGFILTER"); if (tag_filter != "") { cmt_string package; CmtSystem::basename (module, package); cmt_string pattern = ""; tag_filter.replace_all (pattern, package); cmt_regexp exp (tag_filter); cmt_string text; filter_list (tags_top_info, exp); filter_list (tags_info, exp); filter_list (cvsversions_top_info, exp); filter_list (cvsversions_info, exp); } if (m_cmtcvstest) { cout << "## tags_top_info=" << tags_top_info << endl; cout << "## tags_info=" << tags_info << endl; cout << "## cvsversions_top_info=" << cvsversions_top_info << endl; cout << "## cvsversions_info=" << cvsversions_info << endl; } grep.run (m_last_cvs_infos, "branches="); if (grep.result () != "") { branches_info = grep.result (); branches_info.replace ("branches=", ""); } else { branches_info = ""; } grep.run (m_last_cvs_infos, "subpackages="); if (grep.result () != "") { subpackages_info = grep.result (); subpackages_info.replace ("subpackages=", ""); } else { subpackages_info = ""; } } void show_cvs_infos (const cmt_string& offset, const cmt_string& module) { cmt_string full_name; if (offset != "") { full_name = offset; full_name += "/"; while (full_name.find ("//") != cmt_string::npos) { full_name.replace_all ("//", "/"); } } full_name += module; show_cvs_infos (full_name); } // // Resolve all possible "aaa/bbb/../ccc/ddd" patterns into "aaa/ccc/ddd" // void filter_dir (cmt_string& d) { while (true) { int pos = d.find ("/../"); if (pos == cmt_string::npos) break; int slash = d.find ("/"); if (slash < pos) { // // xxxxx/yyy/../zzzz -> xxxxx/zzzz // 01234567890123456 // 1234567 // pos = 9 // slash = 5 // length = 9+3-5 // d.erase (slash + 1, pos + 3 - slash); } else { // // yyy/../zzzz -> zzzz // 01234567890 // 1234567 // pos = 3 // length = 3+1+3 // d.erase (0, pos + 1 + 3); } } } /** From a space-separated list of version tags, try to find one tag matching a given regular expression. o The first matching tag is returned into 'version' o Success is returned as function value. */ bool match_version_request (const cmt_string& text, const cmt_regexp& version_exp, cmt_string& version) { CmtSystem::cmt_string_vector vs; CmtSystem::split (text, " \t", vs); version = ""; for (int i = 0; i < vs.size (); i++) { const cmt_string& vv = vs[i]; if (version_exp.match (vv)) { version = vv; return (true); } } return (false); } bool get_version (const cmt_string& prefix, const cmt_string& package, const cmt_string& version_request, cmt_string& module, cmt_string& version, bool& at_head) { Grep grep; cmt_string topversions; cmt_string versions; cmt_string requested_version = version_request; at_head = false; module = ""; if (prefix != "") { module = prefix; module += "/"; // This is for CVS only thus we don't use the real separator. while (module.find ("//") != cmt_string::npos) { module.replace_all ("//", "/"); } } module += package; /** * Try to figure out what is the effective version tag available * for the requested version expressions (which may contain * wild card) * * the requested version may either be in the top tags (ie those * corresponding to the same most recent CVS version number before * the HEAD) or not. The returned at_head flag will show this. * * then the requested package may either be located in the CVS repository * under the prefix or not, the returned module will contain the effective * location where the requested version has been found. */ if (m_verbose) { cout << "#CMT> requesting cvs infos onto module " << module << endl; } show_cvs_infos (module); if (error_info != "") { versions = ""; cout << "#CMT> Package " << package << " not found in ${CVSROOT}" << endl; return (false); } versions = tags_top_info; cmt_string v = version_request; if (version_request.find ("*") != cmt_string::npos) { v.replace_all ("*", ".*"); } else { v += "$"; } if (m_cmtcvstest) cout << "## (version expression is " << v << ")" << endl; cmt_regexp version_exp (v); if (!match_version_request (versions, version_exp, version)) { if (m_cmtcvstest) cout << "## (no match in " << versions << ")" << endl; // We try on non-top versions versions = tags_info; if (!match_version_request (versions, version_exp, version)) { if (m_cmtcvstest) cout << "## (no match in " << versions << ")" << endl; version = requested_version; int pos = 0; if ((pos = version.find ("*")) != cmt_string::npos) { // // There was a wild card but the expression does not match // any of the existing tags in CVS. // Things will be retreived from HEAD but we have to build // a reasonable version tag from the wild card expression. // If the letter before the * was a digit, then simply remove // the * (v5* -> v5) otherwise add a zero (v5r* -> v5r0) // if (pos > 0) { char letter = version[pos-1]; static const cmt_string digits = "0123456789"; if (digits.find (letter) == cmt_string::npos) { // "v5r*" -> "v5r0" version.replace ("*", "0"); } else { // "v5*" -> "v5" version.replace ("*", ""); } } else { // The expression was simply "*" !!! version = "v0"; } } at_head = true; } else { if (m_cmtcvstest) cout << "## (match in non head " << versions << ")" << endl; at_head = false; } } else { if (m_cmtcvstest) cout << "## (match in head " << versions << ")" << endl; at_head = true; } /** * Here we have at least one version matching the requested expression. */ return (true); } cmt_string build_version_directory (const cmt_string& prefix, const cmt_string& package, const cmt_string& version) { cmt_string dir = m_home_dir; if (m_checkout_dir != "") { dir += CmtSystem::file_separator (); dir += m_checkout_dir; } dir += CmtSystem::file_separator (); dir += prefix; dir += CmtSystem::file_separator (); dir += package; if (Cmt::get_current_structuring_style () == with_version_directory) { dir += CmtSystem::file_separator (); dir += version; } CmtSystem::reduce_file_separators (dir); return (dir); } bool really_checkout_package (const cmt_string& prefix, const cmt_string& package, const cmt_string& version, const cmt_string& module, const cmt_string& basedir, bool at_head) { cmt_string dir = basedir; cmt_string out; cout << "# ================= working on package " << package << " version " << version; if (at_head) cout << " (At head) "; { cmt_string full_prefix; full_prefix = m_offset; full_prefix += prefix; cmt_string echo_ppath; if (prefix != "") { echo_ppath = " path "; echo_ppath += prefix; } cout << echo_ppath << endl; } CmtSystem::dirname (dir, dir); //if (Cmt::get_current_structuring_style () == with_version_directory) { if (m_simulation) { cout << "#CMT> Would mkdir " << dir << endl; } else { if (m_verbose) { cout << "#CMT> About to mkdir " << dir << endl; } if (!CmtSystem::mkdir (dir)) { cout << "# Error creating the base directory :" << dir << endl; cout << "#---------------------------------------------------------" << endl; return (false); } CmtSystem::cd (dir); /* if (m_verbose) { cout << "#CMT> pwd.1=" << CmtSystem::pwd () << endl; } */ } } cout << " # get top files " << endl; cmt_string command = "cvs -Q co -P -l "; if (!at_head) { command += "-r "; command += version; } if (Cmt::get_current_structuring_style () == with_version_directory) { command += " -d "; command += version; } else { command += " -d "; command += package; } command += " "; command += module; if (m_cmtcvstest) { cmt_string cvsroot; CmtSystem::get_cvsroot (cvsroot); cout << "## cvsroot=" << cvsroot << " command[" << command << "]" << endl; } int status = 0; int retry = 0; for (;;) { if (m_verbose || m_simulation) { cout << "#CMT> Executing [" << command << "]" << endl; } if (!m_simulation) { //status = CmtSystem::execute (command, out); status = CmtSystem::execute (command); } if (status != 0) { retry++; cout << "# Error getting package CMT contents: status=" << status << endl; cout << "#---------------------------------------------------------" << endl; if (retry > 5) exit(0); } else { break; } } { if (Cmt::get_current_structuring_style () == with_version_directory) { if (m_simulation) { cout << "#CMT> Would mkdir " << version << endl; } else { if (m_verbose) { cout << "#CMT> About to mkdir " << version << endl; } if (!CmtSystem::cd (version)) { CmtSystem::mkdir (version); if (!CmtSystem::cd (version)) { cout << "# Error creating the version directory :" << version << endl; cout << "#---------------------------------------------------------" << endl; return (false); } } /* if (m_verbose) { cout << "#CMT> pwd.2=" << CmtSystem::pwd () << endl; } */ } dir += CmtSystem::file_separator (); dir += version; } else { if (m_simulation) { cout << "#CMT> will mkdir " << package << endl; } else { if (!CmtSystem::cd (package)) { if (m_verbose) { cout << "#CMT> About to mkdir " << package << endl; } CmtSystem::mkdir (package); if (!CmtSystem::cd (package)) { cout << "# Error creating the package directory :" << package << endl; cout << "#---------------------------------------------------------" << endl; return (false); } } /* if (m_verbose) { cout << "#CMT> pwd.3=" << CmtSystem::pwd () << endl; } */ } dir += CmtSystem::file_separator (); dir += package; } } cmt_string entries_file_name; cmt_string text; cmt_string branches = CmtSystem::getenv ("CMTCVSBRANCHES"); if (branches == "") { branches = branches_info; } CmtSystem::cmt_string_vector branch_vector; CmtSystem::split (branches, " \t", branch_vector); int i; cout << " # get branches " << branches << endl; //command = "("; command = ""; entries_file_name = "CVS"; entries_file_name += CmtSystem::file_separator (); entries_file_name += "Entries"; if (!text.read (entries_file_name)) { // This happens when there were no top files } for (i = 0; i < branch_vector.size (); i++) { cmt_string& branch = branch_vector[i]; if (i > 0) { command += CmtSystem::command_separator (); } //command += "cvs -Q co -P "; command += "cvs -Q co "; // if (branch != "cmt") // { if (!at_head) { command += "-r "; command += version; } // } command += " -d "; command += branch; command += " "; command += module; command += "/"; // CVS uses the '/' notation on all platforms!! command += branch; //command += "\n"; text += "D/"; text += branch; text += "////\n"; } //command += "; echo cmtcvsstatus=$?) 2>&1 "; if (m_cmtcvstest) { cmt_string cvsroot; CmtSystem::get_cvsroot (cvsroot); cout << " cvsroot=" << cvsroot << " command[" << command << "]" << endl; } status = 0; retry = 0; for (;;) { if (m_verbose || m_simulation) { cout << "#CMT> Executing [" << command << "]" << endl; } if (!m_simulation) { //status = CmtSystem::execute (command, out); status = CmtSystem::execute (command); } if (status != 0) { retry++; cout << "# Error getting package contents: status=" << status << endl; cout << "#---------------------------------------------------------" << endl; if (retry > 5) exit(0); } else { break; } } { if (!CmtSystem::test_directory ("CVS")) { /** * The CVS repository had not been created (this is generally * due to the lack of top files) */ if (m_simulation) { cout << "#CMT> Would create the CVS directory" << endl; } else { if (m_verbose) { cout << "#CMT> About to mkdir " << "CVS" << endl; } CmtSystem::mkdir ("CVS"); } cmt_string s; // Let's create first the CVS/Root file. CmtSystem::get_cvsroot (s); s += "\n"; cmt_string f; f = "CVS"; f += CmtSystem::file_separator (); f += "Root"; if (m_simulation) { cout << "#CMT> Would fill in the CVS/Root file with " << endl; cout << s << endl; } else { if (m_verbose) { cout << "#CMT> Fill in the CVS/Root file with " << endl; cout << s << endl; } s.write (f); } // Now we create the CVS/Repository file f = "CVS"; f += CmtSystem::file_separator (); f += "Repository"; CmtSystem::get_cvsroot (s); if (s[0] == ':') { int pos = s.find (1, ":"); s.erase (0, pos+1); pos = s.find (0, ":"); s.erase (0, pos+1); } s += "/"; s += module; s += "\n"; if (m_simulation) { cout << "#CMT> Would fill in the CVS/Repository file with " << endl; cout << s << endl; } else { if (m_verbose) { cout << "#CMT> Fill in the CVS/Repository file with " << endl; cout << s << endl; } s.write (f); } } if (m_simulation) { cout << "#CMT> Would write the top CVS/Entries file with " << endl; cout << text << endl; } else { // Now the CVS/Entries is ready to be created. if (m_verbose) { cout << "#CMT> Fill in the top CVS/Entries file with " << endl; cout << text << endl; } text.write (entries_file_name); } } return (true); } cmt_string find_matching_version (const cmt_string& expression) { cmt_string result; // // Here expression takes the form // / // cmt_string dir; CmtSystem::dirname (expression, dir); dir += CmtSystem::file_separator (); cmt_string version; CmtSystem::basename (expression, version); if (version.find ("*") == cmt_string::npos) { // there is no wildcarding here. A simple test is enough. if (CmtSystem::test_directory (expression)) { if (m_cmtcvstest) cout << "## Found direct match with " << version << endl; result = version; } else { if (m_cmtcvstest) cout << "## Explicit version " << version << " has no direct match" << endl; } } else { version.replace ("*", ".*"); cmt_regexp exp (version); CmtSystem::cmt_string_vector list; if (m_cmtcvstest) cout << "## Trying scan_dir dir=" << dir << " exp=" << version << endl; CmtSystem::scan_dir (dir, exp, list); if (list.size () > 0) { result = list[0]; if (m_cmtcvstest) cout << "## At least one version is matching " << version << "(" << list.size () << " matches) " << result << endl; CmtSystem::basename (result, result); } else { if (m_cmtcvstest) cout << "## There is no version matching " << version << endl; } } return (result); } void checkout_package (const cmt_string& prefix, const cmt_string& package, const cmt_string& specified_version) { if (m_verbose) { cout << "#CMT> checkout_package> prefix=" << prefix << " package=" << package << " specified_version=" << specified_version << endl; } cmt_string version = specified_version; cmt_string empty; cmt_string full_prefix; full_prefix = m_offset; full_prefix += prefix; cmt_string echo_ppath; if (prefix != "") { echo_ppath = " path "; echo_ppath += prefix; } if (version == "") { cout << "# ================= No version specified for package " << package << endl; return; } // // First make an attempt to locate the specified version of // this package "as-it-is" in the work area. // Since 'version' may contain wild-card, it's likely that // we should not simply use CmtSystem::test_directory but // use the wild-card search. // cmt_string dir; dir = build_version_directory (prefix, package, version); if (m_cmtcvstest) cout << "## (testing dir= " << dir << ")" << endl; bool recursive = m_recursive; /* if (m_cmtcvstest) { cmt_string v = find_matching_version (dir); cout << "---> v=" << v << endl; } */ cmt_string effective_version = find_matching_version (dir); if (effective_version != "") { version = effective_version; dir = build_version_directory (prefix, package, version); cout << "# ================= Package " << package << " version " << version << echo_ppath << " already installed in " << dir << endl; recursive = false; } else { bool at_head = false; cmt_string module; // // get_version attempts to find the most appropriate version // tag matching the specification FROM the repository. However, // we should take into account situations where some versions have // already been checked out, in which case they might be sufficient // (or preferred?) // if (version.find ("*") != cmt_string::npos) { cout << "# ================= Package " << package << " version " << version << echo_ppath << " has wild cards and will not be considered." << endl; return; } if (!get_version (full_prefix, package, version, module, version, at_head)) { return; } //cout << " full_prefix=[" << full_prefix << "] module=[" << module << "]" << endl; if (m_cmtcvstest) cout << "## after get_version at_head=" << at_head << " m_head=" << m_head << endl; if (m_head) { m_head = false; at_head = true; } else { at_head = false; } // // Make a second try after having selected a version from all the // available versions compatible with the specified version // dir = build_version_directory (prefix, package, version); if (CmtSystem::test_directory (dir)) { cout << "# ================= Package " << package << " version " << version << echo_ppath << " already installed." << endl; recursive = false; } else { // // Now we can say that we have to perform the real checkout. // if (!really_checkout_package (prefix, package, version, module, dir, at_head)) { cout << "# bad return from really_checkout_package" << endl; return; } } } // // Now reach the newly checked out package. // if (m_simulation) { cout << "#CMT> Package directory not really created " << dir << endl; } else { if (!CmtSystem::cd (dir)) { cout << "#CMT> Package directory not created " << dir << endl; } /* if (m_verbose) { cout << "#CMT> pwd.4=" << CmtSystem::pwd () << endl; } */ // Check if it is a true CMT package. cmt_string file_name; file_name = "cmt"; file_name += CmtSystem::file_separator (); file_name += "requirements"; if (CmtSystem::test_file (file_name)) { dir += CmtSystem::file_separator (); dir += "cmt"; CmtSystem::cd ("cmt"); /* if (m_verbose) { cout << "#CMT> pwd.5=" << CmtSystem::pwd () << endl; } */ if (Cmt::get_current_structuring_style () == without_version_directory) { cmt_string text = version; text += "\n"; text.write ("version.cmt"); } } else { file_name = "mgr"; file_name += CmtSystem::file_separator (); file_name += "requirements"; if (CmtSystem::test_file (file_name)) { dir += CmtSystem::file_separator (); dir += "mgr"; CmtSystem::cd ("mgr"); /* if (m_verbose) { cout << "#CMT> pwd.6=" << CmtSystem::pwd () << endl; } */ } else { cout << "# " << package << " not a CMT package" << endl; return; } } //cout << "# (recursive is " << recursive << ")" << endl; if (recursive) { checkout_from_requirements ("requirements"); } } } /** * We provide a path to a requirements file. From it we read the use * statements, and we try to checkout the corresponding packages. */ void checkout_from_requirements (const cmt_string& requirements_path) { static cmt_regexp expression ("^[ \t]*use[ \t]"); cmt_string text; text.read (requirements_path); RecursivePass1 p1; p1.run (text, expression); RecursivePass2 p2 (*this); p2.run (p1.result ()); } void tags (const CmtSystem::cmt_string_vector& arguments) { if (arguments.size () < 1) { help (); return; } if (CmtSystem::getenv ("CVSROOT") == "") { cout << "# Please set CVSROOT first !" << endl; return; } if (CmtSystem::getenv ("CMTCVSTEST") != "") { m_cmtcvstest = true; } else { m_cmtcvstest = false; } m_offset = CmtSystem::getenv ("CMTCVSOFFSET"); if (m_offset != "") { m_offset += "/"; m_offset.replace_all ("//", "/"); } bool all = false; for (int arg = 0; arg < arguments.size (); arg++) { const cmt_string& option = arguments[arg]; if (option == "-all") { all = true; } else { show_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), option); if (error_info != "") { cout << error_info << endl; } else { cmt_string tags; if (all) { tags = cvsversions_top_info; tags += " "; tags += cvsversions_info; } else { tags = tags_top_info; tags += " "; tags += tags_info; } CmtSystem::cmt_string_vector v; CmtSystem::split (tags, " \t", v); for (int i = 0; i < v.size (); i++) { const cmt_string& s = v[i]; cout << s << endl; } } } } } void branches (const cmt_string& module) { cmt_string out; show_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), module); if (error_info != "") { cout << error_info << endl; } else { cout << branches_info << endl; } } void subpackages (const cmt_string& module) { cmt_string out; show_cvs_infos (CmtSystem::getenv ("CMTCVSOFFSET"), module); if (error_info != "") { cout << error_info << endl; } else { cout << subpackages_info << endl; } } void help () { cout << "> cd " << endl; cout << "> cmt checkout [modifier ...] " << endl; cout << "" << endl; cout << " modifier :" << endl; cout << " -l Do not process used packages (default)." << endl; cout << " -R Process used packages recursively." << endl; cout << " -r rev Check out version tag. (is sticky)" << endl; cout << " -d dir Check out into dir instead of module name." << endl; cout << " -o offset Offset in the CVS repository" << endl; cout << " -requirements Check out packages referenced in this requirements file" << endl; cout << " -n simulation mode on" << endl; cout << " -v verbose mode on" << endl; cout << " --help print this help" << endl; cout << "" << endl; } void do_checkout (const cmt_string& module, const cmt_string& version_tag) { //CMTPATH=${CMTPATH}:${m_home_dir}; export CMTPATH History& h = History::instance (); h.clear (); if (module == "") { if (m_verbose) { cout << "#CMT> Missing module name" << endl; } return; } cmt_string prefix; cmt_string package; cmt_string version; if (version_tag == "") { Cut cut (0); cmt_string m; m = m_offset; m += module; show_cvs_infos (m); if (error_info != "") { cout << error_info << endl; return; } if (tags_top_info != "") version = tags_top_info; else version = tags_info; //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "version=" << version << endl; cut.run (version); version = cut.result (); //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "version=" << version << endl; } else { version = version_tag; } CmtSystem::dirname (module, prefix); CmtSystem::basename (module, package); cmt_string top_dir; top_dir = m_home_dir; top_dir += CmtSystem::file_separator (); top_dir += m_checkout_dir; top_dir += CmtSystem::file_separator (); top_dir += prefix; top_dir += CmtSystem::file_separator (); top_dir += package; top_dir += CmtSystem::file_separator (); top_dir += version; CmtSystem::reduce_file_separators (top_dir); if (m_verbose) { cout << "#CMT> about to checkout package " << package << " version " << version << " into " << top_dir << endl; } checkout_package (prefix, package, version); /* if (m_verbose) { cout << "#CMT> after checkout_package pwd.7=" << CmtSystem::pwd () << " top_dir=" << top_dir << endl; } */ if (m_simulation) return; if (!CmtSystem::cd (top_dir)) return; /* if (m_verbose) { cout << "#CMT> pwd.8=" << CmtSystem::pwd () << endl; } */ cmt_string file_name; file_name = "cmt"; file_name += CmtSystem::file_separator (); file_name += "requirements"; if (CmtSystem::test_file (file_name)) { top_dir += CmtSystem::file_separator (); top_dir += "cmt"; CmtSystem::cd ("cmt"); /* if (m_verbose) { cout << "#CMT> pwd.9=" << CmtSystem::pwd () << endl; } */ } else { file_name = "mgr"; file_name += CmtSystem::file_separator (); file_name += "requirements"; if (CmtSystem::test_file (file_name)) { top_dir += CmtSystem::file_separator (); top_dir += "mgr"; CmtSystem::cd ("mgr"); /* if (m_verbose) { cout << "#CMT> pwd.10=" << CmtSystem::pwd () << endl; } */ } else { cout << "# " << package << " was not properly checked out and is missing its cmt/requirements file" << endl; return; } } if (m_verbose) { cout << "#CMT> package " << package << " has been checked out" << endl; } if (m_recursive) { if (m_verbose || m_simulation) { cout << "#CMT> Executing [" << "cmt -quiet broadcast cmt -quiet config" << "]" << endl; } if (!m_simulation) { CmtSystem::execute ("cmt -quiet broadcast cmt -quiet config"); } } else { if (m_verbose || m_simulation) { cout << "#CMT> Executing [" << "cmt -quiet config" << "]" << endl; } if (!m_simulation) { CmtSystem::execute ("cmt -quiet config"); } } } void checkout (const CmtSystem::cmt_string_vector& arguments) { if (arguments.size () < 1) { help (); return; } if (CmtSystem::getenv ("CVSROOT") == "") { cout << "# Please set CVSROOT first !" << endl; return; } if (CmtSystem::getenv ("CMTCVSTEST") != "") { m_cmtcvstest = true; } else { m_cmtcvstest = false; } m_home_dir = CmtSystem::pwd (); m_checkout_dir = ""; m_offset = ""; m_branch_suffix = ""; cmt_string module; m_recursive = false; bool need_version_tag = false; cmt_string version_tag; bool need_checkout_dir = false; bool need_offset = false; bool need_requirements_file = false; m_simulation = false; //m_verbose = true; m_verbose = false; bool need_branch_suffix = false; m_head = true; m_offset = CmtSystem::getenv ("CMTCVSOFFSET"); if (m_offset != "") { m_offset += "/"; m_offset.replace_all ("//", "/"); } for (int arg = 0; arg < arguments.size (); arg++) { const cmt_string& option = arguments[arg]; if (need_version_tag) { need_version_tag = false; if (option == "HEAD") { m_head = true; } else { version_tag = option; } } else if (need_checkout_dir) { need_checkout_dir = false; m_checkout_dir = option; } else if (need_offset) { need_offset = false; m_offset = option; m_offset += '/'; m_offset.replace_all ("//", "/"); } else if (need_branch_suffix) { need_branch_suffix = false; m_branch_suffix = "-"; m_branch_suffix += option; } else if (need_requirements_file) { need_requirements_file = false; m_head = false; checkout_from_requirements (option); } else { if (option == "-R") { m_recursive = true; } else if (option == "-l") { m_recursive = false; } else if (option == "-r") { need_version_tag = true; m_head = false; } else if (option == "-d") { need_checkout_dir = true; } else if (option == "-o") { need_offset = true; } else if (option == "-n") { m_simulation = true; } else if (option == "-v") { m_verbose = true; } else if (option == "-branch") { need_branch_suffix = true; } else if (option == "-requirements") { need_requirements_file = true; } else if (option == "--help") { help (); return; } else if (option[0] == '-') { help (); return; } else { do_checkout (option, version_tag); } } } } private: bool m_recursive; bool m_head; bool m_cmtcvstest; bool m_verbose; bool m_simulation; cmt_string m_home_dir; cmt_string m_checkout_dir; cmt_string m_offset; cmt_string m_branch_suffix; cmt_string m_last_module; cmt_string m_last_cvs_infos; cmt_string error_info; cmt_string tags_top_info; cmt_string tags_info; cmt_string cvsversions_top_info; cmt_string cvsversions_info; cmt_string branches_info; cmt_string subpackages_info; }; //-------------------------------------------------------------------- void Grep::begin () { m_result = ""; } void Grep::filter (const cmt_string& line) { //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "Grep::filter" << endl; if (m_result != "") m_result += " "; m_result += line; } const cmt_string& Grep::result () const { return (m_result); } //-------------------------------------------------------------------- Cut::Cut (int field) { m_field = field; } void Cut::begin () { //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "Cut::begin" << endl; m_result = ""; } void Cut::filter (const cmt_string& line) { //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "Cut::filter" << endl; static CmtSystem::cmt_string_vector words; CmtSystem::split (line, " \t", words); if (words.size () <= m_field) return; if (m_result != "") m_result += " "; m_result += words[m_field]; } const cmt_string& Cut::result () const { return (m_result); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- History& History::instance () { static History h; return (h); } void History::clear () { m_installed = ""; } void History::install (const cmt_string& line) { m_installed += "|"; m_installed += line; m_installed += "|"; } bool History::is_installed (const cmt_string& line) { if (m_installed.find (line) != cmt_string::npos) { return (true); } return (false); } History::History () { } //-------------------------------------------------------------------- void RecursivePass1::begin () { m_first = true; m_result = ""; } void RecursivePass1::filter (const cmt_string& line) { //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "RecursivePass1::filter> " // << "line=[" << line << "]" << endl; if (line.find ("use CMT") != cmt_string::npos) return; if (line.find ("use cmt") != cmt_string::npos) return; History& h = History::instance (); if (h.is_installed (line)) return; CmtSystem::cmt_string_vector words; CmtSystem::split (line, " \t", words); enum { need_package, need_version, need_path, no_need } state = need_package; cmt_string package; cmt_string version; cmt_string path; for (int i = 1; i < words.size (); i++) { const cmt_string& s = words[i]; if (s[0] == '-') continue; switch (state) { case need_package: package = s; state = need_version; break; case need_version: version = s; state = need_path; break; case need_path: path = s; state = no_need; break; } } if (version.find ("*") != cmt_string::npos) { /* cout << "# ================= Package " << package << " version " << version << " " << path << " has wild cards and will not be considered." << endl; */ return; } /** * At the first pass, we simply accumulate the not-yet handled * use statements. */ m_result += line; m_result += "\n"; if (m_first) { m_first = false; cout << " # --> now propagate cmt checkout to :" << endl; } cout << " # " << package << " " << version << " " << path << endl; } const cmt_string& RecursivePass1::result () const { return (m_result); } //-------------------------------------------------------------------- RecursivePass2::RecursivePass2 (CvsImplementation& cvs) : m_cvs (cvs) { } void RecursivePass2::begin () { } void RecursivePass2::filter (const cmt_string& line) { //if (CmtSystem::testenv ("CMTTESTAWK")) cout << "RecursivePass2::filter> " // << "line=[" << line << "]" << endl; /** * At the second pass, the lines are really handled. Thus * the lines are stored into m_installed so as to avoid * later on re-installation. */ History& h = History::instance (); if (h.is_installed (line)) return; h.install (line); CmtSystem::cmt_string_vector words; CmtSystem::split (line, " \t", words); enum { need_package, need_version, need_path, no_need } state = need_package; cmt_string package; cmt_string version; cmt_string path; for (int i = 1; i < words.size (); i++) { const cmt_string& s = words[i]; if (s[0] == '-') continue; switch (state) { case need_package: package = s; state = need_version; break; case need_version: version = s; state = need_path; break; case need_path: path = s; state = no_need; break; } } if (version.find ("*") != cmt_string::npos) { /* cout << "# ================= Package " << package << " version " << version << " " << path << " has wild cards and will not be considered." << endl; */ } else { m_cvs.checkout_package (path, package, version); } } //-------------------------------------------------------------------- void Cvs::tags (const CmtSystem::cmt_string_vector& arguments) { CvsImplementation cvs; cvs.tags (arguments); } void Cvs::branches (const cmt_string& module) { CvsImplementation cvs; cvs.branches (module); } void Cvs::subpackages (const cmt_string& module) { CvsImplementation cvs; cvs.subpackages (module); } void Cvs::checkout (const CmtSystem::cmt_string_vector& arguments) { CvsImplementation cvs; cvs.checkout (arguments); }