// // aegis - project change supervisor // Copyright (C) 2001, 2002, 2004-2008, 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 static symtab_ty *stp; static void reaper(void *p) { format_version_list *fvlp = (format_version_list *)p; delete fvlp; } static format_version_list * find_user(const nstring &name) { format_version_list *fvlp; if (!stp) { stp = new symtab_ty(5); stp->set_reap(reaper); } fvlp = (format_version_list *)stp->query(name); if (!fvlp) { fvlp = new format_version_list(); stp->assign(name, fvlp); } return fvlp; } static void walker(const symtab_ty *, const nstring &, void *data, void *aux) { trace(("%s\n{\n", __PRETTY_FUNCTION__)); format_version_list *fvlp = (format_version_list *)data; change_set_list_ty *cslp = (change_set_list_ty *)aux; // // Sort each version list by date. // fvlp->sort_by_date(); // // Now walk down the list, looking for clumps. // long window = 300; for (size_t j = 0; j < fvlp->length;) { size_t k; // // Find the end of this clump. // trace(("j = %ld\n", (long)j)); for ( k = j + 1; ( k < fvlp->length && (fvlp->item[k]->when < fvlp->item[k - 1]->when + window) ); ++k ) ; // // Turn the clump into a change set. // nstring_list sl; change_set_ty *csp = new change_set_ty(); csp->who.push_back_unique(fvlp->item[j]->who); csp->when = fvlp->item[k - 1]->when; trace_time(csp->when); for (; j < k; ++j) { format_version *fvp = fvlp->item[j]; if (fvp->description.size()) sl.push_back_unique(fvp->description); fvp->who.push_back_unique(fvp->who); // // Figure out what the file action is. // change_set_file::action_t action = change_set_file::action_modify; nstring edit = fvp->edit.front(); if (fvp->dead) { action = change_set_file::action_remove; if (fvp->before && fvp->before->edit.front()) edit = fvp->before->edit.front(); } else { if (!fvp->before || fvp->before->dead) action = change_set_file::action_create; else action = change_set_file::action_modify; } csp->file.push_back ( change_set_file ( nstring(fvp->filename_logical), edit, action, nstring_list(fvp->tag) ) ); } csp->description.push_back_unique(sl); // // Append the change set to the list. // change_set_list_append(cslp, csp); } trace(("}\n")); } change_set_list_ty * change_set_find(format_search_list *fslp) { // // Sort the file versions into separate buckets for each user. // // For now, only traverse the trunk. I still doen't know how // to associate across files to divine where the branbches are. // trace(("change_set_find()\n{\n")); for (size_t j = 0; j < fslp->length; ++j) { format_search_ty *fsp = fslp->item[j]; format_version *fvp = fsp->root; while (fvp) { format_version_list *fvlp = find_user(fvp->who.front()); fvlp->append(fvp); fvp = fvp->after; } } // // Process each bucket. // trace(("mark\n")); change_set_list_ty *result = change_set_list_new(); stp->walk(walker, result); change_set_list_sort_by_date(result); delete stp; stp = 0; // // Work out where to attach the tags. // // We do this by working BACKWARDS in time, assigning file tags // to change sets. But (and this is why we work backwards in // time) we don't assign tags which have already been seen. // // In common usage, the tags serve a similar purpose as Aegis' // delta numbers. They are all (typically) applied in a single // CVS command, in order that a particular build may be recreated // later. HOWEVER, because each file will be at a different // version, and each will have had its latest version included // in various random change sets. // // Tags are used for other things too. This is simply a guess, // but it's a fairly reasonable one. // nstring_list occupied; for (int j = result->length; j > 0; --j) { change_set_ty *csp = result->item[j - 1]; for (size_t k = 0; k < csp->file.size(); ++k) { change_set_file &csf = csp->file[k]; for (size_t m = 0; m < csf.tag.size(); ++m) { nstring tag(csf.tag[m]); if (occupied.member(tag)) continue; csp->tag.push_back_unique(tag); occupied.push_back(tag); } } } trace(("}\n")); return result; } // vim: set ts=8 sw=4 et :