feat(revparse): add bindings and api

This commit is contained in:
Aleksey Kulikov 2021-09-01 16:53:40 +03:00
parent 3b13646b1b
commit ce9384cac9
8 changed files with 372 additions and 57 deletions

View file

@ -0,0 +1,23 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import '../error.dart';
import 'libgit2_bindings.dart';
import '../util.dart';
/// Find a merge base between two commits.
///
/// Throws a [LibGit2Error] if error occured.
Pointer<git_oid> mergeBase(
Pointer<git_repository> repo,
Pointer<git_oid> one,
Pointer<git_oid> two,
) {
final out = calloc<git_oid>();
final error = libgit2.git_merge_base(out, repo, one, two);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
} else {
return out;
}
}

View file

@ -510,33 +510,5 @@ Pointer<git_repository> wrapODB(Pointer<git_odb> odb) {
}
}
/// Find a single object, as specified by a [spec] string.
/// See `man gitrevisions`, or https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions
/// for information on the syntax accepted.
///
/// The returned object should be released when no longer needed.
///
/// Throws a [LibGit2Error] if error occured.
Pointer<git_object> revParseSingle(
Pointer<git_repository> repo,
String spec,
) {
final out = calloc<Pointer<git_object>>();
final specC = spec.toNativeUtf8().cast<Int8>();
final error = libgit2.git_revparse_single(
out,
repo,
specC,
);
calloc.free(specC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
} else {
return out.value;
}
}
/// Free a previously allocated repository.
void free(Pointer<git_repository> repo) => libgit2.git_repository_free(repo);

View file

@ -0,0 +1,85 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'libgit2_bindings.dart';
import '../error.dart';
import '../util.dart';
/// Parse a revision string for from, to, and intent.
///
/// See `man gitrevisions` or https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions
/// for information on the syntax accepted.
///
/// Throws a [LibGit2Error] if error occured.
Pointer<git_revspec> revParse(
Pointer<git_repository> repo,
String spec,
) {
final out = calloc<git_revspec>();
final specC = spec.toNativeUtf8().cast<Int8>();
final error = libgit2.git_revparse(out, repo, specC);
calloc.free(specC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
} else {
return out;
}
}
/// Find a single object, as specified by a [spec] revision string.
/// See `man gitrevisions`, or https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions
/// for information on the syntax accepted.
///
/// The returned object should be released when no longer needed.
///
/// Throws a [LibGit2Error] if error occured.
Pointer<git_object> revParseSingle(Pointer<git_repository> repo, String spec) {
final out = calloc<Pointer<git_object>>();
final specC = spec.toNativeUtf8().cast<Int8>();
final error = libgit2.git_revparse_single(
out,
repo,
specC,
);
calloc.free(specC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
} else {
return out.value;
}
}
/// Find a single object and intermediate reference by a [spec] revision string.
///
/// See `man gitrevisions`, or https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions
/// for information on the syntax accepted.
///
/// In some cases (@{<-n>} or <branchname>@{upstream}), the expression may point to an
/// intermediate reference. When such expressions are being passed in, reference_out will be
/// valued as well.
///
/// The returned object and reference should be released when no longer needed.
///
/// Throws a [LibGit2Error] if error occured.
List revParseExt(Pointer<git_repository> repo, String spec) {
final objectOut = calloc<Pointer<git_object>>();
final referenceOut = calloc<Pointer<git_reference>>();
final specC = spec.toNativeUtf8().cast<Int8>();
var result = [];
final error = libgit2.git_revparse_ext(objectOut, referenceOut, repo, specC);
calloc.free(specC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
} else {
result.add(objectOut.value);
if (referenceOut.value != nullptr) {
result.add(referenceOut.value);
}
return result;
}
}

View file

@ -19,3 +19,12 @@ enum GitFilemode { undreadable, tree, blob, blobExecutable, link, commit }
enum GitSort { none, topological, time, reverse }
enum GitObject { commit, tree, blob, tag }
/// Revparse flags, indicate the intended behavior of the spec.
///
/// [single]: the spec targeted a single object.
///
/// [range]: the spec targeted a range of commits.
///
/// [mergeBase]: the spec used the '...' operator, which invokes special semantics.
enum GitRevParse { single, range, mergeBase }

View file

