From 2cf974c62432f477321b2771e52f825223b0eda6 Mon Sep 17 00:00:00 2001 From: Aleksey Kulikov Date: Sat, 4 Sep 2021 12:04:28 +0300 Subject: [PATCH] feat(repository): add ability to lookup different types of git objects with [] --- lib/src/blob.dart | 16 +++++++++++--- lib/src/commit.dart | 10 ++++----- lib/src/git_types.dart | 20 ++++++++--------- lib/src/index.dart | 10 ++++----- lib/src/oid.dart | 16 +++++++++----- lib/src/repository.dart | 44 ++++++++++++++++++++++++++++---------- lib/src/tag.dart | 18 ++++++++++++---- lib/src/tree.dart | 15 ++++++++++--- test/blob_test.dart | 8 +++---- test/commit_test.dart | 12 +++++------ test/repository_test.dart | 10 ++++----- test/tag_test.dart | 6 +++--- test/tree_test.dart | 4 ++-- test/treebuilder_test.dart | 2 +- 14 files changed, 124 insertions(+), 67 deletions(-) diff --git a/lib/src/blob.dart b/lib/src/blob.dart index 5a7c595..c518951 100644 --- a/lib/src/blob.dart +++ b/lib/src/blob.dart @@ -3,13 +3,23 @@ import 'bindings/libgit2_bindings.dart'; import 'bindings/blob.dart' as bindings; import 'oid.dart'; import 'repository.dart'; +import 'util.dart'; class Blob { - /// Initializes a new instance of [Blob] class from provided - /// [Repository] and [Oid] objects. + /// Initializes a new instance of [Blob] class from provided pointer to + /// blob object in memory. /// /// Should be freed with `free()` to release allocated memory. - Blob.lookup(Repository repo, Oid oid) { + Blob(this._blobPointer) { + libgit2.git_libgit2_init(); + } + + /// Initializes a new instance of [Blob] class from provided + /// [Repository] object and [sha] hex string. + /// + /// Should be freed with `free()` to release allocated memory. + Blob.lookup(Repository repo, String sha) { + final oid = Oid.fromSHA(repo, sha); _blobPointer = bindings.lookup(repo.pointer, oid.pointer); } diff --git a/lib/src/commit.dart b/lib/src/commit.dart index 3494089..08707b6 100644 --- a/lib/src/commit.dart +++ b/lib/src/commit.dart @@ -16,11 +16,12 @@ class Commit { libgit2.git_libgit2_init(); } - /// Initializes a new instance of [Commit] class from provided [Repository] - /// and [Oid] objects. + /// Initializes a new instance of [Commit] class from provided [Repository] object + /// and [sha] hex string. /// /// Should be freed with `free()` to release allocated memory. - Commit.lookup(Repository repo, Oid oid) { + Commit.lookup(Repository repo, String sha) { + final oid = Oid.fromSHA(repo, sha); _commitPointer = bindings.lookup(repo.pointer, oid.pointer); } @@ -40,8 +41,7 @@ class Commit { String? updateRef, String? messageEncoding, }) { - final treeOid = Oid.fromSHA(repo, treeSHA); - final tree = Tree.lookup(repo, treeOid); + final tree = Tree.lookup(repo, treeSHA); final result = Oid(bindings.create( repo.pointer, diff --git a/lib/src/git_types.dart b/lib/src/git_types.dart index ed9351a..d00da0a 100644 --- a/lib/src/git_types.dart +++ b/lib/src/git_types.dart @@ -63,33 +63,33 @@ class GitSort { } /// Basic type (loose or packed) of any Git object. -class GitObjectType { - const GitObjectType._(this._value); +class GitObject { + const GitObject._(this._value); final int _value; /// Object can be any of the following. - static const any = GitObjectType._(-2); + static const any = GitObject._(-2); /// Object is invalid. - static const invalid = GitObjectType._(-1); + static const invalid = GitObject._(-1); /// A commit object. - static const commit = GitObjectType._(1); + static const commit = GitObject._(1); /// A tree (directory listing) object. - static const tree = GitObjectType._(2); + static const tree = GitObject._(2); /// A file revision object. - static const blob = GitObjectType._(3); + static const blob = GitObject._(3); /// An annotated tag object. - static const tag = GitObjectType._(4); + static const tag = GitObject._(4); /// A delta, base is given by an offset. - static const offsetDelta = GitObjectType._(6); + static const offsetDelta = GitObject._(6); /// A delta, base is given by object id. - static const refDelta = GitObjectType._(7); + static const refDelta = GitObject._(7); int get value => _value; } diff --git a/lib/src/index.dart b/lib/src/index.dart index 666d73e..7df2ea4 100644 --- a/lib/src/index.dart +++ b/lib/src/index.dart @@ -93,21 +93,21 @@ class Index { /// Updates the contents of an existing index object in memory by reading from the /// specified tree. void readTree(Object target) { - late final Oid oid; late final Tree tree; + if (target is Oid) { final repo = Repository(bindings.owner(_indexPointer)); - tree = Tree.lookup(repo, target); + tree = Tree.lookup(repo, target.sha); } else if (target is Tree) { tree = target; - } else if (isValidShaHex(target as String)) { + } else if (target is String) { final repo = Repository(bindings.owner(_indexPointer)); - oid = Oid.fromSHA(repo, target); - tree = Tree.lookup(repo, oid); + tree = Tree.lookup(repo, target); } else { throw ArgumentError.value( '$target should be either Oid object, SHA hex string or Tree object'); } + bindings.readTree(_indexPointer, tree.pointer); tree.free(); } diff --git a/lib/src/oid.dart b/lib/src/oid.dart index 43c5e7a..2360f8f 100644 --- a/lib/src/oid.dart +++ b/lib/src/oid.dart @@ -15,14 +15,20 @@ class Oid { /// in the ODB of [repository] with provided hexadecimal [sha] string that is 40 characters /// long or shorter. /// + /// Throws [ArgumentError] if provided [sha] hex string is not valid. + /// /// Throws a [LibGit2Error] if error occured. Oid.fromSHA(Repository repository, String sha) { - if (sha.length == 40) { - _oidPointer = bindings.fromSHA(sha); + if (isValidShaHex(sha)) { + if (sha.length == 40) { + _oidPointer = bindings.fromSHA(sha); + } else { + final odb = repository.odb; + _oidPointer = odb.existsPrefix(bindings.fromStrN(sha), sha.length); + odb.free(); + } } else { - final odb = repository.odb; - _oidPointer = odb.existsPrefix(bindings.fromStrN(sha), sha.length); - odb.free(); + throw ArgumentError.value('$sha is not a valid sha hex string'); } } diff --git a/lib/src/repository.dart b/lib/src/repository.dart index 3284da5..717dbbe 100644 --- a/lib/src/repository.dart +++ b/lib/src/repository.dart @@ -4,6 +4,7 @@ import 'package:libgit2dart/libgit2dart.dart'; import 'bindings/libgit2_bindings.dart'; import 'bindings/repository.dart' as bindings; import 'bindings/merge.dart' as merge_bindings; +import 'bindings/object.dart' as object_bindings; import 'commit.dart'; import 'config.dart'; import 'index.dart'; @@ -273,8 +274,8 @@ class Repository { late final Oid oid; late final bool isDirect; - if (target.runtimeType == Oid) { - oid = target as Oid; + if (target is Oid) { + oid = target; isDirect = true; } else if (isValidShaHex(target as String)) { oid = Oid.fromSHA(this, target); @@ -314,18 +315,39 @@ class Repository { /// Throws a [LibGit2Error] if error occured. Odb get odb => Odb(bindings.odb(_repoPointer)); - /// Looksup [Commit] for provided [sha] hex string. + /// Looksup git object (commit, tree, blob, tag) for provided [sha] hex string. /// - /// Throws [ArgumentError] if provided [sha] is not valid sha hex string. - Commit operator [](String sha) { - late final Oid oid; + /// Returned object should be explicitly downcasted to one of four of git object types. + /// + /// ```dart + /// final commit = repo['s0m3sh4'] as Commit; + /// final tree = repo['s0m3sh4'] as Tree; + /// final blob = repo['s0m3sh4'] as Blob; + /// final tag = repo['s0m3sh4'] as Tag; + /// ``` + /// + /// Throws [ArgumentError] if provided [sha] is not pointing to commit, tree, blob or tag. + Object operator [](String sha) { + final oid = Oid.fromSHA(this, sha); + final object = object_bindings.lookup( + _repoPointer, + oid.pointer, + GitObject.any.value, + ); + final type = object_bindings.type(object); - if (isValidShaHex(sha)) { - oid = Oid.fromSHA(this, sha); + if (type == GitObject.commit.value) { + return Commit(object.cast()); + } else if (type == GitObject.tree.value) { + return Tree(object.cast()); + } else if (type == GitObject.blob.value) { + return Blob(object.cast()); + } else if (type == GitObject.tag.value) { + return Tag(object.cast()); } else { - throw ArgumentError.value('$sha is not a valid sha hex string'); + throw ArgumentError.value( + '$sha should be pointing to either commit, tree, blob or a tag'); } - return Commit.lookup(this, oid); } /// Returns the list of commits starting from provided [oid]. @@ -415,7 +437,7 @@ class Repository { Oid createTag({ required String tagName, required Oid target, - required GitObjectType targetType, + required GitObject targetType, required Signature tagger, required String message, bool force = false, diff --git a/lib/src/tag.dart b/lib/src/tag.dart index 42d7a4e..c37a9ce 100644 --- a/lib/src/tag.dart +++ b/lib/src/tag.dart @@ -8,13 +8,23 @@ import 'oid.dart'; import 'repository.dart'; import 'signature.dart'; import 'git_types.dart'; +import 'util.dart'; class Tag { - /// Initializes a new instance of [Tag] class from provided - /// [Repository] and [Oid] objects. + /// Initializes a new instance of [Tag] class from provided pointer to + /// tag object in memory. /// /// Should be freed with `free()` to release allocated memory. - Tag.lookup(Repository repo, Oid oid) { + Tag(this._tagPointer) { + libgit2.git_libgit2_init(); + } + + /// Initializes a new instance of [Tag] class from provided + /// [Repository] object and [sha] hex string. + /// + /// Should be freed with `free()` to release allocated memory. + Tag.lookup(Repository repo, String sha) { + final oid = Oid.fromSHA(repo, sha); _tagPointer = bindings.lookup(repo.pointer, oid.pointer); } @@ -39,7 +49,7 @@ class Tag { required Repository repository, required String tagName, required Oid target, - required GitObjectType targetType, + required GitObject targetType, required Signature tagger, required String message, bool force = false, diff --git a/lib/src/tree.dart b/lib/src/tree.dart index 4366e1b..1cb582a 100644 --- a/lib/src/tree.dart +++ b/lib/src/tree.dart @@ -7,11 +7,20 @@ import 'git_types.dart'; import 'util.dart'; class Tree { - /// Initializes a new instance of [Tree] class from provided - /// [Repository] and [Oid] objects. + /// Initializes a new instance of [Tree] class from provided pointer to + /// tree object in memory. /// /// Should be freed with `free()` to release allocated memory. - Tree.lookup(Repository repo, Oid oid) { + Tree(this._treePointer) { + libgit2.git_libgit2_init(); + } + + /// Initializes a new instance of [Tree] class from provided + /// [Repository] object and [sha] hex string. + /// + /// Should be freed with `free()` to release allocated memory. + Tree.lookup(Repository repo, String sha) { + final oid = Oid.fromSHA(repo, sha); _treePointer = bindings.lookup(repo.pointer, oid.pointer); } diff --git a/test/blob_test.dart b/test/blob_test.dart index 29025e3..7e16fc6 100644 --- a/test/blob_test.dart +++ b/test/blob_test.dart @@ -21,7 +21,7 @@ void main() { to: await Directory(tmpDir).create(), ); repo = Repository.open(tmpDir); - blob = Blob.lookup(repo, Oid.fromSHA(repo, blobSHA)); + blob = Blob.lookup(repo, blobSHA); }); tearDown(() async { @@ -44,7 +44,7 @@ void main() { test('successfully creates new blob', () { final oid = Blob.create(repo, newBlobContent); - final newBlob = Blob.lookup(repo, oid); + final newBlob = Blob.lookup(repo, oid.sha); expect(newBlob.id.sha, '18fdaeef018e57a92bcad2d4a35b577f34089af6'); expect(newBlob.isBinary, false); @@ -57,7 +57,7 @@ void main() { test('successfully creates new blob from file at provided relative path', () { final oid = Blob.createFromWorkdir(repo, 'feature_file'); - final newBlob = Blob.lookup(repo, oid); + final newBlob = Blob.lookup(repo, oid.sha); expect(newBlob.id.sha, blobSHA); expect(newBlob.isBinary, false); @@ -89,7 +89,7 @@ void main() { final outsideFile = File('${Directory.current.absolute.path}/test/blob_test.dart'); final oid = Blob.createFromDisk(repo, outsideFile.path); - final newBlob = Blob.lookup(repo, oid); + final newBlob = Blob.lookup(repo, oid.sha); expect(newBlob, isA()); expect(newBlob.isBinary, false); diff --git a/test/commit_test.dart b/test/commit_test.dart index f789112..a29bdc1 100644 --- a/test/commit_test.dart +++ b/test/commit_test.dart @@ -45,13 +45,13 @@ void main() { group('Commit', () { test('successfully returns when 40 char sha hex is provided', () { - final commit = repo[mergeCommit]; + final commit = repo[mergeCommit] as Commit; expect(commit, isA()); commit.free(); }); test('successfully returns when sha hex is short', () { - final commit = repo[mergeCommit.substring(0, 5)]; + final commit = repo[mergeCommit.substring(0, 5)] as Commit; expect(commit, isA()); commit.free(); }); @@ -66,7 +66,7 @@ void main() { parents: [mergeCommit], ); - final commit = repo[oid.sha]; + final commit = repo[oid.sha] as Commit; expect(commit.id.sha, oid.sha); expect(commit.message, message); @@ -91,7 +91,7 @@ void main() { parents: [], ); - final commit = repo[oid.sha]; + final commit = repo[oid.sha] as Commit; expect(commit.id.sha, oid.sha); expect(commit.message, message); @@ -115,7 +115,7 @@ void main() { parents: [mergeCommit, 'fc38877b2552ab554752d9a77e1f48f738cca79b'], ); - final commit = repo[oid.sha]; + final commit = repo[oid.sha] as Commit; expect(commit.id.sha, oid.sha); expect(commit.message, message); @@ -141,7 +141,7 @@ void main() { parents: [mergeCommit], ); - final commit = repo[oid.sha]; + final commit = repo[oid.sha] as Commit; expect(commit.id.sha, oid.sha); expect(commit.message, message); diff --git a/test/repository_test.dart b/test/repository_test.dart index 5976984..4ea886b 100644 --- a/test/repository_test.dart +++ b/test/repository_test.dart @@ -275,7 +275,7 @@ void main() { test('successfully creates new blob', () { final oid = repo.createBlob(newBlobContent); - final newBlob = Blob.lookup(repo, oid); + final newBlob = repo[oid.sha] as Blob; expect(newBlob, isA()); @@ -286,7 +286,7 @@ void main() { 'successfully creates new blob from file at provided relative path', () { final oid = repo.createBlobFromWorkdir('feature_file'); - final newBlob = Blob.lookup(repo, oid); + final newBlob = repo[oid.sha] as Blob; expect(newBlob, isA()); @@ -297,7 +297,7 @@ void main() { final outsideFile = File('${Directory.current.absolute.path}/test/blob_test.dart'); final oid = repo.createBlobFromDisk(outsideFile.path); - final newBlob = Blob.lookup(repo, oid); + final newBlob = repo[oid.sha] as Blob; expect(newBlob, isA()); @@ -320,12 +320,12 @@ void main() { repository: repo, tagName: tagName, target: target, - targetType: GitObjectType.commit, + targetType: GitObject.commit, tagger: signature, message: message, ); - final newTag = Tag.lookup(repo, oid); + final newTag = repo[oid.sha] as Tag; final tagger = newTag.tagger; final newTagTarget = newTag.target; diff --git a/test/tag_test.dart b/test/tag_test.dart index 6ccfc66..9f77567 100644 --- a/test/tag_test.dart +++ b/test/tag_test.dart @@ -19,7 +19,7 @@ void main() { to: await Directory(tmpDir).create(), ); repo = Repository.open(tmpDir); - tag = Tag.lookup(repo, Oid.fromSHA(repo, tagSHA)); + tag = Tag.lookup(repo, tagSHA); }); tearDown(() async { @@ -68,12 +68,12 @@ void main() { repository: repo, tagName: tagName, target: target, - targetType: GitObjectType.commit, + targetType: GitObject.commit, tagger: signature, message: message, ); - final newTag = Tag.lookup(repo, oid); + final newTag = Tag.lookup(repo, oid.sha); final tagger = newTag.tagger; final newTagTarget = newTag.target; diff --git a/test/tree_test.dart b/test/tree_test.dart index ae80b60..38c444e 100644 --- a/test/tree_test.dart +++ b/test/tree_test.dart @@ -20,7 +20,7 @@ void main() { to: await Directory(tmpDir).create(), ); repo = Repository.open(tmpDir); - tree = Tree.lookup(repo, Oid.fromSHA(repo, treeSHA)); + tree = Tree.lookup(repo, treeSHA); }); tearDown(() async { @@ -73,7 +73,7 @@ void main() { final builder = TreeBuilder(repo); builder.add('filename', fileOid, GitFilemode.blob); - final newTree = Tree.lookup(repo, builder.write()); + final newTree = Tree.lookup(repo, builder.write().sha); final entry = newTree['filename']; expect(newTree.length, 1); diff --git a/test/treebuilder_test.dart b/test/treebuilder_test.dart index 579f36b..232dea3 100644 --- a/test/treebuilder_test.dart +++ b/test/treebuilder_test.dart @@ -19,7 +19,7 @@ void main() { to: await Directory(tmpDir).create(), ); repo = Repository.open(tmpDir); - tree = Tree.lookup(repo, Oid.fromSHA(repo, treeSHA)); + tree = Tree.lookup(repo, treeSHA); }); tearDown(() async {