feat(graph): add bindings and api

This commit is contained in:
Aleksey Kulikov 2021-10-06 11:36:38 +03:00
parent 618b4e7f05
commit 0ed5e7c797
4 changed files with 143 additions and 2 deletions

View file

@ -0,0 +1,53 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'libgit2_bindings.dart';
import '../error.dart';
import '../util.dart';
/// Determine if a commit is the descendant of another commit.
///
/// Note that a commit is not considered a descendant of itself, in contrast to
/// `git merge-base --is-ancestor`.
///
/// Throws a [LibGit2Error] if error occured.
bool descendantOf({
required Pointer<git_repository> repoPointer,
required Pointer<git_oid> commitPointer,
required Pointer<git_oid> ancestorPointer,
}) {
final result = libgit2.git_graph_descendant_of(
repoPointer,
commitPointer,
ancestorPointer,
);
if (result < 0) {
throw LibGit2Error(libgit2.git_error_last());
} else {
return result == 1 ? true : false;
}
}
/// Count the number of unique commits between two commit objects.
///
/// There is no need for branches containing the commits to have any upstream relationship,
/// but it helps to think of one as a branch and the other as its upstream, the ahead and
/// behind values will be what git would report for the branches.
List<int> aheadBehind({
required Pointer<git_repository> repoPointer,
required Pointer<git_oid> localPointer,
required Pointer<git_oid> upstreamPointer,
}) {
final ahead = calloc<Uint64>();
final behind = calloc<Uint64>();
libgit2.git_graph_ahead_behind(
ahead,
behind,
repoPointer,
localPointer,
upstreamPointer,
);
return [ahead.value, behind.value];
}

View file

@ -1,7 +1,5 @@
import 'dart:ffi';
import 'package:libgit2dart/libgit2dart.dart';
import 'package:libgit2dart/src/git_types.dart';
import 'bindings/libgit2_bindings.dart';
import 'bindings/odb.dart' as bindings;
import 'oid.dart';

View file

@ -12,6 +12,7 @@ import 'bindings/reset.dart' as reset_bindings;
import 'bindings/diff.dart' as diff_bindings;
import 'bindings/stash.dart' as stash_bindings;
import 'bindings/attr.dart' as attr_bindings;
import 'bindings/graph.dart' as graph_bindings;
import 'branch.dart';
import 'commit.dart';
import 'config.dart';
@ -1181,4 +1182,40 @@ class Repository {
force: force,
);
}
/// Checks if a commit is the descendant of another commit.
///
/// Note that a commit is not considered a descendant of itself, in contrast to
/// `git merge-base --is-ancestor`.
///
/// Throws a [LibGit2Error] if error occured.
bool descendantOf({required String commitSHA, required String ancestorSHA}) {
final commit = Oid.fromSHA(repo: this, sha: commitSHA);
final ancestor = Oid.fromSHA(repo: this, sha: ancestorSHA);
return graph_bindings.descendantOf(
repoPointer: _repoPointer,
commitPointer: commit.pointer,
ancestorPointer: ancestor.pointer,
);
}
/// Returns list with the `ahead` and `behind` number of unique commits respectively.
///
/// There is no need for branches containing the commits to have any upstream relationship,
/// but it helps to think of one as a branch and the other as its upstream, the ahead and
/// behind values will be what git would report for the branches.
List<int> aheadBehind({
required String localSHA,
required String upstreamSHA,
}) {
final local = Oid.fromSHA(repo: this, sha: localSHA);
final upstream = Oid.fromSHA(repo: this, sha: upstreamSHA);
return graph_bindings.aheadBehind(
repoPointer: _repoPointer,
localPointer: local.pointer,
upstreamPointer: upstream.pointer,
);
}
}

View file

@ -251,5 +251,58 @@ void main() {
expect(repo.getAttribute(path: 'file.jpg', name: 'text'), false);
expect(repo.getAttribute(path: 'file.sh', name: 'eol'), 'lf');
});
test('checks if commit is a descendant of another commit', () {
final commit1 = repo['821ed6e8'] as Commit;
final commit2 = repo['78b8bf12'] as Commit;
expect(
repo.descendantOf(
commitSHA: commit1.id.sha,
ancestorSHA: commit2.id.sha,
),
true,
);
expect(
repo.descendantOf(
commitSHA: commit1.id.sha,
ancestorSHA: commit1.id.sha,
),
false,
);
expect(
repo.descendantOf(
commitSHA: commit2.id.sha,
ancestorSHA: commit1.id.sha,
),
false,
);
commit1.free();
commit2.free();
});
test('returns number of ahead behind commits', () {
final commit1 = repo['821ed6e8'] as Commit;
final commit2 = repo['c68ff54a'] as Commit;
expect(
repo.aheadBehind(localSHA: commit1.id.sha, upstreamSHA: commit2.id.sha),
[4, 0],
);
expect(
repo.aheadBehind(localSHA: commit2.id.sha, upstreamSHA: commit1.id.sha),
[0, 4],
);
expect(
repo.aheadBehind(localSHA: commit1.id.sha, upstreamSHA: commit1.id.sha),
[0, 0],
);
commit1.free();
commit2.free();
});
});
}