feat(repository)!: add more aliases for api methods

BREAKING CHANGE: Make repository entry point for most operations
This commit is contained in:
Aleksey Kulikov 2021-10-11 20:06:36 +03:00
parent 9205a3ad82
commit 3a0fa75929
51 changed files with 1380 additions and 1062 deletions

View file

@ -2,9 +2,9 @@ import 'dart:io';
import 'package:libgit2dart/libgit2dart.dart'; import 'package:libgit2dart/libgit2dart.dart';
import '../test/helpers/util.dart'; import '../test/helpers/util.dart';
void main() async { void main() {
// Preparing example repository. // Preparing example repository.
final tmpDir = await setupRepo(Directory('test/assets/testrepo/')); final tmpDir = setupRepo(Directory('test/assets/testrepo/'));
// Open system + global config file. // Open system + global config file.
final config = Config.open(); final config = Config.open();
@ -54,5 +54,5 @@ void main() async {
} }
// Removing example repository. // Removing example repository.
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
} }

View file

@ -2,17 +2,17 @@ import 'dart:io';
import 'package:libgit2dart/libgit2dart.dart'; import 'package:libgit2dart/libgit2dart.dart';
import '../test/helpers/util.dart'; import '../test/helpers/util.dart';
void main() async { void main() {
// Preparing example repository. // Preparing example repository.
final tmpDir = await setupRepo(Directory('test/assets/testrepo/')); final tmpDir = setupRepo(Directory('test/assets/testrepo/'));
final repo = Repository.open(tmpDir.path); final repo = Repository.open(tmpDir.path);
// Get list of repo's references. // Get list of repo's references.
print('Repository references: ${repo.references.list}'); print('Repository references: ${repo.references}');
// Get reference by name. // Get reference by name.
final ref = repo.references['refs/heads/master']; final ref = repo.lookupReference('refs/heads/master');
print('Reference SHA hex: ${ref.target.sha}'); print('Reference SHA hex: ${ref.target.sha}');
print('Is reference a local branch: ${ref.isBranch}'); print('Is reference a local branch: ${ref.isBranch}');
@ -20,16 +20,16 @@ void main() async {
print('Reference shorthand name: ${ref.shorthand}'); print('Reference shorthand name: ${ref.shorthand}');
// Create new reference (direct or symbolic). // Create new reference (direct or symbolic).
final newRef = repo.references.create( final newRef = repo.createReference(
name: 'refs/tags/v1', name: 'refs/tags/v1',
target: 'refs/heads/master', target: 'refs/heads/master',
); );
// Rename reference. // Rename reference.
newRef.rename(newName: 'refs/tags/v1.1'); repo.renameReference(oldName: 'v1', newName: 'refs/tags/v1.1');
// Delete reference. // Delete reference.
newRef.delete(); repo.deleteReference('v1.1');
// free() should be called on object to free memory when done. // free() should be called on object to free memory when done.
ref.free(); ref.free();
@ -37,5 +37,5 @@ void main() async {
repo.free(); repo.free();
// Removing example repository. // Removing example repository.
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
} }

View file

@ -9,7 +9,7 @@ import '../util.dart';
/// Return a list of branches. /// Return a list of branches.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
List<String> list({ List<Pointer<git_reference>> list({
required Pointer<git_repository> repoPointer, required Pointer<git_repository> repoPointer,
required int flags, required int flags,
}) { }) {
@ -24,7 +24,7 @@ List<String> list({
throw LibGit2Error(libgit2.git_error_last()); throw LibGit2Error(libgit2.git_error_last());
} }
var result = <String>[]; var result = <Pointer<git_reference>>[];
var error = 0; var error = 0;
while (error == 0) { while (error == 0) {
@ -32,10 +32,8 @@ List<String> list({
final refType = calloc<Int32>(); final refType = calloc<Int32>();
error = libgit2.git_branch_next(reference, refType, iterator.value); error = libgit2.git_branch_next(reference, refType, iterator.value);
if (error == 0) { if (error == 0) {
final refName = reference_bindings.shorthand(reference.value); result.add(reference.value);
result.add(refName);
calloc.free(refType); calloc.free(refType);
calloc.free(reference);
} else { } else {
break; break;
} }
@ -129,11 +127,8 @@ void delete(Pointer<git_reference> branch) {
/// ///
/// The new branch name will be checked for validity. /// The new branch name will be checked for validity.
/// ///
/// Note that if the move succeeds, the old reference object will not be valid anymore,
/// and will be freed immediately.
///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
Pointer<git_reference> rename({ void rename({
required Pointer<git_reference> branchPointer, required Pointer<git_reference> branchPointer,
required String newBranchName, required String newBranchName,
required bool force, required bool force,
@ -149,8 +144,7 @@ Pointer<git_reference> rename({
if (error < 0) { if (error < 0) {
throw LibGit2Error(libgit2.git_error_last()); throw LibGit2Error(libgit2.git_error_last());
} else { } else {
reference_bindings.free(branchPointer); reference_bindings.free(out.value);
return out.value;
} }
} }

View file

@ -3,7 +3,6 @@ import 'package:ffi/ffi.dart';
import '../error.dart'; import '../error.dart';
import 'libgit2_bindings.dart'; import 'libgit2_bindings.dart';
import '../util.dart'; import '../util.dart';
import 'oid.dart' as oid_bindings;
/// Lookup a commit object from a repository. /// Lookup a commit object from a repository.
/// ///
@ -92,26 +91,21 @@ Pointer<git_oid> create({
required String message, required String message,
required Pointer<git_tree> treePointer, required Pointer<git_tree> treePointer,
required int parentCount, required int parentCount,
required List<String> parents, required List<Pointer<git_commit>> parents,
}) { }) {
final out = calloc<git_oid>(); final out = calloc<git_oid>();
final updateRefC = updateRef?.toNativeUtf8().cast<Int8>() ?? nullptr; final updateRefC = updateRef?.toNativeUtf8().cast<Int8>() ?? nullptr;
final messageEncodingC = final messageEncodingC =
messageEncoding?.toNativeUtf8().cast<Int8>() ?? nullptr; messageEncoding?.toNativeUtf8().cast<Int8>() ?? nullptr;
final messageC = message.toNativeUtf8().cast<Int8>(); final messageC = message.toNativeUtf8().cast<Int8>();
Pointer<Pointer<git_commit>> parentsC = final parentsC = calloc<Pointer<git_commit>>(parentCount);
calloc.call<Pointer<git_commit>>(parentCount);
if (parents.isNotEmpty) { if (parents.isNotEmpty) {
for (var i = 0; i < parentCount; i++) { for (var i = 0; i < parentCount; i++) {
final oid = oid_bindings.fromSHA(parents[i]); parentsC[i] = parents[i];
var commit = calloc<IntPtr>();
commit = lookup(repoPointer: repoPointer, oidPointer: oid).cast();
parentsC[i] = commit.cast();
} }
} else { } else {
final commit = calloc<IntPtr>(); parentsC[0] = nullptr;
parentsC[0] = commit.cast();
} }
final error = libgit2.git_commit_create( final error = libgit2.git_commit_create(
@ -130,9 +124,6 @@ Pointer<git_oid> create({
calloc.free(updateRefC); calloc.free(updateRefC);
calloc.free(messageEncodingC); calloc.free(messageEncodingC);
calloc.free(messageC); calloc.free(messageC);
for (var i = 0; i < parentCount; i++) {
free(parentsC[i]);
}
calloc.free(parentsC); calloc.free(parentsC);
if (error < 0) { if (error < 0) {

View file

@ -107,10 +107,10 @@ Pointer<git_oid> create({
} }
} }
/// Remove the note for an object. /// Delete the note for an object.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
void remove({ void delete({
required Pointer<git_repository> repoPointer, required Pointer<git_repository> repoPointer,
String notesRef = 'refs/notes/commits', String notesRef = 'refs/notes/commits',
required Pointer<git_signature> authorPointer, required Pointer<git_signature> authorPointer,

View file

@ -130,5 +130,5 @@ void remove({
} }
} }
/// Free a tree builder to release memory. /// Free a tree builder and all the entries to release memory.
void free(Pointer<git_treebuilder> bld) => libgit2.git_treebuilder_free(bld); void free(Pointer<git_treebuilder> bld) => libgit2.git_treebuilder_free(bld);

View file

@ -20,13 +20,22 @@ Pointer<git_worktree> create({
final out = calloc<Pointer<git_worktree>>(); final out = calloc<Pointer<git_worktree>>();
final nameC = name.toNativeUtf8().cast<Int8>(); final nameC = name.toNativeUtf8().cast<Int8>();
final pathC = path.toNativeUtf8().cast<Int8>(); final pathC = path.toNativeUtf8().cast<Int8>();
final opts =
calloc<git_worktree_add_options>(sizeOf<git_worktree_add_options>()); final opts = calloc<git_worktree_add_options>();
opts.ref.version = 1; final optsError = libgit2.git_worktree_add_options_init(
opts.ref.lock = 0; opts,
GIT_WORKTREE_ADD_OPTIONS_VERSION,
);
if (optsError < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
opts.ref.ref = nullptr;
if (refPointer != null) { if (refPointer != null) {
opts.ref.ref = refPointer; opts.ref.ref = refPointer;
} }
final error = libgit2.git_worktree_add(out, repoPointer, nameC, pathC, opts); final error = libgit2.git_worktree_add(out, repoPointer, nameC, pathC, opts);
calloc.free(nameC); calloc.free(nameC);
@ -82,6 +91,7 @@ List<String> list(Pointer<git_repository> repo) {
final result = <String>[]; final result = <String>[];
if (error < 0) { if (error < 0) {
calloc.free(out);
throw LibGit2Error(libgit2.git_error_last()); throw LibGit2Error(libgit2.git_error_last());
} else { } else {
for (var i = 0; i < out.ref.count; i++) { for (var i = 0; i < out.ref.count; i++) {

View file

@ -8,18 +8,16 @@ class Blob {
/// Initializes a new instance of [Blob] class from provided pointer to /// Initializes a new instance of [Blob] class from provided pointer to
/// blob object in memory. /// blob object in memory.
/// ///
/// Should be freed with `free()` to release allocated memory. /// Should be freed to release allocated memory.
Blob(this._blobPointer); Blob(this._blobPointer);
/// Initializes a new instance of [Blob] class from provided /// Lookups a blob object for provided [id] in a [repo]sitory.
/// [Repository] object and [sha] hex string.
/// ///
/// Should be freed with `free()` to release allocated memory. /// Should be freed to release allocated memory.
Blob.lookup({required Repository repo, required String sha}) { Blob.lookup({required Repository repo, required Oid id}) {
final oid = Oid.fromSHA(repo: repo, sha: sha);
_blobPointer = bindings.lookup( _blobPointer = bindings.lookup(
repoPointer: repo.pointer, repoPointer: repo.pointer,
oidPointer: oid.pointer, oidPointer: id.pointer,
); );
} }

View file

@ -4,134 +4,131 @@ import 'bindings/libgit2_bindings.dart';
import 'bindings/branch.dart' as bindings; import 'bindings/branch.dart' as bindings;
import 'bindings/reference.dart' as reference_bindings; import 'bindings/reference.dart' as reference_bindings;
class Branches { class Branch {
/// Initializes a new instance of the [Branches] class /// Initializes a new instance of [Branch] class from provided pointer to
/// from provided [Repository] object. /// branch object in memory.
Branches(Repository repo) {
_repoPointer = repo.pointer;
}
/// Pointer to memory address for allocated repository object.
late final Pointer<git_repository> _repoPointer;
/// Returns a list of all branches that can be found in a repository.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Should be freed with [free] to release allocated memory when no longer
List<String> list() { /// needed.
return bindings.list( Branch(this._branchPointer);
repoPointer: _repoPointer,
flags: GitBranch.all.value,
);
}
/// Returns a list of local branches that can be found in a repository.
///
/// Throws a [LibGit2Error] if error occured.
List<String> get local {
return bindings.list(
repoPointer: _repoPointer,
flags: GitBranch.local.value,
);
}
/// Returns a list of remote branches that can be found in a repository.
///
/// Throws a [LibGit2Error] if error occured.
List<String> get remote {
return bindings.list(
repoPointer: _repoPointer,
flags: GitBranch.remote.value,
);
}
/// Lookups a branch by its name in a repository.
///
/// The generated reference must be freed. The branch name will be checked for validity.
///
/// Throws a [LibGit2Error] if error occured.
Branch operator [](String branchName) {
final ref = Reference(
reference_bindings.lookupDWIM(
repoPointer: _repoPointer,
name: branchName,
),
);
late final GitBranch type;
ref.isBranch ? type = GitBranch.local : GitBranch.remote;
ref.free();
return Branch(bindings.lookup(
repoPointer: _repoPointer,
branchName: branchName,
branchType: type.value,
));
}
/// Creates a new branch pointing at a [target] commit. /// Creates a new branch pointing at a [target] commit.
/// ///
/// A new direct reference will be created pointing to this target commit. /// A new direct reference will be created pointing to this target commit.
/// If [force] is true and a reference already exists with the given name, it'll be replaced. /// If [force] is true and a reference already exists with the given name, it'll be replaced.
/// ///
/// The returned reference must be freed. /// Should be freed with [free] to release allocated memory when no longer
/// needed.
/// ///
/// The branch name will be checked for validity. /// The branch name will be checked for validity.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
Reference create({ Branch.create({
required Repository repo,
required String name, required String name,
required Commit target, required Commit target,
bool force = false, bool force = false,
}) { }) {
return Reference(bindings.create( _branchPointer = bindings.create(
repoPointer: _repoPointer, repoPointer: repo.pointer,
branchName: name, branchName: name,
targetPointer: target.pointer, targetPointer: target.pointer,
force: force, force: force,
)); );
} }
}
class Branch { /// Lookups a branch by its [name] in a [repo]sitory.
/// Initializes a new instance of [Branch] class from provided pointer to
/// branch object in memory.
/// ///
/// Should be freed with `free()` to release allocated memory. /// The branch name will be checked for validity.
const Branch(this._branchPointer); ///
/// Should be freed with [free] to release allocated memory when no longer
/// needed.
///
/// Throws a [LibGit2Error] if error occured.
Branch.lookup({required Repository repo, required String name}) {
final ref = Reference(
reference_bindings.lookupDWIM(
repoPointer: repo.pointer,
name: name,
),
);
late final GitBranch type;
ref.isBranch ? type = GitBranch.local : GitBranch.remote;
ref.free();
_branchPointer = bindings.lookup(
repoPointer: repo.pointer,
branchName: name,
branchType: type.value,
);
}
late final Pointer<git_reference> _branchPointer;
/// Pointer to memory address for allocated branch object. /// Pointer to memory address for allocated branch object.
final Pointer<git_reference> _branchPointer; Pointer<git_reference> get pointer => _branchPointer;
/// Returns the OID pointed to by a branch. /// Returns a list of branches that can be found in a [repo]sitory for provided [type].
/// Default is all branches (local and remote).
/// ///
/// Throws an exception if error occured. /// IMPORTANT: Branches must be freed manually when no longer needed to prevent
Oid get target => Oid(reference_bindings.target(_branchPointer)); /// memory leak.
///
/// Throws a [LibGit2Error] if error occured.
static List<Branch> list({
required Repository repo,
GitBranch type = GitBranch.all,
}) {
final pointers = bindings.list(
repoPointer: repo.pointer,
flags: type.value,
);
final result = <Branch>[];
for (var pointer in pointers) {
result.add(Branch(pointer));
}
return result;
}
/// Deletes an existing branch reference. /// Deletes an existing branch reference.
/// ///
/// Note that if the deletion succeeds, the reference object will not be valid anymore,
/// and will be freed.
///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
void delete() => bindings.delete(_branchPointer); static void delete({required Repository repo, required String name}) {
final branch = Branch.lookup(repo: repo, name: name);
bindings.delete(branch.pointer);
}
/// Renames an existing local branch reference. /// Renames an existing local branch reference.
/// ///
/// The new branch name will be checked for validity. /// The new branch name will be checked for validity.
/// ///
/// Note that if the move succeeds, the old reference object will not be valid anymore,
/// and will be freed immediately.
///
/// If [force] is true, existing branch will be overwritten. /// If [force] is true, existing branch will be overwritten.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
Branch rename({required String newName, bool force = false}) { static void rename({
return Branch(bindings.rename( required Repository repo,
branchPointer: _branchPointer, required String oldName,
required String newName,
bool force = false,
}) {
final branch = Branch.lookup(repo: repo, name: oldName);
bindings.rename(
branchPointer: branch.pointer,
newBranchName: newName, newBranchName: newName,
force: force, force: force,
)); );
branch.free();
} }
/// Returns the OID pointed to by a branch.
///
/// Throws an exception if error occured.
Oid get target => Oid(reference_bindings.target(_branchPointer));
/// Checks if HEAD points to the given branch. /// Checks if HEAD points to the given branch.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
@ -155,4 +152,9 @@ class Branch {
/// Releases memory allocated for branch object. /// Releases memory allocated for branch object.
void free() => bindings.free(_branchPointer); void free() => bindings.free(_branchPointer);
@override
String toString() {
return 'Branch{name: $name, target: $target}';
}
} }

View file

@ -8,18 +8,16 @@ class Commit {
/// Initializes a new instance of [Commit] class from provided pointer to /// Initializes a new instance of [Commit] class from provided pointer to
/// commit object in memory. /// commit object in memory.
/// ///
/// Should be freed with `free()` to release allocated memory. /// Should be freed to release allocated memory.
Commit(this._commitPointer); Commit(this._commitPointer);
/// Initializes a new instance of [Commit] class from provided [Repository] object /// Lookups commit object for provided [id] in a [repo]sitory.
/// and [sha] hex string.
/// ///
/// Should be freed with `free()` to release allocated memory. /// Should be freed to release allocated memory.
Commit.lookup({required Repository repo, required String sha}) { Commit.lookup({required Repository repo, required Oid id}) {
final oid = Oid.fromSHA(repo: repo, sha: sha);
_commitPointer = bindings.lookup( _commitPointer = bindings.lookup(
repoPointer: repo.pointer, repoPointer: repo.pointer,
oidPointer: oid.pointer, oidPointer: id.pointer,
); );
} }
@ -42,14 +40,14 @@ class Commit {
required String message, required String message,
required Signature author, required Signature author,
required Signature commiter, required Signature commiter,
required String treeSHA, required Tree tree,
required List<String> parents, required List<Commit> parents,
String? updateRef, String? updateRef,
String? messageEncoding, String? messageEncoding,
}) { }) {
final tree = Tree.lookup(repo: repo, sha: treeSHA); final parentsPointers = parents.map((parent) => parent.pointer).toList();
final result = Oid(bindings.create( return Oid(bindings.create(
repoPointer: repo.pointer, repoPointer: repo.pointer,
updateRef: updateRef, updateRef: updateRef,
authorPointer: author.pointer, authorPointer: author.pointer,
@ -58,12 +56,8 @@ class Commit {
message: message, message: message,
treePointer: tree.pointer, treePointer: tree.pointer,
parentCount: parents.length, parentCount: parents.length,
parents: parents, parents: parentsPointers,
)); ));
tree.free();
return result;
} }
/// Returns the encoding for the message of a commit, as a string /// Returns the encoding for the message of a commit, as a string

View file

@ -139,25 +139,9 @@ class Index with IterableMixin<IndexEntry> {
bindings.read(indexPointer: _indexPointer, force: force); bindings.read(indexPointer: _indexPointer, force: force);
/// Updates the contents of an existing index object in memory by reading from the /// Updates the contents of an existing index object in memory by reading from the
/// specified tree. /// specified [tree].
void readTree(Object target) { void readTree(Tree tree) {
late final Tree tree;
if (target is Oid) {
final repo = Repository(bindings.owner(_indexPointer));
tree = Tree.lookup(repo: repo, sha: target.sha);
} else if (target is Tree) {
tree = target;
} else if (target is String) {
final repo = Repository(bindings.owner(_indexPointer));
tree = Tree.lookup(repo: repo, sha: target);
} else {
throw ArgumentError.value(
'$target should be either Oid object, SHA hex string or Tree object');
}
bindings.readTree(indexPointer: _indexPointer, treePointer: tree.pointer); bindings.readTree(indexPointer: _indexPointer, treePointer: tree.pointer);
tree.free();
} }
/// Writes an existing index object from memory back to disk using an atomic file lock. /// Writes an existing index object from memory back to disk using an atomic file lock.

View file

@ -3,43 +3,44 @@ import 'package:libgit2dart/libgit2dart.dart';
import 'bindings/libgit2_bindings.dart'; import 'bindings/libgit2_bindings.dart';
import 'bindings/note.dart' as bindings; import 'bindings/note.dart' as bindings;
class Notes { class Note {
/// Initializes a new instance of the [Notes] class from /// Initializes a new instance of the [Note] class from provided
/// provided [Repository] object. /// pointer to note and annotatedId objects in memory.
Notes(Repository repo) { Note(this._notePointer, this._annotatedIdPointer);
_repoPointer = repo.pointer;
}
/// Pointer to memory address for allocated repository object. /// Reads the note for an [annotatedId].
late final Pointer<git_repository> _repoPointer;
/// Reads the note for an object.
/// ///
/// The note must be freed manually by the user. /// IMPORTANT: Notes must be freed manually when no longer needed to prevent
/// memory leak.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
static Note lookup({ Note.lookup({
required Repository repo, required Repository repo,
required Oid annotatedId, required Oid annotatedId,
String notesRef = 'refs/notes/commits', String notesRef = 'refs/notes/commits',
}) { }) {
final note = bindings.lookup( _notePointer = bindings.lookup(
repoPointer: repo.pointer, repoPointer: repo.pointer,
oidPointer: annotatedId.pointer, oidPointer: annotatedId.pointer,
notesRef: notesRef, notesRef: notesRef,
); );
_annotatedIdPointer = annotatedId.pointer;
return Note(note, annotatedId.pointer, repo.pointer);
} }
/// Adds a note for an [object]. /// Pointer to memory address for allocated note object.
late final Pointer<git_note> _notePointer;
/// Pointer to memory address for allocated annotetedId object.
late final Pointer<git_oid> _annotatedIdPointer;
/// Adds a note for an [annotatedId].
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
static Oid create({ static Oid create({
required Repository repo, required Repository repo,
required Signature author, required Signature author,
required Signature committer, required Signature committer,
required Oid object, required Oid annotatedId,
required String note, required String note,
String notesRef = 'refs/notes/commits', String notesRef = 'refs/notes/commits',
bool force = false, bool force = false,
@ -48,62 +49,49 @@ class Notes {
repoPointer: repo.pointer, repoPointer: repo.pointer,
authorPointer: author.pointer, authorPointer: author.pointer,
committerPointer: committer.pointer, committerPointer: committer.pointer,
oidPointer: object.pointer, oidPointer: annotatedId.pointer,
note: note, note: note,
notesRef: notesRef, notesRef: notesRef,
force: force, force: force,
)); ));
} }
/// Returns list of notes for repository. /// Deletes the note for an [annotatedId].
///
/// Notes must be freed manually by the user.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
List<Note> get list { static void delete({
final notesPointers = bindings.list(_repoPointer); required Repository repo,
required Oid annotatedId,
required Signature author,
required Signature committer,
String notesRef = 'refs/notes/commits',
}) {
bindings.delete(
repoPointer: repo.pointer,
authorPointer: author.pointer,
committerPointer: committer.pointer,
oidPointer: annotatedId.pointer,
);
}
/// Returns list of notes for repository.
///
/// IMPORTANT: Notes must be freed manually when no longer needed to prevent
/// memory leak.
///
/// Throws a [LibGit2Error] if error occured.
static List<Note> list(Repository repo) {
final notesPointers = bindings.list(repo.pointer);
var result = <Note>[]; var result = <Note>[];
for (var note in notesPointers) { for (var note in notesPointers) {
result.add(Note( result.add(Note(
note['note'] as Pointer<git_note>, note['note'] as Pointer<git_note>,
note['annotatedId'] as Pointer<git_oid>, note['annotatedId'] as Pointer<git_oid>,
_repoPointer,
)); ));
} }
return result; 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]. /// Returns the note object's [Oid].
Oid get id => Oid(bindings.id(_notePointer)); Oid get id => Oid(bindings.id(_notePointer));

View file

@ -7,53 +7,31 @@ import 'bindings/refdb.dart' as refdb_bindings;
import 'bindings/repository.dart' as repository_bindings; import 'bindings/repository.dart' as repository_bindings;
import 'util.dart'; import 'util.dart';
class References { class Reference {
/// Initializes a new instance of the [References] class /// Initializes a new instance of the [Reference] class.
/// from provided [Repository] object. /// Should be freed to release allocated memory.
References(Repository repo) { Reference(this._refPointer);
_repoPointer = repo.pointer;
}
/// Pointer to memory address for allocated repository object.
late final Pointer<git_repository> _repoPointer;
/// Returns a list of all the references that can be found in a repository.
///
/// Throws a [LibGit2Error] if error occured.
List<String> 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.
///
/// Should be freed with `free()` to release allocated memory.
///
/// The name will be checked for validity.
///
/// Throws a [LibGit2Error] if error occured.
Reference operator [](String name) {
return Reference(bindings.lookup(repoPointer: _repoPointer, name: name));
}
/// Creates a new reference. /// Creates a new reference.
/// ///
/// The reference will be created in the repository and written to the disk. /// The reference will be created in the [repo]sitory and written to the disk.
/// The generated [Reference] object must be freed by the user. /// The generated [Reference] object must be freed by the user.
/// ///
/// Valid reference names must follow one of two patterns: /// Valid reference [name]s must follow one of two patterns:
/// ///
/// Top-level names must contain only capital letters and underscores, and must begin and end /// Top-level names must contain only capital letters and underscores, and must begin and end
/// with a letter. (e.g. "HEAD", "ORIG_HEAD"). /// with a letter. (e.g. "HEAD", "ORIG_HEAD").
/// Names prefixed with "refs/" can be almost anything. You must avoid the characters /// Names prefixed with "refs/" can be almost anything. You must avoid the characters
/// '~', '^', ':', '\', '?', '[', and '*', and the sequences ".." and "@{" which have /// '~', '^', ':', '\', '?', '[', and '*', and the sequences ".." and "@{" which have
/// special meaning to revparse. /// 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 /// Throws a [LibGit2Error] if a reference already exists with the given [name]
/// unless [force] is true, in which case it will be overwritten.
///
/// The [logMessage] 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. /// standard set (HEAD, branches and remote-tracking branches) and it does not have a reflog.
Reference create({ Reference.create({
required Repository repo,
required String name, required String name,
required Object target, required Object target,
bool force = false, bool force = false,
@ -66,7 +44,6 @@ class References {
oid = target; oid = target;
isDirect = true; isDirect = true;
} else if (isValidShaHex(target as String)) { } else if (isValidShaHex(target as String)) {
final repo = Repository(_repoPointer);
oid = Oid.fromSHA(repo: repo, sha: target); oid = Oid.fromSHA(repo: repo, sha: target);
isDirect = true; isDirect = true;
} else { } else {
@ -74,46 +51,97 @@ class References {
} }
if (isDirect) { if (isDirect) {
return Reference(bindings.createDirect( _refPointer = bindings.createDirect(
repoPointer: _repoPointer, repoPointer: repo.pointer,
name: name, name: name,
oidPointer: oid.pointer, oidPointer: oid.pointer,
force: force, force: force,
logMessage: logMessage, logMessage: logMessage,
)); );
} else { } else {
return Reference(bindings.createSymbolic( _refPointer = bindings.createSymbolic(
repoPointer: _repoPointer, repoPointer: repo.pointer,
name: name, name: name,
target: target as String, target: target as String,
force: force, force: force,
logMessage: logMessage, logMessage: logMessage,
)); );
} }
} }
/// Suggests that the given refdb compress or optimize its references. /// Lookups reference [name] in a [repo]sitory.
/// This mechanism is implementation specific. For on-disk reference databases, ///
/// for example, this may pack all loose references. /// Should be freed to release allocated memory.
///
/// The [name] will be checked for validity.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
void compress() { Reference.lookup({required Repository repo, required String name}) {
final refdb = repository_bindings.refdb(_repoPointer); _refPointer = bindings.lookup(repoPointer: repo.pointer, name: name);
refdb_bindings.compress(refdb);
refdb_bindings.free(refdb);
} }
}
class Reference {
/// Initializes a new instance of the [Reference] class.
/// Should be freed with `free()` to release allocated memory.
Reference(this._refPointer);
late Pointer<git_reference> _refPointer; late Pointer<git_reference> _refPointer;
/// Pointer to memory address for allocated reference object. /// Pointer to memory address for allocated reference object.
Pointer<git_reference> get pointer => _refPointer; Pointer<git_reference> get pointer => _refPointer;
/// Deletes an existing reference with provided [name].
///
/// This method works for both direct and symbolic references.
///
/// Throws a [LibGit2Error] if error occured.
static void delete({required Repository repo, required String name}) {
final ref = Reference.lookup(repo: repo, name: name);
bindings.delete(ref.pointer);
ref.free();
}
/// Renames an existing reference.
///
/// This method works for both direct and symbolic references.
///
/// The [newName] will be checked for validity.
///
/// If the [force] flag is set to false, and there's already a reference with the given name,
/// the renaming will fail.
///
/// IMPORTANT: The user needs to write a proper reflog entry [logMessage] if the reflog is
/// enabled for the repository. We only rename the reflog if it exists.
///
/// Throws a [LibGit2Error] if error occured.
static void rename({
required Repository repo,
required String oldName,
required String newName,
bool force = false,
String? logMessage,
}) {
final ref = Reference.lookup(repo: repo, name: oldName);
bindings.rename(
refPointer: ref.pointer,
newName: newName,
force: force,
logMessage: logMessage,
);
ref.free();
}
/// Returns a list of all the references that can be found in a [repo]sitory.
///
/// Throws a [LibGit2Error] if error occured.
static List<String> list(Repository repo) => bindings.list(repo.pointer);
/// Suggests that the [repo]sitory's refdb compress or optimize its references.
/// This mechanism is implementation specific. For on-disk reference databases,
/// for example, this may pack all loose references.
///
/// Throws a [LibGit2Error] if error occured.
static void compress(Repository repo) {
final refdb = repository_bindings.refdb(repo.pointer);
refdb_bindings.compress(refdb);
refdb_bindings.free(refdb);
}
/// Returns the type of the reference. /// Returns the type of the reference.
ReferenceType get type { ReferenceType get type {
return bindings.referenceType(_refPointer) == 1 return bindings.referenceType(_refPointer) == 1
@ -180,6 +208,8 @@ class Reference {
/// ```dart /// ```dart
/// final commit = ref.peel(GitObject.commit) as Commit; /// final commit = ref.peel(GitObject.commit) as Commit;
/// final tree = ref.peel(GitObject.tree) as Tree; /// final tree = ref.peel(GitObject.tree) as Tree;
/// final blob = ref.peel(GitObject.blob) as Blob;
/// final tag = ref.peel(GitObject.tag) as Tag;
/// ``` /// ```
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
@ -207,32 +237,6 @@ class Reference {
/// If no shortname is appropriate, it will return the full name. /// If no shortname is appropriate, it will return the full name.
String get shorthand => bindings.shorthand(_refPointer); String get shorthand => bindings.shorthand(_refPointer);
/// Renames an existing reference.
///
/// This method works for both direct and symbolic references.
///
/// The new name will be checked for validity.
///
/// If the force flag is not enabled, and there's already a reference with the given name,
/// the renaming will fail.
///
/// IMPORTANT: The user needs to write a proper reflog entry if the reflog is enabled for
/// the repository. We only rename the reflog if it exists.
///
/// Throws a [LibGit2Error] if error occured.
void rename({
required String newName,
bool force = false,
String? logMessage,
}) {
_refPointer = bindings.rename(
refPointer: _refPointer,
newName: newName,
force: force,
logMessage: logMessage,
);
}
/// Checks if a reflog exists for the specified reference [name]. /// Checks if a reflog exists for the specified reference [name].
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
@ -261,14 +265,6 @@ class Reference {
/// Returns the repository where a reference resides. /// Returns the repository where a reference resides.
Repository get owner => Repository(bindings.owner(_refPointer)); Repository get owner => Repository(bindings.owner(_refPointer));
/// Delete an existing reference.
///
/// This method works for both direct and symbolic references.
/// The reference will be immediately removed on disk but the memory will not be freed.
///
/// Throws a [LibGit2Error] if the reference has changed from the time it was looked up.
void delete() => bindings.delete(_refPointer);
@override @override
bool operator ==(other) { bool operator ==(other) {
return (other is Reference) && return (other is Reference) &&
@ -283,4 +279,9 @@ class Reference {
/// Releases memory allocated for reference object. /// Releases memory allocated for reference object.
void free() => bindings.free(_refPointer); void free() => bindings.free(_refPointer);
@override
String toString() {
return 'Reference{name: $name, target: $target}';
}
} }

View file

@ -3,70 +3,63 @@ import 'package:libgit2dart/libgit2dart.dart';
import 'bindings/libgit2_bindings.dart'; import 'bindings/libgit2_bindings.dart';
import 'bindings/remote.dart' as bindings; import 'bindings/remote.dart' as bindings;
class Remotes { class Remote {
/// Initializes a new instance of the [Remotes] class from /// Initializes a new instance of [Remote] class from provided pointer
/// provided [Repository] object. /// to remote object in memory.
Remotes(Repository repo) { Remote(this._remotePointer);
_repoPointer = repo.pointer;
}
/// Pointer to memory address for allocated repository object. /// Initializes a new instance of [Remote] class by looking up remote with
late final Pointer<git_repository> _repoPointer; /// provided [name] in a [repo]sitory.
/// Returns a list of the configured remotes for a repo.
///
/// Throws a [LibGit2Error] if error occured.
List<String> get list {
return bindings.list(_repoPointer);
}
/// Returns number of the configured remotes for a repo.
int get length => list.length;
/// Returns [Remote] by looking up [name] in a repository.
/// ///
/// The name will be checked for validity. /// The name will be checked for validity.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
Remote operator [](String name) { Remote.lookup({required Repository repo, required String name}) {
return Remote(bindings.lookup(repoPointer: _repoPointer, name: name)); _remotePointer = bindings.lookup(repoPointer: repo.pointer, name: name);
} }
/// Adds a remote to the repository's configuration with the default [fetch] /// Initializes a new instance of [Remote] class by adding a remote with
/// refspec if none provided . /// provided [name] and [url] to the [repo]sitory's configuration with the
/// default [fetch] refspec if none provided .
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
Remote create({ Remote.create({
required Repository repo,
required String name, required String name,
required String url, required String url,
String? fetch, String? fetch,
}) { }) {
if (fetch == null) { if (fetch == null) {
return Remote(bindings.create( _remotePointer = bindings.create(
repoPointer: _repoPointer, repoPointer: repo.pointer,
name: name, name: name,
url: url, url: url,
)); );
} else { } else {
return Remote(bindings.createWithFetchSpec( _remotePointer = bindings.createWithFetchSpec(
repoPointer: _repoPointer, repoPointer: repo.pointer,
name: name, name: name,
url: url, url: url,
fetch: fetch, fetch: fetch,
)); );
} }
} }
late final Pointer<git_remote> _remotePointer;
/// Pointer to memory address for allocated remote object.
Pointer<git_remote> get pointer => _remotePointer;
/// Deletes an existing persisted remote. /// Deletes an existing persisted remote.
/// ///
/// All remote-tracking branches and configuration settings for the remote will be removed. /// All remote-tracking branches and configuration settings for the remote will be removed.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
void delete(String name) { static void delete({required Repository repo, required String name}) {
bindings.delete(repoPointer: _repoPointer, name: name); bindings.delete(repoPointer: repo.pointer, name: name);
} }
/// Give the remote a new name. /// Gives the remote a new name.
/// ///
/// Returns list of non-default refspecs that cannot be renamed. /// Returns list of non-default refspecs that cannot be renamed.
/// ///
@ -78,23 +71,38 @@ class Remotes {
/// their list of refspecs. /// their list of refspecs.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
List<String> rename({required String remote, required String newName}) { static List<String> rename({
required Repository repo,
required String oldName,
required String newName,
}) {
return bindings.rename( return bindings.rename(
repoPointer: _repoPointer, repoPointer: repo.pointer,
name: remote, name: oldName,
newName: newName, newName: newName,
); );
} }
/// Returns a list of the configured remotes for a [repo]sitory.
///
/// Throws a [LibGit2Error] if error occured.
static List<String> list(Repository repo) {
return bindings.list(repo.pointer);
}
/// Sets the remote's url in the configuration. /// Sets the remote's url in the configuration.
/// ///
/// Remote objects already in memory will not be affected. This assumes the common /// Remote objects already in memory will not be affected. This assumes the common
/// case of a single-url remote and will otherwise return an error. /// case of a single-url remote and will otherwise return an error.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
void setUrl({required String remote, required String url}) { static void setUrl({
required Repository repo,
required String remote,
required String url,
}) {
bindings.setUrl( bindings.setUrl(
repoPointer: _repoPointer, repoPointer: repo.pointer,
remote: remote, remote: remote,
url: url, url: url,
); );
@ -106,9 +114,13 @@ class Remotes {
/// case of a single-url remote and will otherwise return an error. /// case of a single-url remote and will otherwise return an error.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
void setPushUrl({required String remote, required String url}) { static void setPushUrl({
required Repository repo,
required String remote,
required String url,
}) {
bindings.setPushUrl( bindings.setPushUrl(
repoPointer: _repoPointer, repoPointer: repo.pointer,
remote: remote, remote: remote,
url: url, url: url,
); );
@ -119,9 +131,13 @@ class Remotes {
/// No loaded remote instances will be affected. /// No loaded remote instances will be affected.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
void addFetch({required String remote, required String refspec}) { static void addFetch({
required Repository repo,
required String remote,
required String refspec,
}) {
bindings.addFetch( bindings.addFetch(
repoPointer: _repoPointer, repoPointer: repo.pointer,
remote: remote, remote: remote,
refspec: refspec, refspec: refspec,
); );
@ -132,24 +148,17 @@ class Remotes {
/// No loaded remote instances will be affected. /// No loaded remote instances will be affected.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
void addPush({required String remote, required String refspec}) { static void addPush({
required Repository repo,
required String remote,
required String refspec,
}) {
bindings.addPush( bindings.addPush(
repoPointer: _repoPointer, repoPointer: repo.pointer,
remote: remote, remote: remote,
refspec: refspec, refspec: refspec,
); );
} }
}
class Remote {
/// Initializes a new instance of [Remote] class from provided pointer
/// to remote object in memory.
const Remote(this._remotePointer);
final Pointer<git_remote> _remotePointer;
/// Pointer to memory address for allocated remote object.
Pointer<git_remote> get pointer => _remotePointer;
/// Returns the remote's name. /// Returns the remote's name.
String get name => bindings.name(_remotePointer); String get name => bindings.name(_remotePointer);

View file

@ -130,6 +130,16 @@ class Repository {
); );
} }
/// Returns [Oid] object if it can be found 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 operator [](String sha) {
return Oid.fromSHA(repo: this, sha: sha);
}
/// Returns path to the `.git` folder for normal repositories /// Returns path to the `.git` folder for normal repositories
/// or path to the repository itself for bare repositories. /// or path to the repository itself for bare repositories.
String get path => bindings.path(_repoPointer); String get path => bindings.path(_repoPointer);
@ -322,8 +332,89 @@ class Repository {
/// Must be freed once it's no longer being used. /// Must be freed once it's no longer being used.
Reference get head => Reference(bindings.head(_repoPointer)); Reference get head => Reference(bindings.head(_repoPointer));
/// Returns [References] object. /// Returns a list of all the references that can be found in a repository.
References get references => References(this); ///
/// Throws a [LibGit2Error] if error occured.
List<String> get references => Reference.list(this);
/// Lookups reference [name] in a [repo]sitory.
///
/// Should be freed to release allocated memory.
///
/// The [name] will be checked for validity.
///
/// Throws a [LibGit2Error] if error occured.
Reference lookupReference(String name) {
return Reference.lookup(repo: this, name: 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 [name]s 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 [logMessage] 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,
}) {
return Reference.create(
repo: this,
name: name,
target: target,
force: force,
logMessage: logMessage,
);
}
/// Deletes an existing reference with provided [name].
///
/// This method works for both direct and symbolic references.
///
/// Throws a [LibGit2Error] if error occured.
void deleteReference(String name) => Reference.delete(repo: this, name: name);
/// Renames an existing reference.
///
/// This method works for both direct and symbolic references.
///
/// The [newName] will be checked for validity.
///
/// If the [force] flag is set to false, and there's already a reference with the given name,
/// the renaming will fail.
///
/// IMPORTANT: The user needs to write a proper reflog entry [logMessage] if the reflog is
/// enabled for the repository. We only rename the reflog if it exists.
///
/// Throws a [LibGit2Error] if error occured.
void renameReference({
required String oldName,
required String newName,
bool force = false,
String? logMessage,
}) {
Reference.rename(
repo: this,
oldName: oldName,
newName: newName,
force: force,
logMessage: logMessage,
);
}
/// Returns [Index] file for this repository. /// Returns [Index] file for this repository.
/// ///
@ -337,39 +428,11 @@ class Repository {
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
Odb get odb => Odb(bindings.odb(_repoPointer)); Odb get odb => Odb(bindings.odb(_repoPointer));
/// Looksup git object (commit, tree, blob, tag) for provided [sha] hex string. /// Lookups a tree object for provided [id].
/// ///
/// Returned object should be explicitly downcasted to one of four of git object types. /// Should be freed to release allocated memory.
/// Tree lookupTree(Oid id) {
/// ```dart return Tree.lookup(repo: this, id: id);
/// 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(repo: this, sha: sha);
final object = object_bindings.lookup(
repoPointer: _repoPointer,
oidPointer: oid.pointer,
type: GitObject.any.value,
);
final type = object_bindings.type(object);
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 should be pointing to either commit, tree, blob or a tag');
}
} }
/// Creates a new action signature with default user and now timestamp. /// Creates a new action signature with default user and now timestamp.
@ -410,6 +473,13 @@ class Repository {
return RevParse.single(repo: this, spec: spec); return RevParse.single(repo: this, spec: spec);
} }
/// Lookups commit object for provided [id].
///
/// Should be freed to release allocated memory.
Commit lookupCommit(Oid id) {
return Commit.lookup(repo: this, id: id);
}
/// Creates new commit in the repository. /// Creates new commit in the repository.
/// ///
/// [updateRef] is name of the reference that will be updated to point to this commit. /// [updateRef] is name of the reference that will be updated to point to this commit.
@ -423,8 +493,8 @@ class Repository {
required String message, required String message,
required Signature author, required Signature author,
required Signature commiter, required Signature commiter,
required String treeSHA, required Tree tree,
required List<String> parents, required List<Commit> parents,
String? updateRef, String? updateRef,
String? messageEncoding, String? messageEncoding,
}) { }) {
@ -433,7 +503,7 @@ class Repository {
message: message, message: message,
author: author, author: author,
commiter: commiter, commiter: commiter,
treeSHA: treeSHA, tree: tree,
parents: parents, parents: parents,
); );
} }
@ -464,6 +534,13 @@ class Repository {
return RevParse.range(repo: this, spec: spec); return RevParse.range(repo: this, spec: spec);
} }
/// Lookups a blob object for provided [id].
///
/// Should be freed to release allocated memory.
Blob lookupBlob(Oid id) {
return Blob.lookup(repo: this, id: id);
}
/// Creates a new blob from a [content] string and writes it to ODB. /// Creates a new blob from a [content] string and writes it to ODB.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
@ -487,12 +564,22 @@ class Repository {
return Blob.createFromDisk(repo: this, path: path); return Blob.createFromDisk(repo: this, path: path);
} }
/// Creates a new tag in the repository from provided Oid object. /// Returns a list with all the tags in the repository.
/// ///
/// A new reference will also be created pointing to this tag object. If force is true /// Throws a [LibGit2Error] if error occured.
List<String> get tags => Tag.list(this);
/// Lookups tag object for provided [id].
///
/// Should be freed to release allocated memory.
Tag lookupTag(Oid id) => Tag.lookup(repo: this, id: id);
/// Creates a new tag in the repository for provided [target] object.
///
/// A new reference will also be created pointing to this tag object. If [force] is true
/// and a reference already exists with the given name, it'll be replaced. /// and a reference already exists with the given name, it'll be replaced.
/// ///
/// The message will not be cleaned up. /// The [message] will not be cleaned up.
/// ///
/// The tag name will be checked for validity. You must avoid the characters /// The tag name will be checked for validity. You must avoid the characters
/// '~', '^', ':', '\', '?', '[', and '*', and the sequences ".." and "@{" which have /// '~', '^', ':', '\', '?', '[', and '*', and the sequences ".." and "@{" which have
@ -501,7 +588,7 @@ class Repository {
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
Oid createTag({ Oid createTag({
required String tagName, required String tagName,
required String target, required Oid target,
required GitObject targetType, required GitObject targetType,
required Signature tagger, required Signature tagger,
required String message, required String message,
@ -517,13 +604,93 @@ class Repository {
force: force); force: force);
} }
/// Returns a list with all the tags in the repository. /// Deletes an existing tag reference with provided [name].
///
/// The tag [name] will be checked for validity.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
List<String> get tags => Tag.list(this); void deleteTag(String name) => Tag.delete(repo: this, name: name);
/// Returns a [Branches] object. /// Returns a list of all branches that can be found in a repository.
Branches get branches => Branches(this); ///
/// IMPORTANT: Branches must be freed manually when no longer needed to prevent
/// memory leak.
///
/// Throws a [LibGit2Error] if error occured.
List<Branch> get branches => Branch.list(repo: this);
/// Returns a list of local branches that can be found in a repository.
///
/// IMPORTANT: Branches must be freed manually when no longer needed to prevent
/// memory leak.
///
/// Throws a [LibGit2Error] if error occured.
List<Branch> get branchesLocal =>
Branch.list(repo: this, type: GitBranch.local);
/// Returns a list of remote branches that can be found in a repository.
///
/// IMPORTANT: Branches must be freed manually when no longer needed to prevent
/// memory leak.
///
/// Throws a [LibGit2Error] if error occured.
List<Branch> get branchesRemote =>
Branch.list(repo: this, type: GitBranch.remote);
/// Lookups a branch by its [name] in a repository.
///
/// The branch name will be checked for validity.
///
/// Should be freed to release allocated memory when no longer needed.
///
/// Throws a [LibGit2Error] if error occured.
Branch lookupBranch(String name) {
return Branch.lookup(repo: this, name: name);
}
/// Creates a new branch pointing at a [target] commit.
///
/// A new direct reference will be created pointing to this target commit.
/// If [force] is true and a reference already exists with the given name, it'll be replaced.
///
/// Should be freed with [free] to release allocated memory when no longer
/// needed.
///
/// The branch name will be checked for validity.
///
/// Throws a [LibGit2Error] if error occured.
Branch createBranch({
required String name,
required Commit target,
bool force = false,
}) {
return Branch.create(
repo: this,
name: name,
target: target,
force: force,
);
}
/// Deletes an existing branch reference.
///
/// Throws a [LibGit2Error] if error occured.
void deleteBranch(String name) => Branch.delete(repo: this, name: name);
/// Renames an existing local branch reference.
///
/// The new branch name will be checked for validity.
///
/// If [force] is true, existing branch will be overwritten.
///
/// Throws a [LibGit2Error] if error occured.
void renameBranch({
required String oldName,
required String newName,
bool force = false,
}) {
Branch.rename(repo: this, oldName: oldName, newName: newName, force: force);
}
/// Checks status of the repository and returns map of file paths and their statuses. /// Checks status of the repository and returns map of file paths and their statuses.
/// ///
@ -619,7 +786,7 @@ class Repository {
required Oid theirHead, required Oid theirHead,
String ourRef = 'HEAD', String ourRef = 'HEAD',
}) { }) {
final ref = references[ourRef]; final ref = lookupReference(ourRef);
final head = commit_bindings.annotatedLookup( final head = commit_bindings.annotatedLookup(
repoPointer: _repoPointer, repoPointer: _repoPointer,
oidPointer: theirHead.pointer, oidPointer: theirHead.pointer,
@ -831,7 +998,7 @@ class Repository {
paths: paths, paths: paths,
); );
} else { } else {
final ref = references[refName]; final ref = lookupReference(refName);
final treeish = object_bindings.lookup( final treeish = object_bindings.lookup(
repoPointer: _repoPointer, repoPointer: _repoPointer,
oidPointer: ref.target.pointer, oidPointer: ref.target.pointer,
@ -1062,8 +1229,57 @@ class Repository {
return stash_bindings.list(_repoPointer); return stash_bindings.list(_repoPointer);
} }
/// Returns [Remotes] object. /// Returns a list of the configured remotes for a repository.
Remotes get remotes => Remotes(this); ///
/// Throws a [LibGit2Error] if error occured.
List<String> get remotes => Remote.list(this);
/// Lookups remote with provided [name].
///
/// The name will be checked for validity.
///
/// Throws a [LibGit2Error] if error occured.
Remote lookupRemote(String name) {
return Remote.lookup(repo: this, name: name);
}
/// Adds a remote with provided [name] and [url] to the repository's
/// configuration with the default [fetch] refspec if none provided .
///
/// Throws a [LibGit2Error] if error occured.
Remote createRemote({
required String name,
required String url,
String? fetch,
}) {
return Remote.create(repo: this, name: name, url: url, fetch: fetch);
}
/// Deletes an existing persisted remote.
///
/// All remote-tracking branches and configuration settings for the remote will be removed.
///
/// Throws a [LibGit2Error] if error occured.
void deleteRemote(String name) => Remote.delete(repo: this, name: name);
/// Gives the remote a new name.
///
/// Returns list of non-default refspecs that cannot be renamed.
///
/// All remote-tracking branches and configuration settings for the remote are updated.
///
/// The new name will be checked for validity.
///
/// No loaded instances of a the remote with the old name will change their name or
/// their list of refspecs.
///
/// Throws a [LibGit2Error] if error occured.
List<String> renameRemote({
required String oldName,
required String newName,
}) {
return Remote.rename(repo: this, oldName: oldName, newName: newName);
}
/// Looks up the value of one git attribute for path. /// Looks up the value of one git attribute for path.
/// ///
@ -1132,49 +1348,69 @@ class Repository {
/// Returns list of notes for repository. /// Returns list of notes for repository.
/// ///
/// Notes must be freed manually. /// IMPORTANT: Notes must be freed manually when no longer needed to prevent
/// memory leak.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
List<Note> get notes => Notes(this).list; List<Note> get notes => Note.list(this);
/// Reads the note for an object. /// Reads the note for an [annotatedId].
/// ///
/// The note must be freed manually. /// IMPORTANT: Notes must be freed manually when no longer needed to prevent
/// memory leak.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
Note lookupNote({ Note lookupNote({
required Oid annotatedId, required Oid annotatedId,
String notesRef = 'refs/notes/commits', String notesRef = 'refs/notes/commits',
}) { }) {
return Notes.lookup( return Note.lookup(
repo: this, repo: this,
annotatedId: annotatedId, annotatedId: annotatedId,
notesRef: notesRef, notesRef: notesRef,
); );
} }
/// Adds a note for an [object]. /// Adds a note for an [annotatedId].
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
Oid createNote({ Oid createNote({
required Signature author, required Signature author,
required Signature committer, required Signature committer,
required Oid object, required Oid annotatedId,
required String note, required String note,
String notesRef = 'refs/notes/commits', String notesRef = 'refs/notes/commits',
bool force = false, bool force = false,
}) { }) {
return Notes.create( return Note.create(
repo: this, repo: this,
author: author, author: author,
committer: committer, committer: committer,
object: object, annotatedId: annotatedId,
note: note, note: note,
notesRef: notesRef, notesRef: notesRef,
force: force, force: force,
); );
} }
/// Deletes the note for an [annotatedId].
///
/// Throws a [LibGit2Error] if error occured.
void deleteNote({
required Oid annotatedId,
required Signature author,
required Signature committer,
String notesRef = 'refs/notes/commits',
}) {
Note.delete(
repo: this,
annotatedId: annotatedId,
author: author,
committer: committer,
notesRef: notesRef,
);
}
/// Checks if a commit is the descendant of another commit. /// Checks if a commit is the descendant of another commit.
/// ///
/// Note that a commit is not considered a descendant of itself, in contrast to /// Note that a commit is not considered a descendant of itself, in contrast to
@ -1397,4 +1633,34 @@ class Repository {
callbacks: callbacks, callbacks: callbacks,
); );
} }
/// Returns list of names of linked working trees.
///
/// Throws a [LibGit2Error] if error occured.
List<String> get worktrees => Worktree.list(this);
/// Lookups up existing worktree for provided [name].
///
/// Should be freed to release allocated memory.
///
/// Throws a [LibGit2Error] if error occured.
Worktree lookupWorktree(String name) {
return Worktree.lookup(repo: this, name: name);
}
/// Creates new worktree.
///
/// If [ref] is provided, no new branch will be created but specified [ref] will
/// be used instead.
///
/// Should be freed with `free()` to release allocated memory.
///
/// Throws a [LibGit2Error] if error occured.
Worktree createWorktree({
required String name,
required String path,
Reference? ref,
}) {
return Worktree.create(repo: this, name: name, path: path, ref: ref);
}
} }

View file

@ -8,18 +8,16 @@ class Tag {
/// Initializes a new instance of [Tag] class from provided pointer to /// Initializes a new instance of [Tag] class from provided pointer to
/// tag object in memory. /// tag object in memory.
/// ///
/// Should be freed with `free()` to release allocated memory. /// Should be freed to release allocated memory.
Tag(this._tagPointer); Tag(this._tagPointer);
/// Initializes a new instance of [Tag] class from provided /// Lookups tag object for provided [id] in a [repo]sitory.
/// [Repository] object and [sha] hex string.
/// ///
/// Should be freed with `free()` to release allocated memory. /// Should be freed to release allocated memory.
Tag.lookup({required Repository repo, required String sha}) { Tag.lookup({required Repository repo, required Oid id}) {
final oid = Oid.fromSHA(repo: repo, sha: sha);
_tagPointer = bindings.lookup( _tagPointer = bindings.lookup(
repoPointer: repo.pointer, repoPointer: repo.pointer,
oidPointer: oid.pointer, oidPointer: id.pointer,
); );
} }
@ -28,12 +26,12 @@ class Tag {
/// Pointer to memory address for allocated tag object. /// Pointer to memory address for allocated tag object.
Pointer<git_tag> get pointer => _tagPointer; Pointer<git_tag> get pointer => _tagPointer;
/// Creates a new tag in the repository from provided Oid object. /// Creates a new tag in the repository for provided [target] object.
/// ///
/// A new reference will also be created pointing to this tag object. If force is true /// A new reference will also be created pointing to this tag object. If [force] is true
/// and a reference already exists with the given name, it'll be replaced. /// and a reference already exists with the given name, it'll be replaced.
/// ///
/// The message will not be cleaned up. /// The [message] will not be cleaned up.
/// ///
/// The tag name will be checked for validity. You must avoid the characters /// The tag name will be checked for validity. You must avoid the characters
/// '~', '^', ':', '\', '?', '[', and '*', and the sequences ".." and "@{" which have /// '~', '^', ':', '\', '?', '[', and '*', and the sequences ".." and "@{" which have
@ -43,16 +41,15 @@ class Tag {
static Oid create({ static Oid create({
required Repository repo, required Repository repo,
required String tagName, required String tagName,
required String target, required Oid target,
required GitObject targetType, required GitObject targetType,
required Signature tagger, required Signature tagger,
required String message, required String message,
bool force = false, bool force = false,
}) { }) {
final targetOid = Oid.fromSHA(repo: repo, sha: target);
final object = object_bindings.lookup( final object = object_bindings.lookup(
repoPointer: repo.pointer, repoPointer: repo.pointer,
oidPointer: targetOid.pointer, oidPointer: target.pointer,
type: targetType.value, type: targetType.value,
); );
final result = bindings.create( final result = bindings.create(
@ -68,6 +65,15 @@ class Tag {
return Oid(result); return Oid(result);
} }
/// Deletes an existing tag reference with provided [name] in a [repo]sitory.
///
/// The tag [name] will be checked for validity.
///
/// Throws a [LibGit2Error] if error occured.
static void delete({required Repository repo, required String name}) {
bindings.delete(repoPointer: repo.pointer, tagName: name);
}
/// Returns a list with all the tags in the repository. /// Returns a list with all the tags in the repository.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
@ -123,16 +129,6 @@ class Tag {
} }
} }
/// Deletes an existing tag reference.
///
/// The tag name will be checked for validity.
///
/// Throws a [LibGit2Error] if error occured.
void delete() {
final owner = bindings.owner(_tagPointer);
bindings.delete(repoPointer: owner, tagName: name);
}
/// Releases memory allocated for tag object. /// Releases memory allocated for tag object.
void free() => bindings.free(_tagPointer); void free() => bindings.free(_tagPointer);
} }

View file

@ -8,18 +8,16 @@ class Tree {
/// Initializes a new instance of [Tree] class from provided pointer to /// Initializes a new instance of [Tree] class from provided pointer to
/// tree object in memory. /// tree object in memory.
/// ///
/// Should be freed with `free()` to release allocated memory. /// Should be freed to release allocated memory.
Tree(this._treePointer); Tree(this._treePointer);
/// Initializes a new instance of [Tree] class from provided /// Lookups a tree object for provided [id] in a [repo]sitory.
/// [Repository] object and [sha] hex string.
/// ///
/// Should be freed with `free()` to release allocated memory. /// Should be freed to release allocated memory.
Tree.lookup({required Repository repo, required String sha}) { Tree.lookup({required Repository repo, required Oid id}) {
final oid = Oid.fromSHA(repo: repo, sha: sha);
_treePointer = bindings.lookup( _treePointer = bindings.lookup(
repoPointer: repo.pointer, repoPointer: repo.pointer,
oidPointer: oid.pointer, oidPointer: id.pointer,
); );
} }

View file

@ -5,9 +5,9 @@ import 'bindings/treebuilder.dart' as bindings;
class TreeBuilder { class TreeBuilder {
/// Initializes a new instance of [TreeBuilder] class from provided /// Initializes a new instance of [TreeBuilder] class from provided
/// [Repository] and optional [Tree] objects. /// [repo]sitory and optional [tree] objects.
/// ///
/// Should be freed with `free()` to release allocated memory. /// Should be freed to release allocated memory.
/// ///
/// Throws a [LibGit2Error] if error occured. /// Throws a [LibGit2Error] if error occured.
TreeBuilder({required Repository repo, Tree? tree}) { TreeBuilder({required Repository repo, Tree? tree}) {
@ -79,6 +79,6 @@ class TreeBuilder {
); );
} }
/// Releases memory allocated for tree builder object. /// Releases memory allocated for tree builder object and all the entries.
void free() => bindings.free(_treeBuilderPointer); void free() => bindings.free(_treeBuilderPointer);
} }

View file

@ -10,8 +10,8 @@ void main() {
late Signature sig2; late Signature sig2;
var hunks = <Map<String, dynamic>>[]; var hunks = <Map<String, dynamic>>[];
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/blamerepo/')); tmpDir = setupRepo(Directory('test/assets/blamerepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
sig1 = Signature.create( sig1 = Signature.create(
name: 'Aleksey Kulikov', name: 'Aleksey Kulikov',
@ -48,11 +48,11 @@ void main() {
]; ];
}); });
tearDown(() async { tearDown(() {
sig1.free(); sig1.free();
sig2.free(); sig2.free();
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Blame', () { group('Blame', () {

View file

@ -11,16 +11,16 @@ void main() {
const blobContent = 'Feature edit\n'; const blobContent = 'Feature edit\n';
const newBlobContent = 'New blob\n'; const newBlobContent = 'New blob\n';
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
blob = Blob.lookup(repo: repo, sha: blobSHA); blob = repo.lookupBlob(repo[blobSHA]);
}); });
tearDown(() async { tearDown(() {
blob.free(); blob.free();
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Blob', () { group('Blob', () {
@ -36,8 +36,8 @@ void main() {
}); });
test('successfully creates new blob', () { test('successfully creates new blob', () {
final oid = Blob.create(repo: repo, content: newBlobContent); final oid = repo.createBlob(newBlobContent);
final newBlob = Blob.lookup(repo: repo, sha: oid.sha); final newBlob = repo.lookupBlob(oid);
expect(newBlob.id.sha, '18fdaeef018e57a92bcad2d4a35b577f34089af6'); expect(newBlob.id.sha, '18fdaeef018e57a92bcad2d4a35b577f34089af6');
expect(newBlob.isBinary, false); expect(newBlob.isBinary, false);
@ -49,11 +49,8 @@ void main() {
test('successfully creates new blob from file at provided relative path', test('successfully creates new blob from file at provided relative path',
() { () {
final oid = Blob.createFromWorkdir( final oid = repo.createBlobFromWorkdir('feature_file');
repo: repo, final newBlob = repo.lookupBlob(oid);
relativePath: 'feature_file',
);
final newBlob = Blob.lookup(repo: repo, sha: oid.sha);
expect(newBlob.id.sha, blobSHA); expect(newBlob.id.sha, blobSHA);
expect(newBlob.isBinary, false); expect(newBlob.isBinary, false);
@ -65,10 +62,7 @@ void main() {
test('throws when creating new blob from invalid path', () { test('throws when creating new blob from invalid path', () {
expect( expect(
() => Blob.createFromWorkdir( () => repo.createBlobFromWorkdir('invalid/path.txt'),
repo: repo,
relativePath: 'invalid/path.txt',
),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
}); });
@ -79,10 +73,7 @@ void main() {
final outsideFile = final outsideFile =
File('${Directory.current.absolute.path}/test/blob_test.dart'); File('${Directory.current.absolute.path}/test/blob_test.dart');
expect( expect(
() => Blob.createFromWorkdir( () => repo.createBlobFromWorkdir(outsideFile.path),
repo: repo,
relativePath: outsideFile.path,
),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
}); });
@ -90,8 +81,8 @@ void main() {
test('successfully creates new blob from file at provided path', () { test('successfully creates new blob from file at provided path', () {
final outsideFile = final outsideFile =
File('${Directory.current.absolute.path}/test/blob_test.dart'); File('${Directory.current.absolute.path}/test/blob_test.dart');
final oid = Blob.createFromDisk(repo: repo, path: outsideFile.path); final oid = repo.createBlobFromDisk(outsideFile.path);
final newBlob = Blob.lookup(repo: repo, sha: oid.sha); final newBlob = repo.lookupBlob(oid);
expect(newBlob, isA<Blob>()); expect(newBlob, isA<Blob>());
expect(newBlob.isBinary, false); expect(newBlob.isBinary, false);
@ -101,8 +92,6 @@ void main() {
group('diff', () { group('diff', () {
const path = 'feature_file'; const path = 'feature_file';
const oldBlobSha = 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391';
const newBlobSha = '9c78c21d6680a7ffebc76f7ac68cacc11d8f48bc';
const blobPatch = """ const blobPatch = """
diff --git a/feature_file b/feature_file diff --git a/feature_file b/feature_file
index e69de29..9c78c21 100644 index e69de29..9c78c21 100644
@ -120,8 +109,12 @@ index e69de29..0000000
+++ /dev/null +++ /dev/null
"""; """;
test('successfully creates from blobs', () { test('successfully creates from blobs', () {
final a = repo[oldBlobSha] as Blob; final a = repo.lookupBlob(
final b = repo[newBlobSha] as Blob; repo['e69de29bb2d1d6434b8b29ae775ad8c2e48c5391'],
);
final b = repo.lookupBlob(
repo['9c78c21d6680a7ffebc76f7ac68cacc11d8f48bc'],
);
final patch = repo.diffBlobs( final patch = repo.diffBlobs(
a: a, a: a,
b: b, b: b,
@ -135,7 +128,9 @@ index e69de29..0000000
}); });
test('successfully creates from one blob (delete)', () { test('successfully creates from one blob (delete)', () {
final a = repo[oldBlobSha] as Blob; final a = repo.lookupBlob(
repo['e69de29bb2d1d6434b8b29ae775ad8c2e48c5391'],
);
final patch = a.diff( final patch = a.diff(
newBlob: null, newBlob: null,
oldAsPath: path, oldAsPath: path,
@ -148,7 +143,9 @@ index e69de29..0000000
}); });
test('successfully creates from blob and buffer', () { test('successfully creates from blob and buffer', () {
final a = repo[oldBlobSha] as Blob; final a = repo.lookupBlob(
repo['e69de29bb2d1d6434b8b29ae775ad8c2e48c5391'],
);
final patch = Patch.createFrom( final patch = Patch.createFrom(
a: a, a: a,
b: 'Feature edit\n', b: 'Feature edit\n',
@ -162,7 +159,9 @@ index e69de29..0000000
}); });
test('successfully creates from blob and buffer (delete)', () { test('successfully creates from blob and buffer (delete)', () {
final a = repo[oldBlobSha] as Blob; final a = repo.lookupBlob(
repo['e69de29bb2d1d6434b8b29ae775ad8c2e48c5391'],
);
final patch = Patch.createFrom( final patch = Patch.createFrom(
a: a, a: a,
b: null, b: null,

View file

@ -6,48 +6,59 @@ import 'helpers/util.dart';
void main() { void main() {
late Repository repo; late Repository repo;
late Directory tmpDir; late Directory tmpDir;
const lastCommit = '821ed6e80627b8769d170a293862f9fc60825226'; late Oid lastCommit;
const featureCommit = '5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'; late Oid featureCommit;
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
lastCommit = repo['821ed6e80627b8769d170a293862f9fc60825226'];
featureCommit = repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'];
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Branch', () { group('Branch', () {
test('returns a list of all branches', () { test('returns a list of all branches', () {
final branches = Branches(repo); const branchesExpected = ['feature', 'master'];
expect(branches.list(), ['feature', 'master']); final branches = repo.branches;
for (var i = 0; i < branches.length; i++) {
expect(branches[i].name, branchesExpected[i]);
branches[i].free();
}
}); });
test('returns a list of local branches', () { test('returns a list of local branches', () {
final branches = repo.branches.local; const branchesExpected = ['feature', 'master'];
expect(branches, ['feature', 'master']); final branches = repo.branchesLocal;
for (var i = 0; i < branches.length; i++) {
expect(branches[i].name, branchesExpected[i]);
branches[i].free();
}
}); });
test('returns a list of remote branches for provided type', () { test('returns a list of remote branches', () {
final branches = repo.branches.remote; expect(repo.branchesRemote, []);
expect(branches, []);
}); });
test('returns a branch with provided name', () { test('returns a branch with provided name', () {
final branch = repo.branches['master']; final branch = repo.lookupBranch('master');
expect(branch.target.sha, lastCommit); expect(branch.target.sha, lastCommit.sha);
branch.free(); branch.free();
}); });
test('throws when provided name not found', () { test('throws when provided name not found', () {
expect(() => repo.branches['invalid'], throwsA(isA<LibGit2Error>())); expect(() => repo.lookupBranch('invalid'), throwsA(isA<LibGit2Error>()));
}); });
test('checks if branch is current head', () { test('checks if branch is current head', () {
final masterBranch = repo.branches['master']; final masterBranch = repo.lookupBranch('master');
final featureBranch = repo.branches['feature']; final featureBranch = repo.lookupBranch('feature');
expect(masterBranch.isHead, true); expect(masterBranch.isHead, true);
expect(featureBranch.isHead, false); expect(featureBranch.isHead, false);
@ -57,30 +68,33 @@ void main() {
}); });
test('returns name', () { test('returns name', () {
final branch = repo.branches['master']; final branch = repo.lookupBranch('master');
expect(branch.name, 'master'); expect(branch.name, 'master');
branch.free(); branch.free();
}); });
group('create()', () { group('create()', () {
test('successfully creates', () { test('successfully creates', () {
final commit = repo[lastCommit] as Commit; final commit = repo.lookupCommit(lastCommit);
final ref = repo.branches.create(name: 'testing', target: commit); final branch = repo.createBranch(name: 'testing', target: commit);
final branch = repo.branches['testing']; final branches = repo.branches;
expect(repo.branches.list().length, 3);
expect(branch.target.sha, lastCommit);
expect(repo.branches.length, 3);
expect(branch.target, lastCommit);
for (final branch in branches) {
branch.free();
}
branch.free(); branch.free();
ref.free();
commit.free(); commit.free();
}); });
test('throws when name already exists', () { test('throws when name already exists', () {
final commit = repo[lastCommit] as Commit; final commit = repo.lookupCommit(lastCommit);
expect( expect(
() => repo.branches.create(name: 'feature', target: commit), () => repo.createBranch(name: 'feature', target: commit),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
@ -88,30 +102,39 @@ void main() {
}); });
test('successfully creates with force flag when name already exists', () { test('successfully creates with force flag when name already exists', () {
final commit = repo[lastCommit] as Commit; final commit = repo.lookupCommit(lastCommit);
final ref = final branch = repo.createBranch(
repo.branches.create(name: 'feature', target: commit, force: true); name: 'feature',
final branch = repo.branches['feature']; target: commit,
expect(repo.branches.local.length, 2); force: true,
expect(branch.target.sha, lastCommit); );
final localBranches = repo.branchesLocal;
expect(localBranches.length, 2);
expect(branch.target, lastCommit);
for (final branch in localBranches) {
branch.free();
}
branch.free(); branch.free();
ref.free();
commit.free(); commit.free();
}); });
}); });
group('delete()', () { group('delete()', () {
test('successfully deletes', () { test('successfully deletes', () {
repo.branches['feature'].delete(); repo.deleteBranch('feature');
expect(repo.branches.local.length, 1);
expect(() => repo.branches['feature'], throwsA(isA<LibGit2Error>())); expect(
() => repo.lookupBranch('feature'),
throwsA(isA<LibGit2Error>()),
);
}); });
test('throws when trying to delete current HEAD', () { test('throws when trying to delete current HEAD', () {
expect( expect(
() => repo.branches['master'].delete(), () => repo.deleteBranch('master'),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
}); });
@ -119,43 +142,48 @@ void main() {
group('rename()', () { group('rename()', () {
test('successfully renames', () { test('successfully renames', () {
final renamed = repo.branches['feature'].rename(newName: 'renamed'); repo.renameBranch(oldName: 'feature', newName: 'renamed');
final branch = repo.branches['renamed']; final branch = repo.lookupBranch('renamed');
final branches = repo.branches;
expect(renamed.target.sha, featureCommit); expect(branches.length, 2);
expect(branch.target.sha, featureCommit); expect(
() => repo.lookupBranch('feature'),
throwsA(isA<LibGit2Error>()),
);
expect(branch.target, featureCommit);
for (final branch in branches) {
branch.free();
}
branch.free(); branch.free();
renamed.free();
}); });
test('throws when name already exists', () { test('throws when name already exists', () {
final branch = repo.branches['feature'];
expect( expect(
() => branch.rename(newName: 'master'), () => repo.renameBranch(oldName: 'feature', newName: 'master'),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
branch.free();
}); });
test('successfully renames with force flag when name already exists', () { test('successfully renames with force flag when name already exists', () {
final renamed = repo.branches['master'].rename( repo.renameBranch(
oldName: 'master',
newName: 'feature', newName: 'feature',
force: true, force: true,
); );
final branch = repo.lookupBranch('feature');
expect(renamed.target.sha, lastCommit); expect(branch.target, lastCommit);
renamed.free(); branch.free();
}); });
test('throws when name is invalid', () { test('throws when name is invalid', () {
final branch = repo.branches['feature'];
expect( expect(
() => branch.rename(newName: 'inv@{id'), () => repo.renameBranch(oldName: 'feature', newName: 'inv@{id'),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
branch.free();
}); });
}); });
}); });

View file

@ -8,14 +8,14 @@ void main() {
late Repository repo; late Repository repo;
late Directory tmpDir; late Directory tmpDir;
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Checkout', () { group('Checkout', () {
@ -39,8 +39,9 @@ void main() {
}); });
test('successfully checkouts tree', () { test('successfully checkouts tree', () {
final masterHead = final masterHead = repo.lookupCommit(
repo['821ed6e80627b8769d170a293862f9fc60825226'] as Commit; repo['821ed6e80627b8769d170a293862f9fc60825226'],
);
final masterTree = masterHead.tree; final masterTree = masterHead.tree;
expect( expect(
masterTree.entries.any((e) => e.name == 'another_feature_file'), masterTree.entries.any((e) => e.name == 'another_feature_file'),
@ -48,8 +49,9 @@ void main() {
); );
repo.checkout(refName: 'refs/heads/feature'); repo.checkout(refName: 'refs/heads/feature');
final featureHead = final featureHead = repo.lookupCommit(
repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'] as Commit; repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'],
);
final featureTree = featureHead.tree; final featureTree = featureHead.tree;
final repoHead = repo.head; final repoHead = repo.head;
expect(repoHead.target.sha, featureHead.id.sha); expect(repoHead.target.sha, featureHead.id.sha);

View file

@ -6,15 +6,14 @@ import 'helpers/util.dart';
void main() { void main() {
late Repository repo; late Repository repo;
late Directory tmpDir; late Directory tmpDir;
const mergeCommit = '78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e8';
const message = "Commit message.\n\nSome description.\n";
const tree = '7796359a96eb722939c24bafdb1afe9f07f2f628';
late Signature author; late Signature author;
late Signature commiter; late Signature commiter;
late Tree tree;
late Oid mergeCommit;
const message = "Commit message.\n\nSome description.\n";
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
author = Signature.create( author = Signature.create(
name: 'Author Name', name: 'Author Name',
@ -26,31 +25,35 @@ void main() {
email: 'commiter@email.com', email: 'commiter@email.com',
time: 124, time: 124,
); );
mergeCommit = repo['78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e8'];
tree = Tree.lookup(
repo: repo,
id: repo['7796359a96eb722939c24bafdb1afe9f07f2f628'],
);
}); });
tearDown(() async { tearDown(() {
author.free(); author.free();
commiter.free(); commiter.free();
tree.free();
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Commit', () { group('Commit', () {
test('successfully returns when 40 char sha hex is provided', () { test('successfully returns when 40 char sha hex is provided', () {
final commit = repo[mergeCommit] as Commit; final commit = repo.lookupCommit(mergeCommit);
expect(commit, isA<Commit>());
commit.free();
});
test('successfully returns when sha hex is short', () {
final commit = repo[mergeCommit.substring(0, 5)] as Commit;
expect(commit, isA<Commit>()); expect(commit, isA<Commit>());
commit.free(); commit.free();
}); });
test('successfully reverts commit', () { test('successfully reverts commit', () {
final to = repo['78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e8'] as Commit; final to = repo.lookupCommit(
final from = repo['821ed6e80627b8769d170a293862f9fc60825226'] as Commit; repo['78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e8'],
);
final from = repo.lookupCommit(
repo['821ed6e80627b8769d170a293862f9fc60825226'],
);
final index = repo.index; final index = repo.index;
expect(index.find('dir/dir_file.txt'), true); expect(index.find('dir/dir_file.txt'), true);
@ -64,16 +67,16 @@ void main() {
}); });
test('successfully creates commit', () { test('successfully creates commit', () {
final oid = Commit.create( final parent = repo.lookupCommit(mergeCommit);
repo: repo, final oid = repo.createCommit(
message: message, message: message,
author: author, author: author,
commiter: commiter, commiter: commiter,
treeSHA: tree, tree: tree,
parents: [mergeCommit], parents: [parent],
); );
final commit = repo[oid.sha] as Commit; final commit = repo.lookupCommit(oid);
expect(commit.id.sha, oid.sha); expect(commit.id.sha, oid.sha);
expect(commit.message, message); expect(commit.message, message);
@ -81,11 +84,12 @@ void main() {
expect(commit.author, author); expect(commit.author, author);
expect(commit.committer, commiter); expect(commit.committer, commiter);
expect(commit.time, 124); expect(commit.time, 124);
expect(commit.tree.id.sha, tree); expect(commit.tree.id, tree.id);
expect(commit.parents.length, 1); expect(commit.parents.length, 1);
expect(commit.parents[0].sha, mergeCommit); expect(commit.parents[0], mergeCommit);
commit.free(); commit.free();
parent.free();
}); });
test('successfully creates commit without parents', () { test('successfully creates commit without parents', () {
@ -93,11 +97,11 @@ void main() {
message: message, message: message,
author: author, author: author,
commiter: commiter, commiter: commiter,
treeSHA: tree, tree: tree,
parents: [], parents: [],
); );
final commit = repo[oid.sha] as Commit; final commit = repo.lookupCommit(oid);
expect(commit.id.sha, oid.sha); expect(commit.id.sha, oid.sha);
expect(commit.message, message); expect(commit.message, message);
@ -105,23 +109,28 @@ void main() {
expect(commit.author, author); expect(commit.author, author);
expect(commit.committer, commiter); expect(commit.committer, commiter);
expect(commit.time, 124); expect(commit.time, 124);
expect(commit.tree.id.sha, tree); expect(commit.tree.id, tree.id);
expect(commit.parents.length, 0); expect(commit.parents.length, 0);
commit.free(); commit.free();
}); });
test('successfully creates commit with 2 parents', () { test('successfully creates commit with 2 parents', () {
final parent1 = repo.lookupCommit(mergeCommit);
final parent2 = repo.lookupCommit(
repo['fc38877b2552ab554752d9a77e1f48f738cca79b'],
);
final oid = Commit.create( final oid = Commit.create(
repo: repo, repo: repo,
message: message, message: message,
author: author, author: author,
commiter: commiter, commiter: commiter,
treeSHA: tree, tree: tree,
parents: [mergeCommit, 'fc38877b2552ab554752d9a77e1f48f738cca79b'], parents: [parent1, parent2],
); );
final commit = repo[oid.sha] as Commit; final commit = repo.lookupCommit(oid);
expect(commit.id.sha, oid.sha); expect(commit.id.sha, oid.sha);
expect(commit.message, message); expect(commit.message, message);
@ -129,36 +138,13 @@ void main() {
expect(commit.author, author); expect(commit.author, author);
expect(commit.committer, commiter); expect(commit.committer, commiter);
expect(commit.time, 124); expect(commit.time, 124);
expect(commit.tree.id.sha, tree); expect(commit.tree.id, tree.id);
expect(commit.parents.length, 2); expect(commit.parents.length, 2);
expect(commit.parents[0].sha, mergeCommit); expect(commit.parents[0], mergeCommit);
expect(commit.parents[1].sha, 'fc38877b2552ab554752d9a77e1f48f738cca79b'); expect(commit.parents[1], parent2.id);
commit.free();
});
test('successfully creates commit with short sha of tree', () {
final oid = Commit.create(
repo: repo,
message: message,
author: author,
commiter: commiter,
treeSHA: tree.substring(0, 5),
parents: [mergeCommit],
);
final commit = repo[oid.sha] as Commit;
expect(commit.id.sha, oid.sha);
expect(commit.message, message);
expect(commit.messageEncoding, 'utf-8');
expect(commit.author, author);
expect(commit.committer, commiter);
expect(commit.time, 124);
expect(commit.tree.id.sha, tree);
expect(commit.parents.length, 1);
expect(commit.parents[0].sha, mergeCommit);
parent1.free();
parent2.free();
commit.free(); commit.free();
}); });
}); });

View file

@ -7,14 +7,14 @@ void main() {
late Repository repo; late Repository repo;
late Directory tmpDir; late Directory tmpDir;
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Describe', () { group('Describe', () {
@ -23,25 +23,22 @@ void main() {
}); });
test('successfully describes commit', () { test('successfully describes commit', () {
final tag = Tag.lookup(repo: repo, sha: 'f0fdbf5'); repo.deleteTag('v0.2');
tag.delete();
expect( expect(
repo.describe(describeStrategy: GitDescribeStrategy.tags), repo.describe(describeStrategy: GitDescribeStrategy.tags),
'v0.1-1-g821ed6e', 'v0.1-1-g821ed6e',
); );
tag.free();
}); });
test('throws when trying to describe and no reference found', () { test('throws when trying to describe and no reference found', () {
final commit = repo['f17d0d48'] as Commit; final commit = repo.lookupCommit(repo['f17d0d48']);
expect(() => repo.describe(commit: commit), throwsA(isA<LibGit2Error>())); expect(() => repo.describe(commit: commit), throwsA(isA<LibGit2Error>()));
commit.free(); commit.free();
}); });
test('returns oid when fallback argument is provided', () { test('returns oid when fallback argument is provided', () {
final commit = repo['f17d0d48'] as Commit; final commit = repo.lookupCommit(repo['f17d0d48']);
expect( expect(
repo.describe(commit: commit, showCommitOidAsFallback: true), repo.describe(commit: commit, showCommitOidAsFallback: true),
'f17d0d4', 'f17d0d4',
@ -50,7 +47,7 @@ void main() {
}); });
test('successfully describes with provided strategy', () { test('successfully describes with provided strategy', () {
final commit = repo['5aecfa0'] as Commit; final commit = repo.lookupCommit(repo['5aecfa0']);
expect( expect(
repo.describe( repo.describe(
commit: commit, commit: commit,
@ -63,10 +60,10 @@ void main() {
test('successfully describes with provided pattern', () { test('successfully describes with provided pattern', () {
final signature = repo.defaultSignature; final signature = repo.defaultSignature;
final commit = repo['fc38877'] as Commit; final commit = repo.lookupCommit(repo['fc38877']);
repo.createTag( repo.createTag(
tagName: 'test/tag1', tagName: 'test/tag1',
target: 'f17d0d48', target: repo['f17d0d48'],
targetType: GitObject.commit, targetType: GitObject.commit,
tagger: signature, tagger: signature,
message: '', message: '',
@ -82,10 +79,9 @@ void main() {
}); });
test('successfully describes and follows first parent only', () { test('successfully describes and follows first parent only', () {
final tag = Tag.lookup(repo: repo, sha: 'f0fdbf5'); final commit = repo.lookupCommit(repo['821ed6e']);
tag.delete(); repo.deleteTag('v0.2');
final commit = repo['821ed6e'] as Commit;
expect( expect(
repo.describe( repo.describe(
commit: commit, commit: commit,
@ -95,15 +91,13 @@ void main() {
'v0.1-1-g821ed6e', 'v0.1-1-g821ed6e',
); );
tag.free();
commit.free(); commit.free();
}); });
test('successfully describes with abbreviated size provided', () { test('successfully describes with provided abbreviated size', () {
final tag = Tag.lookup(repo: repo, sha: 'f0fdbf5'); final commit = repo.lookupCommit(repo['821ed6e']);
tag.delete(); repo.deleteTag('v0.2');
final commit = repo['821ed6e'] as Commit;
expect( expect(
repo.describe( repo.describe(
commit: commit, commit: commit,
@ -122,7 +116,6 @@ void main() {
'v0.1', 'v0.1',
); );
tag.free();
commit.free(); commit.free();
}); });

View file

@ -74,14 +74,14 @@ index e69de29..c217c63 100644
8 files changed, 4 insertions(+), 2 deletions(-) 8 files changed, 4 insertions(+), 2 deletions(-)
"""; """;
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/dirtyrepo/')); tmpDir = setupRepo(Directory('test/assets/dirtyrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Diff', () { group('Diff', () {
@ -100,7 +100,9 @@ index e69de29..c217c63 100644
test('successfully returns diff between index and tree', () { test('successfully returns diff between index and tree', () {
final index = repo.index; final index = repo.index;
final tree = (repo[repo.head.target.sha] as Commit).tree; final head = repo.head;
final commit = repo.lookupCommit(head.target);
final tree = commit.tree;
final diff = index.diffToTree(tree: tree); final diff = index.diffToTree(tree: tree);
expect(diff.length, 8); expect(diff.length, 8);
@ -108,13 +110,17 @@ index e69de29..c217c63 100644
expect(diff.deltas[i].newFile.path, indexToTree[i]); expect(diff.deltas[i].newFile.path, indexToTree[i]);
} }
commit.free();
head.free();
tree.free(); tree.free();
diff.free(); diff.free();
index.free(); index.free();
}); });
test('successfully returns diff between tree and workdir', () { test('successfully returns diff between tree and workdir', () {
final tree = (repo[repo.head.target.sha] as Commit).tree; final head = repo.head;
final commit = repo.lookupCommit(head.target);
final tree = commit.tree;
final diff = repo.diff(a: tree); final diff = repo.diff(a: tree);
expect(diff.length, 9); expect(diff.length, 9);
@ -122,13 +128,17 @@ index e69de29..c217c63 100644
expect(diff.deltas[i].newFile.path, treeToWorkdir[i]); expect(diff.deltas[i].newFile.path, treeToWorkdir[i]);
} }
commit.free();
head.free();
tree.free(); tree.free();
diff.free(); diff.free();
}); });
test('successfully returns diff between tree and index', () { test('successfully returns diff between tree and index', () {
final index = repo.index; final index = repo.index;
final tree = (repo[repo.head.target.sha] as Commit).tree; final head = repo.head;
final commit = repo.lookupCommit(head.target);
final tree = commit.tree;
final diff = repo.diff(a: tree, cached: true); final diff = repo.diff(a: tree, cached: true);
expect(diff.length, 8); expect(diff.length, 8);
@ -136,14 +146,20 @@ index e69de29..c217c63 100644
expect(diff.deltas[i].newFile.path, indexToTree[i]); expect(diff.deltas[i].newFile.path, indexToTree[i]);
} }
commit.free();
head.free();
tree.free(); tree.free();
diff.free(); diff.free();
index.free(); index.free();
}); });
test('successfully returns diff between tree and tree', () { test('successfully returns diff between tree and tree', () {
final tree1 = (repo[repo.head.target.sha] as Commit).tree; final head = repo.head;
final tree2 = repo['b85d53c9236e89aff2b62558adaa885fd1d6ff1c'] as Tree; final commit = repo.lookupCommit(head.target);
final tree1 = commit.tree;
final tree2 = repo.lookupTree(
repo['b85d53c9236e89aff2b62558adaa885fd1d6ff1c'],
);
final diff = repo.diff(a: tree1, b: tree2); final diff = repo.diff(a: tree1, b: tree2);
expect(diff.length, 10); expect(diff.length, 10);
@ -151,14 +167,20 @@ index e69de29..c217c63 100644
expect(diff.deltas[i].newFile.path, treeToTree[i]); expect(diff.deltas[i].newFile.path, treeToTree[i]);
} }
commit.free();
head.free();
tree1.free(); tree1.free();
tree2.free(); tree2.free();
diff.free(); diff.free();
}); });
test('successfully merges diffs', () { test('successfully merges diffs', () {
final tree1 = (repo[repo.head.target.sha] as Commit).tree; final head = repo.head;
final tree2 = repo['b85d53c9236e89aff2b62558adaa885fd1d6ff1c'] as Tree; final commit = repo.lookupCommit(head.target);
final tree1 = commit.tree;
final tree2 = repo.lookupTree(
repo['b85d53c9236e89aff2b62558adaa885fd1d6ff1c'],
);
final diff1 = tree1.diffToTree(tree: tree2); final diff1 = tree1.diffToTree(tree: tree2);
final diff2 = tree1.diffToWorkdir(); final diff2 = tree1.diffToWorkdir();
@ -168,6 +190,8 @@ index e69de29..c217c63 100644
diff1.merge(diff2); diff1.merge(diff2);
expect(diff1.length, 11); expect(diff1.length, 11);
commit.free();
head.free();
tree1.free(); tree1.free();
tree2.free(); tree2.free();
diff1.free(); diff1.free();
@ -219,8 +243,10 @@ index e69de29..c217c63 100644
test('successfully finds similar entries', () { test('successfully finds similar entries', () {
final index = repo.index; final index = repo.index;
final oldTree = (repo[repo.head.target.sha] as Commit).tree; final head = repo.head;
final newTree = repo[index.writeTree().sha] as Tree; final commit = repo.lookupCommit(head.target);
final oldTree = commit.tree;
final newTree = repo.lookupTree(index.writeTree());
final diff = oldTree.diffToTree(tree: newTree); final diff = oldTree.diffToTree(tree: newTree);
expect( expect(
@ -234,6 +260,8 @@ index e69de29..c217c63 100644
GitDelta.renamed, GitDelta.renamed,
); );
commit.free();
head.free();
diff.free(); diff.free();
index.free(); index.free();
oldTree.free(); oldTree.free();

View file

@ -3,29 +3,31 @@ import 'package:path/path.dart' as p;
final tmpDir = Directory.systemTemp.createTempSync('testrepo'); final tmpDir = Directory.systemTemp.createTempSync('testrepo');
Future<Directory> setupRepo(Directory repoDir) async { Directory setupRepo(Directory repoDir) {
if (await tmpDir.exists()) { if (tmpDir.existsSync()) {
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
} }
await copyRepo(from: repoDir, to: await tmpDir.create()); tmpDir.createSync();
copyRepo(from: repoDir, to: tmpDir);
return tmpDir; return tmpDir;
} }
Future<void> copyRepo({required Directory from, required Directory to}) async { void copyRepo({required Directory from, required Directory to}) {
await for (final entity in from.list()) { for (final entity in from.listSync()) {
if (entity is Directory) { if (entity is Directory) {
Directory newDir; Directory newDir;
if (p.basename(entity.path) == '.gitdir') { if (p.basename(entity.path) == '.gitdir') {
newDir = Directory(p.join(to.absolute.path, '.git')); newDir = Directory(p.join(to.absolute.path, '.git'))..createSync();
} else { } else {
newDir = Directory(p.join(to.absolute.path, p.basename(entity.path))); newDir = Directory(p.join(to.absolute.path, p.basename(entity.path)))
..createSync();
} }
await copyRepo(from: entity.absolute, to: await newDir.create()); copyRepo(from: entity.absolute, to: newDir);
} else if (entity is File) { } else if (entity is File) {
if (p.basename(entity.path) == 'gitignore') { if (p.basename(entity.path) == 'gitignore') {
await entity.copy(p.join(to.path, '.gitignore')); entity.copySync(p.join(to.path, '.gitignore'));
} else { } else {
await entity.copy(p.join(to.path, p.basename(entity.path))); entity.copySync(p.join(to.path, p.basename(entity.path)));
} }
} }
} }

View file

@ -8,16 +8,16 @@ void main() {
late Index index; late Index index;
late Directory tmpDir; late Directory tmpDir;
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
index = repo.index; index = repo.index;
}); });
tearDown(() async { tearDown(() {
index.free(); index.free();
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Index', () { group('Index', () {
@ -156,11 +156,12 @@ void main() {
expect(index.find('feature_file'), false); expect(index.find('feature_file'), false);
}); });
group('read tree', () { test('successfully reads tree with provided SHA hex', () {
const treeSha = 'df2b8fc99e1c1d4dbc0a854d9f72157f1d6ea078'; final tree = repo.lookupTree(
test('successfully reads with provided SHA hex', () { repo['df2b8fc99e1c1d4dbc0a854d9f72157f1d6ea078'],
);
expect(index.length, 4); expect(index.length, 4);
index.readTree(treeSha); index.readTree(tree);
expect(index.length, 1); expect(index.length, 1);
@ -169,14 +170,6 @@ void main() {
expect(index.length, 4); expect(index.length, 4);
}); });
test('successfully reads with provided short SHA hex', () {
expect(index.length, 4);
index.readTree(treeSha.substring(0, 5));
expect(index.length, 1);
});
});
test('successfully writes tree', () { test('successfully writes tree', () {
final oid = index.writeTree(); final oid = index.writeTree();
expect(oid.sha, 'a8ae3dd59e6e1802c6f78e05e301bfd57c9f334f'); expect(oid.sha, 'a8ae3dd59e6e1802c6f78e05e301bfd57c9f334f');

View file

@ -126,14 +126,14 @@ Santa Claus <santa.claus@northpole.xx> <me@company.xx>
late Repository repo; late Repository repo;
late Directory tmpDir; late Directory tmpDir;
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/mailmaprepo/')); tmpDir = setupRepo(Directory('test/assets/mailmaprepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Mailmap', () { group('Mailmap', () {

View file

@ -9,21 +9,22 @@ void main() {
late Repository repo; late Repository repo;
late Directory tmpDir; late Directory tmpDir;
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/mergerepo/')); tmpDir = setupRepo(Directory('test/assets/mergerepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Merge', () { group('Merge', () {
group('analysis', () { group('analysis', () {
test('is up to date when no reference is provided', () { test('is up to date when no reference is provided', () {
final commit = final commit = repo.lookupCommit(
repo['c68ff54aabf660fcdd9a2838d401583fe31249e3'] as Commit; repo['c68ff54aabf660fcdd9a2838d401583fe31249e3'],
);
final result = repo.mergeAnalysis(theirHead: commit.id); final result = repo.mergeAnalysis(theirHead: commit.id);
expect(result[0], {GitMergeAnalysis.upToDate}); expect(result[0], {GitMergeAnalysis.upToDate});
@ -34,8 +35,9 @@ void main() {
}); });
test('is up to date for provided ref', () { test('is up to date for provided ref', () {
final commit = final commit = repo.lookupCommit(
repo['c68ff54aabf660fcdd9a2838d401583fe31249e3'] as Commit; repo['c68ff54aabf660fcdd9a2838d401583fe31249e3'],
);
final result = repo.mergeAnalysis( final result = repo.mergeAnalysis(
theirHead: commit.id, theirHead: commit.id,
@ -48,18 +50,20 @@ void main() {
}); });
test('is fast forward', () { test('is fast forward', () {
final theirHead = final theirHead = repo.lookupCommit(
repo['6cbc22e509d72758ab4c8d9f287ea846b90c448b'] as Commit; repo['6cbc22e509d72758ab4c8d9f287ea846b90c448b'],
final ffCommit = );
repo['f17d0d48eae3aa08cecf29128a35e310c97b3521'] as Commit; final ffCommit = repo.lookupCommit(
final ffBranch = repo.branches.create( repo['f17d0d48eae3aa08cecf29128a35e310c97b3521'],
);
final ffBranch = repo.createBranch(
name: 'ff-branch', name: 'ff-branch',
target: ffCommit, target: ffCommit,
); );
final result = repo.mergeAnalysis( final result = repo.mergeAnalysis(
theirHead: theirHead.id, theirHead: theirHead.id,
ourRef: ffBranch.name, ourRef: 'refs/heads/${ffBranch.name}',
); );
expect( expect(
result[0], result[0],
@ -73,8 +77,9 @@ void main() {
}); });
test('is not fast forward and there is no conflicts', () { test('is not fast forward and there is no conflicts', () {
final commit = final commit = repo.lookupCommit(
repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'] as Commit; repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'],
);
final result = repo.mergeAnalysis(theirHead: commit.id); final result = repo.mergeAnalysis(theirHead: commit.id);
expect(result[0], {GitMergeAnalysis.normal}); expect(result[0], {GitMergeAnalysis.normal});
@ -85,7 +90,7 @@ void main() {
}); });
test('writes conflicts to index', () { test('writes conflicts to index', () {
final conflictBranch = repo.branches['conflict-branch']; final conflictBranch = repo.lookupBranch('conflict-branch');
final index = repo.index; final index = repo.index;
final result = repo.mergeAnalysis(theirHead: conflictBranch.target); final result = repo.mergeAnalysis(theirHead: conflictBranch.target);
@ -123,7 +128,7 @@ void main() {
}); });
test('successfully removes conflicts', () { test('successfully removes conflicts', () {
final conflictBranch = repo.branches['conflict-branch']; final conflictBranch = repo.lookupBranch('conflict-branch');
final index = repo.index; final index = repo.index;
repo.merge(conflictBranch.target); repo.merge(conflictBranch.target);
@ -149,7 +154,7 @@ master conflict edit
conflict branch edit conflict branch edit
>>>>>>> conflict_file >>>>>>> conflict_file
"""; """;
final conflictBranch = repo.branches['conflict-branch']; final conflictBranch = repo.lookupBranch('conflict-branch');
final index = repo.index; final index = repo.index;
repo.merge(conflictBranch.target); repo.merge(conflictBranch.target);
@ -171,10 +176,12 @@ conflict branch edit
group('merge commits', () { group('merge commits', () {
test('successfully merges with default values', () { test('successfully merges with default values', () {
final theirCommit = final theirCommit = repo.lookupCommit(
repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'] as Commit; repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'],
final ourCommit = );
repo['14905459d775f3f56a39ebc2ff081163f7da3529'] as Commit; final ourCommit = repo.lookupCommit(
repo['14905459d775f3f56a39ebc2ff081163f7da3529'],
);
final mergeIndex = repo.mergeCommits( final mergeIndex = repo.mergeCommits(
ourCommit: ourCommit, ourCommit: ourCommit,
@ -197,10 +204,12 @@ conflict branch edit
}); });
test('successfully merges with provided favor', () { test('successfully merges with provided favor', () {
final theirCommit = final theirCommit = repo.lookupCommit(
repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'] as Commit; repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'],
final ourCommit = );
repo['14905459d775f3f56a39ebc2ff081163f7da3529'] as Commit; final ourCommit = repo.lookupCommit(
repo['14905459d775f3f56a39ebc2ff081163f7da3529'],
);
final mergeIndex = repo.mergeCommits( final mergeIndex = repo.mergeCommits(
ourCommit: ourCommit, ourCommit: ourCommit,
@ -215,10 +224,12 @@ conflict branch edit
}); });
test('successfully merges with provided merge and file flags', () { test('successfully merges with provided merge and file flags', () {
final theirCommit = final theirCommit = repo.lookupCommit(
repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'] as Commit; repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'],
final ourCommit = );
repo['14905459d775f3f56a39ebc2ff081163f7da3529'] as Commit; final ourCommit = repo.lookupCommit(
repo['14905459d775f3f56a39ebc2ff081163f7da3529'],
);
final mergeIndex = repo.mergeCommits( final mergeIndex = repo.mergeCommits(
ourCommit: ourCommit, ourCommit: ourCommit,
@ -243,13 +254,15 @@ conflict branch edit
group('merge trees', () { group('merge trees', () {
test('successfully merges with default values', () { test('successfully merges with default values', () {
final theirCommit = final theirCommit = repo.lookupCommit(
repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'] as Commit; repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'],
final ourCommit = );
repo['14905459d775f3f56a39ebc2ff081163f7da3529'] as Commit; final ourCommit = repo.lookupCommit(
final baseCommit = repo['14905459d775f3f56a39ebc2ff081163f7da3529'],
repo[repo.mergeBase(a: ourCommit.id.sha, b: theirCommit.id.sha).sha] );
as Commit; final baseCommit = repo.lookupCommit(
repo.mergeBase(a: ourCommit.id.sha, b: theirCommit.id.sha),
);
final theirTree = theirCommit.tree; final theirTree = theirCommit.tree;
final ourTree = ourCommit.tree; final ourTree = ourCommit.tree;
final ancestorTree = baseCommit.tree; final ancestorTree = baseCommit.tree;
@ -281,13 +294,15 @@ conflict branch edit
}); });
test('successfully merges with provided favor', () { test('successfully merges with provided favor', () {
final theirCommit = final theirCommit = repo.lookupCommit(
repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'] as Commit; repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'],
final ourCommit = );
repo['14905459d775f3f56a39ebc2ff081163f7da3529'] as Commit; final ourCommit = repo.lookupCommit(
final baseCommit = repo['14905459d775f3f56a39ebc2ff081163f7da3529'],
repo[repo.mergeBase(a: ourCommit.id.sha, b: theirCommit.id.sha).sha] );
as Commit; final baseCommit = repo.lookupCommit(
repo.mergeBase(a: ourCommit.id.sha, b: theirCommit.id.sha),
);
final theirTree = theirCommit.tree; final theirTree = theirCommit.tree;
final ourTree = ourCommit.tree; final ourTree = ourCommit.tree;
final ancestorTree = baseCommit.tree; final ancestorTree = baseCommit.tree;
@ -311,7 +326,9 @@ conflict branch edit
}); });
test('successfully cherry-picks commit', () { test('successfully cherry-picks commit', () {
final cherry = repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'] as Commit; final cherry = repo.lookupCommit(
repo['5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'],
);
repo.cherryPick(cherry); repo.cherryPick(cherry);
expect(repo.state, GitRepositoryState.cherrypick); expect(repo.state, GitRepositoryState.cherrypick);
expect(repo.message, 'add another feature file\n'); expect(repo.message, 'add another feature file\n');

View file

@ -19,14 +19,14 @@ void main() {
}, },
]; ];
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Note', () { group('Note', () {
@ -39,10 +39,7 @@ void main() {
expect(notes[i].id.sha, notesExpected[i]['id']); expect(notes[i].id.sha, notesExpected[i]['id']);
expect(notes[i].message, notesExpected[i]['message']); expect(notes[i].message, notesExpected[i]['message']);
expect(notes[i].annotatedId.sha, notesExpected[i]['annotatedId']); expect(notes[i].annotatedId.sha, notesExpected[i]['annotatedId']);
} notes[i].free();
for (var note in notes) {
note.free();
} }
}); });
@ -64,11 +61,11 @@ void main() {
final noteOid = repo.createNote( final noteOid = repo.createNote(
author: signature, author: signature,
committer: signature, committer: signature,
object: head.target, annotatedId: head.target,
note: 'New note for HEAD', note: 'New note for HEAD',
force: true, force: true,
); );
final noteBlob = repo[noteOid.sha] as Blob; final noteBlob = repo.lookupBlob(noteOid);
expect(noteOid.sha, 'ffd6e2ceaf91c00ea6d29e2e897f906da720529f'); expect(noteOid.sha, 'ffd6e2ceaf91c00ea6d29e2e897f906da720529f');
expect(noteBlob.content, 'New note for HEAD'); expect(noteBlob.content, 'New note for HEAD');
@ -81,15 +78,18 @@ void main() {
test('successfully removes note', () { test('successfully removes note', () {
final signature = repo.defaultSignature; final signature = repo.defaultSignature;
final head = repo.head; final head = repo.head;
final note = repo.lookupNote(annotatedId: head.target);
note.remove(author: signature, committer: signature); repo.deleteNote(
annotatedId: repo.head.target,
author: signature,
committer: signature,
);
expect( expect(
() => repo.lookupNote(annotatedId: head.target), () => repo.lookupNote(annotatedId: head.target),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
note.free();
head.free(); head.free();
signature.free(); signature.free();
}); });

View file

@ -10,14 +10,14 @@ void main() {
const blobSha = '9c78c21d6680a7ffebc76f7ac68cacc11d8f48bc'; const blobSha = '9c78c21d6680a7ffebc76f7ac68cacc11d8f48bc';
const blobContent = 'Feature edit\n'; const blobContent = 'Feature edit\n';
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Odb', () { group('Odb', () {

View file

@ -11,14 +11,14 @@ void main() {
const biggerSha = '78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e9'; const biggerSha = '78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e9';
const lesserSha = '78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e7'; const lesserSha = '78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e7';
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Oid', () { group('Oid', () {

View file

@ -7,14 +7,14 @@ void main() {
late Repository repo; late Repository repo;
late Directory tmpDir; late Directory tmpDir;
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('PackBuilder', () { group('PackBuilder', () {
@ -86,12 +86,14 @@ void main() {
test('successfully packs with provided packDelegate', () { test('successfully packs with provided packDelegate', () {
void packDelegate(PackBuilder packBuilder) { void packDelegate(PackBuilder packBuilder) {
for (var branchName in repo.branches.list()) { final branches = repo.branches;
final branch = repo.references['refs/heads/$branchName']; for (var branch in branches) {
for (var commit in repo.log(sha: branch.target.sha)) { final ref = repo.lookupReference('refs/heads/${branch.name}');
for (var commit in repo.log(sha: ref.target.sha)) {
packBuilder.addRecursively(commit.id); packBuilder.addRecursively(commit.id);
commit.free(); commit.free();
} }
ref.free();
branch.free(); branch.free();
} }
} }

View file

@ -8,9 +8,9 @@ void main() {
late Directory tmpDir; late Directory tmpDir;
const oldBlob = ''; const oldBlob = '';
const newBlob = 'Feature edit\n'; const newBlob = 'Feature edit\n';
late Oid oldBlobID;
late Oid newBlobID;
const path = 'feature_file'; const path = 'feature_file';
const oldBlobSha = 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391';
const newBlobSha = '9c78c21d6680a7ffebc76f7ac68cacc11d8f48bc';
const blobPatch = """ const blobPatch = """
diff --git a/feature_file b/feature_file diff --git a/feature_file b/feature_file
index e69de29..9c78c21 100644 index e69de29..9c78c21 100644
@ -38,14 +38,16 @@ index e69de29..0000000
+++ /dev/null +++ /dev/null
"""; """;
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
oldBlobID = repo['e69de29bb2d1d6434b8b29ae775ad8c2e48c5391'];
newBlobID = repo['9c78c21d6680a7ffebc76f7ac68cacc11d8f48bc'];
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Patch', () { group('Patch', () {
@ -90,8 +92,8 @@ index e69de29..0000000
}); });
test('successfully creates from blobs', () { test('successfully creates from blobs', () {
final a = repo[oldBlobSha] as Blob; final a = repo.lookupBlob(oldBlobID);
final b = repo[newBlobSha] as Blob; final b = repo.lookupBlob(newBlobID);
final patch = Patch.createFrom( final patch = Patch.createFrom(
a: a, a: a,
b: b, b: b,
@ -105,7 +107,7 @@ index e69de29..0000000
}); });
test('successfully creates from one blob (add)', () { test('successfully creates from one blob (add)', () {
final b = repo[newBlobSha] as Blob; final b = repo.lookupBlob(newBlobID);
final patch = Patch.createFrom( final patch = Patch.createFrom(
a: null, a: null,
b: b, b: b,
@ -119,7 +121,7 @@ index e69de29..0000000
}); });
test('successfully creates from one blob (delete)', () { test('successfully creates from one blob (delete)', () {
final a = repo[oldBlobSha] as Blob; final a = repo.lookupBlob(oldBlobID);
final patch = Patch.createFrom( final patch = Patch.createFrom(
a: a, a: a,
b: null, b: null,
@ -133,7 +135,7 @@ index e69de29..0000000
}); });
test('successfully creates from blob and buffer', () { test('successfully creates from blob and buffer', () {
final a = repo[oldBlobSha] as Blob; final a = repo.lookupBlob(oldBlobID);
final patch = Patch.createFrom( final patch = Patch.createFrom(
a: a, a: a,
b: newBlob, b: newBlob,
@ -147,7 +149,9 @@ index e69de29..0000000
}); });
test('throws when argument is not Blob or String', () { test('throws when argument is not Blob or String', () {
final commit = repo['fc38877b2552ab554752d9a77e1f48f738cca79b'] as Commit; final commit = repo.lookupCommit(
repo['fc38877b2552ab554752d9a77e1f48f738cca79b'],
);
expect( expect(
() => Patch.createFrom( () => Patch.createFrom(
a: commit, a: commit,

View file

@ -12,21 +12,21 @@ void main() {
'14905459d775f3f56a39ebc2ff081163f7da3529', '14905459d775f3f56a39ebc2ff081163f7da3529',
]; ];
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/mergerepo/')); tmpDir = setupRepo(Directory('test/assets/mergerepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Rebase', () { group('Rebase', () {
test('successfully performs rebase when there is no conflicts', () { test('successfully performs rebase when there is no conflicts', () {
final signature = repo.defaultSignature; final signature = repo.defaultSignature;
final master = repo.references['refs/heads/master']; final master = repo.lookupReference('refs/heads/master');
final feature = repo.references['refs/heads/feature']; final feature = repo.lookupReference('refs/heads/feature');
repo.checkout(refName: feature.name); repo.checkout(refName: feature.name);
expect(() => repo.index['.gitignore'], throwsA(isA<ArgumentError>())); expect(() => repo.index['.gitignore'], throwsA(isA<ArgumentError>()));
@ -60,9 +60,9 @@ void main() {
test('successfully performs rebase with provided upstream', () { test('successfully performs rebase with provided upstream', () {
final signature = repo.defaultSignature; final signature = repo.defaultSignature;
final master = repo.references['refs/heads/master']; final master = repo.lookupReference('refs/heads/master');
final feature = repo.references['refs/heads/feature']; final feature = repo.lookupReference('refs/heads/feature');
final startCommit = repo[shas[1]] as Commit; final startCommit = repo.lookupCommit(repo[shas[1]]);
repo.checkout(refName: feature.name); repo.checkout(refName: feature.name);
expect( expect(
@ -97,8 +97,8 @@ void main() {
test('stops when there is conflicts', () { test('stops when there is conflicts', () {
final signature = repo.defaultSignature; final signature = repo.defaultSignature;
final master = repo.references['refs/heads/master']; final master = repo.lookupReference('refs/heads/master');
final conflict = repo.references['refs/heads/conflict-branch']; final conflict = repo.lookupReference('refs/heads/conflict-branch');
repo.checkout(refName: conflict.name); repo.checkout(refName: conflict.name);
@ -124,8 +124,8 @@ void main() {
}); });
test('successfully aborts rebase in progress', () { test('successfully aborts rebase in progress', () {
final master = repo.references['refs/heads/master']; final master = repo.lookupReference('refs/heads/master');
final conflict = repo.references['refs/heads/conflict-branch']; final conflict = repo.lookupReference('refs/heads/conflict-branch');
repo.checkout(refName: conflict.name); repo.checkout(refName: conflict.name);

View file

@ -9,20 +9,20 @@ void main() {
const lastCommit = '821ed6e80627b8769d170a293862f9fc60825226'; const lastCommit = '821ed6e80627b8769d170a293862f9fc60825226';
const newCommit = 'c68ff54aabf660fcdd9a2838d401583fe31249e3'; const newCommit = 'c68ff54aabf660fcdd9a2838d401583fe31249e3';
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Reference', () { group('Reference', () {
test('returns a list', () { test('returns a list', () {
expect( expect(
repo.references.list, repo.references,
[ [
'refs/heads/feature', 'refs/heads/feature',
'refs/heads/master', 'refs/heads/master',
@ -38,7 +38,7 @@ void main() {
expect(head.type, ReferenceType.direct); expect(head.type, ReferenceType.direct);
head.free(); head.free();
final ref = repo.references['HEAD']; final ref = repo.lookupReference('HEAD');
expect(ref.type, ReferenceType.symbolic); expect(ref.type, ReferenceType.symbolic);
ref.free(); ref.free();
}); });
@ -50,7 +50,7 @@ void main() {
}); });
test('returns SHA hex of symbolic reference', () { test('returns SHA hex of symbolic reference', () {
final ref = repo.references['HEAD']; final ref = repo.lookupReference('HEAD');
expect(ref.target.sha, lastCommit); expect(ref.target.sha, lastCommit);
ref.free(); ref.free();
}); });
@ -62,7 +62,7 @@ void main() {
}); });
test('returns the short name', () { test('returns the short name', () {
final ref = repo.references.create( final ref = repo.createReference(
name: 'refs/remotes/origin/master', name: 'refs/remotes/origin/master',
target: lastCommit, target: lastCommit,
); );
@ -77,19 +77,19 @@ void main() {
}); });
test('checks if reference is a local branch', () { test('checks if reference is a local branch', () {
final ref = repo.references['refs/heads/feature']; final ref = repo.lookupReference('refs/heads/feature');
expect(ref.isBranch, true); expect(ref.isBranch, true);
ref.free(); ref.free();
}); });
test('checks if reference is a note', () { test('checks if reference is a note', () {
final ref = repo.references['refs/heads/master']; final ref = repo.lookupReference('refs/heads/master');
expect(ref.isNote, false); expect(ref.isNote, false);
ref.free(); ref.free();
}); });
test('checks if reference is a remote branch', () { test('checks if reference is a remote branch', () {
final ref = repo.references.create( final ref = repo.createReference(
name: 'refs/remotes/origin/master', name: 'refs/remotes/origin/master',
target: lastCommit, target: lastCommit,
); );
@ -100,16 +100,16 @@ void main() {
}); });
test('checks if reference is a tag', () { test('checks if reference is a tag', () {
final ref = repo.references['refs/tags/v0.1']; final ref = repo.lookupReference('refs/tags/v0.1');
expect(ref.isTag, true); expect(ref.isTag, true);
ref.free(); ref.free();
}); });
test('checks if reflog exists for the reference', () { test('checks if reflog exists for the reference', () {
var ref = repo.references['refs/heads/master']; var ref = repo.lookupReference('refs/heads/master');
expect(ref.hasLog, true); expect(ref.hasLog, true);
ref = repo.references['refs/tags/v0.1']; ref = repo.lookupReference('refs/tags/v0.1');
expect(ref.hasLog, false); expect(ref.hasLog, false);
ref.free(); ref.free();
@ -117,43 +117,43 @@ void main() {
group('create direct', () { group('create direct', () {
test('successfully creates with Oid as target', () { test('successfully creates with Oid as target', () {
final ref = repo.references['refs/heads/master']; final ref = repo.lookupReference('refs/heads/master');
final refFromOid = repo.references.create( final refFromOid = repo.createReference(
name: 'refs/tags/from.oid', name: 'refs/tags/from.oid',
target: ref.target, target: ref.target,
); );
expect(repo.references.list, contains('refs/tags/from.oid')); expect(repo.references, contains('refs/tags/from.oid'));
refFromOid.free(); refFromOid.free();
ref.free(); ref.free();
}); });
test('successfully creates with SHA hash as target', () { test('successfully creates with SHA hash as target', () {
final refFromHash = repo.references.create( final refFromHash = repo.createReference(
name: 'refs/tags/from.hash', name: 'refs/tags/from.hash',
target: lastCommit, target: lastCommit,
); );
expect(repo.references.list, contains('refs/tags/from.hash')); expect(repo.references, contains('refs/tags/from.hash'));
refFromHash.free(); refFromHash.free();
}); });
test('successfully creates with short SHA hash as target', () { test('successfully creates with short SHA hash as target', () {
final refFromHash = repo.references.create( final refFromHash = repo.createReference(
name: 'refs/tags/from.short.hash', name: 'refs/tags/from.short.hash',
target: '78b8bf', target: '78b8bf',
); );
expect(repo.references.list, contains('refs/tags/from.short.hash')); expect(repo.references, contains('refs/tags/from.short.hash'));
refFromHash.free(); refFromHash.free();
}); });
test('successfully creates with log message', () { test('successfully creates with log message', () {
repo.setIdentity(name: 'name', email: 'email'); repo.setIdentity(name: 'name', email: 'email');
final ref = repo.references.create( final ref = repo.createReference(
name: 'refs/heads/log.message', name: 'refs/heads/log.message',
target: lastCommit, target: lastCommit,
logMessage: 'log message', logMessage: 'log message',
@ -172,7 +172,7 @@ void main() {
test('throws if target is not valid', () { test('throws if target is not valid', () {
expect( expect(
() => repo.references.create( () => repo.createReference(
name: 'refs/tags/invalid', name: 'refs/tags/invalid',
target: '78b', target: '78b',
), ),
@ -182,7 +182,7 @@ void main() {
test('throws if name is not valid', () { test('throws if name is not valid', () {
expect( expect(
() => repo.references.create( () => repo.createReference(
name: 'refs/tags/invalid~', name: 'refs/tags/invalid~',
target: lastCommit, target: lastCommit,
), ),
@ -191,12 +191,12 @@ void main() {
}); });
test('successfully creates with force flag if name already exists', () { test('successfully creates with force flag if name already exists', () {
final ref = repo.references.create( final ref = repo.createReference(
name: 'refs/tags/test', name: 'refs/tags/test',
target: lastCommit, target: lastCommit,
); );
final forceRef = repo.references.create( final forceRef = repo.createReference(
name: 'refs/tags/test', name: 'refs/tags/test',
target: lastCommit, target: lastCommit,
force: true, force: true,
@ -209,13 +209,13 @@ void main() {
}); });
test('throws if name already exists', () { test('throws if name already exists', () {
final ref = repo.references.create( final ref = repo.createReference(
name: 'refs/tags/test', name: 'refs/tags/test',
target: lastCommit, target: lastCommit,
); );
expect( expect(
() => repo.references.create( () => repo.createReference(
name: 'refs/tags/test', name: 'refs/tags/test',
target: lastCommit, target: lastCommit,
), ),
@ -228,24 +228,24 @@ void main() {
group('create symbolic', () { group('create symbolic', () {
test('successfully creates with valid target', () { test('successfully creates with valid target', () {
final ref = repo.references.create( final ref = repo.createReference(
name: 'refs/tags/symbolic', name: 'refs/tags/symbolic',
target: 'refs/heads/master', target: 'refs/heads/master',
); );
expect(repo.references.list, contains('refs/tags/symbolic')); expect(repo.references, contains('refs/tags/symbolic'));
expect(ref.type, ReferenceType.symbolic); expect(ref.type, ReferenceType.symbolic);
ref.free(); ref.free();
}); });
test('successfully creates with force flag if name already exists', () { test('successfully creates with force flag if name already exists', () {
final ref = repo.references.create( final ref = repo.createReference(
name: 'refs/tags/test', name: 'refs/tags/test',
target: 'refs/heads/master', target: 'refs/heads/master',
); );
final forceRef = repo.references.create( final forceRef = repo.createReference(
name: 'refs/tags/test', name: 'refs/tags/test',
target: 'refs/heads/master', target: 'refs/heads/master',
force: true, force: true,
@ -259,13 +259,13 @@ void main() {
}); });
test('throws if name already exists', () { test('throws if name already exists', () {
final ref = repo.references.create( final ref = repo.createReference(
name: 'refs/tags/exists', name: 'refs/tags/exists',
target: 'refs/heads/master', target: 'refs/heads/master',
); );
expect( expect(
() => repo.references.create( () => repo.createReference(
name: 'refs/tags/exists', name: 'refs/tags/exists',
target: 'refs/heads/master', target: 'refs/heads/master',
), ),
@ -277,7 +277,7 @@ void main() {
test('throws if name is not valid', () { test('throws if name is not valid', () {
expect( expect(
() => repo.references.create( () => repo.createReference(
name: 'refs/tags/invalid~', name: 'refs/tags/invalid~',
target: 'refs/heads/master', target: 'refs/heads/master',
), ),
@ -287,7 +287,7 @@ void main() {
test('successfully creates with log message', () { test('successfully creates with log message', () {
repo.setIdentity(name: 'name', email: 'email'); repo.setIdentity(name: 'name', email: 'email');
final ref = repo.references.create( final ref = repo.createReference(
name: 'HEAD', name: 'HEAD',
target: 'refs/heads/feature', target: 'refs/heads/feature',
force: true, force: true,
@ -307,34 +307,34 @@ void main() {
}); });
test('successfully deletes reference', () { test('successfully deletes reference', () {
final ref = repo.references.create( final ref = repo.createReference(
name: 'refs/tags/test', name: 'refs/tags/test',
target: lastCommit, target: lastCommit,
); );
expect(repo.references.list, contains('refs/tags/test')); expect(repo.references, contains('refs/tags/test'));
ref.delete(); repo.deleteReference('refs/tags/test');
expect(repo.references.list, isNot(contains('refs/tags/test'))); expect(repo.references, isNot(contains('refs/tags/test')));
ref.free(); ref.free();
}); });
group('finds', () { group('finds', () {
test('with provided name', () { test('with provided name', () {
final ref = repo.references['refs/heads/master']; final ref = repo.lookupReference('refs/heads/master');
expect(ref.target.sha, lastCommit); expect(ref.target.sha, lastCommit);
ref.free(); ref.free();
}); });
test('throws when error occured', () { test('throws when error occured', () {
expect( expect(
() => repo.references['refs/heads/not/there'], () => repo.lookupReference('refs/heads/not/there'),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
}); });
}); });
test('returns log for reference', () { test('returns log for reference', () {
final ref = repo.references['refs/heads/master']; final ref = repo.lookupReference('refs/heads/master');
final reflog = ref.log; final reflog = ref.log;
expect(reflog.last.message, 'commit (initial): init'); expect(reflog.last.message, 'commit (initial): init');
@ -344,7 +344,7 @@ void main() {
group('set target', () { group('set target', () {
test('successfully sets with SHA hex', () { test('successfully sets with SHA hex', () {
final ref = repo.references['refs/heads/master']; final ref = repo.lookupReference('refs/heads/master');
ref.setTarget(target: newCommit); ref.setTarget(target: newCommit);
expect(ref.target.sha, newCommit); expect(ref.target.sha, newCommit);
@ -352,7 +352,7 @@ void main() {
}); });
test('successfully sets target with short SHA hex', () { test('successfully sets target with short SHA hex', () {
final ref = repo.references['refs/heads/master']; final ref = repo.lookupReference('refs/heads/master');
ref.setTarget(target: newCommit.substring(0, 5)); ref.setTarget(target: newCommit.substring(0, 5));
expect(ref.target.sha, newCommit); expect(ref.target.sha, newCommit);
@ -360,7 +360,7 @@ void main() {
}); });
test('successfully sets symbolic target', () { test('successfully sets symbolic target', () {
final ref = repo.references['HEAD']; final ref = repo.lookupReference('HEAD');
expect(ref.target.sha, lastCommit); expect(ref.target.sha, lastCommit);
ref.setTarget(target: 'refs/heads/feature'); ref.setTarget(target: 'refs/heads/feature');
@ -370,7 +370,7 @@ void main() {
}); });
test('successfully sets target with log message', () { test('successfully sets target with log message', () {
final ref = repo.references['HEAD']; final ref = repo.lookupReference('HEAD');
expect(ref.target.sha, lastCommit); expect(ref.target.sha, lastCommit);
repo.setIdentity(name: 'name', email: 'email'); repo.setIdentity(name: 'name', email: 'email');
@ -386,7 +386,7 @@ void main() {
}); });
test('throws on invalid target', () { test('throws on invalid target', () {
final ref = repo.references['HEAD']; final ref = repo.lookupReference('HEAD');
expect( expect(
() => ref.setTarget(target: 'refs/heads/invalid~'), () => ref.setTarget(target: 'refs/heads/invalid~'),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
@ -398,67 +398,56 @@ void main() {
group('rename', () { group('rename', () {
test('successfully renames reference', () { test('successfully renames reference', () {
final ref = repo.references.create( repo.renameReference(
name: 'refs/tags/v1', oldName: 'refs/tags/v0.1',
target: lastCommit, newName: 'refs/tags/renamed',
); );
expect(ref.name, 'refs/tags/v1');
ref.rename(newName: 'refs/tags/v2'); expect(repo.references, contains('refs/tags/renamed'));
expect(ref.name, 'refs/tags/v2'); expect(repo.references, isNot(contains('refs/tags/v0.1')));
ref.free();
}); });
test('throws on invalid name', () { test('throws on invalid name', () {
final ref = repo.references.create(
name: 'refs/tags/v1',
target: lastCommit,
);
expect( expect(
() => ref.rename(newName: 'refs/tags/invalid~'), () => repo.renameReference(
oldName: 'refs/tags/v0.1',
newName: 'refs/tags/invalid~',
),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
ref.free();
}); });
test('throws if name already exists', () { test('throws if name already exists', () {
final ref1 = repo.references.create(
name: 'refs/tags/v1',
target: lastCommit,
);
final ref2 = repo.references.create(
name: 'refs/tags/v2',
target: lastCommit,
);
expect( expect(
() => ref1.rename(newName: 'refs/tags/v2'), () => repo.renameReference(
oldName: 'refs/tags/v0.1',
newName: 'refs/tags/v0.2',
),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
ref1.free();
ref2.free();
}); });
test('successfully renames with force flag set to true', () { test('successfully renames with force flag set to true', () {
final ref1 = repo.references.create( final ref1 = repo.lookupReference('refs/tags/v0.1');
name: 'refs/tags/v1', final ref2 = repo.lookupReference('refs/tags/v0.2');
target: lastCommit,
expect(ref1.target.sha, '78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e8');
expect(ref2.target.sha, 'f0fdbf506397e9f58c59b88dfdd72778ec06cc0c');
expect(repo.references.length, 5);
repo.renameReference(
oldName: 'refs/tags/v0.1',
newName: 'refs/tags/v0.2',
force: true,
); );
final ref2 = repo.references.create( final updatedRef1 = repo.lookupReference('refs/tags/v0.2');
name: 'refs/tags/v2', expect(
target: newCommit, updatedRef1.target.sha,
'78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e8',
); );
expect(repo.references, isNot(contains('refs/tags/v0.1')));
expect(ref2.target.sha, newCommit); expect(repo.references.length, 4);
ref1.rename(newName: 'refs/tags/v2', force: true);
expect(ref1.name, 'refs/tags/v2');
ref1.free(); ref1.free();
ref2.free(); ref2.free();
@ -466,9 +455,9 @@ void main() {
}); });
test('checks equality', () { test('checks equality', () {
final ref1 = repo.references['refs/heads/master']; final ref1 = repo.lookupReference('refs/heads/master');
final ref2 = repo.references['refs/heads/master']; final ref2 = repo.lookupReference('refs/heads/master');
final ref3 = repo.references['refs/heads/feature']; final ref3 = repo.lookupReference('refs/heads/feature');
expect(ref1 == ref2, true); expect(ref1 == ref2, true);
expect(ref1 != ref2, false); expect(ref1 != ref2, false);
@ -481,8 +470,8 @@ void main() {
}); });
test('successfully peels to non-tag object when no type is provided', () { test('successfully peels to non-tag object when no type is provided', () {
final ref = repo.references['refs/heads/master']; final ref = repo.lookupReference('refs/heads/master');
final commit = repo[ref.target.sha] as Commit; final commit = repo.lookupCommit(ref.target);
final peeled = ref.peel() as Commit; final peeled = ref.peel() as Commit;
expect(peeled.id, commit.id); expect(peeled.id, commit.id);
@ -493,8 +482,8 @@ void main() {
}); });
test('successfully peels to object of provided type', () { test('successfully peels to object of provided type', () {
final ref = repo.references['refs/heads/master']; final ref = repo.lookupReference('refs/heads/master');
final commit = repo[ref.target.sha] as Commit; final commit = repo.lookupCommit(ref.target);
final tree = commit.tree; final tree = commit.tree;
final peeledCommit = ref.peel(GitObject.commit) as Commit; final peeledCommit = ref.peel(GitObject.commit) as Commit;
final peeledTree = ref.peel(GitObject.tree) as Tree; final peeledTree = ref.peel(GitObject.tree) as Tree;
@ -511,12 +500,12 @@ void main() {
test('successfully compresses references', () { test('successfully compresses references', () {
final packedRefsFile = File('${tmpDir.path}/.git/packed-refs'); final packedRefsFile = File('${tmpDir.path}/.git/packed-refs');
expect(packedRefsFile.existsSync(), false); expect(packedRefsFile.existsSync(), false);
final oldRefs = repo.references.list; final oldRefs = repo.references;
repo.references.compress(); Reference.compress(repo);
expect(packedRefsFile.existsSync(), true); expect(packedRefsFile.existsSync(), true);
final newRefs = repo.references.list; final newRefs = repo.references;
expect(newRefs, oldRefs); expect(newRefs, oldRefs);
}); });
}); });

View file

@ -9,18 +9,18 @@ void main() {
late Reference head; late Reference head;
late Directory tmpDir; late Directory tmpDir;
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
head = repo.head; head = repo.head;
reflog = RefLog(head); reflog = RefLog(head);
}); });
tearDown(() async { tearDown(() {
reflog.free(); reflog.free();
head.free(); head.free();
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('RefLog', () { group('RefLog', () {

View file

@ -10,43 +10,61 @@ void main() {
late Remote remote; late Remote remote;
final cloneDir = Directory('${Directory.systemTemp.path}/cloned'); final cloneDir = Directory('${Directory.systemTemp.path}/cloned');
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
if (await cloneDir.exists()) { if (cloneDir.existsSync()) {
cloneDir.delete(recursive: true); cloneDir.deleteSync(recursive: true);
} }
originRepo = Repository.open(tmpDir.path); originRepo = Repository.open(tmpDir.path);
clonedRepo = Repository.clone( clonedRepo = Repository.clone(
url: tmpDir.path, url: tmpDir.path,
localPath: cloneDir.path, localPath: cloneDir.path,
); );
originRepo.branches['feature'].delete(); originRepo.deleteBranch('feature');
remote = clonedRepo.remotes['origin']; remote = clonedRepo.lookupRemote('origin');
}); });
tearDown(() async { tearDown(() {
remote.free(); remote.free();
originRepo.free(); originRepo.free();
clonedRepo.free(); clonedRepo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
if (await cloneDir.exists()) { if (cloneDir.existsSync()) {
cloneDir.delete(recursive: true); cloneDir.deleteSync(recursive: true);
} }
}); });
group('Remote', () { group('Remote', () {
test('fetch() does not prune branch by default', () { test('fetch() does not prune branch by default', () {
remote.fetch(); remote.fetch();
expect(clonedRepo.branches.list(), contains('origin/feature'));
final branches = clonedRepo.branches;
expect(branches.any((branch) => branch.name == 'origin/feature'), true);
for (final branch in branches) {
branch.free();
}
}); });
test('fetch() successfully prunes branch with provided flag', () { test('fetch() successfully prunes branch with provided flag', () {
remote.fetch(prune: GitFetchPrune.prune); remote.fetch(prune: GitFetchPrune.prune);
expect(clonedRepo.branches.list(), isNot(contains('origin/feature')));
final branches = clonedRepo.branches;
expect(branches.any((branch) => branch.name == 'origin/feature'), false);
for (final branch in branches) {
branch.free();
}
}); });
test('fetch() does not prune branch with provided flag', () { test('fetch() does not prune branch with provided flag', () {
remote.fetch(prune: GitFetchPrune.noPrune); remote.fetch(prune: GitFetchPrune.noPrune);
expect(clonedRepo.branches.list(), contains('origin/feature'));
final branches = clonedRepo.branches;
expect(branches.any((branch) => branch.name == 'origin/feature'), true);
for (final branch in branches) {
branch.free();
}
}); });
test('prune() successfully prunes branches', () { test('prune() successfully prunes branches', () {
@ -58,11 +76,22 @@ void main() {
final callbacks = Callbacks(updateTips: updateTips); final callbacks = Callbacks(updateTips: updateTips);
remote.fetch(prune: GitFetchPrune.noPrune); remote.fetch(prune: GitFetchPrune.noPrune);
expect(clonedRepo.branches.list(), contains('origin/feature')); var branches = clonedRepo.branches;
expect(branches.any((branch) => branch.name == 'origin/feature'), true);
for (final branch in branches) {
branch.free();
}
remote.prune(callbacks); remote.prune(callbacks);
branches = clonedRepo.branches;
expect(pruned, contains('refs/remotes/origin/feature')); expect(pruned, contains('refs/remotes/origin/feature'));
expect(clonedRepo.branches.list(), isNot(contains('origin/feature'))); expect(branches.any((branch) => branch.name == 'origin/feature'), false);
for (final branch in branches) {
branch.free();
}
}); });
}); });
} }

View file

@ -9,23 +9,23 @@ void main() {
const remoteName = 'origin'; const remoteName = 'origin';
const remoteUrl = 'git://github.com/SkinnyMind/libgit2dart.git'; const remoteUrl = 'git://github.com/SkinnyMind/libgit2dart.git';
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Remote', () { group('Remote', () {
test('returns list of remotes', () { test('returns list of remotes', () {
expect(repo.remotes.list, ['origin']); expect(repo.remotes, ['origin']);
}); });
test('successfully looks up remote for provided name', () { test('successfully looks up remote for provided name', () {
final remote = repo.remotes['origin']; final remote = repo.lookupRemote('origin');
expect(remote.name, remoteName); expect(remote.name, remoteName);
expect(remote.url, remoteUrl); expect(remote.url, remoteUrl);
@ -35,11 +35,11 @@ void main() {
}); });
test('throws when provided name for lookup is not found', () { test('throws when provided name for lookup is not found', () {
expect(() => repo.remotes['upstream'], throwsA(isA<LibGit2Error>())); expect(() => repo.lookupRemote('upstream'), throwsA(isA<LibGit2Error>()));
}); });
test('successfully creates without fetchspec', () { test('successfully creates without fetchspec', () {
final remote = repo.remotes.create(name: 'upstream', url: remoteUrl); final remote = repo.createRemote(name: 'upstream', url: remoteUrl);
expect(repo.remotes.length, 2); expect(repo.remotes.length, 2);
expect(remote.name, 'upstream'); expect(remote.name, 'upstream');
@ -51,7 +51,7 @@ void main() {
test('successfully creates with provided fetchspec', () { test('successfully creates with provided fetchspec', () {
const spec = '+refs/*:refs/*'; const spec = '+refs/*:refs/*';
final remote = repo.remotes.create( final remote = repo.createRemote(
name: 'upstream', name: 'upstream',
url: remoteUrl, url: remoteUrl,
fetch: spec, fetch: spec,
@ -67,23 +67,23 @@ void main() {
}); });
test('successfully deletes', () { test('successfully deletes', () {
final remote = repo.remotes.create(name: 'upstream', url: remoteUrl); final remote = repo.createRemote(name: 'upstream', url: remoteUrl);
expect(repo.remotes.length, 2); expect(repo.remotes.length, 2);
repo.remotes.delete(remote.name); repo.deleteRemote(remote.name);
expect(repo.remotes.length, 1); expect(repo.remotes.length, 1);
remote.free(); remote.free();
}); });
test('successfully renames', () { test('successfully renames', () {
final remote = repo.remotes[remoteName]; final remote = repo.lookupRemote(remoteName);
final problems = repo.remotes.rename(remote: remoteName, newName: 'new'); final problems = repo.renameRemote(oldName: remoteName, newName: 'new');
expect(problems, isEmpty); expect(problems, isEmpty);
expect(remote.name, isNot('new')); expect(remote.name, isNot('new'));
final newRemote = repo.remotes['new']; final newRemote = repo.lookupRemote('new');
expect(newRemote.name, 'new'); expect(newRemote.name, 'new');
newRemote.free(); newRemote.free();
@ -92,19 +92,19 @@ void main() {
test('throws when renaming with invalid names', () { test('throws when renaming with invalid names', () {
expect( expect(
() => repo.remotes.rename(remote: '', newName: ''), () => repo.renameRemote(oldName: '', newName: ''),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
}); });
test('successfully sets url', () { test('successfully sets url', () {
final remote = repo.remotes[remoteName]; final remote = repo.lookupRemote(remoteName);
expect(remote.url, remoteUrl); expect(remote.url, remoteUrl);
const newUrl = 'git://new/url.git'; const newUrl = 'git://new/url.git';
repo.remotes.setUrl(remote: remoteName, url: newUrl); Remote.setUrl(repo: repo, remote: remoteName, url: newUrl);
final newRemote = repo.remotes[remoteName]; final newRemote = repo.lookupRemote(remoteName);
expect(newRemote.url, newUrl); expect(newRemote.url, newUrl);
newRemote.free(); newRemote.free();
@ -113,16 +113,16 @@ void main() {
test('throws when trying to set invalid url name', () { test('throws when trying to set invalid url name', () {
expect( expect(
() => repo.remotes.setUrl(remote: 'origin', url: ''), () => Remote.setUrl(repo: repo, remote: 'origin', url: ''),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
}); });
test('successfully sets url for pushing', () { test('successfully sets url for pushing', () {
const newUrl = 'git://new/url.git'; const newUrl = 'git://new/url.git';
repo.remotes.setPushUrl(remote: remoteName, url: newUrl); Remote.setPushUrl(repo: repo, remote: remoteName, url: newUrl);
final remote = repo.remotes[remoteName]; final remote = repo.lookupRemote(remoteName);
expect(remote.pushUrl, newUrl); expect(remote.pushUrl, newUrl);
remote.free(); remote.free();
@ -130,13 +130,13 @@ void main() {
test('throws when trying to set invalid push url name', () { test('throws when trying to set invalid push url name', () {
expect( expect(
() => repo.remotes.setPushUrl(remote: 'origin', url: ''), () => Remote.setPushUrl(repo: repo, remote: 'origin', url: ''),
throwsA(isA<LibGit2Error>()), throwsA(isA<LibGit2Error>()),
); );
}); });
test('returns refspec', () { test('returns refspec', () {
final remote = repo.remotes['origin']; final remote = repo.lookupRemote('origin');
expect(remote.refspecCount, 1); expect(remote.refspecCount, 1);
final refspec = remote.getRefspec(0); final refspec = remote.getRefspec(0);
@ -162,11 +162,12 @@ void main() {
}); });
test('successfully adds fetch refspec', () { test('successfully adds fetch refspec', () {
repo.remotes.addFetch( Remote.addFetch(
repo: repo,
remote: 'origin', remote: 'origin',
refspec: '+refs/test/*:refs/test/remotes/*', refspec: '+refs/test/*:refs/test/remotes/*',
); );
final remote = repo.remotes['origin']; final remote = repo.lookupRemote('origin');
expect(remote.fetchRefspecs.length, 2); expect(remote.fetchRefspecs.length, 2);
expect( expect(
remote.fetchRefspecs, remote.fetchRefspecs,
@ -180,11 +181,12 @@ void main() {
}); });
test('successfully adds push refspec', () { test('successfully adds push refspec', () {
repo.remotes.addPush( Remote.addPush(
repo: repo,
remote: 'origin', remote: 'origin',
refspec: '+refs/test/*:refs/test/remotes/*', refspec: '+refs/test/*:refs/test/remotes/*',
); );
final remote = repo.remotes['origin']; final remote = repo.lookupRemote('origin');
expect(remote.pushRefspecs.length, 1); expect(remote.pushRefspecs.length, 1);
expect(remote.pushRefspecs, ['+refs/test/*:refs/test/remotes/*']); expect(remote.pushRefspecs, ['+refs/test/*:refs/test/remotes/*']);
@ -192,11 +194,12 @@ void main() {
}); });
test('successfully returns remote repo\'s reference list', () { test('successfully returns remote repo\'s reference list', () {
repo.remotes.setUrl( Remote.setUrl(
repo: repo,
remote: 'libgit2', remote: 'libgit2',
url: 'https://github.com/libgit2/TestGitRepository', url: 'https://github.com/libgit2/TestGitRepository',
); );
final remote = repo.remotes['libgit2']; final remote = repo.lookupRemote('libgit2');
final refs = remote.ls(); final refs = remote.ls();
expect(refs.first['local'], false); expect(refs.first['local'], false);
@ -212,11 +215,12 @@ void main() {
}); });
test('successfully fetches data', () { test('successfully fetches data', () {
repo.remotes.setUrl( Remote.setUrl(
repo: repo,
remote: 'libgit2', remote: 'libgit2',
url: 'https://github.com/libgit2/TestGitRepository', url: 'https://github.com/libgit2/TestGitRepository',
); );
final remote = repo.remotes['libgit2']; final remote = repo.lookupRemote('libgit2');
final stats = remote.fetch(); final stats = remote.fetch();
@ -233,11 +237,12 @@ void main() {
test('successfully fetches data with provided transfer progress callback', test('successfully fetches data with provided transfer progress callback',
() { () {
repo.remotes.setUrl( Remote.setUrl(
repo: repo,
remote: 'libgit2', remote: 'libgit2',
url: 'https://github.com/libgit2/TestGitRepository', url: 'https://github.com/libgit2/TestGitRepository',
); );
final remote = repo.remotes['libgit2']; final remote = repo.lookupRemote('libgit2');
TransferProgress? callbackStats; TransferProgress? callbackStats;
void tp(TransferProgress stats) => callbackStats = stats; void tp(TransferProgress stats) => callbackStats = stats;
@ -263,11 +268,12 @@ Enumerating objects: 69, done.
Counting objects: 100% (1/1)\rCounting objects: 100% (1/1), done. Counting objects: 100% (1/1)\rCounting objects: 100% (1/1), done.
Total 69 (delta 0), reused 1 (delta 0), pack-reused 68 Total 69 (delta 0), reused 1 (delta 0), pack-reused 68
"""; """;
repo.remotes.setUrl( Remote.setUrl(
repo: repo,
remote: 'libgit2', remote: 'libgit2',
url: 'https://github.com/libgit2/TestGitRepository', url: 'https://github.com/libgit2/TestGitRepository',
); );
final remote = repo.remotes['libgit2']; final remote = repo.lookupRemote('libgit2');
var sidebandOutput = StringBuffer(); var sidebandOutput = StringBuffer();
void sideband(String message) { void sideband(String message) {
@ -283,11 +289,12 @@ Total 69 (delta 0), reused 1 (delta 0), pack-reused 68
}); });
test('successfully fetches data with provided update tips callback', () { test('successfully fetches data with provided update tips callback', () {
repo.remotes.setUrl( Remote.setUrl(
repo: repo,
remote: 'libgit2', remote: 'libgit2',
url: 'https://github.com/libgit2/TestGitRepository', url: 'https://github.com/libgit2/TestGitRepository',
); );
final remote = repo.remotes['libgit2']; final remote = repo.lookupRemote('libgit2');
const tipsExpected = [ const tipsExpected = [
{ {
'refname': 'refs/tags/annotated_tag', 'refname': 'refs/tags/annotated_tag',
@ -323,21 +330,22 @@ Total 69 (delta 0), reused 1 (delta 0), pack-reused 68
remote.free(); remote.free();
}); });
test('successfully pushes with update reference callback', () async { test('successfully pushes with update reference callback', () {
final originDir = final originDir =
Directory('${Directory.systemTemp.path}/origin_testrepo'); Directory('${Directory.systemTemp.path}/origin_testrepo');
if (await originDir.exists()) { if (originDir.existsSync()) {
await originDir.delete(recursive: true); originDir.deleteSync(recursive: true);
} }
await copyRepo( originDir.createSync();
copyRepo(
from: Directory('test/assets/empty_bare.git/'), from: Directory('test/assets/empty_bare.git/'),
to: await originDir.create(), to: originDir,
); );
final originRepo = Repository.open(originDir.path); final originRepo = Repository.open(originDir.path);
repo.remotes.create(name: 'local', url: originDir.path); repo.createRemote(name: 'local', url: originDir.path);
final remote = repo.remotes['local']; final remote = repo.lookupRemote('local');
var updateRefOutput = <String, String>{}; var updateRefOutput = <String, String>{};
void updateRef(String refname, String message) { void updateRef(String refname, String message) {
@ -348,7 +356,7 @@ Total 69 (delta 0), reused 1 (delta 0), pack-reused 68
remote.push(refspecs: ['refs/heads/master'], callbacks: callbacks); remote.push(refspecs: ['refs/heads/master'], callbacks: callbacks);
expect( expect(
(originRepo[originRepo.head.target.sha] as Commit).id.sha, originRepo.lookupCommit(originRepo.head.target).id.sha,
'821ed6e80627b8769d170a293862f9fc60825226', '821ed6e80627b8769d170a293862f9fc60825226',
); );
expect(updateRefOutput, {'refs/heads/master': ''}); expect(updateRefOutput, {'refs/heads/master': ''});

View file

@ -8,20 +8,19 @@ void main() {
late Directory tmpDir; late Directory tmpDir;
final cloneDir = Directory('${Directory.systemTemp.path}/cloned'); final cloneDir = Directory('${Directory.systemTemp.path}/cloned');
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
if (cloneDir.existsSync()) {
if (await cloneDir.exists()) {
cloneDir.delete(recursive: true); cloneDir.delete(recursive: true);
} }
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
if (await cloneDir.exists()) { if (cloneDir.existsSync()) {
cloneDir.delete(recursive: true); cloneDir.deleteSync(recursive: true);
} }
}); });
@ -69,7 +68,7 @@ void main() {
test('successfully clones repository with provided remote callback', () { test('successfully clones repository with provided remote callback', () {
Remote remote(Repository repo, String name, String url) => Remote remote(Repository repo, String name, String url) =>
repo.remotes.create(name: 'test', url: tmpDir.path); repo.createRemote(name: 'test', url: tmpDir.path);
final clonedRepo = Repository.clone( final clonedRepo = Repository.clone(
url: tmpDir.path, url: tmpDir.path,
@ -79,15 +78,15 @@ void main() {
expect(clonedRepo.isEmpty, false); expect(clonedRepo.isEmpty, false);
expect(clonedRepo.isBare, false); expect(clonedRepo.isBare, false);
expect(clonedRepo.remotes.list, ['test']); expect(clonedRepo.remotes, ['test']);
expect(clonedRepo.references.list, contains('refs/remotes/test/master')); expect(clonedRepo.references, contains('refs/remotes/test/master'));
clonedRepo.free(); clonedRepo.free();
}); });
test('throws when cloning repository with invalid remote callback', () { test('throws when cloning repository with invalid remote callback', () {
Remote remote(Repository repo, String name, String url) => Remote remote(Repository repo, String name, String url) =>
repo.remotes.create(name: '', url: ''); repo.createRemote(name: '', url: '');
expect( expect(
() => Repository.clone( () => Repository.clone(

View file

@ -6,17 +6,17 @@ void main() {
late Repository repo; late Repository repo;
final initDir = Directory('${Directory.systemTemp.path}/init_repo'); final initDir = Directory('${Directory.systemTemp.path}/init_repo');
setUp(() async { setUp(() {
if (await initDir.exists()) { if (initDir.existsSync()) {
await initDir.delete(recursive: true); initDir.deleteSync(recursive: true);
} else { } else {
await initDir.create(); initDir.createSync();
} }
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await initDir.delete(recursive: true); initDir.deleteSync(recursive: true);
}); });
group('Repository.init', () { group('Repository.init', () {
test('successfully creates new bare repo at provided path', () { test('successfully creates new bare repo at provided path', () {
@ -49,7 +49,7 @@ void main() {
File('${initDir.path}/.git/description').readAsStringSync(), File('${initDir.path}/.git/description').readAsStringSync(),
'test repo', 'test repo',
); );
expect(repo.remotes['origin'].url, 'test.url'); expect(repo.lookupRemote('origin').url, 'test.url');
}); });
}); });
} }

View file

@ -9,14 +9,14 @@ void main() {
const lastCommit = '821ed6e80627b8769d170a293862f9fc60825226'; const lastCommit = '821ed6e80627b8769d170a293862f9fc60825226';
const featureCommit = '5aecfa0fb97eadaac050ccb99f03c3fb65460ad4'; const featureCommit = '5aecfa0fb97eadaac050ccb99f03c3fb65460ad4';
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Repository', () { group('Repository', () {
@ -125,7 +125,7 @@ void main() {
test('successfully creates new blob', () { test('successfully creates new blob', () {
final oid = repo.createBlob(newBlobContent); final oid = repo.createBlob(newBlobContent);
final newBlob = repo[oid.sha] as Blob; final newBlob = repo.lookupBlob(oid);
expect(newBlob, isA<Blob>()); expect(newBlob, isA<Blob>());
@ -135,7 +135,7 @@ void main() {
test('successfully creates new blob from file at provided relative path', test('successfully creates new blob from file at provided relative path',
() { () {
final oid = repo.createBlobFromWorkdir('feature_file'); final oid = repo.createBlobFromWorkdir('feature_file');
final newBlob = repo[oid.sha] as Blob; final newBlob = repo.lookupBlob(oid);
expect(newBlob, isA<Blob>()); expect(newBlob, isA<Blob>());
@ -146,7 +146,7 @@ void main() {
final outsideFile = final outsideFile =
File('${Directory.current.absolute.path}/test/blob_test.dart'); File('${Directory.current.absolute.path}/test/blob_test.dart');
final oid = repo.createBlobFromDisk(outsideFile.path); final oid = repo.createBlobFromDisk(outsideFile.path);
final newBlob = repo[oid.sha] as Blob; final newBlob = repo.lookupBlob(oid);
expect(newBlob, isA<Blob>()); expect(newBlob, isA<Blob>());
@ -161,11 +161,10 @@ void main() {
time: 1234, time: 1234,
); );
const tagName = 'tag'; const tagName = 'tag';
const target = 'f17d0d48eae3aa08cecf29128a35e310c97b3521'; final target = repo['f17d0d48eae3aa08cecf29128a35e310c97b3521'];
const message = 'init tag\n'; const message = 'init tag\n';
final oid = Tag.create( final oid = repo.createTag(
repo: repo,
tagName: tagName, tagName: tagName,
target: target, target: target,
targetType: GitObject.commit, targetType: GitObject.commit,
@ -173,7 +172,7 @@ void main() {
message: message, message: message,
); );
final newTag = repo[oid.sha] as Tag; final newTag = repo.lookupTag(oid);
final tagger = newTag.tagger; final tagger = newTag.tagger;
final newTagTarget = newTag.target as Commit; final newTagTarget = newTag.target as Commit;
@ -181,7 +180,7 @@ void main() {
expect(newTag.name, tagName); expect(newTag.name, tagName);
expect(newTag.message, message); expect(newTag.message, message);
expect(tagger, signature); expect(tagger, signature);
expect(newTagTarget.id.sha, target); expect(newTagTarget.id, target);
newTag.free(); newTag.free();
newTagTarget.free(); newTagTarget.free();
@ -252,8 +251,8 @@ void main() {
}); });
test('checks if commit is a descendant of another commit', () { test('checks if commit is a descendant of another commit', () {
final commit1 = repo['821ed6e8'] as Commit; final commit1 = repo.lookupCommit(repo['821ed6e8']);
final commit2 = repo['78b8bf12'] as Commit; final commit2 = repo.lookupCommit(repo['78b8bf12']);
expect( expect(
repo.descendantOf( repo.descendantOf(
@ -284,8 +283,8 @@ void main() {
}); });
test('returns number of ahead behind commits', () { test('returns number of ahead behind commits', () {
final commit1 = repo['821ed6e8'] as Commit; final commit1 = repo.lookupCommit(repo['821ed6e8']);
final commit2 = repo['c68ff54a'] as Commit; final commit2 = repo.lookupCommit(repo['c68ff54a']);
expect( expect(
repo.aheadBehind(localSHA: commit1.id.sha, upstreamSHA: commit2.id.sha), repo.aheadBehind(localSHA: commit1.id.sha, upstreamSHA: commit2.id.sha),

View file

@ -9,15 +9,15 @@ void main() {
late File file; late File file;
const sha = '6cbc22e509d72758ab4c8d9f287ea846b90c448b'; const sha = '6cbc22e509d72758ab4c8d9f287ea846b90c448b';
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
file = File('${tmpDir.path}/feature_file'); file = File('${tmpDir.path}/feature_file');
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Reset', () { group('Reset', () {

View file

@ -9,14 +9,14 @@ void main() {
const headSHA = '821ed6e80627b8769d170a293862f9fc60825226'; const headSHA = '821ed6e80627b8769d170a293862f9fc60825226';
const parentSHA = '78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e8'; const parentSHA = '78b8bf123e3952c970ae5c1ce0a3ea1d1336f6e8';
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('revParse', () { group('revParse', () {
@ -36,7 +36,7 @@ void main() {
}); });
test('.ext() returns commit and reference', () { test('.ext() returns commit and reference', () {
final masterRef = repo.references['refs/heads/master']; final masterRef = repo.lookupReference('refs/heads/master');
var headParse = repo.revParseExt('master'); var headParse = repo.revParseExt('master');
expect(headParse.object.id.sha, headSHA); expect(headParse.object.id.sha, headSHA);
@ -46,7 +46,7 @@ void main() {
headParse.object.free(); headParse.object.free();
headParse.reference?.free(); headParse.reference?.free();
final featureRef = repo.references['refs/heads/feature']; final featureRef = repo.lookupReference('refs/heads/feature');
headParse = repo.revParseExt('feature'); headParse = repo.revParseExt('feature');
expect( expect(

View file

@ -14,14 +14,14 @@ void main() {
'f17d0d48eae3aa08cecf29128a35e310c97b3521', 'f17d0d48eae3aa08cecf29128a35e310c97b3521',
]; ];
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('RevWalk', () { group('RevWalk', () {

View file

@ -8,8 +8,8 @@ void main() {
late Directory tmpDir; late Directory tmpDir;
late Signature stasher; late Signature stasher;
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
stasher = Signature.create( stasher = Signature.create(
name: 'Stasher', name: 'Stasher',
@ -17,10 +17,10 @@ void main() {
); );
}); });
tearDown(() async { tearDown(() {
stasher.free(); stasher.free();
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Stash', () { group('Stash', () {

View file

@ -10,14 +10,14 @@ void main() {
const submoduleUrl = 'https://github.com/libgit2/TestGitRepository'; const submoduleUrl = 'https://github.com/libgit2/TestGitRepository';
const submoduleHeadSha = '49322bb17d3acc9146f98c97d078513228bbf3c0'; const submoduleHeadSha = '49322bb17d3acc9146f98c97d078513228bbf3c0';
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/submodulerepo/')); tmpDir = setupRepo(Directory('test/assets/submodulerepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Submodule', () { group('Submodule', () {

View file

@ -7,18 +7,19 @@ void main() {
late Repository repo; late Repository repo;
late Tag tag; late Tag tag;
late Directory tmpDir; late Directory tmpDir;
const tagSHA = 'f0fdbf506397e9f58c59b88dfdd72778ec06cc0c'; late Oid tagID;
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
tag = Tag.lookup(repo: repo, sha: tagSHA); tagID = repo['f0fdbf506397e9f58c59b88dfdd72778ec06cc0c'];
tag = repo.lookupTag(tagID);
}); });
tearDown(() async { tearDown(() {
tag.free(); tag.free();
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Tag', () { group('Tag', () {
@ -36,7 +37,7 @@ void main() {
final target = tag.target as Commit; final target = tag.target as Commit;
final tagger = tag.tagger; final tagger = tag.tagger;
expect(tag.id.sha, tagSHA); expect(tag.id, tagID);
expect(tag.name, 'v0.2'); expect(tag.name, 'v0.2');
expect(tag.message, 'annotated tag\n'); expect(tag.message, 'annotated tag\n');
expect(target.message, 'add subdirectory file\n'); expect(target.message, 'add subdirectory file\n');
@ -53,11 +54,10 @@ void main() {
time: 1234, time: 1234,
); );
const tagName = 'tag'; const tagName = 'tag';
final target = 'f17d0d48eae3aa08cecf29128a35e310c97b3521'; final target = repo['f17d0d48eae3aa08cecf29128a35e310c97b3521'];
const message = 'init tag\n'; const message = 'init tag\n';
final oid = Tag.create( final oid = repo.createTag(
repo: repo,
tagName: tagName, tagName: tagName,
target: target, target: target,
targetType: GitObject.commit, targetType: GitObject.commit,
@ -65,7 +65,7 @@ void main() {
message: message, message: message,
); );
final newTag = Tag.lookup(repo: repo, sha: oid.sha); final newTag = repo.lookupTag(oid);
final tagger = newTag.tagger; final tagger = newTag.tagger;
final newTagTarget = newTag.target as Commit; final newTagTarget = newTag.target as Commit;
@ -73,7 +73,7 @@ void main() {
expect(newTag.name, tagName); expect(newTag.name, tagName);
expect(newTag.message, message); expect(newTag.message, message);
expect(tagger, signature); expect(tagger, signature);
expect(newTagTarget.id.sha, target); expect(newTagTarget.id, target);
newTag.free(); newTag.free();
newTagTarget.free(); newTagTarget.free();
@ -87,7 +87,7 @@ void main() {
test('successfully deletes tag', () { test('successfully deletes tag', () {
expect(repo.tags, ['v0.1', 'v0.2']); expect(repo.tags, ['v0.1', 'v0.2']);
tag.delete(); repo.deleteTag('v0.2');
expect(repo.tags, ['v0.1']); expect(repo.tags, ['v0.1']);
}); });
}); });

View file

@ -7,19 +7,20 @@ void main() {
late Repository repo; late Repository repo;
late Tree tree; late Tree tree;
late Directory tmpDir; late Directory tmpDir;
const treeSHA = 'a8ae3dd59e6e1802c6f78e05e301bfd57c9f334f';
const fileSHA = '1377554ebea6f98a2c748183bc5a96852af12ac2'; const fileSHA = '1377554ebea6f98a2c748183bc5a96852af12ac2';
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
tree = Tree.lookup(repo: repo, sha: treeSHA); tree = repo.lookupTree(
repo['a8ae3dd59e6e1802c6f78e05e301bfd57c9f334f'],
);
}); });
tearDown(() async { tearDown(() {
tree.free(); tree.free();
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('Tree', () { group('Tree', () {
@ -70,7 +71,7 @@ void main() {
oid: fileOid, oid: fileOid,
filemode: GitFilemode.blob, filemode: GitFilemode.blob,
); );
final newTree = Tree.lookup(repo: repo, sha: builder.write().sha); final newTree = repo.lookupTree(builder.write());
final entry = newTree['filename']; final entry = newTree['filename'];
expect(newTree.length, 1); expect(newTree.length, 1);

View file

@ -7,18 +7,17 @@ void main() {
late Repository repo; late Repository repo;
late Tree tree; late Tree tree;
late Directory tmpDir; late Directory tmpDir;
const treeSHA = 'a8ae3dd59e6e1802c6f78e05e301bfd57c9f334f';
setUp(() async { setUp(() {
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
tree = Tree.lookup(repo: repo, sha: treeSHA); tree = repo.lookupTree(repo['a8ae3dd59e6e1802c6f78e05e301bfd57c9f334f']);
}); });
tearDown(() async { tearDown(() {
tree.free(); tree.free();
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
}); });
group('TreeBuilder', () { group('TreeBuilder', () {
@ -56,11 +55,13 @@ void main() {
expect(() => builder[entry.name], throwsA(isA<ArgumentError>())); expect(() => builder[entry.name], throwsA(isA<ArgumentError>()));
builder.add( builder.add(
filename: entry.name, oid: entry.id, filemode: entry.filemode); filename: entry.name,
oid: entry.id,
filemode: entry.filemode,
);
expect(builder[entry.name].name, entry.name); expect(builder[entry.name].name, entry.name);
builder.free(); builder.free();
entry.free();
}); });
test('successfully removes an entry', () { test('successfully removes an entry', () {

View file

@ -7,91 +7,98 @@ void main() {
late Repository repo; late Repository repo;
late Directory tmpDir; late Directory tmpDir;
final worktreeDir = Directory('${Directory.systemTemp.path}/worktree'); final worktreeDir = Directory('${Directory.systemTemp.path}/worktree');
const worktreeName = 'worktree';
setUp(() async { setUp(() {
if (await worktreeDir.exists()) { if (worktreeDir.existsSync()) {
await worktreeDir.delete(recursive: true); worktreeDir.deleteSync(recursive: true);
} }
tmpDir = await setupRepo(Directory('test/assets/testrepo/')); tmpDir = setupRepo(Directory('test/assets/testrepo/'));
repo = Repository.open(tmpDir.path); repo = Repository.open(tmpDir.path);
}); });
tearDown(() async { tearDown(() {
repo.free(); repo.free();
await tmpDir.delete(recursive: true); tmpDir.deleteSync(recursive: true);
if (await worktreeDir.exists()) { if (worktreeDir.existsSync()) {
await worktreeDir.delete(recursive: true); worktreeDir.deleteSync(recursive: true);
} }
}); });
group('Worktree', () { group('Worktree', () {
test('successfully creates worktree at provided path', () { test('successfully creates worktree at provided path', () {
const worktreeName = 'worktree'; expect(repo.worktrees, []);
expect(Worktree.list(repo), []);
final worktree = Worktree.create( final worktree = repo.createWorktree(
repo: repo,
name: worktreeName, name: worktreeName,
path: worktreeDir.path, path: worktreeDir.path,
); );
final lookedupWorktree = repo.lookupWorktree(worktreeName);
final branches = repo.branches;
expect(Worktree.list(repo), [worktreeName]); expect(repo.worktrees, [worktreeName]);
expect(repo.branches.list(), contains(worktreeName)); expect(branches.any((branch) => branch.name == worktreeName), true);
expect(worktree.name, worktreeName); expect(worktree.name, worktreeName);
expect(lookedupWorktree.name, worktreeName);
expect(worktree.path, worktreeDir.path); expect(worktree.path, worktreeDir.path);
expect(lookedupWorktree.path, worktreeDir.path);
expect(File('${worktreeDir.path}/.git').existsSync(), true); expect(File('${worktreeDir.path}/.git').existsSync(), true);
for (final branch in branches) {
branch.free();
}
lookedupWorktree.free();
worktree.free(); worktree.free();
}); });
test( test(
'successfully creates worktree at provided path from provided reference', 'successfully creates worktree at provided path from provided reference',
() { () {
const worktreeName = 'worktree';
final head = repo.revParseSingle('HEAD'); final head = repo.revParseSingle('HEAD');
final worktreeRef = repo.branches.create(name: 'v1', target: head); final worktreeBranch = repo.createBranch(name: 'v1', target: head);
final worktreeBranch = repo.branches['v1']; final ref = repo.lookupReference('refs/heads/v1');
expect(Worktree.list(repo), []); expect(repo.worktrees, []);
final worktree = Worktree.create( final worktree = repo.createWorktree(
repo: repo,
name: worktreeName, name: worktreeName,
path: worktreeDir.path, path: worktreeDir.path,
ref: worktreeRef, ref: ref,
); );
final branches = repo.branches;
expect(Worktree.list(repo), [worktreeName]); expect(repo.worktrees, [worktreeName]);
expect(repo.branches.list(), contains('v1')); expect(branches.any((branch) => branch.name == 'v1'), true);
expect(repo.branches.list(), isNot(contains(worktreeName))); expect(branches.any((branch) => branch.name == worktreeName), false);
expect(worktreeBranch.isCheckedOut, true); expect(worktreeBranch.isCheckedOut, true);
worktreeDir.deleteSync(recursive: true); worktreeDir.deleteSync(recursive: true);
worktree.prune(); worktree.prune();
expect(Worktree.list(repo), []); expect(repo.worktrees, []);
expect(worktreeBranch.isCheckedOut, false); expect(worktreeBranch.isCheckedOut, false);
expect(repo.branches.list(), contains('v1')); expect(branches.any((branch) => branch.name == 'v1'), true);
for (final branch in branches) {
branch.free();
}
worktreeBranch.free(); worktreeBranch.free();
worktreeRef.free(); ref.free();
head.free(); head.free();
worktree.free(); worktree.free();
}); });
test('successfully prunes worktree', () { test('successfully prunes worktree', () {
const worktreeName = 'worktree'; expect(repo.worktrees, []);
expect(Worktree.list(repo), []);
final worktree = Worktree.create( final worktree = repo.createWorktree(
repo: repo,
name: worktreeName, name: worktreeName,
path: worktreeDir.path, path: worktreeDir.path,
); );
expect(Worktree.list(repo), [worktreeName]); expect(repo.worktrees, [worktreeName]);
worktreeDir.deleteSync(recursive: true); worktreeDir.deleteSync(recursive: true);
worktree.prune(); worktree.prune();
expect(Worktree.list(repo), []); expect(repo.worktrees, []);
worktree.free(); worktree.free();
}); });