Skip to content

Commit

Permalink
Merge pull request #17 from adamralph/no-stackoverflow
Browse files Browse the repository at this point in the history
remove recursion to avoid stack overflow on large histories
  • Loading branch information
adamralph authored Oct 21, 2018
2 parents 2dd82d0 + f7a6222 commit f5b194b
Showing 1 changed file with 70 additions and 14 deletions.
84 changes: 70 additions & 14 deletions MinVer/Versioner.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace MinVer
{
using System;
using System.Collections.Generic;
using System.Linq;
using LibGit2Sharp;
Expand All @@ -10,38 +11,93 @@ public static Version GetVersion(string path)
{
using (var repo = new Repository(path))
{
return GetVersion(repo.Commits.FirstOrDefault(), 0, repo.Tags, new HashSet<string>());
return GetVersion(repo.Commits.FirstOrDefault(), repo.Tags.ToList());
}
}

private static Version GetVersion(Commit commit, int height, TagCollection tags, HashSet<string> commitsChecked)
private static Version GetVersion(Commit commit, List<Tag> tags)
{
if (commit == default)
{
return new Version();
}

if (!commitsChecked.Add(commit.Sha))
var commitsChecked = new HashSet<string>();
var count = 0;
var height = 0;
var candidates = new List<Candidate>();
var commitsToCheck = new Stack<Tuple<Commit, int>>();

while (true)
{
return null;
if (commitsChecked.Add(commit.Sha))
{
++count;

var commitVersion = GetVersionOrDefault(tags, commit);

if (commitVersion != default)
{
var candidate = new Candidate { Version = commitVersion, Commit = commit, Height = height };
Log($"Detected {candidate}.");
candidates.Add(candidate);
}
else
{
foreach (var parent in commit.Parents.Reverse())
{
commitsToCheck.Push(Tuple.Create(parent, height + 1));
}

if (commitsToCheck.Count == 0 || commitsToCheck.Peek().Item2 <= height)
{
var candidate = new Candidate { Version = new Version(), Commit = commit, Height = height };
Log($"Inferred {candidate}.");
candidates.Add(candidate);
}
}
}

if (commitsToCheck.Count == 0)
{
break;
}

(commit, height) = commitsToCheck.Pop();
}

var version = GetVersionOrDefault(tags, commit);
Log($"{count:N0} commits checked.");

if (version != default)
var orderedCandidates = candidates.OrderBy(candidate => candidate.Version).ToList();

foreach (var candidate in orderedCandidates.Take(orderedCandidates.Count - 1))
{
return version.AddHeight(height);
Log($"Ignoring {candidate}...");
}

return commit.Parents
.Select(parent => GetVersion(parent, height + 1, tags, commitsChecked))
.Where(_ => _ != default)
.OrderByDescending(_ => _)
.FirstOrDefault() ??
new Version().AddHeight(height);
var selectedCandidate = orderedCandidates.Last();
Log($"Using {selectedCandidate}.");

var calculatedVersion = selectedCandidate.Version.AddHeight(selectedCandidate.Height);
Log($"Calculated {calculatedVersion}.");

return calculatedVersion;
}

private class Candidate
{
public Version Version { get; set; }

public Commit Commit { get; set; }

public int Height { get; set; }

public override string ToString() => $"{{ {nameof(this.Version)}: {this.Version}, {nameof(this.Commit)}: {this.Commit}, {nameof(this.Height)}: {this.Height} }}";
}

private static Version GetVersionOrDefault(TagCollection tags, Commit commit) => tags
private static void Log(string message) => Console.Error.WriteLine($"MinVer: {message}");

private static Version GetVersionOrDefault(List<Tag> tags, Commit commit) => tags
.Where(tag => tag.Target.Sha == commit.Sha)
.Select(tag => Version.ParseOrDefault(tag.FriendlyName))
.Where(_ => _ != default)
Expand Down

0 comments on commit f5b194b

Please sign in to comment.