diff --git a/lib/src/bindings/reference.dart b/lib/src/bindings/reference.dart index 5a3734d..42434e1 100644 --- a/lib/src/bindings/reference.dart +++ b/lib/src/bindings/reference.dart @@ -65,6 +65,25 @@ Pointer lookup(Pointer 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 lookupDWIM(Pointer repo, String name) { + final out = calloc>(); + final nameC = name.toNativeUtf8().cast(); + 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 ref) { var result = calloc(); diff --git a/lib/src/reference.dart b/lib/src/reference.dart index 5363be9..338c172 100644 --- a/lib/src/reference.dart +++ b/lib/src/reference.dart @@ -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 repo, String name) { + libgit2.git_libgit2_init(); + _refPointer = bindings.lookupDWIM(repo, name); + } + /// Pointer to memory address for allocated reference object. late Pointer _refPointer; diff --git a/lib/src/repository.dart b/lib/src/repository.dart index 573b549..cf557b1 100644 --- a/lib/src/repository.dart +++ b/lib/src/repository.dart @@ -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. diff --git a/test/reference_test.dart b/test/reference_test.dart index 65a12cc..51e58f7 100644 --- a/test/reference_test.dart +++ b/test/reference_test.dart @@ -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()), + ); + }); + }); + test('returns log for reference', () { final ref = repo.getReference('refs/heads/master'); expect(ref.log.last.message, 'commit (initial): init');