feat(repository): add ability to lookup different types of git objects with []

This commit is contained in:
Aleksey Kulikov 2021-09-04 12:04:28 +03:00
parent f19a34a768
commit 2cf974c624
14 changed files with 124 additions and 67 deletions

View file

@ -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);
}

View file

@ -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,

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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');
}
}

View file

@ -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,

View file

@ -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,

View file

@ -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);
}

View file

@ -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<Blob>());
expect(newBlob.isBinary, false);

View file

@ -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>());
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>());
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);

View file

@ -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<Blob>());
@ -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<Blob>());
@ -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<Blob>());
@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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 {