//
// 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 :