Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add revwalk globs #184

Closed
wants to merge 6 commits into from

2 participants

Timothy Clem nulltoken
Timothy Clem
Owner

This adds in the ability to filter your revwalk by pushing or hiding globs enabling functionality like:

git log --not --remotes or git log --branches

I'm open to suggestions on the filter API. The glob patterns didn't make sense to add in with the rest of the list of stuff that Since and Until know how to deal with because they are never really git objects of any sort. Improving the Filter object gave me the chance to refactor how it was use internally a little bit and pass the filter down a few more layers to get rid of a few ctors with growing parameter lists.

LibGit2Sharp.Tests/CommitFixture.cs
@@ -98,7 +98,6 @@ public void QueryingTheCommitHistoryWithUnknownShaOrInvalidEntryPointThrows()
{
Assert.Throws<LibGit2SharpException>(() => repo.Commits.QueryBy(new Filter { Since = Constants.UnknownSha }).Count());
Assert.Throws<LibGit2SharpException>(() => repo.Commits.QueryBy(new Filter { Since = "refs/heads/deadbeef" }).Count());
- Assert.Throws<ArgumentNullException>(() => repo.Commits.QueryBy(new Filter { Since = null }).Count());
nulltoken Owner

Why removing this? What should the following statements be expected to return?

  • repo.Commits.QueryBy(new Filter { Since = null })
  • repo.Commits.QueryBy(new Filter { Since = string.Empty })
Timothy Clem Owner
tclem added a note

Good catch - see aec0563

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
nulltoken
Owner

I like the refactoring proposal which pushes the logic inside the Filter type. This is where it belongs.
However, I'm not a fan of publicly exposing the SinceList|UntilList properties. Could you make them internal?

nulltoken
Owner

Rather than adding a SinceGlob|UntilGlob property to the Filter type, I I'd prefer adding to the ReferenceCollection type a new IEnumerable<Reference> FromGlob(string pattern) method.

This would allow such construct

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

@nulltoken isn't that going to be expensive in terms of having to lookup all the refs that match the glob pattern? Wouldn't you rather have the existing libgit2 apis for pushing and hiding a glob do that?

nulltoken
Owner

isn't that going to be expensive in terms of having to lookup all the refs that match the glob pattern? Wouldn't you rather have the existing libgit2 apis for pushing and hiding a glob do that?

Well, behind the scene, this is what git_revwalk_push_glob() does. I'd really like to have this unfolded and allow the API consumer to retrieve a list of refs from a glob, which could be eventually used to retrieve a commit log (or used to a different end).

The fast way would be to quickly implement that in C# on top of the current Refs enumerator (porting the libgit2 normalization algorithm and regex love). If you feel performance may become a concern, instead of the Refs enumerator, one could work against the result of Libgit2UnsafeHelper.ListAllReferenceNames() which would avoid the parsing/building of every reference.

Eventually, once this code is proven ok and covered with some tests, it'll be pushed down in libgit2.

nulltoken nulltoken referenced this pull request in libgit2/libgit2
Merged

Topic/refs fromglob #785

nulltoken
Owner

Very nice proposal and awesome refactoring!

Manually merged in vNext.

nulltoken nulltoken closed this
Timothy Clem
Owner

Awesome! Thanks @nulltoken!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
22 LibGit2Sharp.Tests/CommitFixture.cs
View
@@ -290,6 +290,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()
{
CanEnumerateCommitsFromATag(t => t);
71 LibGit2Sharp/CommitLog.cs
View
@@ -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.
@@ -30,7 +28,7 @@ protected CommitLog()
/// </summary>
/// <param name = "repo">The repository.</param>
internal CommitLog(Repository repo)
- : this(repo, GitSortOptions.Time)
+ : this(repo, new Filter())
{
}
@@ -38,11 +36,11 @@ internal CommitLog(Repository repo)
/// 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>
@@ -50,7 +48,7 @@ internal CommitLog(Repository repo, GitSortOptions sortingStrategy)
/// </summary>
public virtual GitSortOptions SortedBy
{
- get { return sortOptions; }
+ get { return queryFilter.SortBy; }
}
#region IEnumerable<Commit> Members
@@ -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>
@@ -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)
@@ -222,7 +193,7 @@ 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);
@@ -230,9 +201,19 @@ public CommitEnumerator(Repository repo, IList<object> includedIdentifier, IList
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
6 LibGit2Sharp/Core/NativeMethods.cs
View
@@ -612,6 +612,9 @@ public static bool RepositoryStateChecker(RepositorySafeHandle repositoryPtr, Fu
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);
[DllImport(libgit2)]
@@ -621,6 +624,9 @@ public static bool RepositoryStateChecker(RepositorySafeHandle repositoryPtr, Fu
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);
[DllImport(libgit2)]
62 LibGit2Sharp/Filter.cs
View
@@ -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>
@@ -34,6 +41,19 @@ public Filter()
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>
/// Can be either a <see cref = "string" /> containing the sha or reference canonical name to use,
@@ -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;
+ }
}
}
Something went wrong with that request. Please try again.