// // aegis - project change supervisor // Copyright (C) 2007, 2008, 2011, 2012, 2014 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see // . // #include #include #include #include #include #include #include #include #include #include #include #include #include #include static long is_a_change_number(const char *s) { char *ep = 0; long n = strtol(s, &ep, 10); if (ep == s || *ep) return 0; if (n < 0) return 0; return magic_zero_encode(n); } static long project_dot_change(const nstring &s, const nstring &projnam) { if ( s.size() <= projnam.size() + 1 || memcmp(s.c_str(), projnam.c_str(), projnam.size()) || !ispunct((unsigned char)s.c_str()[projnam.size()]) ) return 0; const char *suffix = s.c_str() + projnam.size() + 1; while (isupper((unsigned char)*suffix)) ++suffix; return is_a_change_number(suffix); } static bool is_below(const nstring &hi, const nstring &lo) { if (hi == lo) return true; return ( lo.size() > hi.size() && lo.c_str()[hi.size()] == '/' && !memcmp(hi.c_str(), lo.c_str(), hi.size()) ); } long user_ty::default_change(project *pp) { trace(("user_ty::default_change(this = %p, pp = %p)\n{\n", this, pp)); long change_number = 0; // // check the AEGIS_CHANGE environment variable // const char *cp = getenv("AEGIS_CHANGE"); if (cp) { change_number = is_a_change_number(cp); if (!change_number) { sub_context_ty sc; sc.var_set_charstar("Name", "AEGIS_CHANGE"); sc.fatal_intl(i18n("$$$name must be positive")); // NOTREACHED } } // // check the $HOME/.aegisrc file // if (!change_number) { uconf_ty *ucp = uconf_get(); if (ucp->mask & uconf_default_change_number_mask) { change_number = magic_zero_encode(ucp->default_change_number); } } // // examine the pathname of the current directory // to see if we can extract the change number // // This only works if the development directory was created // by aegis, and not specified by the -DIRectory option. // It doesn't work at all for IntDir or BL. // if (!change_number) { // // get the current directory // os_become_orig(); nstring cwd(os_curdir()); os_become_undo(); assert(cwd); // // break it into file names // nstring_list part; part.split(cwd, "/"); // // search for . // nstring projnam(project_name_get(pp)); for (size_t j = 0; j < part.size(); ++j) { change_number = project_dot_change(part[j], projnam); if (change_number) break; } } // // slower method than above, but works with any directory // if (!change_number) { // // get the current directory // os_become_orig(); nstring cwd(os_curdir()); os_become_undo(); assert(cwd); // // Examine each open change set // for (size_t j = 0;; ++j) { long cn = 0; if (!project_change_nth(pp, j, &cn)) break; change::pointer cp2 = change::create(pp, cn); cp2->bind_existing(); cstate_ty *cstate_data = cp2->cstate_get(); switch (cstate_data->state) { case cstate_state_being_integrated: { nstring d(cp2->integration_directory_get(false)); if (is_below(d, cwd)) { change_number = cn; break; } } // fall through... case cstate_state_awaiting_review: case cstate_state_awaiting_integration: case cstate_state_being_reviewed: case cstate_state_being_developed: { nstring d(cp2->development_directory_get(0)); if (is_below(d, cwd)) { change_number = cn; } } break; case cstate_state_awaiting_development: case cstate_state_completed: break; } if (change_number) break; } } // // If the user is only working on one change within the given // project, then that is the change. // if (!change_number) { ustate_ty *usp = ustate_get(pp); assert(usp->own); for (size_t j = 0; j < usp->own->length; ++j) { ustate_own_ty *own_data = usp->own->list[j]; nstring project_name(project_name_get(pp)); if (nstring(own_data->project_name) == project_name) { if (own_data->changes->length == 1) change_number = own_data->changes->list[0]; break; } } } // // It is an error if no change number has been given. // if (!change_number) project_fatal(pp, 0, i18n("no change number")); trace(("return %ld;\n", change_number)); trace(("}\n")); return change_number; } nstring user_ty::default_project() { trace(("user_ty::default_project()\n{\n")); // // from the AEGIS_PROJECT environment variable. // const char *cp = getenv("AEGIS_PROJECT"); if (cp && *cp) { nstring result(cp); trace(("return %s;\n", result.quote_c().c_str())); trace(("}\n")); return result; } // // From the $HOME/.aegisrc file. // uconf_ty *ucp = uconf_get(); if (ucp->default_project_name) { nstring result(ucp->default_project_name); trace(("return %s;\n", result.quote_c().c_str())); trace(("}\n")); return result; } // // check the search path, see if we use just one // // else check the current dirctory to see if we are within one // // This only works if the development directory was created // by aegis, and not specified by the -DIRectory option. // It doesn't work at all for IntDir or BL. // nstring_list names; gonzo_project_list_user(login_name, names); if (names.size() == 1) { nstring result(names[0]); trace(("return %s;\n", result.quote_c().c_str())); trace(("}\n")); return result; } // // get pathname of the current directory // os_become_orig(); nstring cwd(os_curdir()); os_become_undo(); assert(cwd); // // break into pieces // nstring_list part; part.split(cwd, "/"); // // search the path // looking for . // for (size_t j = 0; j < part.size(); ++j) { for (size_t k = 0; k < names.size(); ++k) { if (project_dot_change(part[j], names[k])) { nstring result(names[k]); trace(("return %s;\n", result.quote_c().c_str())); trace(("}\n")); return result; } } } // // check current directory more intensively. // this method is slower than previous, but works for // baseline and integration directories. // for (size_t j = 0; j < names.size(); ++j) { project *pp = project_alloc(names[j].get_ref()); pp->bind_existing(); // // first check if it is in baseline // nstring d(pp->baseline_path_get()); if (is_below(d, cwd)) { nstring result(names[j]); pp->free(); trace(("return %s;\n", result.quote_c().c_str())); trace(("}\n")); return result; } // // second check for every change // for (size_t k = 0;; ++k) { long change_number = 0; if (!project_change_nth(pp, k, &change_number)) break; change::pointer cp3 = change::create(pp, change_number); cp3->bind_existing(); cstate_ty *cstate_data = cp3->cstate_get(); switch (cstate_data->state) { case cstate_state_being_integrated: { nstring id(cp3->integration_directory_get(false)); if (is_below(id, cwd)) { nstring result(names[j]); trace(("return %s;\n", result.quote_c().c_str())); trace(("}\n")); return result; } } // fall through... case cstate_state_awaiting_review: case cstate_state_awaiting_integration: case cstate_state_being_reviewed: case cstate_state_being_developed: { nstring dd(cp3->development_directory_get(0)); if (is_below(dd, cwd)) { nstring result(names[j]); trace(("return %s;\n", result.quote_c().c_str())); trace(("}\n")); return result; } } break; case cstate_state_awaiting_development: case cstate_state_completed: break; } } pp->free(); } // // It is an error if no project name has been given. // fatal_intl(0, i18n("no project name")); // NOTREACHED trace(("}\n")); return ""; } // vim: set ts=8 sw=4 et :