@ -1,6 +1,7 @@
import 'dart:ffi';
import 'bindings/libgit2_bindings.dart';
import 'bindings/repository.dart' as bindings;
import 'bindings/merge.dart' as merge_bindings;
import 'commit.dart';
import 'config.dart';
import 'index.dart';
@ -8,6 +9,7 @@ import 'odb.dart';
import 'oid.dart';
import 'reference.dart';
import 'revwalk.dart';
import 'revparse.dart';
import 'enums.dart';
import 'util.dart';
@ -323,17 +325,6 @@ class Repository {
return Commit.lookup(this, oid);
}
/// Find a single object, as specified by a [spec] string.
/// See `man gitrevisions`, or https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions
/// for information on the syntax accepted.
///
/// The returned object should be released when no longer needed.
///
/// Throws a [LibGit2Error] if error occured.
Commit revParseSingle(String spec) {
return Commit(bindings.revParseSingle(_repoPointer, spec).cast());
}
/// Returns the list of commits starting from provided [oid].
///
/// If [sorting] isn't provided default will be used (reverse chronological order, like in git).
@ -348,4 +339,46 @@ class Repository {
return result;
}
/// Finds a single object, as specified by a [spec] revision string.
/// See `man gitrevisions`, or https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions
/// for information on the syntax accepted.
///
/// The returned object should be released when no longer needed.
///
/// Throws a [LibGit2Error] if error occured.
Commit revParseSingle(String spec) => RevParse.single(this, spec);
/// Finds a single object and intermediate reference (if there is one) by a [spec] revision string.
///
/// See `man gitrevisions`, or https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions
/// for information on the syntax accepted.
///
/// In some cases (@{<-n>} or <branchname>@{upstream}), the expression may point to an
/// intermediate reference. When such expressions are being passed in, reference_out will be
/// valued as well.
///
/// The returned object and reference should be released when no longer needed.
///
/// Throws a [LibGit2Error] if error occured.
RevParse revParseExt(String spec) => RevParse.ext(this, spec);
/// Parses a revision string for from, to, and intent.
///
/// See `man gitrevisions` or https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions
/// for information on the syntax accepted.
///
/// Throws a [LibGit2Error] if error occured.
RevSpec revParse(String spec) => RevParse.range(this, spec);
/// Finds a merge base between two commits.
///
/// Throws a [LibGit2Error] if error occured.
Oid mergeBase(Oid one, Oid two) {
return Oid(merge_bindings.mergeBase(
_repoPointer,
one.pointer,
two.pointer,
));
}
}

91
lib/src/revparse.dart Normal file
View file

@ -0,0 +1,91 @@
import 'dart:ffi';
import 'bindings/libgit2_bindings.dart';
import 'bindings/revparse.dart' as bindings;
import 'commit.dart';
import 'reference.dart';
import 'repository.dart';
import 'enums.dart';
class RevParse {
/// Finds a single object and intermediate reference (if there is one) by a [spec] revision string.
///
/// See `man gitrevisions`, or https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions
/// for information on the syntax accepted.
///
/// In some cases (@{<-n>} or <branchname>@{upstream}), the expression may point to an
/// intermediate reference. When such expressions are being passed in, reference_out will be
/// valued as well.
///
/// The returned object and reference should be released when no longer needed.
///
/// Throws a [LibGit2Error] if error occured.
RevParse.ext(Repository repo, String spec) {
final pointers = bindings.revParseExt(repo.pointer, spec);
object = Commit(pointers[0].cast<git_commit>());
if (pointers.length == 2) {
reference = Reference(repo.pointer, pointers[1].cast<git_reference>());
} else {
reference = null;
}
}
/// Object found by a revision string.
late final Commit object;
/// Intermediate reference found by a revision string.
late final Reference? reference;
/// Finds a single object, as specified by a [spec] revision string.
/// See `man gitrevisions`, or https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions
/// for information on the syntax accepted.
///
/// The returned object should be released when no longer needed.
///
/// Throws a [LibGit2Error] if error occured.
static Commit single(Repository repo, String spec) {
return Commit(bindings.revParseSingle(repo.pointer, spec).cast());
}
/// Parses a revision string for from, to, and intent.
///
/// See `man gitrevisions` or https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions
/// for information on the syntax accepted.
///
/// Throws a [LibGit2Error] if error occured.
static RevSpec range(Repository repo, String spec) {
return RevSpec(bindings.revParse(repo.pointer, spec));
}
}
class RevSpec {
/// Initializes a new instance of [RevSpec] class from provided
/// pointer to revspec object in memory.
RevSpec(this._revSpecPointer);
/// Pointer to memory address for allocated revspec object.
late final Pointer<git_revspec> _revSpecPointer;
/// The left element of the revspec; must be freed by the user.
Commit get from => Commit(_revSpecPointer.ref.from.cast());
/// The right element of the revspec; must be freed by the user.
Commit? get to {
if (_revSpecPointer.ref.to == nullptr) {
return null;
} else {
return Commit(_revSpecPointer.ref.to.cast());
}
}
/// The intent of the revspec.
GitRevParse get flags {
final flag = _revSpecPointer.ref.flags;
if (flag == 1) {
return GitRevParse.single;
} else if (flag == 2) {
return GitRevParse.range;
} else {
return GitRevParse.mergeBase;
}
}
}