public ITree Build( IRepositoryData repository, IRemote remoteToUse, IBranchesKnowledge branchesKnowledge, IBranchPickingOptions branchPickingOptions, ITagPickingOptions tagPickingOptions) { ITree tree = new Tree(); tree.SetCommits(repository.Commits); AddBranches(branchesKnowledge, repository.Commits, branchPickingOptions, tree); AddTags(repository.Tags, tagPickingOptions, tree); return(tree); }
private void AddBranches( IBranchesKnowledge branchesKnowledge, ICommitsData commitsData, IBranchPickingOptions branchPickingOptions, ITree tree) { // Branches in the writing order. IBranch[] branchesOrdered = branchesKnowledge.EnumerateBranchesInLogicalOrder().ToArray(); IBranchPicker branchPicker = _branchPickerFactory.CreateBranchPicker(branchPickingOptions); // Filter them so that we get only those we want to write. IBranch[] branchesFiltered = branchesOrdered.Where(b => branchPicker.ShouldBePicked(b.Label)).ToArray(); var commitsSet = new HashSet <ICommit>(commitsData); foreach (IBranch b in branchesFiltered) { ICommit tip = commitsData.GetByHash(b.Tip); var hashesInBranch = new List <IHash>(commitsSet.Count / 3); IEnumerable <ICommit> upTheTree = commitsData.EnumerateUpTheHistoryFrom(tip); foreach (ICommit commit in upTheTree) { if (!commitsSet.Contains(commit)) { break; } hashesInBranch.Add(commit.Hash); commitsSet.Remove(commit); } hashesInBranch.Reverse(); tree.AddBranch(b, hashesInBranch); } }
protected override void RunInternal() { // Get the immutable repository information. IRepositoryData repositoryData = _loader.LoadFrom(_repositoryDir.FullName); // Pick the remote to work on. IRemote remoteToUse = _remoteHelper.PickRemote(repositoryData, Options.RemoteToUse); // Create the tree. IBranchingStrategy strategy = _strategyProvider.GetStrategy(Options.LesserBranchesRegex); IBranch[] allBranches = repositoryData.Branches.GetFor(remoteToUse).ToArray(); IBranchesKnowledge branchesKnowledge = strategy.CreateKnowledge(allBranches); // Options for building the tree. ITagPickingOptions tagPickingOptions = TagPickingOptions.Set( Options.TagPickingMode, Options.TagCount, Options.IncludeOrphanedTags); IBranchPickingOptions branchPickingOptions = BranchPickingOptions.Set( Options.IncludeBranchesRegices, Options.ExcludeBranchesRegices); ITree tree = _treeBuilder.Build( repositoryData, remoteToUse, branchesKnowledge, branchPickingOptions, tagPickingOptions); SimplifyTree(tree); string tempPath = _fileSystem.Path.GetTempFileName(); tempPath = _fileSystem.Path.ChangeExtension(tempPath, "gv"); // Rendering options. TreeRenderingOptions renderingOptions = TreeRenderingOptions.Default; renderingOptions.ForceTreatAsGitHub = Options.ForceTreatAsGitHub; // ReSharper disable once AssignNullToNotNullAttribute using (IFileStream fileStream = _fileSystem.File.OpenWrite(tempPath)) { using (IStreamWriter textWriter = _textWriterFactory.CreateStreamWriter(fileStream)) { IGraphVizWriter graphVizWriter = _graphVizFactory.CreateGraphVizWriter(textWriter); ITreeRenderer treeRenderer = _treeRendererFactory.CreateRenderer(graphVizWriter); treeRenderer.Render(tree, remoteToUse, branchesKnowledge, renderingOptions); } } string targetPath = PrepareTargetPath(); string graphVizCommand = _appPathProvider.GetProperAppPath(ExternalApp.GraphViz); string graphVizArgs = $@"""{tempPath}"" -T{_outputFormat} -o""{targetPath}"""; Log.Debug($"Starting GraphViz with arguments: [{graphVizArgs}]."); int code = _processRunner.Execute(graphVizCommand, graphVizArgs); if (code != 0) { Log.Fatal("GraphViz execution failed."); } else { Log.Info("GraphViz execution succeeded."); Log.Info($"Saved to {targetPath}."); } }
public IBranchesKnowledge CreateKnowledge(IEnumerable <IBranch> branches) { IBranchesKnowledge branchesKnowledge = _knowledgeMaker(this, _workItemRegex, _colorsAndRegices, branches); return(branchesKnowledge); }
public void Render( ITree tree, IRemote usedRemote, IBranchesKnowledge branchesKnowledge, ITreeRenderingOptions options) { IRemoteWebUrlProvider remoteUrlProvider = _remoteWebUrlProviderFactory.CreateUrlProvider(usedRemote.Url, options.ForceTreatAsGitHub); WriteHeader(); IBranch[] branchesWithNodes = tree.Branches.Where(b => tree.EnumerateNodes(b).Any()).ToArray(); IBranch[] currentBranchesSorted = OrderByFirstCommitDate(branchesWithNodes, tree).ToArray(); IPairList <INode, INode> unwrittenMerges = new PairList <INode, INode>(); IPairList <INode, INode> writtenMerges = new PairList <INode, INode>(); // Main branches. foreach (IBranch b in currentBranchesSorted) { _gvWriter.EmptyLine(); _gvWriter.Comment($"Branch {b.Label}."); using (_gvWriter.StartSubGraph()) { _gvWriter.SetNodeAttributes(AttrSet.Empty.Group(b.Label)); Color drawColor = branchesKnowledge.GetSuggestedDrawingColorFor(b); bool isLesser = branchesKnowledge.IsAWorkItemBranch(b); IAttrSet nodeStyle = _style.GetBranchNodeStyle(drawColor, isLesser); IAttrSet edgeStyle = _style.GetBranchEdgeStyle(drawColor, isLesser); _gvWriter.SetNodeAttributes(nodeStyle); _gvWriter.SetEdgeAttributes(edgeStyle); INode[] nodes = tree.EnumerateNodes(b).ToArray(); for (int i = 0; i < nodes.Length; i++) { INode currentNode = nodes[i]; WriteNode(currentNode, remoteUrlProvider); if (i == 0) { // Starting node. INode parent = currentNode.Parents.FirstOrDefault(); bool hasParent = parent != null; if (!hasParent) { _gvWriter.Comment("Starting line."); string id = string.Format($"{currentNode.Commit.Treeish}_start"); // Write starting empty node. using (_gvWriter.StartSubGraph()) { _gvWriter.RawAttributes(AttrSet.Empty.Rank(RankType.Source)); _gvWriter.Node(id, AttrSet.Empty.Width(0).Height(0).PenWidth(0)); } _gvWriter.Edge(id, currentNode.Commit, _style.EdgeBranchStartVirtual); _gvWriter.EmptyLine(); } else { // It is some other branch, and we draw that edge. WriteEdge(parent, currentNode, remoteUrlProvider); writtenMerges.Add(parent, currentNode); } } bool isLast = i == nodes.Length - 1; INode nextNode = isLast ? null : nodes[i + 1]; if (!isLast) { // Edge to the next node. WriteEdge(currentNode, nextNode, remoteUrlProvider); } else { WriteBranchPointer(b, tree, isLesser, remoteUrlProvider); } INode[] otherChildren = currentNode.Children.Except(nextNode).ToArray(); foreach (INode child in otherChildren) { unwrittenMerges.Add(currentNode, child); } } } } IBranch[] branchesWithoutNodes = tree.Branches.Except(branchesWithNodes).ToArray(); foreach (IBranch b in branchesWithoutNodes) { bool isLesser = branchesKnowledge.IsAWorkItemBranch(b); WriteBranchPointer(b, tree, isLesser, remoteUrlProvider); } // Tags. ITag[] tags = tree.Tags.ToArray(); foreach (ITag t in tags) { _gvWriter.EmptyLine(); INode n = tree.GetNode(t.Tip); string id = MakeNodeIdForPointerLabel(n, t); using (_gvWriter.StartSubGraph()) { _gvWriter.Comment($"Tag {t.Label}."); _gvWriter.RawAttributes(AttrSet.Empty.Rank(RankType.Same)); string url = remoteUrlProvider?.GetTagLink(t); _gvWriter.Node(id, _style.LabelTag.Label(t.Label).Url(url)); _gvWriter.Edge(n.Commit, id, _style.EdgeTagLabel); } } INode[] allLeftOvers = tree.Nodes.Where(n => tree.GetContainingBranch(n) == null).ToArray(); if (allLeftOvers.Length > 0) { using (_gvWriter.StartSubGraph()) { _gvWriter.EmptyLine(); _gvWriter.Comment("Leftover nodes."); _gvWriter.SetNodeAttributes(_style.NodeOrphaned); foreach (INode currentNode in allLeftOvers) { WriteNode(currentNode, remoteUrlProvider); // Remember children. foreach (INode child in currentNode.Children) { unwrittenMerges.Add(currentNode, child); } } } } PairList <INode, INode> edgesToWrite = unwrittenMerges.Except(writtenMerges).ToPairList(); if (edgesToWrite.Count > 0) { using (_gvWriter.StartSubGraph()) { _gvWriter.EmptyLine(); _gvWriter.Comment("Other edges."); _gvWriter.SetEdgeAttributes(_style.EdgeOther); foreach (Tuple <INode, INode> edge in edgesToWrite) { _gvWriter.Edge(edge.Item1.Commit, edge.Item2.Commit); } } } WriteFooter(); }