Skip to content

Add revwalk globs #184

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions LibGit2Sharp.Tests/CommitFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,28 @@ public void CanEnumerateCommitsFromMixedStartingPoints()
});
}

[Fact]
public void CanEnumerateCommitsUsingGlob()
{
AssertEnumerationOfCommits(
repo => new Filter { SinceGlob = "heads" },
new[]
{
"4c062a6", "e90810b", "6dcf9bf", "a4a7dce", "be3563a", "c47800c", "9fd738e", "4a202b3", "41bc8c6", "5001298", "5b5b025", "8496071"
});
}

[Fact]
public void CanHideCommitsUsingGlob()
{
AssertEnumerationOfCommits(
repo => new Filter { Since = "refs/heads/packed-test", UntilGlob = "packed" },
new[]
{
"4a202b3", "5b5b025", "8496071"
});
}

[Fact]
public void CanEnumerateCommitsFromAnAnnotatedTag()
{
Expand Down
71 changes: 26 additions & 45 deletions LibGit2Sharp/CommitLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ namespace LibGit2Sharp
public class CommitLog : IQueryableCommitLog
{
private readonly Repository repo;
private IList<object> includedIdentifier = new List<object> { "HEAD" };
private IList<object> excludedIdentifier = new List<object>();
private readonly GitSortOptions sortOptions;
readonly Filter queryFilter;

/// <summary>
/// Needed for mocking purposes.
Expand All @@ -30,27 +28,27 @@ protected CommitLog()
/// </summary>
/// <param name = "repo">The repository.</param>
internal CommitLog(Repository repo)
: this(repo, GitSortOptions.Time)
: this(repo, new Filter())
{
}

/// <summary>
/// Initializes a new instance of the <see cref = "CommitLog" /> class.
/// </summary>
/// <param name = "repo">The repository.</param>
/// <param name = "sortingStrategy">The sorting strategy which should be applied when enumerating the commits.</param>
internal CommitLog(Repository repo, GitSortOptions sortingStrategy)
/// <param name="queryFilter">The filter to use in querying commits</param>
internal CommitLog(Repository repo, Filter queryFilter)
{
this.repo = repo;
sortOptions = sortingStrategy;
this.queryFilter = queryFilter;
}

/// <summary>
/// Gets the current sorting strategy applied when enumerating the log
/// </summary>
public virtual GitSortOptions SortedBy
{
get { return sortOptions; }
get { return queryFilter.SortBy; }
}

#region IEnumerable<Commit> Members
Expand All @@ -61,12 +59,12 @@ public virtual GitSortOptions SortedBy
/// <returns>An <see cref = "IEnumerator{T}" /> object that can be used to iterate through the log.</returns>
public virtual IEnumerator<Commit> GetEnumerator()
{
if ((repo.Info.IsEmpty) && includedIdentifier.Any(o => PointsAtTheHead(o.ToString()))) // TODO: ToString() == fragile
if ((repo.Info.IsEmpty) && queryFilter.SinceList.Any(o => PointsAtTheHead(o.ToString()))) // TODO: ToString() == fragile
{
return Enumerable.Empty<Commit>().GetEnumerator();
}

return new CommitEnumerator(repo, includedIdentifier, excludedIdentifier, sortOptions);
return new CommitEnumerator(repo, queryFilter);
}

/// <summary>
Expand All @@ -88,41 +86,14 @@ IEnumerator IEnumerable.GetEnumerator()
public virtual ICommitLog QueryBy(Filter filter)
{
Ensure.ArgumentNotNull(filter, "filter");
Ensure.ArgumentNotNull(filter.Since, "filter.Since");
Ensure.ArgumentNotNullOrEmptyString(filter.Since.ToString(), "filter.Since");

return new CommitLog(repo, filter.SortBy)
{
includedIdentifier = ToList(filter.Since),
excludedIdentifier = ToList(filter.Until)
};
}

private static IList<object> ToList(object obj)
{
var list = new List<object>();

if (obj == null)
{
return list;
}

var types = new[]
{
typeof(string), typeof(ObjectId),
typeof(Commit), typeof(TagAnnotation),
typeof(Tag), typeof(Branch), typeof(DetachedHead),
typeof(Reference), typeof(DirectReference), typeof(SymbolicReference)
};

if (types.Contains(obj.GetType()))
if(string.IsNullOrEmpty(filter.SinceGlob))
{
list.Add(obj);
return list;
Ensure.ArgumentNotNull(filter.Since, "filter.Since");
Ensure.ArgumentNotNullOrEmptyString(filter.Since.ToString(), "filter.Since");
}

list.AddRange(((IEnumerable)obj).Cast<object>());
return list;
return new CommitLog(repo, filter);
}

private static bool PointsAtTheHead(string shaOrRefName)
Expand Down Expand Up @@ -222,17 +193,27 @@ private class CommitEnumerator : IEnumerator<Commit>
private readonly RevWalkerSafeHandle handle;
private ObjectId currentOid;

public CommitEnumerator(Repository repo, IList<object> includedIdentifier, IList<object> excludedIdentifier, GitSortOptions sortingStrategy)
public CommitEnumerator(Repository repo, Filter filter)
{
this.repo = repo;
int res = NativeMethods.git_revwalk_new(out handle, repo.Handle);
repo.RegisterForCleanup(handle);

Ensure.Success(res);

Sort(sortingStrategy);
Push(includedIdentifier);
Hide(excludedIdentifier);
Sort(filter.SortBy);
Push(filter.SinceList);
Hide(filter.UntilList);

if(!string.IsNullOrEmpty(filter.SinceGlob))
{
Ensure.Success(NativeMethods.git_revwalk_push_glob(handle, filter.SinceGlob));
}

if(!string.IsNullOrEmpty(filter.UntilGlob))
{
Ensure.Success(NativeMethods.git_revwalk_hide_glob(handle, filter.UntilGlob));
}
}

#region IEnumerator<Commit> Members
Expand Down
6 changes: 6 additions & 0 deletions LibGit2Sharp/Core/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,9 @@ public static extern int git_repository_set_workdir(
[DllImport(libgit2)]
public static extern int git_revwalk_hide(RevWalkerSafeHandle walker, ref GitOid oid);

[DllImport(libgit2)]
public static extern int git_revwalk_hide_glob(RevWalkerSafeHandle walker, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string glob);

[DllImport(libgit2)]
public static extern int git_revwalk_new(out RevWalkerSafeHandle walker, RepositorySafeHandle repo);

Expand All @@ -620,6 +623,9 @@ public static extern int git_repository_set_workdir(
[DllImport(libgit2)]
public static extern int git_revwalk_push(RevWalkerSafeHandle walker, ref GitOid oid);

[DllImport(libgit2)]
public static extern int git_revwalk_push_glob(RevWalkerSafeHandle walker, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string glob);

[DllImport(libgit2)]
public static extern void git_revwalk_reset(RevWalkerSafeHandle walker);

Expand Down
62 changes: 61 additions & 1 deletion LibGit2Sharp/Filter.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
namespace LibGit2Sharp
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace LibGit2Sharp
{
/// <summary>
/// Criterias used to filter out and order the commits of the repository when querying its history.
/// </summary>
public class Filter
{
IList<object> sinceList;
IList<object> untilList;

/// <summary>
/// Initializes a new instance of <see cref = "Filter" />.
/// </summary>
Expand Down Expand Up @@ -33,6 +40,19 @@ public Filter()
/// </summary>
public object Since { get; set; }

/// <summary>
/// Return a parsed list of Since objects.
/// </summary>
internal IList<object> SinceList
{
get { return sinceList ?? (sinceList = ToList(Since)); }
}

/// <summary>
/// A string glob to using as a starting point for the revwalk.
/// </summary>
public string SinceGlob { get; set; }

/// <summary>
/// A pointer to a commit object or a list of pointers which will be excluded (along with ancestors) from the enumeration.
/// <para>
Expand All @@ -42,5 +62,45 @@ public Filter()
/// </para>
/// </summary>
public object Until { get; set; }

/// <summary>
/// Return a parsed list of Until objects.
/// </summary>
internal IList<object> UntilList
{
get { return untilList ?? (untilList = ToList(Until)); }
}

/// <summary>
/// A string glob to hide from the revwalk.
/// </summary>
public string UntilGlob { get; set; }

static IList<object> ToList(object obj)
{
var list = new List<object>();

if (obj == null)
{
return list;
}

var types = new[]
{
typeof(string), typeof(ObjectId),
typeof(Commit), typeof(TagAnnotation),
typeof(Tag), typeof(Branch), typeof(DetachedHead),
typeof(Reference), typeof(DirectReference), typeof(SymbolicReference)
};

if (types.Contains(obj.GetType()))
{
list.Add(obj);
return list;
}

list.AddRange(((IEnumerable)obj).Cast<object>());
return list;
}
}
}