#include #include #include #include "cmt_use.h" #include "cmt_system.h" #include "cmt_symbol.h" #include "cmt_error.h" #include "cmt_database.h" static Use* CurrentUse = 0; //---------------------------------------------------------- class VersionSelector { public: static VersionSelector& instance (); virtual Use* operate (Use* ref_use, Use* new_use) { return (ref_use); } }; class BestFitSelector : public VersionSelector { public: Use* operate (Use* ref_use, Use* new_use); }; class BestFitNoCheckSelector : public VersionSelector { public: Use* operate (Use* ref_use, Use* new_use); }; class FirstChoiceSelector : public VersionSelector { public: Use* operate (Use* ref_use, Use* new_use); }; class LastChoiceSelector : public VersionSelector { public: Use* operate (Use* ref_use, Use* new_use); }; class KeepAllSelector : public VersionSelector { public: Use* operate (Use* ref_use, Use* new_use); }; //---------------------------------------------------------- //---------------------------------------------------------- // // Operations on Use // //---------------------------------------------------------- //---------------------------------------------------------- void Use::select_clients (const cmt_string& package, const cmt_string& version) { static UsePtrVector& Uses = uses (); int number; Use* use = 0; unselect_all (); undiscard_all (); for (number = Uses.size () - 1; number >= 0; number--) { use = Uses[number]; if (use == 0) continue; if (use->is_selected ()) continue; use->select (); if (!use->is_client (package, version)) use->discard (); } } //---------------------------------------------------------- void Use::show_all (bool skip_discarded) { show_all ("use ", skip_discarded); } //---------------------------------------------------------- void Use::show_all (const cmt_string& prefix, bool skip_discarded) { static UsePtrVector& Uses = uses (); Use* use; int number; unselect_all (); use = &(current ()); use->unselect (); if (!Cmt::quiet) use->show_sub_uses (skip_discarded); if (Uses.size () > 0) { if (!Cmt::quiet) { cout << "#\n"; cout << "# Selection :\n"; } // // First move the CMT package to the end of the use set. // (ie. used by everybody) // use = Use::find ("CMT"); Use::move (use); for (number = Uses.size () - 1; number >= 0; number--) { use = Uses[number]; if (use->discarded) continue; if (use->real_path == "") { if (!Cmt::quiet) { cout << "# package " << use->package << " " << use->version << " " << use->path << " not found" << endl; } CmtError::set (CmtError::package_not_found, use->package); } else { cout << prefix << use->package << " " << use->version << " " << use->real_path << endl; } } if (Cmt::cmt_home != "") { cout << prefix << CmtSystem::get_home_package () << " " << Cmt::cmt_home << endl; } if (Cmt::cmt_user_context != "") { cout << prefix << CmtSystem::get_user_context_package () << " " << Cmt::cmt_user_context << endl; } } } class use_action_iterator { public: use_action_iterator () { state = need_package; auto_imports = request_auto_imports; } void set (const cmt_string& w) { if (w == "-auto_imports") { auto_imports = request_auto_imports; } else if (w == "-no_auto_imports") { auto_imports = no_auto_imports; } else if (w == "|") { state = need_version_alias; } else { switch (state) { case need_package: package = w; state = need_version; break; case need_version: version = w; state = need_path; break; case need_path: path = w; state = finished; break; case need_version_alias: version_alias = w; state = need_path_alias; break; case need_path_alias: path_alias = w; state = finished; break; } } } bool ok () { if (package == "") return (false); if (CmtSystem::is_home_package (package, version)) return (false); if (CmtSystem::is_user_context_package (package, version)) return (false); return (true); } Use* get_use (Use* use) { static Use::UsePtrVector& Uses = Use::uses (); if (version == "") version = "*"; if (Cmt::debug) { int i; cout << "use::action1> current=" << use->package << " package=" << package << " "; for (i = 0; i < Uses.size (); i++) { Use* use = Uses[i]; cout << use->package << " "; } cout << endl; } const Use& cu = Use::current (); if ((use != 0) && (use->package != cu.package) && (Cmt::scope == ScopePrivate)) { return (0); } // Here the version may contain wild cards Use* new_use = Use::add (path, package, version, version_alias, path_alias, use); switch (auto_imports) { case keep_auto_imports: break; case request_auto_imports: new_use->auto_imports = true; break; case no_auto_imports: new_use->auto_imports = false; break; } Use::reorder (new_use, use); if (Cmt::debug) { int i; cout << "use::action2> current=" << use->package << " package=" << package << " "; for (i = 0; i < Uses.size (); i++) { Use* use = Uses[i]; cout << use->package << " "; } cout << endl; } return (new_use); } private: enum { need_package, need_version, need_path, need_version_alias, need_path_alias, finished } state; enum { keep_auto_imports, request_auto_imports, no_auto_imports } auto_imports; cmt_string package; cmt_string version; cmt_string path; cmt_string version_alias; cmt_string path_alias; }; //---------------------------------------------------------- Use* Use::action (const CmtSystem::cmt_string_vector& words, Use* use) { Use* new_use; // // complete syntax : "use " // minimal syntax : "use " // // o if is omitted then take any version available // o can be specified using "v*" or "vr*" or "vrp*" // // o the notation "v*" is preferred to omission (particularly since // omission does not permit ) // if (words.size () < 2) return (0); use_action_iterator it; for (int i = 1; i < words.size (); i++) { const cmt_string& w = words[i]; cmt_string ew = w; Symbol::expand (ew); if (ew != w) { CmtSystem::cmt_string_vector ws; CmtSystem::split (ew, " ", ws); for (int j = 0; j < ws.size (); ++j) { const cmt_string& ww = ws[j]; it.set (ww); } } else { it.set (ew); } } if (!it.ok ()) return (0); static int level = 0; level++; new_use = it.get_use (use); level--; return (new_use); } //---------------------------------------------------------- void Use::author_action (const CmtSystem::cmt_string_vector& words) { if (author != "") author += "\n"; for (int i = 1; i < words.size (); i++) { const cmt_string& w = words[i]; if (i > 1) author += " "; author += w; } } //---------------------------------------------------------- void Use::manager_action (const CmtSystem::cmt_string_vector& words) { if (manager != "") manager += "\n"; for (int i = 1; i < words.size (); i++) { const cmt_string& w = words[i]; if (i > 1) manager += " "; manager += w; } } //---------------------------------------------------------- Use* Use::find (const cmt_string& package, const cmt_string& version, const cmt_string& path) { static UsePtrVector& Uses = uses (); static UseVector& AllUses = all_uses (); int use_index; if (AllUses.size () == 0) return (0); for (use_index = 0; use_index < Uses.size (); use_index++) { Use& use = (*Uses[use_index]); if (use.package == package) { // If the version argument is omitted then // take the first registered version if (version == "") return (&use); // Otherwise compare against specified_version and path //if ((use.specified_version == version) && // (use.specified_path == path)) return (&use); // what about comparing wild cards? if (use.specified_version == version) return (&use); } } return (0); } //---------------------------------------------------------- // // Move use to the end // //---------------------------------------------------------- void Use::move (Use* use1) { static UsePtrVector& Uses = uses (); int use_index; Use* use; int found = 0; if (Uses.size () == 0) return; if (use1 == 0) return; // // On se positionne sur le pointeur. // for (use_index = 0; use_index < Uses.size (); use_index++) { use = Uses[use_index]; if (use == use1) { found = 1; break; } } if (!found) return; // // On deplace tous les pointeurs d'une case en arriere // for (use_index++; use_index < Uses.size (); use_index++) { Uses[use_index - 1] = Uses[use_index]; } // // use1 est donc replace en derniere position // { Uses[Uses.size () - 1] = use1; } } //---------------------------------------------------------- void Use::reorder (Use* use1, Use* use2) { static UsePtrVector& Uses = uses (); int use_index; int index1 = -1; int index2 = -1; Use* use; if (Uses.size () == 0) return; if (use1 == use2) return; // // First locate the two use objects into the Uses vector. // -> index1 and index 2 // for (use_index = 0; use_index < Uses.size (); use_index++) { use = (Use*) Uses[use_index]; if (use == use1) index1 = use_index; if (use == use2) index2 = use_index; } if (Cmt::debug) { cout << "Use::reorder> 1=" << index1 << " 2=" << index2 << endl; } // // Both objects must be installed in Uses before acting. // if (index1 == -1) return; if (index2 == -1) return; if (index2 < index1) { // // 2 is already before 1 so job is finished // return; } else { // // before : // // o move "1 bbbb" by one place to the right // thus : // // o move "2" to [1] // // after : // use = use2; for (use_index = index2 - 1; use_index >= index1; use_index--) { Uses[use_index + 1] = Uses[use_index]; } Uses[index1] = use; } } //---------------------------------------------------------- void Use::clear_all () { static UsePtrVector& Uses = uses (); static UseVector& AllUses = all_uses (); int use_index; for (use_index = 0; use_index < AllUses.size (); use_index++) { Use& use = AllUses[use_index]; use.clear (); } Uses.clear (); AllUses.clear (); CurrentUse = 0; } //---------------------------------------------------------- void Use::unselect_all () { static UsePtrVector& Uses = uses (); int use_index; if (Uses.size () == 0) return; for (use_index = 0; use_index < Uses.size (); use_index++) { Use* use = Uses[use_index]; if (use != 0) { use->unselect (); } } } //---------------------------------------------------------- void Use::undiscard_all () { static UsePtrVector& Uses = uses (); int use_index; if (Uses.size () == 0) return; for (use_index = 0; use_index < Uses.size (); use_index++) { Use* use = Uses[use_index]; if (use != 0) { use->undiscard (); } } } //---------------------------------------------------------- void Use::fill_macro_all (cmt_string& buffer, const cmt_string& suffix) { UsePtrVector& Uses = uses (); buffer = "macro_append use_"; buffer += suffix; buffer += " \" "; (Use::current()).fill_macro (buffer, suffix); for (int number = 0; number < Uses.size (); number++) { Use* use = Uses[number]; if (use->package == "CMT") continue; if (use->package == "methods") continue; if (use->discarded) continue; if (!use->auto_imports) continue; use->fill_macro (buffer, suffix); } buffer += "\""; } //---------------------------------------------------------- Use::Use () { done = false; discarded = false; auto_imports = true; clear (); } //---------------------------------------------------------- Use::Use (const cmt_string& new_package, const cmt_string& new_version, const cmt_string& new_path) { auto_imports = true; set (new_package, new_version, new_path); } //---------------------------------------------------------- Use::~Use () { clear (); } //---------------------------------------------------------- void Use::clear () { specified_path = ""; path = ""; package = ""; version = ""; author = ""; manager = ""; real_path = ""; prefix = ""; style = mgr_style; cmt_scope = Cmt::scope; scope = Cmt::scope; done = false; discarded = false; selected = false; auto_imports = true; includes.clear (); include_path = ""; scripts.clear (); apply_patterns.clear (); ignore_patterns.clear (); sub_uses.clear (); alternate_versions.clear (); alternate_paths.clear (); version_alias = ""; path_alias = ""; } //---------------------------------------------------------- void Use::set (const cmt_string& new_package, const cmt_string& new_version, const cmt_string& new_path, const cmt_string& new_version_alias, const cmt_string& new_path_alias) { clear (); package = new_package; specified_path = new_path; // specified_path.replace_all ("\\", "/"); specified_version = new_version; version = new_version; path = specified_path; Symbol::expand (path); real_path = ""; style = mgr_style; cmt_scope = Cmt::scope; scope = Cmt::scope; done = false; discarded = false; Cmt::build_prefix (new_package, prefix); version_alias = new_version_alias; path_alias = new_path_alias; } //---------------------------------------------------------- void Use::change_path (const cmt_string& new_path) { // // This methods changes real_path after an actual location // where this package/version has been found. // real_path = ""; if (new_path != "") { if ((path.size () > 0) && (!CmtSystem::absolute_path (path))) { real_path = new_path; real_path += CmtSystem::file_separator (); real_path += path; } else { real_path = new_path; } // real_path.replace_all ("\\", "/"); } } //---------------------------------------------------------- int Use::reach_package (const cmt_string& from_path) { //cerr << "Use::reach_package> (" << package << " " << version << ")from " << from_path << endl; // // We try to reach a package/version starting from from_path // // check if from_path is at least real if ((from_path != "") && !CmtSystem::cd (from_path)) return (0); // check in case from_path is a new search path if (from_path != real_path) { // Move to that prefix only if it is a relative path. if ((path.size () > 0) && (!CmtSystem::absolute_path (path))) { if (!CmtSystem::cd (path)) { return (0); } } } // Special treatment for HOME package... if (package == CmtSystem::get_home_package ()) { discarded = 1; if (!CmtSystem::test_file ("requirements")) { return (0); } else { return (1); } } // Special treatment for USERCONTEXT package... if (package == CmtSystem::get_user_context_package ()) { discarded = 1; if (!CmtSystem::test_file ("requirements")) { return (0); } else { return (1); } } // Now from_path exists, try if the package exists there if (!CmtSystem::cd (package)) { return (0); } if (!CmtSystem::cd (version)) { // // The specified version cannot be found per-se // There are alternate possibilities when it contains wild cards // if ((version == "") || (version.find ("*") != cmt_string::npos)) { static CmtSystem::cmt_string_vector versions; static cmt_string name; name = "."; name += CmtSystem::file_separator (); if (version == "") name += "*"; else name += version; CmtSystem::scan_dir (name, versions); int i; for (i = 0; i < versions.size (); i++) { const cmt_string& vers = versions[i]; if (Cmt::debug) { cout << " ... version " << vers << " exists" << endl; } CmtSystem::basename (vers, name); int v; int r; int p; if (CmtSystem::is_version_directory (name, v, r, p)) { /* This check is not sufficient !! We need to check in addition that the selected directory is really the start of a true CMT package (ie with either /mgr/requirements or /cmt/requirements below) */ cmt_string req; req = name; req += CmtSystem::file_separator (); req += "mgr"; req += CmtSystem::file_separator (); req += "requirements"; if (!CmtSystem::test_file (req)) { req = name; req += CmtSystem::file_separator (); req += "cmt"; req += CmtSystem::file_separator (); req += "requirements"; if (!CmtSystem::test_file (req)) continue; } cmt_string& new_v = alternate_versions.add (); new_v = name; cmt_string& new_p = alternate_paths.add (); new_p = from_path; } } } //cerr << " ... end of version scan" << endl; // // We have now the list of possible alternate versions. However // we return that the expected package/version was not found (yet). // return (0); } //cerr << " ... version " << version << " exists" << endl; // Now we have met the exact specified version! if (!CmtSystem::test_file ("cmt/requirements")) { if (!CmtSystem::test_file ("mgr/requirements")) { return (0); } else { CmtSystem::cd ("mgr"); style = mgr_style; } } else { CmtSystem::cd ("cmt"); style = cmt_style; } return (1); } //---------------------------------------------------------- bool Use::move_to () { if (real_path != "") { // // The real path where this version/package can be found // has already been resolved. We thus first go there. // if (Cmt::debug) { cout << "move_to1> " << real_path << endl; } reach_package (real_path); return (true); } cmt_string expanded_path = path; // // Try here. // if (expanded_path == "") { if (reach_package ("")) { if (Cmt::debug) { cout << "move_to2> " << expanded_path << endl; } change_path (expanded_path); return (true); } } // // If the path specified in this use is a true absolute path, // then we search the package from there first. // if (CmtSystem::absolute_path (expanded_path)) { if (reach_package (expanded_path)) { if (Cmt::debug) { cout << "move_to3> " << expanded_path << endl; } change_path (expanded_path); return (true); } } // // Second try is among the CMTPATHs // static const CmtSystem::cmt_string_vector& search_path = Cmt::cmt_path; int path_index = 0; for (path_index = 0; path_index < search_path.size (); path_index++) { const cmt_string& next_path = search_path[path_index]; if (reach_package (next_path)) { if (Cmt::debug) { cout << "move_to4> " << next_path << endl; } change_path (next_path); return (true); } } if (select_alternate ()) { if (Cmt::debug) { cout << "move_to5> " << real_path << endl; } return (true); } return (false); } //---------------------------------------------------------- bool Use::select_alternate () { int i; int v0 = 0; int r0 = 0; int p0 = 0; int v = 0; int r = 0; int p = 0; int selected_index = -1; for (i = 0; i < alternate_versions.size (); i++) { cmt_string& name = alternate_versions[i]; /* if (CmtSystem::getenv ("CMTTESTUSEWILDCARDS") != "") { cout << "select_alternate[" << this << "]> package " << package << " sv=" << specified_version << " v=" << version << " av[" << i << "]=" << name << endl; } */ if (i == 0) { CmtSystem::is_version_directory (name, v0, r0, p0); selected_index = 0; } else { CmtSystem::is_version_directory (name, v, r, p); if (v > v0) { selected_index = i; v0 = v; r0 = r; p0 = p; } else if (v == v0) { if (r > r0) { selected_index = i; r0 = r; p0 = p; } else if (r == r0) { if (p > p0) { selected_index = i; p0 = p; } } } } } if (selected_index >= 0) { if (CmtSystem::cd (alternate_paths[selected_index])) { version = alternate_versions[selected_index]; if (reach_package (alternate_paths[selected_index])) { /* if (CmtSystem::getenv ("CMTTESTUSEWILDCARDS") != "") { cout << "select_alternate2> package " << package << " sv=" << specified_version << " v=" << version << endl; } */ if (Cmt::debug) { cout << "select_alternate> " << alternate_paths[selected_index] << endl; } change_path (alternate_paths[selected_index]); return (true); } } } return (false); } //---------------------------------------------------------- bool Use::need_new (const cmt_string& path, const cmt_string& package, const cmt_string& version, Use** old_use) { Use* use; // find any possible existing version for that package use = find (package); if (old_use != 0) *old_use = use; if (use == 0) { // No version was not found at all return (true); } //cerr << "Use::need_new> (" << package << ") requested version=" << version << " vs existing=" << use->version << " (specified as " << use->specified_version << ")" << endl; // There was a version. We want to install a priority to the // explicit specifications over wildcarded ones. // So we say that : // // - if the existing spec. was specified as explicit, and the new // request is wildcarded, then the new one is discarded. // // - if the existing spec. was specified as wildcarded and the new // request is explicit, then the new one wins. // if ((version.find ("*") != cmt_string::npos) && (use->specified_version.find ("*") == cmt_string::npos)) { //cerr << " ... wild card loses against existing specific" << endl; return (false); } if ((version.find ("*") == cmt_string::npos) && (use->specified_version.find ("*") != cmt_string::npos)) { //cerr << " ... specific should win against existing wildcarded" << endl; return (true); } if (version == use->specified_version) { if (path == use->specified_path) { // exactly same version and path! return (false); } else { // same version but different path. return (true); } } // at least one version has been found (different from what is requested), // can we find the exact match ? use = find (package, version, path); if (use == 0) { // The required version was not found return (true); } if (path != use->specified_path) { // The required version was found but on another path return (true); } // The required version was exactly found return (false); } //---------------------------------------------------------- // // Here the version which is provided here is the specified version. // It may contain wild cards or it may be simply empty. // //---------------------------------------------------------- Use* Use::create (const cmt_string& path, const cmt_string& package, const cmt_string& version, const cmt_string& version_alias, const cmt_string& path_alias) { static UseVector& AllUses = all_uses (); // We first look in the database. for (int use_index = 0; use_index < AllUses.size (); use_index++) { Use& use = AllUses[use_index]; if (use.package == package) { if ((use.specified_version == version) && (use.specified_path == path)) return (&use); } } // We now really create a new Use entry. Use& use_object = AllUses.add (); use_object.set (package, version, path, version_alias, path_alias); return (&use_object); } //---------------------------------------------------------- // Add a use request into the database. // // o If a use request already exist in the database, // check the version compatibility // //---------------------------------------------------------- Use* Use::add (const cmt_string& path, const cmt_string& package, const cmt_string& version, const cmt_string& version_alias, const cmt_string& path_alias, Use* context_use) { static UsePtrVector& Uses = uses (); bool do_need_new = false; Use* old_use = 0; Use* use = 0; do_need_new = need_new (path, package, version, &old_use); /* if (old_use != 0) { cout << "add> old_use " << old_use->package << " " << old_use->version << " " << old_use->path << endl; } */ if (do_need_new) { use = create (path, package, version, version_alias, path_alias); } else { // Since we don't need a new Use, it means that old_use exists ! use = old_use; old_use = 0; } if (package == CmtSystem::get_home_package ()) { return (use); } if (package == CmtSystem::get_user_context_package ()) { return (use); } cmt_string here = CmtSystem::pwd (); // // Store the specified sub_uses. Some of them may become discarded // later on. // if (context_use != 0) { context_use->sub_uses.push_back (use); } bool found = use->move_to (); if (Cmt::debug) { cout << "add> use " << use->package << " " << use->version << " " << use->path << " found=" << found << endl; } if (old_use != 0) { /* if (CmtSystem::getenv ("CMTTESTUSEWILDCARDS") != "") { cout << "select? [" << use << "] vs old_use[" << old_use << "] " << old_use->package << " " << old_use->version << " " << old_use->path << endl; } */ if (use != old_use) { // // This new version is different from the old one // thus we have to choose // VersionSelector& selector = VersionSelector::instance (); Use* selected_use = selector.operate (old_use, use); // // Some situations managed by selector.operate happen // to fail discarding the rejected Use. // if (use != selected_use) { use->discard (); } use = selected_use; found = use->move_to (); } } { bool registered = false; // // A pointer to this new object is also added or replaced. // for (int i = 0; i < Uses.size(); i++) { Use* u = Uses[i]; if (u->package == package) { registered = true; Uses[i] = use; break; } } if (!registered) Uses.push_back (use); } // // The following statement is no longer considered as useful. // It is commented. But we should clarify why it was really needed! // //use->undiscard (); if (!found) { if (!Cmt::quiet) { cout << "# package " << use->package << " " << use->version << " " << use->path << " not found" << endl; } CmtError::set (CmtError::package_not_found, use->package); } if (found && !use->done && Cmt::recursive) { use->done = true; /* if (CmtSystem::getenv ("CMTTESTUSEWILDCARDS") != "") { for (int use_index = 0; use_index < Uses.size (); use_index++) { Use* u = (Use*) Uses[use_index]; cout << " use[" << use_index << "] p=" << u->package << " v=" << u->version << " discarded=" << u->discarded << " selected=" << u->selected << endl; } cout << "parsing at " << CmtSystem::pwd () << endl; } */ /** Get the previous set of effective use statements that might have been obtained in a previous build. This is stored in uses.log. Ignored if file does not exist. */ //Cmt::parse_requirements ("uses.log", use); if (Cmt::debug) { cout << "Parsing requirements file at " << CmtSystem::pwd () << endl; } Cmt::parse_requirements ("requirements", use); } CmtSystem::cd (here); return (use); } //---------------------------------------------------------- void Use::discard () { discarded = true; } //---------------------------------------------------------- void Use::undiscard () { discarded = false; } //---------------------------------------------------------- void Use::select () { selected = true; } //---------------------------------------------------------- void Use::unselect () { selected = false; } //---------------------------------------------------------- bool Use::is_selected () { return (selected); } //---------------------------------------------------------- bool Use::is_client (const cmt_string& used_package, const cmt_string& used_version) { if ((package == used_package) && (version == used_version)) return (true); if (discarded) return (false); int i; for (i = 0; i < sub_uses.size (); i++) { Use* use = sub_uses[i]; if (use == 0) continue; if ((use->package == used_package) && (use->version == used_version)) return (true); /* if (use->is_client (used_package, used_version)) { return (true); } */ } return (false); } //---------------------------------------------------------- void Use::apply_global_patterns () { int i; Pattern::PatternVector& vector = Pattern::patterns (); for (i = 0; i < vector.size (); i++) { Pattern& p = vector[i]; if (p.global) { p.apply (this); } } } //---------------------------------------------------------- void Use::set_include_path (const cmt_string& new_path) { include_path = new_path; } //---------------------------------------------------------- void Use::fill_includes_macro (cmt_string& buffer) const { if (include_path == "") { buffer += "$(ppcmd)\"$("; buffer += package; buffer += "_root)"; buffer += CmtSystem::file_separator (); buffer += "src\" "; } else if (include_path != "none") { buffer += "$(ppcmd)\""; buffer += include_path; buffer += "\" "; } for (int i = 0; i < includes.size (); i++) { Include& incl = includes[i]; buffer += "$(ppcmd)\""; buffer += incl.name; buffer += "\" "; } } //---------------------------------------------------------- void Use::fill_macro (cmt_string& buffer, const cmt_string& suffix) const { buffer += " $("; buffer += package; buffer += "_"; buffer += suffix; buffer += ") "; } /** * This function tries to get the replacement of a Use when it has * been discarded by a better match to version constraints. */ Use* Use::get_selected_version () { static Use::UsePtrVector& Uses = uses (); //cout << "get_selected_version for package " << package << endl; if (!discarded) return (this); for (int i = 0; i < Uses.size (); i++) { Use* u = Uses[i]; if (u == 0) continue; if (u->discarded) continue; if (u->package == package) { //cout << " got a version" << endl; return (u); } } return (0); } //---------------------------------------------------------- bool Use::get_paths (Use* to, UsePtrVector& list) { bool found = false; bool cycle = false; static int level = 0; static UsePtrVector stack; if (level == 0) { stack.clear (); } for (int k = 0; k < stack.size (); k++) { Use* u = stack[k]; if (u == this) return (false); } if (stack.size () <= level) { stack.push_back (this); } else { stack[level] = this; } // First figure out whether 'to' is used by 'this'. if (Cmt::debug) { cout << "Use::get_paths." << level << ">" << package << " list[" << list.size () << "]" << endl; } if (this == to) { found = true; } else { for (int n = 0; n < sub_uses.size (); n++) { Use* use = sub_uses[n]; if (use == 0) continue; if (use->discarded) { Use* u; u = use->get_selected_version (); if (u == 0) continue; use = u; } cycle = false; // This use must not be already in the list (protection against cycles) for (int m = 0; m < list.size (); m++) { Use* u = list[m]; if (u == use) { cycle = true; break; } } if (cycle) { found = true; continue; } level++; bool r = use->get_paths (to, list); level--; if (r) { found = true; } } } if (found) { cycle = false; for (int m = 0; m < list.size (); m++) { Use* u = list[m]; if (u == this) { cycle = true; break; } } if (!cycle) { list.push_back (this); } } return (found); } //---------------------------------------------------------- void Use::show_sub_uses (bool skip_discarded) { int n; Use* use; static int level = 0; if (skip_discarded && discarded) return; if (level > 0) { cout << "# "; for (n = 0; n < (level-1); n++) cout << " "; cout << "use " << package << " " << specified_version; if (specified_path != "") cout << " " << specified_path; if (version_alias != "") { cout << " | " << version_alias << " " << path_alias; } if (scope == ScopeUnspecified) cout << " unspecified"; else if (scope == ScopePublic) cout << " public"; else cout << " private"; cout << endl; } if (selected) return; selected = true; level++; for (n = 0; n < sub_uses.size (); n++) { use = sub_uses[n]; if (use != 0) use->show_sub_uses (skip_discarded); } level--; } //---------------------------------------------------------- Use& Use::current () { static UseVector& AllUses = all_uses (); if (CurrentUse == 0) { Use& use_object = AllUses.add (); CurrentUse = &use_object; } return (*CurrentUse); } //---------------------------------------------------------- const Use& Use::const_current () { static UseVector& AllUses = all_uses (); if (CurrentUse == 0) { Use& use_object = AllUses.add (); CurrentUse = &use_object; } const Use& use = *CurrentUse; return (use); } //---------------------------------------------------------- Use::UseVector& Use::all_uses () { static Database& db = Database::instance (); static UseVector& AllUses = db.all_uses (); return (AllUses); } //---------------------------------------------------------- Use::UsePtrVector& Use::uses () { static Database& db = Database::instance (); static UsePtrVector& Uses = db.uses (); return (Uses); } //---------------------------------------------------------- VersionSelector& VersionSelector::instance () { static BestFitSelector best_fit; static BestFitNoCheckSelector best_fit_no_check; static FirstChoiceSelector first_choice; static LastChoiceSelector last_choice; static KeepAllSelector keep_all; switch (Cmt::current_strategy) { case BestFit: return (best_fit); case BestFitNoCheck: return (best_fit_no_check); case FirstChoice: return (first_choice); case LastChoice: return (last_choice); case KeepAll: return (keep_all); default: return (best_fit); } } //---------------------------------------------------------- // // Check if the specified version is better than the // current one. // //---------------------------------------------------------- Use* BestFitSelector::operate (Use* ref_use, Use* new_use) { Use* selected = ref_use; int old_v = -1; int old_r = -1; int old_p = -1; cmt_string old_pp; int new_v = -1; int new_r = -1; int new_p = -1; cmt_string new_pp; int alias_v = -1; int alias_r = -1; int alias_p = -1; cmt_string alias_pp; enum { no_alias, new_has_alias, ref_has_alias } has_alias = no_alias; CmtSystem::is_version_directory (ref_use->version, old_v, old_r, old_p); old_pp = ref_use->path; CmtSystem::is_version_directory (new_use->version, new_v, new_r, new_p); new_pp = new_use->path; if (new_use->version_alias != "") { has_alias = new_has_alias; CmtSystem::is_version_directory (new_use->version_alias, alias_v, alias_r, alias_p); alias_pp = new_use->path_alias; } else if (ref_use->version_alias != "") { has_alias = ref_has_alias; CmtSystem::is_version_directory (ref_use->version_alias, alias_v, alias_r, alias_p); alias_pp = ref_use->path_alias; } ref_use->undiscard (); new_use->undiscard (); if (new_v != old_v) { if (has_alias != no_alias) { if (has_alias == new_has_alias) { new_v = alias_v; new_r = alias_r; new_p = alias_p; new_pp = alias_pp; } else if (has_alias == ref_has_alias) { old_v = alias_v; old_r = alias_r; old_p = alias_p; old_pp = alias_pp; } } } if (new_v != old_v) { if (!Cmt::quiet) cout << "# Required version " << new_use->version << " of package " << ref_use->package << " incompatible with selected version " << ref_use->version << endl; CmtError::set (CmtError::version_conflict, "BestFitSelector::operate> "); if (ref_use != new_use) new_use->discard (); } else if (new_r < old_r) { // // we plan to discard new_use, but if it was specified as explicit // and ref_use was wildcarded then new_use will win !! // // So then we'll have to understand where are the wild // cards... If they are on v or r, then we consider them. // // bool new_is_wildcarded = false; bool ref_is_wildcarded = false; if (new_use->specified_version.find ("*") != cmt_string::npos) { int nv = -1; int nr = -1; int np = -1; CmtSystem::is_version_directory (new_use->specified_version, nv, nr, np); if ((nv == -1) || (nr == -1)) new_is_wildcarded = true; } if (ref_use->specified_version.find ("*") != cmt_string::npos) { int nv = -1; int nr = -1; int np = -1; CmtSystem::is_version_directory (ref_use->specified_version, nv, nr, np); if ((nv == -1) || (nr == -1)) new_is_wildcarded = true; } if (!ref_is_wildcarded && new_is_wildcarded) { if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements } else { if (!Cmt::quiet) cout << "# keep release " << ref_use->version << " of package " << ref_use->package << " (ignore release " << new_use->version << ")" << endl; if (ref_use != new_use) new_use->discard (); } } else if (new_r > old_r) { if (!Cmt::quiet) { cout << "# Select release " << new_use->version << " of package " << ref_use->package << " instead of existing " << ref_use->version << endl; } if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements } else if (new_p > old_p) { if (!Cmt::quiet) { cout << "# Select patch " << new_use->version << " of package " << ref_use->package << " instead of existing " << ref_use->version << endl; } if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements } else if (new_pp != old_pp) // same version-r-p but from different path { if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements } return (selected); } //---------------------------------------------------------- // // Check if the specified version is better than the // current one. We don't check major ids incompatibilities // //---------------------------------------------------------- Use* BestFitNoCheckSelector::operate (Use* ref_use, Use* new_use) { Use* selected = ref_use; int old_v = -1; int old_r = -1; int old_p = -1; cmt_string old_pp; int new_v = -1; int new_r = -1; int new_p = -1; cmt_string new_pp; int alias_v = -1; int alias_r = -1; int alias_p = -1; cmt_string alias_pp; enum { no_alias, new_has_alias, ref_has_alias } has_alias = no_alias; CmtSystem::is_version_directory (ref_use->version, old_v, old_r, old_p); old_pp = ref_use->path; CmtSystem::is_version_directory (new_use->version, new_v, new_r, new_p); new_pp = new_use->path; if (new_use->version_alias != "") { has_alias = new_has_alias; CmtSystem::is_version_directory (new_use->version_alias, alias_v, alias_r, alias_p); alias_pp = new_use->path_alias; } else if (ref_use->version_alias != "") { has_alias = ref_has_alias; CmtSystem::is_version_directory (ref_use->version_alias, alias_v, alias_r, alias_p); alias_pp = ref_use->path_alias; } ref_use->undiscard (); new_use->undiscard (); if (new_v != old_v) { if (has_alias != no_alias) { if (has_alias == new_has_alias) { new_v = alias_v; new_r = alias_r; new_p = alias_p; new_pp = alias_pp; } else if (has_alias == ref_has_alias) { old_v = alias_v; old_r = alias_r; old_p = alias_p; old_pp = alias_pp; } } } if (new_v < old_v) { if (!Cmt::quiet) { cout << "# Keep version " << ref_use->version << " of package " << ref_use->package << " (ignore version " << new_use->version << ")" << endl; } if (ref_use != new_use) new_use->discard (); } else if (new_v > old_v) { if (!Cmt::quiet) { cout << "# Select version " << new_use->version << " of package " << ref_use->package << " instead of existing " << ref_use->version << endl; } if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements } else if (new_r < old_r) { if (!Cmt::quiet) { cout << "# keep release " << ref_use->version << " of package " << ref_use->package << " (ignore release " << new_use->version << ")" << endl; } if (ref_use != new_use) new_use->discard (); } else if (new_r > old_r) { if (!Cmt::quiet) { cout << "# Select release " << new_use->version << " of package " << ref_use->package << " instead of existing " << ref_use->version << endl; } if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements } else if (new_p > old_p) { if (!Cmt::quiet) { cout << "# Select patch " << new_use->version << " of package " << ref_use->package << " instead of existing " << ref_use->version << endl; } if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements } else if (new_pp != old_pp) // same version-r-p but from different path { if (ref_use != new_use) ref_use->discard (); selected = new_use; selected->done = false; // Will read the new requirements } return (selected); } //---------------------------------------------------------- Use* FirstChoiceSelector::operate (Use* ref_use, Use* new_use) { ref_use->undiscard (); new_use->undiscard (); new_use->done = false; // Will read the new requirements if (ref_use != new_use) new_use->discard (); return (ref_use); } //---------------------------------------------------------- Use* LastChoiceSelector::operate (Use* ref_use, Use* new_use) { ref_use->undiscard (); new_use->undiscard (); new_use->done = false; // Will read the new requirements if (ref_use != new_use) ref_use->discard (); return (new_use); } //---------------------------------------------------------- Use* KeepAllSelector::operate (Use* ref_use, Use* new_use) { ref_use->undiscard (); new_use->undiscard (); new_use->done = false; // Will read the new requirements return (new_use); }