query_merges(VersionControlServer vcs, string srcPath, VersionSpec srcVer, string targetPath, VersionSpec targetVer, VersionSpec fromVer, VersionSpec toVer, RecursionType recurType) { RBDictTree <int, SortedDictionary <int, ChangesetMerge> > merges = new RBDictTree <int, SortedDictionary <int, ChangesetMerge> >(); ++_queries; logger.DebugFormat("query_merges {0}, {1}, {2}, {3}, {4}, {5}", (srcPath == null ? "(null)": srcPath), (srcVer == null ? "(null)" : srcVer.DisplayString), targetPath, targetVer.DisplayString, (fromVer == null ? "(null)" : fromVer.DisplayString), (toVer == null ? "(null)" : toVer.DisplayString)); _queryTimer.start(); try { ChangesetMerge[] mergesrc = vcs.QueryMerges(srcPath, srcVer, targetPath, targetVer, fromVer, toVer, recurType); /* group by merged changesets. */ for (int i = 0; i < mergesrc.Length; ++i) { RBDictTree <int, SortedDictionary <int, ChangesetMerge> > .iterator it = merges.find(mergesrc[i].TargetVersion); if (merges.end() == it) { /* create the list... */ SortedDictionary <int, ChangesetMerge> group = new SortedDictionary <int, ChangesetMerge>(); group.Add(mergesrc[i].SourceVersion, mergesrc[i]); merges.insert(mergesrc[i].TargetVersion, group); } else { it.value().second.Add(mergesrc[i].SourceVersion, mergesrc[i]); } } } catch (Exception e) { Console.Error.WriteLine("Error querying: {0},{1}", targetPath, targetVer); Console.Error.WriteLine(e.ToString()); } _queryTimer.stop(); return(merges); }
/** visit an explicit list of changesets. */ private bool _visit(int parentID, List <string> targetBranches, string srcPath, VersionSpec srcVer, string target, VersionSpec targetVer, VersionSpec fromVer, VersionSpec toVer, RecursionType recursionType) { logger.DebugFormat("{{_visit: parent={0}", parentID); /* so, here we might have a few top-level merge changesets. * the red-black binary tree sorts the changesets in decending order */ RBDictTree <int, SortedDictionary <int, ChangesetMerge> > merges = query_merges(_vcs, srcPath, srcVer, target, targetVer, fromVer, toVer, recursionType); RBDictTree <int, SortedDictionary <int, ChangesetMerge> > .iterator it = merges.begin(); /* walk through the merge changesets * - this should return only one merge changeset for the recursive calls. */ for (; it != merges.end(); ++it) { int csID = it.value().first; try { /* visit the 'target' merge changeset here. * it's parent is the one passed in. */ Changeset cs = _vcs.GetChangeset(csID); string path_part = _get_path_part(target); ChangesetVersionSpec cstargetVer = targetVer as ChangesetVersionSpec; /* pass in the known set of branches in this changeset, or let it figure that out. */ if (cstargetVer.ChangesetId == csID) { _visitor.visit(parentID, cs, targetBranches); } else { _visitor.visit(parentID, cs); } { Visitor.PatchInfo p = _visitor[csID]; /* if the user chose to heed our warnings, * and there are no branches to visit for this changeset? * move on to the next result, ignoring all the 'composites' of this 'fake' changeset. */ if (!_options.ForceDecomposition && (p != null && (p.treeBranches == null || p.treeBranches.Count == 0))) { continue; } } foreach (KeyValuePair <int, ChangesetMerge> cng in it.value().second) { ChangesetMerge csm = cng.Value; /* now visit each of the children. * we've already expanded cs.ChangesetId (hopefully...) */ try { Changeset child = _vcs.GetChangeset(csm.SourceVersion); List <string> branches = null; { /* speed-up. if we already have the branches, don't do it again. * looking through 40K+ records takes some time... */ Visitor.PatchInfo p = _visitor[child.ChangesetId]; if (p != null) { branches = p.treeBranches; } else { branches = FindChangesetBranches(child); } } /* - this is for the recursive query - * you have to have specific branches here. * a query of the entire project will probably not return. * * eg: * query target $/IGT_0803/main/EGS,78029 = 41s * query target $/IGT_0803,78029 = DNF (waited 6+m) */ if (_options.NoRecurse) { /* they just want the top-level query. */ _visitor.visit(cs.ChangesetId, child, branches); } else { if (!_visitor.visited(child.ChangesetId)) { /* we just wanted to see the initial list, not a full tree of changes. */ ChangesetVersionSpec tv = new ChangesetVersionSpec(child.ChangesetId); bool results = false; /* this is going to execute a number of queries to get * all of the source changesets for this merge. * since using a branch is an(several hundred) order(s) of magnitude faster, * we're doing this by branch(path) */ for (int i = 0; i < branches.Count; ++i) { if (_options.AllowBranchRevisiting || !_visitor.visited(branches[i])) { logger.DebugFormat("visiting ({0}) {1}{2}", child.ChangesetId, branches[i], path_part); /* this recurisve call needs to then * handle visiting the results of this query. */ bool branchResult = _visit(cs.ChangesetId, branches, null, null, branches[i] + path_part, tv, tv, tv, RecursionType.Full); if (branchResult) { results = true; } } } if (!results) { /* we got no results from our query, so display the changeset * (it won't be displayed otherwise) */ _visitor.visit(cs.ChangesetId, child, branches); //, branches); } } else { /* do we want to see it again? */ _visitor.visit(cs.ChangesetId, child, branches); //, branches); } } } catch (Exception e) { _visitor.visit(cs.ChangesetId, csm.SourceVersion, e); } } } catch (Exception e) { _visitor.visit(parentID, csID, e); } } logger.DebugFormat("}}_visit:{0}", parentID); return(false == merges.empty()); }