From 50a6087a5b99448878c0d4ce084382690d07a726 Mon Sep 17 00:00:00 2001 From: Aleksey Kulikov Date: Tue, 21 Dec 2021 18:28:44 +0300 Subject: [PATCH] feat(packbuilder): add more bindings and API methods (#25) --- lib/src/bindings/packbuilder.dart | 57 ++++++++++++++++++++++ lib/src/packbuilder.dart | 41 ++++++++++++++++ lib/src/revwalk.dart | 4 +- test/packbuilder_test.dart | 78 ++++++++++++++++++++++++++++--- 4 files changed, 173 insertions(+), 7 deletions(-) diff --git a/lib/src/bindings/packbuilder.dart b/lib/src/bindings/packbuilder.dart index ef18699..c0b7e6a 100644 --- a/lib/src/bindings/packbuilder.dart +++ b/lib/src/bindings/packbuilder.dart @@ -61,6 +61,55 @@ void addRecursively({ } } +/// Insert a commit object. +/// +/// This will add a commit as well as the completed referenced tree. +/// +/// Throws a [LibGit2Error] if error occured. +void addCommit({ + required Pointer packbuilderPointer, + required Pointer oidPointer, +}) { + final error = libgit2.git_packbuilder_insert_commit( + packbuilderPointer, + oidPointer, + ); + + if (error < 0) { + throw LibGit2Error(libgit2.git_error_last()); + } +} + +/// Insert a root tree object. +/// +/// This will add the tree as well as all referenced trees and blobs. +/// +/// Throws a [LibGit2Error] if error occured. +void addTree({ + required Pointer packbuilderPointer, + required Pointer oidPointer, +}) { + final error = libgit2.git_packbuilder_insert_tree( + packbuilderPointer, + oidPointer, + ); + + if (error < 0) { + throw LibGit2Error(libgit2.git_error_last()); + } +} + +/// Insert objects as given by the walk. +/// +/// Those commits and all objects they reference will be inserted into the +/// packbuilder. +void addWalk({ + required Pointer packbuilderPointer, + required Pointer walkerPointer, +}) { + libgit2.git_packbuilder_insert_walk(packbuilderPointer, walkerPointer); +} + /// Write the new pack and corresponding index file to path. /// /// Throws a [LibGit2Error] if error occured. @@ -94,6 +143,14 @@ int writtenCount(Pointer pb) { return libgit2.git_packbuilder_written(pb); } +/// Get the packfile's hash. +/// +/// A packfile's name is derived from the sorted hashing of all object names. +/// This is only correct after the packfile has been written. +Pointer hash(Pointer pb) { + return libgit2.git_packbuilder_hash(pb); +} + /// Set number of threads to spawn. /// /// By default, libgit2 won't spawn any threads at all; when set to 0, diff --git a/lib/src/packbuilder.dart b/lib/src/packbuilder.dart index 1963418..2feda34 100644 --- a/lib/src/packbuilder.dart +++ b/lib/src/packbuilder.dart @@ -41,6 +41,41 @@ class PackBuilder { ); } + /// Adds a commit object. + /// + /// This will add a commit as well as the completed referenced tree. + /// + /// Throws a [LibGit2Error] if error occured. + void addCommit(Oid oid) { + bindings.addCommit( + packbuilderPointer: _packbuilderPointer, + oidPointer: oid.pointer, + ); + } + + /// Adds a root tree object. + /// + /// This will add the tree as well as all referenced trees and blobs. + /// + /// Throws a [LibGit2Error] if error occured. + void addTree(Oid oid) { + bindings.addTree( + packbuilderPointer: _packbuilderPointer, + oidPointer: oid.pointer, + ); + } + + /// Adds objects as given by the walker. + /// + /// Those commits and all objects they reference will be inserted into the + /// packbuilder. + void addWalk(RevWalk walker) { + bindings.addWalk( + packbuilderPointer: _packbuilderPointer, + walkerPointer: walker.pointer, + ); + } + /// Writes the new pack and corresponding index file to [path] if provided /// or default location. /// @@ -55,6 +90,12 @@ class PackBuilder { /// Number of objects the packbuilder has already written out. int get writtenLength => bindings.writtenCount(_packbuilderPointer); + /// Packfile's hash. + /// + /// A packfile's name is derived from the sorted hashing of all object names. + /// This is only correct after the packfile has been written. + Oid get hash => Oid(bindings.hash(_packbuilderPointer)); + /// Sets and returns the number of threads to spawn. /// /// By default, libgit2 won't spawn any threads at all. When set to 0, diff --git a/lib/src/revwalk.dart b/lib/src/revwalk.dart index aac9054..2088a4b 100644 --- a/lib/src/revwalk.dart +++ b/lib/src/revwalk.dart @@ -11,9 +11,11 @@ class RevWalk { _revWalkPointer = bindings.create(repo.pointer); } - /// Pointer to memory address for allocated [RevWalk] object. late final Pointer _revWalkPointer; + /// Pointer to memory address for allocated [RevWalk] object. + Pointer get pointer => _revWalkPointer; + /// Returns the list of commits from the revision walk. /// /// Default sorting is reverse chronological order (default in git). diff --git a/test/packbuilder_test.dart b/test/packbuilder_test.dart index 90042f6..b97ce08 100644 --- a/test/packbuilder_test.dart +++ b/test/packbuilder_test.dart @@ -37,7 +37,7 @@ void main() { ); }); - test('successfully adds objects', () { + test('adds objects', () { final packbuilder = PackBuilder(repo); final odb = repo.odb; @@ -62,7 +62,7 @@ void main() { packbuilder.free(); }); - test('successfully adds object recursively', () { + test('adds object recursively', () { final packbuilder = PackBuilder(repo); final oid = Oid.fromSHA(repo: repo, sha: 'f17d0d48'); @@ -83,7 +83,59 @@ void main() { packbuilder.free(); }); - test('successfully sets number of threads', () { + test('adds commit', () { + final packbuilder = PackBuilder(repo); + final oid = repo['f17d0d4']; + + packbuilder.addCommit(oid); + expect(packbuilder.length, 3); + + packbuilder.free(); + }); + + test('throws when trying to add commit with invalid oid', () { + final packbuilder = PackBuilder(repo); + final oid = Oid.fromSHA(repo: repo, sha: '0' * 40); + + expect(() => packbuilder.addCommit(oid), throwsA(isA())); + + packbuilder.free(); + }); + + test('adds tree', () { + final packbuilder = PackBuilder(repo); + final oid = repo['df2b8fc']; + + packbuilder.addTree(oid); + expect(packbuilder.length, 2); + + packbuilder.free(); + }); + + test('throws when trying to add tree with invalid oid', () { + final packbuilder = PackBuilder(repo); + final oid = Oid.fromSHA(repo: repo, sha: '0' * 40); + + expect(() => packbuilder.addTree(oid), throwsA(isA())); + + packbuilder.free(); + }); + + test('adds objects with walker', () { + final oid = repo['f17d0d4']; + final packbuilder = PackBuilder(repo); + final walker = RevWalk(repo); + walker.sorting({GitSort.none}); + walker.push(oid); + + packbuilder.addWalk(walker); + expect(packbuilder.length, 3); + + walker.free(); + packbuilder.free(); + }); + + test('sets number of threads', () { final packbuilder = PackBuilder(repo); expect(packbuilder.setThreads(1), 1); @@ -91,7 +143,21 @@ void main() { packbuilder.free(); }); - test('successfully packs with default arguments', () { + test('returns hash of packfile', () { + final packbuilder = PackBuilder(repo); + final odb = repo.odb; + + packbuilder.add(odb.objects[0]); + Directory('${repo.workdir}.git/objects/pack/').createSync(); + + expect(packbuilder.hash.sha, '0' * 40); + packbuilder.write(null); + expect(packbuilder.hash.sha, isNot('0' * 40)); + + packbuilder.free(); + }); + + test('packs with default arguments', () { final odb = repo.odb; final objectsCount = odb.objects.length; Directory('${repo.workdir}.git/objects/pack/').createSync(); @@ -102,7 +168,7 @@ void main() { odb.free(); }); - test('successfully packs into provided path with threads set', () { + test('packs into provided path with threads set', () { final odb = repo.odb; final objectsCount = odb.objects.length; Directory('${repo.workdir}test-pack').createSync(); @@ -120,7 +186,7 @@ void main() { odb.free(); }); - test('successfully packs with provided packDelegate', () { + test('packs with provided packDelegate', () { Directory('${repo.workdir}.git/objects/pack/').createSync(); void packDelegate(PackBuilder packBuilder) { final branches = repo.branchesLocal;