Add functionality for converting Diff objects to a buffer and back
This commit is contained in:
parent
462ebd83e0
commit
de24abbdae
74
diff.go
74
diff.go
|
@ -3,6 +3,7 @@ package git
|
||||||
/*
|
/*
|
||||||
#include <git2.h>
|
#include <git2.h>
|
||||||
|
|
||||||
|
extern void _go_git_apply_init_options(git_apply_options *options);
|
||||||
extern int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLine, void *payload);
|
extern int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLine, void *payload);
|
||||||
extern void _go_git_setup_diff_notify_callbacks(git_diff_options* opts);
|
extern void _go_git_setup_diff_notify_callbacks(git_diff_options* opts);
|
||||||
extern int _go_git_diff_blobs(git_blob *old, const char *old_path, git_blob *new, const char *new_path, git_diff_options *opts, int eachFile, int eachHunk, int eachLine, void *payload);
|
extern int _go_git_diff_blobs(git_blob *old, const char *old_path, git_blob *new, const char *new_path, git_diff_options *opts, int eachFile, int eachHunk, int eachLine, void *payload);
|
||||||
|
@ -847,3 +848,76 @@ func DiffBlobs(oldBlob *Blob, oldAsPath string, newBlob *Blob, newAsPath string,
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ApplyOptions struct {
|
||||||
|
Version uint
|
||||||
|
Flags uint
|
||||||
|
// TODO: there are some more flags, not currently used
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultApplyOptions() (*ApplyOptions, error) {
|
||||||
|
opts := C.git_apply_options{}
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
C._go_git_apply_init_options(&opts)
|
||||||
|
|
||||||
|
return applyOptionsFromC(&opts), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApplyOptions) toC() *C.git_apply_options {
|
||||||
|
if a == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := &C.git_apply_options{
|
||||||
|
version: C.uint(a.Version),
|
||||||
|
flags: C.uint(a.Flags),
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyOptionsFromC(opts *C.git_apply_options) *ApplyOptions {
|
||||||
|
return &ApplyOptions{
|
||||||
|
Version: uint(opts.version),
|
||||||
|
Flags: uint(opts.flags),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type GitApplyLocation int
|
||||||
|
|
||||||
|
const (
|
||||||
|
GitApplyLocationWorkdir GitApplyLocation = C.GIT_APPLY_LOCATION_WORKDIR
|
||||||
|
GitApplyLocationIndex GitApplyLocation = C.GIT_APPLY_LOCATION_INDEX
|
||||||
|
GitApplyLocationBoth GitApplyLocation = C.GIT_APPLY_LOCATION_BOTH
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v *Repository) ApplyDiff(diff *Diff, location GitApplyLocation, opts *ApplyOptions) error {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
ecode := C.git_apply(v.ptr, diff.ptr, C.git_apply_location_t(location), opts.toC())
|
||||||
|
runtime.KeepAlive(v)
|
||||||
|
if ecode < 0 {
|
||||||
|
return MakeGitError(ecode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DiffFromBuffer(buffer []byte, repo *Repository) (*Diff, error) {
|
||||||
|
var diff *C.git_diff
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
ecode := C.git_diff_from_buffer(&diff, C.CString(string(buffer)), C.size_t(len(buffer)))
|
||||||
|
if ecode < 0 {
|
||||||
|
return nil, MakeGitError(ecode)
|
||||||
|
}
|
||||||
|
runtime.KeepAlive(diff)
|
||||||
|
|
||||||
|
return newDiffFromC(diff, repo), nil
|
||||||
|
}
|
||||||
|
|
62
diff_test.go
62
diff_test.go
|
@ -236,3 +236,65 @@ func TestDiffBlobs(t *testing.T) {
|
||||||
t.Fatalf("Bad number of lines iterated")
|
t.Fatalf("Bad number of lines iterated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_ApplyDiff_Addfile(t *testing.T) {
|
||||||
|
repo := createTestRepo(t)
|
||||||
|
defer cleanupTestRepo(t, repo)
|
||||||
|
|
||||||
|
seedTestRepo(t, repo)
|
||||||
|
|
||||||
|
addFirstFileCommit, addFileTree := addAndGetTree(t, repo, "file1", `hello`)
|
||||||
|
addSecondFileCommit, addSecondFileTree := addAndGetTree(t, repo, "file2", `hello2`)
|
||||||
|
|
||||||
|
diff, err := repo.DiffTreeToTree(addFileTree, addSecondFileTree, nil)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
t.Run("check does not apply to current tree because file exists", func(t *testing.T) {
|
||||||
|
err = repo.ResetToCommit(addSecondFileCommit, ResetHard, &CheckoutOpts{})
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
err = repo.ApplyDiff(diff, GitApplyLocationBoth, nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expecting applying patch to current repo to fail")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("check apply to correct commit", func(t *testing.T) {
|
||||||
|
err = repo.ResetToCommit(addFirstFileCommit, ResetHard, &CheckoutOpts{})
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
err = repo.ApplyDiff(diff, GitApplyLocationBoth, nil)
|
||||||
|
checkFatal(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("check convert to raw buffer and apply", func(t *testing.T) {
|
||||||
|
err = repo.ResetToCommit(addFirstFileCommit, ResetHard, &CheckoutOpts{})
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
raw, err := diff.ToBuf(DiffFormatPatch)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
if len(raw) == 0 {
|
||||||
|
t.Error("empty diff created")
|
||||||
|
}
|
||||||
|
|
||||||
|
diff2, err := DiffFromBuffer(raw, repo)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
err = repo.ApplyDiff(diff2, GitApplyLocationBoth, nil)
|
||||||
|
checkFatal(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func addAndGetTree(t *testing.T, repo *Repository, filename string, content string) (*Commit, *Tree) {
|
||||||
|
commitId, err := commitSomething(repo, filename, content)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
commit, err := repo.LookupCommit(commitId)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
tree, err := commit.Tree()
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
return commit, tree
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue