diff --git a/lib/src/bindings/revwalk.dart b/lib/src/bindings/revwalk.dart index c584663..a60be4c 100644 --- a/lib/src/bindings/revwalk.dart +++ b/lib/src/bindings/revwalk.dart @@ -63,6 +63,68 @@ void push({ } } +/// Push matching references. +/// +/// The OIDs pointed to by the references that match the given glob pattern +/// will be pushed to the revision walker. +/// +/// A leading 'refs/' is implied if not present as well as a trailing '/\*' +/// if the glob lacks '?', '*' or '['. +/// +/// Any references matching this glob which do not point to a committish will +/// be ignored. +void pushGlob({ + required Pointer walkerPointer, + required String glob, +}) { + final globC = glob.toNativeUtf8().cast(); + libgit2.git_revwalk_push_glob(walkerPointer, globC); + calloc.free(globC); +} + +/// Push the repository's HEAD. +void pushHead(Pointer walker) => + libgit2.git_revwalk_push_head(walker); + +/// Push the OID pointed to by a reference. +/// +/// The reference must point to a committish. +/// +/// Throws a [LibGit2Error] if error occured. +void pushRef({ + required Pointer walkerPointer, + required String refName, +}) { + final refNameC = refName.toNativeUtf8().cast(); + final error = libgit2.git_revwalk_push_ref(walkerPointer, refNameC); + + calloc.free(refNameC); + + if (error < 0) { + throw LibGit2Error(libgit2.git_error_last()); + } +} + +/// Push and hide the respective endpoints of the given range. +/// +/// The range should be of the form `..` The left-hand commit will be hidden +/// and the right-hand commit pushed. +/// +/// Throws a [LibGit2Error] if error occured. +void pushRange({ + required Pointer walkerPointer, + required String range, +}) { + final rangeC = range.toNativeUtf8().cast(); + final error = libgit2.git_revwalk_push_range(walkerPointer, rangeC); + + calloc.free(rangeC); + + if (error < 0) { + throw LibGit2Error(libgit2.git_error_last()); + } +} + /// Get the list of commits from the revision walk. /// /// The initial call to this method is not blocking when iterating through a @@ -118,6 +180,48 @@ void hide({ } } +/// Hide matching references. +/// +/// The OIDs pointed to by the references that match the given glob pattern and +/// their ancestors will be hidden from the output on the revision walk. +/// +/// A leading 'refs/' is implied if not present as well as a trailing '/\*' if +/// the glob lacks '?', '*' or '['. +/// +/// Any references matching this glob which do not point to a committish will +/// be ignored. +void hideGlob({ + required Pointer walkerPointer, + required String glob, +}) { + final globC = glob.toNativeUtf8().cast(); + libgit2.git_revwalk_hide_glob(walkerPointer, globC); + calloc.free(globC); +} + +/// Hide the repository's HEAD. +void hideHead(Pointer walker) => + libgit2.git_revwalk_hide_head(walker); + +/// Hide the OID pointed to by a reference. +/// +/// The reference must point to a committish. +/// +/// Throws a [LibGit2Error] if error occured. +void hideRef({ + required Pointer walkerPointer, + required String refName, +}) { + final refNameC = refName.toNativeUtf8().cast(); + final error = libgit2.git_revwalk_hide_ref(walkerPointer, refNameC); + + calloc.free(refNameC); + + if (error < 0) { + throw LibGit2Error(libgit2.git_error_last()); + } +} + /// Reset the revision walker for reuse. /// /// This will clear all the pushed and hidden commits, and leave the walker in diff --git a/lib/src/revwalk.dart b/lib/src/revwalk.dart index 2088a4b..29faf68 100644 --- a/lib/src/revwalk.dart +++ b/lib/src/revwalk.dart @@ -57,6 +57,43 @@ class RevWalk { ); } + /// Adds matching references for the traversal. + /// + /// The OIDs pointed to by the references that match the given [glob] pattern + /// will be pushed to the revision walker. + /// + /// A leading "refs/" is implied if not present as well as a trailing "/\*" + /// if the glob lacks "?", "*" or "[". + /// + /// Any references matching this glob which do not point to a committish will + /// be ignored. + void pushGlob(String glob) { + bindings.pushGlob(walkerPointer: _revWalkPointer, glob: glob); + } + + /// Adds the repository's HEAD for the traversal. + void pushHead() => bindings.pushHead(_revWalkPointer); + + /// Adds the oid pointed to by a [reference] for the traversal. + /// + /// The reference must point to a committish. + /// + /// Throws a [LibGit2Error] if error occured. + void pushReference(String reference) { + bindings.pushRef(walkerPointer: _revWalkPointer, refName: reference); + } + + /// Adds and hide the respective endpoints of the given [range] for the + /// traversal. + /// + /// The range should be of the form `..` The left-hand commit will be hidden + /// and the right-hand commit pushed. + /// + /// Throws a [LibGit2Error] if error occured. + void pushRange(String range) { + bindings.pushRange(walkerPointer: _revWalkPointer, range: range); + } + /// Marks a commit [oid] (and its ancestors) uninteresting for the output. /// /// The given id must belong to a committish on the walked repository. @@ -72,6 +109,32 @@ class RevWalk { ); } + /// Hides matching references. + /// + /// The OIDs pointed to by the references that match the given [glob] pattern + /// and their ancestors will be hidden from the output on the revision walk. + /// + /// A leading "refs/" is implied if not present as well as a trailing "/\*" if + /// the glob lacks "?", "*" or "[". + /// + /// Any references matching this glob which do not point to a committish will + /// be ignored. + void hideGlob(String glob) { + bindings.hideGlob(walkerPointer: _revWalkPointer, glob: glob); + } + + /// Hides the repository's HEAD and it's ancestors. + void hideHead() => bindings.hideHead(_revWalkPointer); + + /// Hides the oid pointed to by a [reference]. + /// + /// The reference must point to a committish. + /// + /// Throws a [LibGit2Error] if error occured. + void hideReference(String reference) { + bindings.hideRef(walkerPointer: _revWalkPointer, refName: reference); + } + /// Resets the revision walker for reuse. /// /// This will clear all the pushed and hidden commits, and leave the walker diff --git a/test/revwalk_test.dart b/test/revwalk_test.dart index 3728e3d..005430b 100644 --- a/test/revwalk_test.dart +++ b/test/revwalk_test.dart @@ -94,6 +94,81 @@ void main() { walker.free(); }); + test('adds matching references for traversal with provided glob', () { + final walker = RevWalk(repo); + + walker.pushGlob('heads'); + final commits = walker.walk(); + expect(commits.length, 7); + + for (final c in commits) { + c.free(); + } + walker.free(); + }); + + test("adds repository's head for traversal", () { + final walker = RevWalk(repo); + + walker.pushHead(); + final commits = walker.walk(); + expect(commits.length, 6); + + for (final c in commits) { + c.free(); + } + walker.free(); + }); + + test('adds reference for traversal with provided name', () { + final walker = RevWalk(repo); + + walker.pushReference('refs/heads/master'); + final commits = walker.walk(); + expect(commits.length, 6); + + for (final c in commits) { + c.free(); + } + walker.free(); + }); + + test('throws when trying to add reference for traversal with invalid name', + () { + final walker = RevWalk(repo); + + expect( + () => walker.pushReference('invalid'), + throwsA(isA()), + ); + + walker.free(); + }); + + test('adds range for traversal', () { + final walker = RevWalk(repo); + + walker.pushRange('HEAD..@{-1}'); + final commits = walker.walk(); + expect(commits.length, 1); + + for (final c in commits) { + c.free(); + } + walker.free(); + }); + + test('throws when trying to add invalid range for traversal', () { + final walker = RevWalk(repo); + + expect( + () => walker.pushRange('HEAD..invalid'), + throwsA(isA()), + ); + + walker.free(); + }); + test('successfully hides commit and its ancestors', () { final walker = RevWalk(repo); @@ -120,6 +195,76 @@ void main() { walker.free(); }); + test('hides oids of references for provided glob pattern', () { + final walker = RevWalk(repo); + + walker.pushGlob('heads'); + final commits = walker.walk(); + expect(commits.length, 7); + + walker.pushGlob('heads'); + walker.hideGlob('*master'); + final hiddenCommits = walker.walk(); + expect(hiddenCommits.length, 1); + + hiddenCommits[0].free(); + for (final c in commits) { + c.free(); + } + walker.free(); + }); + + test('hides head', () { + final head = repo.head; + final walker = RevWalk(repo); + + walker.push(head.target); + final commits = walker.walk(); + expect(commits.length, 6); + + walker.push(head.target); + walker.hideHead(); + final hiddenCommits = walker.walk(); + expect(hiddenCommits.length, 0); + + for (final c in commits) { + c.free(); + } + head.free(); + walker.free(); + }); + + test('hides oids of reference with provided name', () { + final head = repo.head; + final walker = RevWalk(repo); + + walker.push(head.target); + final commits = walker.walk(); + expect(commits.length, 6); + + walker.push(head.target); + walker.hideReference('refs/heads/master'); + final hiddenCommits = walker.walk(); + expect(hiddenCommits.length, 0); + + for (final c in commits) { + c.free(); + } + head.free(); + walker.free(); + }); + + test('throws when trying to hide oids of reference with invalid name', () { + final walker = RevWalk(repo); + + expect( + () => walker.hideReference('invalid'), + throwsA(isA()), + ); + + walker.free(); + }); + test('successfully resets walker', () { final walker = RevWalk(repo); final start = Oid.fromSHA(repo: repo, sha: log.first);