// // aegis - project change supervisor // Copyright (C) 2001, 2002, 2004-2008 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_ty *fvlp; fvlp = (format_version_list_ty *)p; format_version_list_delete(fvlp, 0); } static format_version_list_ty * find_user(string_ty *name) { format_version_list_ty *fvlp; if (!stp) { stp = new symtab_ty(5); stp->set_reap(reaper); } fvlp = (format_version_list_ty *)stp->query(name); if (!fvlp) { fvlp = format_version_list_new(); stp->assign(name, fvlp); } return fvlp; } static void walker(const symtab_ty *, const nstring &, void *data, void *aux) { format_version_list_ty *fvlp = (format_version_list_ty *)data; change_set_list_ty *cslp = (change_set_list_ty *)aux; long window; size_t j; // // Sort each version list by date. // trace(("walker()\n{\n")); format_version_list_sort_by_date(fvlp); // // Now walk down the list, looking for clumps. // window = 300; for (j = 0; j < fvlp->length;) { size_t k; change_set_ty *csp; // // 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. // string_list_ty sl; csp = new change_set_ty(); csp->who = str_copy(fvlp->item[j]->who); csp->when = fvlp->item[k - 1]->when; trace(("when = %ld\n", (long)csp->when)); for (; j < k; ++j) { format_version_ty *fvp; change_set_file_action_ty action; string_ty *edit; fvp = fvlp->item[j]; if (fvp->description && fvp->description->str_length) sl.push_back_unique(fvp->description); // // Figure out what the file action is. // edit = fvp->edit; if (fvp->dead) { action = change_set_file_action_remove; if (fvp->before && fvp->before->edit) edit = fvp->before->edit; } else { if (!fvp->before || fvp->before->dead) action = change_set_file_action_create; else action = change_set_file_action_modify; } change_set_file_list_append ( &csp->file, fvp->filename_logical, edit, action, &fvp->tag ); } csp->description = sl.unsplit("\n"); // // 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_ty *fslp) { size_t j; change_set_list_ty *result; // // 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 (j = 0; j < fslp->length; ++j) { format_search_ty *fsp; format_version_ty *fvp; fsp = fslp->item[j]; fvp = fsp->root; while (fvp) { format_version_list_ty *fvlp; fvlp = find_user(fvp->who); format_version_list_append(fvlp, fvp); fvp = fvp->after; } } // // Process each bucket. // trace(("mark\n")); 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. // string_list_ty occupied; for (j = result->length; j > 0; --j) { change_set_ty *csp = result->item[j - 1]; for (size_t k = 0; k < csp->file.size(); ++k) { size_t m; change_set_file_ty *csfp = csp->file[k]; for (m = 0; m < csfp->tag.nstrings; ++m) { string_ty *tag; tag = csfp->tag.string[m]; if (occupied.member(tag)) continue; csp->tag.push_back_unique(tag); occupied.push_back(tag); } } } trace(("}\n")); return result; }