feat(reference): add ability to lookup reference by shorthand name

This commit is contained in:
Aleksey Kulikov 2021-08-06 20:28:38 +03:00
parent cfc6d0412b
commit 2170965ad8
4 changed files with 83 additions and 0 deletions

View file

@ -65,6 +65,25 @@ Pointer<git_reference> lookup(Pointer<git_repository> repo, String name) {
}
}
/// Lookup a reference by DWIMing its short name.
///
/// Apply the git precendence rules to the given shorthand to determine which reference
/// the user is referring to.
///
/// Throws a [LibGit2Error] if error occured.
Pointer<git_reference> lookupDWIM(Pointer<git_repository> repo, String name) {
final out = calloc<Pointer<git_reference>>();
final nameC = name.toNativeUtf8().cast<Int8>();
final error = libgit2.git_reference_dwim(out, repo, nameC);
calloc.free(nameC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
} else {
return out.value;
}
}
/// Get the full name of a reference.
String name(Pointer<git_reference> ref) {
var result = calloc<Int8>();

View file

@ -90,6 +90,19 @@ class Reference {
_refPointer = bindings.lookup(repo, name);
}
/// Initializes a new instance of the [Reference] class by
/// lookingup a reference by DWIMing it's short [name] in a repository.
///
/// Should be freed with `free()` to release allocated memory.
///
/// The name will be checked for validity.
///
/// Throws a [LibGit2Error] if error occured.
Reference.lookupDWIM(Pointer<git_repository> repo, String name) {
libgit2.git_libgit2_init();
_refPointer = bindings.lookupDWIM(repo, name);
}
/// Pointer to memory address for allocated reference object.
late Pointer<git_reference> _refPointer;

View file

@ -227,6 +227,12 @@ class Repository {
/// Throws a [LibGit2Error] if error occured.
Reference getReference(String name) => Reference.lookup(_repoPointer, name);
/// Returns [Reference] object by lookingup a short [name] in repository.
///
/// Throws a [LibGit2Error] if error occured.
Reference getReferenceDWIM(String name) =>
Reference.lookupDWIM(_repoPointer, name);
/// Checks if a reflog exists for the specified reference [name].
///
/// Throws a [LibGit2Error] if error occured.

View file

@ -16,6 +16,12 @@ void main() {
late final Repository repo;
final tmpDir = '${Directory.systemTemp.path}/ref_testrepo/';
// pros of using setUpAll:
// - reduced amount of writes that leads to lesser burden on SSD drive
// - better speed of test suite than with setUp
// cons of using setUpAll:
// - fail in test might lead to failing tests below it in file
// - necessity to do clean up at the end of test if it creates references
setUpAll(() async {
if (await Directory(tmpDir).exists()) {
await Directory(tmpDir).delete(recursive: true);
@ -352,6 +358,45 @@ void main() {
});
});
group('.lookupDWIM()', () {
test('finds a reference with provided name', () {
final remoteRef = repo.createReference(
name: 'refs/remotes/origin/master',
target: lastCommit,
);
expect(remoteRef.shorthand, 'origin/master');
final tagRef = repo.createReference(
name: 'refs/tags/v1',
target: lastCommit,
);
expect(tagRef.shorthand, 'v1');
var ref = repo.getReferenceDWIM('refs/heads/master');
expect(ref.name, 'refs/heads/master');
ref = repo.getReferenceDWIM('master');
expect(ref.name, 'refs/heads/master');
ref = repo.getReferenceDWIM('origin/master');
expect(ref.name, 'refs/remotes/origin/master');
ref = repo.getReferenceDWIM('v1');
expect(ref.name, 'refs/tags/v1');
remoteRef.delete();
tagRef.delete();
ref.free();
});
test('throws when error occured', () {
expect(
() => repo.getReferenceDWIM('refs/heads/not/there'),
throwsA(isA<LibGit2Error>()),
);
});
});
test('returns log for reference', () {
final ref = repo.getReference('refs/heads/master');
expect(ref.log.last.message, 'commit (initial): init');