diff --git a/example/reference_example.dart b/example/reference_example.dart index a10fe61..dd91a4f 100644 --- a/example/reference_example.dart +++ b/example/reference_example.dart @@ -9,7 +9,7 @@ void main() async { final repo = Repository.open(tmpDir.path); // Get list of repo's references. - print('Repository references: ${repo.references.list()}'); + print('Repository references: ${repo.references.list}'); // Get reference by name. final ref = repo.references['refs/heads/master']; @@ -20,7 +20,7 @@ void main() async { print('Reference shorthand name: ${ref.shorthand}'); // Create new reference (direct or symbolic). - final newRef = repo.createReference( + final newRef = repo.references.create( name: 'refs/tags/v1', target: 'refs/heads/master', ); diff --git a/lib/src/branch.dart b/lib/src/branch.dart index 56fe586..14c35cd 100644 --- a/lib/src/branch.dart +++ b/lib/src/branch.dart @@ -41,7 +41,8 @@ class Branches { /// Throws a [LibGit2Error] if error occured. Branch operator [](String branchName) { final ref = Reference( - _repoPointer, reference_bindings.lookupDWIM(_repoPointer, branchName)); + reference_bindings.lookupDWIM(_repoPointer, branchName), + ); late final GitBranch type; ref.isBranch ? type = GitBranch.local : GitBranch.remote; ref.free(); @@ -64,14 +65,12 @@ class Branches { required Commit target, bool force = false, }) { - final result = bindings.create( + return Reference(bindings.create( _repoPointer, name, target.pointer, force, - ); - - return Reference(_repoPointer, result); + )); } } diff --git a/lib/src/reference.dart b/lib/src/reference.dart index e7646cb..63e3a94 100644 --- a/lib/src/reference.dart +++ b/lib/src/reference.dart @@ -1,6 +1,4 @@ import 'dart:ffi'; -import 'package:libgit2dart/libgit2dart.dart'; - import 'bindings/libgit2_bindings.dart'; import 'bindings/reference.dart' as bindings; import 'bindings/object.dart' as object_bindings; @@ -29,7 +27,10 @@ class References { /// Returns a list of all the references that can be found in a repository. /// /// Throws a [LibGit2Error] if error occured. - List list() => bindings.list(_repoPointer); + List get list => bindings.list(_repoPointer); + + /// Returns number of all the references that can be found in a repository. + int get length => list.length; /// Returns a [Reference] by lookingup [name] in a repository. /// @@ -39,8 +40,63 @@ class References { /// /// Throws a [LibGit2Error] if error occured. Reference operator [](String name) { - final refPointer = bindings.lookup(_repoPointer, name); - return Reference(_repoPointer, refPointer); + return Reference(bindings.lookup(_repoPointer, name)); + } + + /// Creates a new reference. + /// + /// The reference will be created in the repository and written to the disk. + /// The generated [Reference] object must be freed by the user. + /// + /// Valid reference names must follow one of two patterns: + /// + /// Top-level names must contain only capital letters and underscores, and must begin and end + /// with a letter. (e.g. "HEAD", "ORIG_HEAD"). + /// Names prefixed with "refs/" can be almost anything. You must avoid the characters + /// '~', '^', ':', '\', '?', '[', and '*', and the sequences ".." and "@{" which have + /// special meaning to revparse. + /// Throws a [LibGit2Error] if a reference already exists with the given name + /// unless force is true, in which case it will be overwritten. + /// + /// The message for the reflog will be ignored if the reference does not belong in the + /// standard set (HEAD, branches and remote-tracking branches) and it does not have a reflog. + Reference create({ + required String name, + required Object target, + bool force = false, + String? logMessage, + }) { + late final Oid oid; + late final bool isDirect; + + if (target is Oid) { + oid = target; + isDirect = true; + } else if (isValidShaHex(target as String)) { + final repo = Repository(_repoPointer); + oid = Oid.fromSHA(repo, target); + isDirect = true; + } else { + isDirect = false; + } + + if (isDirect) { + return Reference(bindings.createDirect( + _repoPointer, + name, + oid.pointer, + force, + logMessage, + )); + } else { + return Reference(bindings.createSymbolic( + _repoPointer, + name, + target as String, + force, + logMessage, + )); + } } /// Suggests that the given refdb compress or optimize its references. @@ -58,87 +114,10 @@ class References { class Reference { /// Initializes a new instance of the [Reference] class. /// Should be freed with `free()` to release allocated memory. - Reference(this._repoPointer, this._refPointer); - - /// Initializes a new instance of the [Reference] class by creating a new direct reference. - /// - /// The direct reference will be created in the repository and written to the disk. - /// The generated [Reference] object must be freed by the user. - /// - /// Valid reference names must follow one of two patterns: - /// - /// Top-level names must contain only capital letters and underscores, and must begin and end - /// with a letter. (e.g. "HEAD", "ORIG_HEAD"). - /// Names prefixed with "refs/" can be almost anything. You must avoid the characters - /// '~', '^', ':', '\', '?', '[', and '*', and the sequences ".." and "@{" which have - /// special meaning to revparse. - /// - /// Throws a [LibGit2Error] if a reference already exists with the given name - /// unless force is true, in which case it will be overwritten. - /// - /// The message for the reflog will be ignored if the reference does not belong in the - /// standard set (HEAD, branches and remote-tracking branches) and it does not have a reflog. - Reference.createDirect({ - required Repository repo, - required String name, - required Pointer oid, - required bool force, - String? logMessage, - }) { - _repoPointer = repo.pointer; - _refPointer = bindings.createDirect( - repo.pointer, - name, - oid, - force, - logMessage, - ); - } - - /// Initializes a new instance of the [Reference] class by creating a new symbolic reference. - /// - /// A symbolic reference is a reference name that refers to another reference name. - /// If the other name moves, the symbolic name will move, too. As a simple example, - /// the "HEAD" reference might refer to "refs/heads/master" while on the "master" branch - /// of a repository. - /// - /// The symbolic reference will be created in the repository and written to the disk. - /// The generated reference object must be freed by the user. - /// - /// Valid reference names must follow one of two patterns: - /// - /// Top-level names must contain only capital letters and underscores, and must begin and end - /// with a letter. (e.g. "HEAD", "ORIG_HEAD"). - /// Names prefixed with "refs/" can be almost anything. You must avoid the characters - /// '~', '^', ':', '\', '?', '[', and '*', and the sequences ".." and "@{" which have special - /// meaning to revparse. - /// This function will throw an [LibGit2Error] if a reference already exists with the given - /// name unless force is true, in which case it will be overwritten. - /// - /// The message for the reflog will be ignored if the reference does not belong in the standard - /// set (HEAD, branches and remote-tracking branches) and it does not have a reflog. - Reference.createSymbolic({ - required Repository repo, - required String name, - required String target, - required bool force, - String? logMessage, - }) { - _repoPointer = repo.pointer; - _refPointer = bindings.createSymbolic( - repo.pointer, - name, - target, - force, - logMessage, - ); - } + Reference(this._refPointer); late Pointer _refPointer; - /// Pointer to memory address for allocated repository object. - late final Pointer _repoPointer; - /// Pointer to memory address for allocated reference object. Pointer get pointer => _refPointer; @@ -171,15 +150,13 @@ class Reference { /// Throws a [LibGit2Error] if error occured. void setTarget(String target, [String? logMessage]) { late final Oid oid; + final owner = bindings.owner(_refPointer); if (isValidShaHex(target)) { - final repo = Repository(_repoPointer); + final repo = Repository(owner); oid = Oid.fromSHA(repo, target); } else { - final ref = Reference( - _repoPointer, - bindings.lookup(_repoPointer, target), - ); + final ref = Reference(bindings.lookup(owner, target)); oid = ref.target; ref.free(); } @@ -249,7 +226,10 @@ class Reference { /// Checks if a reflog exists for the specified reference [name]. /// /// Throws a [LibGit2Error] if error occured. - bool get hasLog => bindings.hasLog(_repoPointer, name); + bool get hasLog { + final owner = bindings.owner(_refPointer); + return bindings.hasLog(owner, name); + } /// Returns a [RefLog] object. /// diff --git a/lib/src/repository.dart b/lib/src/repository.dart index 7b1953f..87f476b 100644 --- a/lib/src/repository.dart +++ b/lib/src/repository.dart @@ -32,9 +32,7 @@ class Repository { /// pointer to repository object in memory. /// /// Should be freed with `free()` to release allocated memory. - Repository(this._repoPointer) { - libgit2.git_libgit2_init(); - } + Repository(this._repoPointer); /// Initializes a new instance of the [Repository] class by creating a new /// Git repository in the given folder. @@ -254,66 +252,11 @@ class Repository { /// Returns [Reference] object pointing to repository head. /// /// Must be freed once it's no longer being used. - Reference get head => Reference(_repoPointer, bindings.head(_repoPointer)); + Reference get head => Reference(bindings.head(_repoPointer)); /// Returns [References] object. References get references => References(this); - /// Creates a new reference. - /// - /// The reference will be created in the repository and written to the disk. - /// The generated [Reference] object must be freed by the user. - /// - /// Valid reference names must follow one of two patterns: - /// - /// Top-level names must contain only capital letters and underscores, and must begin and end - /// with a letter. (e.g. "HEAD", "ORIG_HEAD"). - /// Names prefixed with "refs/" can be almost anything. You must avoid the characters - /// '~', '^', ':', '\', '?', '[', and '*', and the sequences ".." and "@{" which have - /// special meaning to revparse. - /// Throws a [LibGit2Error] if a reference already exists with the given name - /// unless force is true, in which case it will be overwritten. - /// - /// The message for the reflog will be ignored if the reference does not belong in the - /// standard set (HEAD, branches and remote-tracking branches) and it does not have a reflog. - Reference createReference({ - required String name, - required Object target, - bool force = false, - String? logMessage, - }) { - late final Oid oid; - late final bool isDirect; - - if (target is Oid) { - oid = target; - isDirect = true; - } else if (isValidShaHex(target as String)) { - oid = Oid.fromSHA(this, target); - isDirect = true; - } else { - isDirect = false; - } - - if (isDirect) { - return Reference.createDirect( - repo: this, - name: name, - oid: oid.pointer, - force: force, - logMessage: logMessage, - ); - } else { - return Reference.createSymbolic( - repo: this, - name: name, - target: target as String, - force: force, - logMessage: logMessage, - ); - } - } - /// Returns [Index] file for this repository. /// /// Must be freed once it's no longer being used. diff --git a/lib/src/revparse.dart b/lib/src/revparse.dart index 268dea8..732feec 100644 --- a/lib/src/revparse.dart +++ b/lib/src/revparse.dart @@ -23,7 +23,7 @@ class RevParse { final pointers = bindings.revParseExt(repo.pointer, spec); object = Commit(pointers[0].cast()); if (pointers.length == 2) { - reference = Reference(repo.pointer, pointers[1].cast()); + reference = Reference(pointers[1].cast()); } else { reference = null; } diff --git a/test/reference_test.dart b/test/reference_test.dart index f2c7235..ec1844d 100644 --- a/test/reference_test.dart +++ b/test/reference_test.dart @@ -24,7 +24,7 @@ void main() { group('Reference', () { test('returns a list', () { expect( - repo.references.list(), + repo.references.list, [ 'refs/heads/feature', 'refs/heads/master', @@ -63,7 +63,7 @@ void main() { }); test('returns the short name', () { - final ref = repo.createReference( + final ref = repo.references.create( name: 'refs/remotes/origin/master', target: lastCommit, ); @@ -90,7 +90,7 @@ void main() { }); test('checks if reference is a remote branch', () { - final ref = repo.createReference( + final ref = repo.references.create( name: 'refs/remotes/origin/master', target: lastCommit, ); @@ -119,42 +119,42 @@ void main() { group('create direct', () { test('successfully creates with Oid as target', () { final ref = repo.references['refs/heads/master']; - final refFromOid = repo.createReference( + final refFromOid = repo.references.create( name: 'refs/tags/from.oid', target: ref.target, ); - expect(repo.references.list(), contains('refs/tags/from.oid')); + expect(repo.references.list, contains('refs/tags/from.oid')); refFromOid.free(); ref.free(); }); test('successfully creates with SHA hash as target', () { - final refFromHash = repo.createReference( + final refFromHash = repo.references.create( name: 'refs/tags/from.hash', target: lastCommit, ); - expect(repo.references.list(), contains('refs/tags/from.hash')); + expect(repo.references.list, contains('refs/tags/from.hash')); refFromHash.free(); }); test('successfully creates with short SHA hash as target', () { - final refFromHash = repo.createReference( + final refFromHash = repo.references.create( name: 'refs/tags/from.short.hash', target: '78b8bf', ); - expect(repo.references.list(), contains('refs/tags/from.short.hash')); + expect(repo.references.list, contains('refs/tags/from.short.hash')); refFromHash.free(); }); test('successfully creates with log message', () { repo.setIdentity(name: 'name', email: 'email'); - final ref = repo.createReference( + final ref = repo.references.create( name: 'refs/heads/log.message', target: lastCommit, logMessage: 'log message', @@ -173,7 +173,7 @@ void main() { test('throws if target is not valid', () { expect( - () => repo.createReference( + () => repo.references.create( name: 'refs/tags/invalid', target: '78b', ), @@ -183,7 +183,7 @@ void main() { test('throws if name is not valid', () { expect( - () => repo.createReference( + () => repo.references.create( name: 'refs/tags/invalid~', target: lastCommit, ), @@ -192,12 +192,12 @@ void main() { }); test('successfully creates with force flag if name already exists', () { - final ref = repo.createReference( + final ref = repo.references.create( name: 'refs/tags/test', target: lastCommit, ); - final forceRef = repo.createReference( + final forceRef = repo.references.create( name: 'refs/tags/test', target: lastCommit, force: true, @@ -210,13 +210,13 @@ void main() { }); test('throws if name already exists', () { - final ref = repo.createReference( + final ref = repo.references.create( name: 'refs/tags/test', target: lastCommit, ); expect( - () => repo.createReference( + () => repo.references.create( name: 'refs/tags/test', target: lastCommit, ), @@ -229,24 +229,24 @@ void main() { group('create symbolic', () { test('successfully creates with valid target', () { - final ref = repo.createReference( + final ref = repo.references.create( name: 'refs/tags/symbolic', target: 'refs/heads/master', ); - expect(repo.references.list(), contains('refs/tags/symbolic')); + expect(repo.references.list, contains('refs/tags/symbolic')); expect(ref.type, ReferenceType.symbolic); ref.free(); }); test('successfully creates with force flag if name already exists', () { - final ref = repo.createReference( + final ref = repo.references.create( name: 'refs/tags/test', target: 'refs/heads/master', ); - final forceRef = repo.createReference( + final forceRef = repo.references.create( name: 'refs/tags/test', target: 'refs/heads/master', force: true, @@ -260,13 +260,13 @@ void main() { }); test('throws if name already exists', () { - final ref = repo.createReference( + final ref = repo.references.create( name: 'refs/tags/exists', target: 'refs/heads/master', ); expect( - () => repo.createReference( + () => repo.references.create( name: 'refs/tags/exists', target: 'refs/heads/master', ), @@ -278,7 +278,7 @@ void main() { test('throws if name is not valid', () { expect( - () => repo.createReference( + () => repo.references.create( name: 'refs/tags/invalid~', target: 'refs/heads/master', ), @@ -288,7 +288,7 @@ void main() { test('successfully creates with log message', () { repo.setIdentity(name: 'name', email: 'email'); - final ref = repo.createReference( + final ref = repo.references.create( name: 'HEAD', target: 'refs/heads/feature', force: true, @@ -308,14 +308,14 @@ void main() { }); test('successfully deletes reference', () { - final ref = repo.createReference( + final ref = repo.references.create( name: 'refs/tags/test', target: lastCommit, ); - expect(repo.references.list(), contains('refs/tags/test')); + expect(repo.references.list, contains('refs/tags/test')); ref.delete(); - expect(repo.references.list(), isNot(contains('refs/tags/test'))); + expect(repo.references.list, isNot(contains('refs/tags/test'))); ref.free(); }); @@ -399,7 +399,7 @@ void main() { group('rename', () { test('successfully renames reference', () { - final ref = repo.createReference( + final ref = repo.references.create( name: 'refs/tags/v1', target: lastCommit, ); @@ -412,7 +412,7 @@ void main() { }); test('throws on invalid name', () { - final ref = repo.createReference( + final ref = repo.references.create( name: 'refs/tags/v1', target: lastCommit, ); @@ -426,12 +426,12 @@ void main() { }); test('throws if name already exists', () { - final ref1 = repo.createReference( + final ref1 = repo.references.create( name: 'refs/tags/v1', target: lastCommit, ); - final ref2 = repo.createReference( + final ref2 = repo.references.create( name: 'refs/tags/v2', target: lastCommit, ); @@ -446,12 +446,12 @@ void main() { }); test('successfully renames with force flag set to true', () { - final ref1 = repo.createReference( + final ref1 = repo.references.create( name: 'refs/tags/v1', target: lastCommit, ); - final ref2 = repo.createReference( + final ref2 = repo.references.create( name: 'refs/tags/v2', target: newCommit, ); @@ -512,12 +512,12 @@ void main() { test('successfully compresses references', () { final packedRefsFile = File('${tmpDir.path}/.git/packed-refs'); expect(packedRefsFile.existsSync(), false); - final oldRefs = repo.references.list(); + final oldRefs = repo.references.list; repo.references.compress(); expect(packedRefsFile.existsSync(), true); - final newRefs = repo.references.list(); + final newRefs = repo.references.list; expect(newRefs, oldRefs); }); });