mirror of
https://github.com/SkinnyMind/libgit2dart.git
synced 2025-05-05 04:39:07 -04:00
feat(note): add bindings and api
This commit is contained in:
parent
5ee0662376
commit
5c8d6647eb
14 changed files with 414 additions and 0 deletions
|
@ -22,6 +22,7 @@ export 'src/refspec.dart';
|
||||||
export 'src/callbacks.dart';
|
export 'src/callbacks.dart';
|
||||||
export 'src/credentials.dart';
|
export 'src/credentials.dart';
|
||||||
export 'src/blame.dart';
|
export 'src/blame.dart';
|
||||||
|
export 'src/note.dart';
|
||||||
export 'src/features.dart';
|
export 'src/features.dart';
|
||||||
export 'src/error.dart';
|
export 'src/error.dart';
|
||||||
export 'src/git_types.dart';
|
export 'src/git_types.dart';
|
||||||
|
|
146
lib/src/bindings/note.dart
Normal file
146
lib/src/bindings/note.dart
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import '../error.dart';
|
||||||
|
import '../util.dart';
|
||||||
|
import 'libgit2_bindings.dart';
|
||||||
|
|
||||||
|
/// Returns list of notes for repository.
|
||||||
|
///
|
||||||
|
/// Notes must be freed manually by the user.
|
||||||
|
///
|
||||||
|
/// Throws a [LibGit2Error] if error occured.
|
||||||
|
List<Map<String, Pointer>> list(Pointer<git_repository> repo) {
|
||||||
|
final notesRef = 'refs/notes/commits'.toNativeUtf8().cast<Int8>();
|
||||||
|
final iterator = calloc<Pointer<git_iterator>>();
|
||||||
|
final iteratorError = libgit2.git_note_iterator_new(iterator, repo, notesRef);
|
||||||
|
|
||||||
|
if (iteratorError < 0) {
|
||||||
|
throw LibGit2Error(libgit2.git_error_last());
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = <Map<String, Pointer>>[];
|
||||||
|
var nextError = 0;
|
||||||
|
|
||||||
|
while (nextError >= 0) {
|
||||||
|
final noteId = calloc<git_oid>();
|
||||||
|
var annotatedId = calloc<git_oid>();
|
||||||
|
nextError = libgit2.git_note_next(noteId, annotatedId, iterator.value);
|
||||||
|
if (nextError >= 0) {
|
||||||
|
final out = calloc<Pointer<git_note>>();
|
||||||
|
final error = libgit2.git_note_read(out, repo, notesRef, annotatedId);
|
||||||
|
|
||||||
|
calloc.free(noteId);
|
||||||
|
|
||||||
|
if (error < 0) {
|
||||||
|
throw LibGit2Error(libgit2.git_error_last());
|
||||||
|
} else {
|
||||||
|
result.add({'note': out.value, 'annotatedId': annotatedId});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
calloc.free(notesRef);
|
||||||
|
libgit2.git_note_iterator_free(iterator.value);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read the note for an object.
|
||||||
|
///
|
||||||
|
/// The note must be freed manually by the user.
|
||||||
|
///
|
||||||
|
/// Throws a [LibGit2Error] if error occured.
|
||||||
|
Pointer<git_note> lookup({
|
||||||
|
required Pointer<git_repository> repoPointer,
|
||||||
|
required Pointer<git_oid> oidPointer,
|
||||||
|
String notesRef = 'refs/notes/commits',
|
||||||
|
}) {
|
||||||
|
final out = calloc<Pointer<git_note>>();
|
||||||
|
final notesRefC = notesRef.toNativeUtf8().cast<Int8>();
|
||||||
|
final error = libgit2.git_note_read(out, repoPointer, notesRefC, oidPointer);
|
||||||
|
|
||||||
|
calloc.free(notesRefC);
|
||||||
|
|
||||||
|
if (error < 0) {
|
||||||
|
throw LibGit2Error(libgit2.git_error_last());
|
||||||
|
} else {
|
||||||
|
return out.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a note for an object.
|
||||||
|
///
|
||||||
|
/// Throws a [LibGit2Error] if error occured.
|
||||||
|
Pointer<git_oid> create({
|
||||||
|
required Pointer<git_repository> repoPointer,
|
||||||
|
String notesRef = 'refs/notes/commits',
|
||||||
|
required Pointer<git_signature> authorPointer,
|
||||||
|
required Pointer<git_signature> committerPointer,
|
||||||
|
required Pointer<git_oid> oidPointer,
|
||||||
|
required String note,
|
||||||
|
bool force = false,
|
||||||
|
}) {
|
||||||
|
final out = calloc<git_oid>();
|
||||||
|
final notesRefC = notesRef.toNativeUtf8().cast<Int8>();
|
||||||
|
final noteC = note.toNativeUtf8().cast<Int8>();
|
||||||
|
final forceC = force ? 1 : 0;
|
||||||
|
final error = libgit2.git_note_create(
|
||||||
|
out,
|
||||||
|
repoPointer,
|
||||||
|
notesRefC,
|
||||||
|
authorPointer,
|
||||||
|
committerPointer,
|
||||||
|
oidPointer,
|
||||||
|
noteC,
|
||||||
|
forceC,
|
||||||
|
);
|
||||||
|
|
||||||
|
calloc.free(notesRefC);
|
||||||
|
calloc.free(noteC);
|
||||||
|
|
||||||
|
if (error < 0) {
|
||||||
|
throw LibGit2Error(libgit2.git_error_last());
|
||||||
|
} else {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the note for an object.
|
||||||
|
///
|
||||||
|
/// Throws a [LibGit2Error] if error occured.
|
||||||
|
void remove({
|
||||||
|
required Pointer<git_repository> repoPointer,
|
||||||
|
String notesRef = 'refs/notes/commits',
|
||||||
|
required Pointer<git_signature> authorPointer,
|
||||||
|
required Pointer<git_signature> committerPointer,
|
||||||
|
required Pointer<git_oid> oidPointer,
|
||||||
|
}) {
|
||||||
|
final notesRefC = notesRef.toNativeUtf8().cast<Int8>();
|
||||||
|
|
||||||
|
final error = libgit2.git_note_remove(
|
||||||
|
repoPointer,
|
||||||
|
notesRefC,
|
||||||
|
authorPointer,
|
||||||
|
committerPointer,
|
||||||
|
oidPointer,
|
||||||
|
);
|
||||||
|
|
||||||
|
calloc.free(notesRefC);
|
||||||
|
|
||||||
|
if (error < 0) {
|
||||||
|
throw LibGit2Error(libgit2.git_error_last());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the note object's id.
|
||||||
|
Pointer<git_oid> id(Pointer<git_note> note) => libgit2.git_note_id(note);
|
||||||
|
|
||||||
|
/// Get the note message.
|
||||||
|
String message(Pointer<git_note> note) {
|
||||||
|
return libgit2.git_note_message(note).cast<Utf8>().toDartString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Free memory allocated for note object.
|
||||||
|
void free(Pointer<git_note> note) => libgit2.git_note_free(note);
|
121
lib/src/note.dart
Normal file
121
lib/src/note.dart
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'bindings/libgit2_bindings.dart';
|
||||||
|
import 'bindings/note.dart' as bindings;
|
||||||
|
import 'oid.dart';
|
||||||
|
import 'repository.dart';
|
||||||
|
import 'signature.dart';
|
||||||
|
|
||||||
|
class Notes {
|
||||||
|
/// Initializes a new instance of the [Notes] class from
|
||||||
|
/// provided [Repository] object.
|
||||||
|
Notes(Repository repo) {
|
||||||
|
_repoPointer = repo.pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pointer to memory address for allocated repository object.
|
||||||
|
late final Pointer<git_repository> _repoPointer;
|
||||||
|
|
||||||
|
/// Reads the note for an object.
|
||||||
|
///
|
||||||
|
/// The note must be freed manually by the user.
|
||||||
|
///
|
||||||
|
/// Throws a [LibGit2Error] if error occured.
|
||||||
|
static Note lookup({
|
||||||
|
required Repository repo,
|
||||||
|
required Oid annotatedId,
|
||||||
|
String notesRef = 'refs/notes/commits',
|
||||||
|
}) {
|
||||||
|
final note = bindings.lookup(
|
||||||
|
repoPointer: repo.pointer,
|
||||||
|
oidPointer: annotatedId.pointer,
|
||||||
|
notesRef: notesRef,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Note(note, annotatedId.pointer, repo.pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a note for an [object].
|
||||||
|
///
|
||||||
|
/// Throws a [LibGit2Error] if error occured.
|
||||||
|
static Oid create({
|
||||||
|
required Repository repo,
|
||||||
|
required Signature author,
|
||||||
|
required Signature committer,
|
||||||
|
required Oid object,
|
||||||
|
required String note,
|
||||||
|
String notesRef = 'refs/notes/commits',
|
||||||
|
bool force = false,
|
||||||
|
}) {
|
||||||
|
return Oid(bindings.create(
|
||||||
|
repoPointer: repo.pointer,
|
||||||
|
authorPointer: author.pointer,
|
||||||
|
committerPointer: committer.pointer,
|
||||||
|
oidPointer: object.pointer,
|
||||||
|
note: note,
|
||||||
|
notesRef: notesRef,
|
||||||
|
force: force,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns list of notes for repository.
|
||||||
|
///
|
||||||
|
/// Notes must be freed manually by the user.
|
||||||
|
///
|
||||||
|
/// Throws a [LibGit2Error] if error occured.
|
||||||
|
List<Note> get list {
|
||||||
|
final notesPointers = bindings.list(_repoPointer);
|
||||||
|
var result = <Note>[];
|
||||||
|
for (var note in notesPointers) {
|
||||||
|
result.add(Note(
|
||||||
|
note['note'] as Pointer<git_note>,
|
||||||
|
note['annotatedId'] as Pointer<git_oid>,
|
||||||
|
_repoPointer,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Note {
|
||||||
|
/// Initializes a new instance of the [Note] class from provided
|
||||||
|
/// pointer to note object in memory.
|
||||||
|
Note(this._notePointer, this._annotatedIdPointer, this._repoPointer);
|
||||||
|
|
||||||
|
/// Pointer to memory address for allocated note object.
|
||||||
|
final Pointer<git_note> _notePointer;
|
||||||
|
|
||||||
|
/// Pointer to memory address for allocated annotetedId object.
|
||||||
|
final Pointer<git_oid> _annotatedIdPointer;
|
||||||
|
|
||||||
|
/// Pointer to memory address for allocated repository object.
|
||||||
|
final Pointer<git_repository> _repoPointer;
|
||||||
|
|
||||||
|
/// Removes the note for an [object].
|
||||||
|
///
|
||||||
|
/// Throws a [LibGit2Error] if error occured.
|
||||||
|
void remove({
|
||||||
|
required Signature author,
|
||||||
|
required Signature committer,
|
||||||
|
String notesRef = 'refs/notes/commits',
|
||||||
|
}) {
|
||||||
|
bindings.remove(
|
||||||
|
repoPointer: _repoPointer,
|
||||||
|
authorPointer: author.pointer,
|
||||||
|
committerPointer: committer.pointer,
|
||||||
|
oidPointer: annotatedId.pointer,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the note object's [Oid].
|
||||||
|
Oid get id => Oid(bindings.id(_notePointer));
|
||||||
|
|
||||||
|
/// Returns the note message.
|
||||||
|
String get message => bindings.message(_notePointer);
|
||||||
|
|
||||||
|
/// Returns the [Oid] of the git object being annotated.
|
||||||
|
Oid get annotatedId => Oid(_annotatedIdPointer);
|
||||||
|
|
||||||
|
/// Releases memory allocated for note object.
|
||||||
|
void free() => bindings.free(_notePointer);
|
||||||
|
}
|
|
@ -1118,4 +1118,49 @@ class Repository {
|
||||||
maxLine: maxLine,
|
maxLine: maxLine,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns list of notes for repository.
|
||||||
|
///
|
||||||
|
/// Notes must be freed manually.
|
||||||
|
///
|
||||||
|
/// Throws a [LibGit2Error] if error occured.
|
||||||
|
List<Note> get notes => Notes(this).list;
|
||||||
|
|
||||||
|
/// Reads the note for an object.
|
||||||
|
///
|
||||||
|
/// The note must be freed manually.
|
||||||
|
///
|
||||||
|
/// Throws a [LibGit2Error] if error occured.
|
||||||
|
Note lookupNote({
|
||||||
|
required Oid annotatedId,
|
||||||
|
String notesRef = 'refs/notes/commits',
|
||||||
|
}) {
|
||||||
|
return Notes.lookup(
|
||||||
|
repo: this,
|
||||||
|
annotatedId: annotatedId,
|
||||||
|
notesRef: notesRef,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a note for an [object].
|
||||||
|
///
|
||||||
|
/// Throws a [LibGit2Error] if error occured.
|
||||||
|
Oid createNote({
|
||||||
|
required Signature author,
|
||||||
|
required Signature committer,
|
||||||
|
required Oid object,
|
||||||
|
required String note,
|
||||||
|
String notesRef = 'refs/notes/commits',
|
||||||
|
bool force = false,
|
||||||
|
}) {
|
||||||
|
return Notes.create(
|
||||||
|
repo: this,
|
||||||
|
author: author,
|
||||||
|
committer: committer,
|
||||||
|
object: object,
|
||||||
|
note: note,
|
||||||
|
notesRef: notesRef,
|
||||||
|
force: force,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
2
test/assets/testrepo/.gitdir/logs/refs/notes/commits
Normal file
2
test/assets/testrepo/.gitdir/logs/refs/notes/commits
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
0000000000000000000000000000000000000000 af1bbb249ea750bbfa66c1e7fd879622c2dbfe3a Aleksey Kulikov <skinny.mind@gmail.com> 1633093379 +0300 notes: Notes added by 'git notes add'
|
||||||
|
af1bbb249ea750bbfa66c1e7fd879622c2dbfe3a 00eb1490ff4e39fa29c0ef352a9f93989b7018f8 Aleksey Kulikov <skinny.mind@gmail.com> 1633093431 +0300 notes: Notes added by 'git notes add'
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
test/assets/testrepo/.gitdir/refs/notes/commits
Normal file
1
test/assets/testrepo/.gitdir/refs/notes/commits
Normal file
|
@ -0,0 +1 @@
|
||||||
|
00eb1490ff4e39fa29c0ef352a9f93989b7018f8
|
97
test/note_test.dart
Normal file
97
test/note_test.dart
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
import 'package:libgit2dart/libgit2dart.dart';
|
||||||
|
import 'helpers/util.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late Repository repo;
|
||||||
|
late Directory tmpDir;
|
||||||
|
const notesExpected = [
|
||||||
|
{
|
||||||
|
'id': 'd854ba919e1bb303f4d6bb4ca9a15c5cab2a2a50',
|
||||||
|
'message': 'Another note\n',
|
||||||
|
'annotatedId': '78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e8',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'd2ffe6b06b11dd90c2ee3f15d2c6b62f018554ed',
|
||||||
|
'message': 'Note for HEAD\n',
|
||||||
|
'annotatedId': '821ed6e80627b8769d170a293862f9fc60825226',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
tmpDir = await setupRepo(Directory('test/assets/testrepo/'));
|
||||||
|
repo = Repository.open(tmpDir.path);
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDown(() async {
|
||||||
|
repo.free();
|
||||||
|
await tmpDir.delete(recursive: true);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Note', () {
|
||||||
|
test('returns list of notes', () {
|
||||||
|
final notes = repo.notes;
|
||||||
|
|
||||||
|
expect(notes.length, 2);
|
||||||
|
|
||||||
|
for (var i = 0; i < notes.length; i++) {
|
||||||
|
expect(notes[i].id.sha, notesExpected[i]['id']);
|
||||||
|
expect(notes[i].message, notesExpected[i]['message']);
|
||||||
|
expect(notes[i].annotatedId.sha, notesExpected[i]['annotatedId']);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var note in notes) {
|
||||||
|
note.free();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('successfully lookups note', () {
|
||||||
|
final head = repo.head;
|
||||||
|
final note = repo.lookupNote(annotatedId: head.target);
|
||||||
|
|
||||||
|
expect(note.id.sha, notesExpected[1]['id']);
|
||||||
|
expect(note.message, notesExpected[1]['message']);
|
||||||
|
expect(note.annotatedId.sha, notesExpected[1]['annotatedId']);
|
||||||
|
|
||||||
|
note.free();
|
||||||
|
head.free();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('successfully creates note', () {
|
||||||
|
final signature = repo.defaultSignature;
|
||||||
|
final head = repo.head;
|
||||||
|
final noteOid = repo.createNote(
|
||||||
|
author: signature,
|
||||||
|
committer: signature,
|
||||||
|
object: head.target,
|
||||||
|
note: 'New note for HEAD',
|
||||||
|
force: true,
|
||||||
|
);
|
||||||
|
final noteBlob = repo[noteOid.sha] as Blob;
|
||||||
|
|
||||||
|
expect(noteOid.sha, 'ffd6e2ceaf91c00ea6d29e2e897f906da720529f');
|
||||||
|
expect(noteBlob.content, 'New note for HEAD');
|
||||||
|
|
||||||
|
noteBlob.free();
|
||||||
|
head.free();
|
||||||
|
signature.free();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('successfully removes note', () {
|
||||||
|
final signature = repo.defaultSignature;
|
||||||
|
final head = repo.head;
|
||||||
|
final note = repo.lookupNote(annotatedId: head.target);
|
||||||
|
|
||||||
|
note.remove(author: signature, committer: signature);
|
||||||
|
expect(
|
||||||
|
() => repo.lookupNote(annotatedId: head.target),
|
||||||
|
throwsA(isA<LibGit2Error>()),
|
||||||
|
);
|
||||||
|
|
||||||
|
note.free();
|
||||||
|
head.free();
|
||||||
|
signature.free();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ void main() {
|
||||||
[
|
[
|
||||||
'refs/heads/feature',
|
'refs/heads/feature',
|
||||||
'refs/heads/master',
|
'refs/heads/master',
|
||||||
|
'refs/notes/commits',
|
||||||
'refs/tags/v0.1',
|
'refs/tags/v0.1',
|
||||||
'refs/tags/v0.2',
|
'refs/tags/v0.2',
|
||||||
],
|
],
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue