// // aegis - project change supervisor // Copyright (C) 2004-2008 Peter Miller // Copyright (C) 2007 Walter Franzini // // 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 // for assert #include #include #include #include #include #include #include #include #include string_list_ty * change_file_list_get(change::pointer cp, view_path_ty as_view_path) { trace(("change_file_list_get(cp = %8.8lX, as_view_path = %s)\n{\n", (long)cp, view_path_ename(as_view_path))); if (!cp->file_list[as_view_path]) { size_t j; string_list_ty *wlp; symtab_iterator *tmpi; string_ty *key; void *data; int top_level; change::pointer cp2; // // Drop all the files into a symbol table. // This has O(1) insertion times. // // We are using the symbol table to mimic the actions of // change_file_find, but for every change and project file in // parallel. It is essential that this function does exactly // what the change_file_find function does. // // Since we must be sure the fstate_src_ty* put in the symtab // survive the change::pointer they belongs to, we will take a // copy. Thus we must set the reaper function to assure // proper cleanup. // symtab_ty tmp(100); tmp.set_reap(fstate_src_type.free); symtab_ty xpar(100); xpar.set_reap(fstate_src_type.free); top_level = !change_is_a_branch(cp); // // In order to make Aegis time safe we need to exclude files // created in the future with respect to the change cp points to. // // There is no need to set the limit if as_view_path == // view_path_first because we only need to consult the change // record without looking in up to parent branches. // // There is no need to set the limit if the change is not // completed. // time_t limit = cp->time_limit_get(); cp2 = change_copy(cp); for (;;) { fstate_ty *fs; trace(("project \"%s\": change %ld\n", project_name_get(cp2->pp)->str_text, cp2->number)); if (cp2->bogus) goto next; if (as_view_path != view_path_first && change_pfstate_get(cp2)) fs = change_pfstate_get(cp2); else fs = change_fstate_get(cp2); trace(("fs->src->length = %ld\n", (long)fs->src->length)); for (j = 0; j < fs->src->length; ++j) { fstate_src_ty *fsp; fsp = fs->src->list[j]; assert(fsp); trace(("%ld: %s \"%s\"\n", (long)j, file_action_ename(fsp->action), fsp->file_name->str_text)); // // If there is a top-level transparent file, // it hides the next instance of the file. // if (xpar.query(fsp->file_name)) { tmp.remove(fsp->file_name); xpar.remove(fsp->file_name); // go onto the next file continue; } // // If we already have a "hit" for this file, ignore any // deeper records. This mimics the way change_file_find // stops as soon as it finds a match. // // This has O(1) query times. // if (tmp.query(fsp->file_name)) continue; switch (as_view_path) { case view_path_first: // // This means that transparent and removed files // are returned. No project file union, either. // break; case view_path_none: // // This means that transparent files are returned // as transparent, no processing or filtering of // the list is performed. // break; case view_path_simple: case view_path_extreme: switch (fsp->action) { case file_action_transparent: // // These cases both mean that transparent files // are resolved (the underlying file is shown). // if (top_level) xpar.assign(fsp->file_name, fstate_src_copy(fsp)); // go onto the next file continue; case file_action_remove: // // For now, we keep removed files in the symbol table. // break; case file_action_create: case file_action_modify: case file_action_insulate: #ifndef DEBUG default: #endif // should be file_action_remove assert(!fsp->deleted_by); if (fsp->deleted_by) break; // should be file_action_transparent assert(!fsp->about_to_be_created_by); if (fsp->about_to_be_created_by) { // go onto the next file continue; } // should be file_action_transparent assert(!fsp->about_to_be_copied_by); if (fsp->about_to_be_copied_by) { // go onto the next file continue; } break; } break; } tmp.assign(fsp->file_name, fstate_src_copy(fsp)); } next: if (as_view_path == view_path_first) break; if (cp2->number == TRUNK_CHANGE_NUMBER) break; if ( limit != TIME_NOT_SET && change_pfstate_get(cp2) && cp2->pp->is_a_trunk() ) break; change::pointer next_change = view_path_next_change(cp2, limit); change_free(cp2); cp2 = next_change; top_level = 0; } // // Walk the symbol table to build the file name list. // This has O(1) query times. // tmpi = symtab_iterator_new(&tmp); wlp = new string_list_ty(); while (symtab_iterator_next(tmpi, &key, &data)) { fstate_src_ty *fsp; switch (as_view_path) { case view_path_first: case view_path_none: case view_path_simple: break; case view_path_extreme: // // This means that transparent files are resolved (the // underlying file is shown), but removed files are // omitted from the result. // fsp = (fstate_src_ty *)tmp.query(key); assert(fsp); if (!fsp) break; switch (fsp->action) { case file_action_remove: continue; case file_action_create: case file_action_modify: case file_action_insulate: case file_action_transparent: #ifndef DEBUG default: #endif // should be file_action_remove assert(!fsp->deleted_by); if (fsp->deleted_by) continue; break; } break; } wlp->push_back(key); } symtab_iterator_delete(tmpi); // // Ensure that the file name list is in lexicographical // order, otherwise the users can see the joins (and it's // harder to find the files in a listing). // (C locale) // // Overall performance is O(n) for file discovery, // plus O(n log n) for the qsort, where n is the number // of files. // wlp->sort(); cp->file_list[as_view_path] = wlp; } trace(("return %8.8lX;\n", (long)cp->file_list[as_view_path])); trace(("}\n")); return cp->file_list[as_view_path]; }