From 6ecd368dafb8a1abe473eaa9354407f8748c13bb Mon Sep 17 00:00:00 2001 From: Tyler Ang-Wanek Date: Wed, 25 Sep 2019 12:27:12 -0700 Subject: [PATCH 1/2] commitWalk optionally returns plain objects with gpgSignature data --- generate/input/libgit2-supplement.json | 6 +- .../templates/manual/revwalk/commit_walk.cc | 170 +++++++++++++++--- generate/templates/templates/class_header.h | 1 + 3 files changed, 153 insertions(+), 24 deletions(-) diff --git a/generate/input/libgit2-supplement.json b/generate/input/libgit2-supplement.json index b8b74abd7..fd827c8bf 100644 --- a/generate/input/libgit2-supplement.json +++ b/generate/input/libgit2-supplement.json @@ -753,7 +753,11 @@ }, { "name": "out", - "type": "std::vector *" + "type": "void *" + }, + { + "name": "returnPlainObjects", + "type": "bool" }, { "name": "walk", diff --git a/generate/templates/manual/revwalk/commit_walk.cc b/generate/templates/manual/revwalk/commit_walk.cc index 91fe7f38c..c230550f2 100644 --- a/generate/templates/manual/revwalk/commit_walk.cc +++ b/generate/templates/manual/revwalk/commit_walk.cc @@ -1,24 +1,149 @@ +#define SET_ON_OBJECT(obj, field, data) Nan::Set(obj, Nan::New(field).ToLocalChecked(), data) + +v8::Local signatureToJavascript(const git_signature *signature) { + v8::Local signatureObject = Nan::New(); + SET_ON_OBJECT(signatureObject, "name", Nan::New(signature->name).ToLocalChecked()); + SET_ON_OBJECT(signatureObject, "email", Nan::New(signature->email).ToLocalChecked()); + SET_ON_OBJECT(signatureObject, "date", Nan::New(signature->when.time * 1000)); + std::stringstream fullSignature; + fullSignature << signature->name << " <" << signature << ">"; + SET_ON_OBJECT(signatureObject, "full", Nan::New(fullSignature.str()).ToLocalChecked()); + return signatureObject; +} + +#include +class CommitModel { +public: + CommitModel(git_commit *commit, bool fetchSignature): + commit(commit), + fetchSignature(fetchSignature), + signature({ 0, 0, 0 }), + signedData({ 0, 0, 0 }) + { + if (fetchSignature) { + int error = git_commit_extract_signature( + &signature, + &signedData, + git_commit_owner(commit), + const_cast(git_commit_id(commit)), + NULL + ); + if (error != GIT_ENOTFOUND) { + assert(error == GIT_OK); + } + } + + size_t parentCount = git_commit_parentcount(commit); + parentIds.reserve(parentCount); + for (size_t parentIndex = 0; parentIndex < parentCount; ++parentIndex) { + parentIds.push_back(git_oid_tostr_s(git_commit_parent_id(commit, parentIndex))); + } + } + + v8::Local toJavascript() { + if (!fetchSignature) { + v8::Local commitObject = GitCommit::New( + commit, + true, + Nan::To(GitRepository::New( + git_commit_owner(commit), + true + )).ToLocalChecked() + ); + commit = NULL; + return commitObject; + } + + v8::Local commitModel = Nan::New(); + SET_ON_OBJECT(commitModel, "sha", Nan::New(git_oid_tostr_s(git_commit_id(commit))).ToLocalChecked()); + SET_ON_OBJECT(commitModel, "message", Nan::New(git_commit_message(commit)).ToLocalChecked()); + SET_ON_OBJECT(commitModel, "author", signatureToJavascript(git_commit_author(commit))); + SET_ON_OBJECT(commitModel, "committer", signatureToJavascript(git_commit_committer(commit))); + + size_t parentCount = parentIds.size(); + v8::Local parents = Nan::New(parentCount); + for (size_t parentIndex = 0; parentIndex < parentCount; ++parentIndex) { + Nan::Set(parents, Nan::New(parentIndex), Nan::New(parentIds[parentIndex]).ToLocalChecked()); + } + SET_ON_OBJECT(commitModel, "parents", parents); + + if (signature.size != 0 || signedData.size != 0) { + v8::Local gpgSignature = Nan::New(); + if (signature.size != 0) { + SET_ON_OBJECT(gpgSignature, "signature", Nan::New(signature.ptr).ToLocalChecked()); + } else { + SET_ON_OBJECT(gpgSignature, "signature", Nan::Null()); + } + + if (signedData.size != 0) { + SET_ON_OBJECT(gpgSignature, "signedData", Nan::New(signedData.ptr).ToLocalChecked()); + } else { + SET_ON_OBJECT(gpgSignature, "signedData", Nan::Null()); + } + + SET_ON_OBJECT(commitModel, "gpgSignature", gpgSignature); + } + + return commitModel; + } + + ~CommitModel() { + git_buf_dispose(&signature); + git_buf_dispose(&signedData); + if (commit) { + git_commit_free(commit); + } + } + +private: + git_commit *commit; + bool fetchSignature; + git_buf signature, signedData; + std::vector parentIds; +}; + NAN_METHOD(GitRevwalk::CommitWalk) { if (info.Length() == 0 || !info[0]->IsNumber()) { return Nan::ThrowError("Max count is required and must be a number."); } - if (info.Length() == 1 || !info[1]->IsFunction()) { + if (info.Length() == 1 || (info.Length() == 2 && !info[1]->IsFunction())) { return Nan::ThrowError("Callback is required and must be a Function."); } + if (info.Length() >= 3) { + if (!info[1]->IsNull() && !info[1]->IsUndefined() && !info[1]->IsObject()) { + return Nan::ThrowError("Options must be an object, null, or undefined."); + } + + if (!info[2]->IsFunction()) { + return Nan::ThrowError("Callback is required and must be a Function."); + } + } + CommitWalkBaton* baton = new CommitWalkBaton; baton->error_code = GIT_OK; baton->error = NULL; baton->max_count = Nan::To(info[0]).FromJust(); - baton->out = new std::vector; - baton->out->reserve(baton->max_count); + std::vector *out = new std::vector; + out->reserve(baton->max_count); + baton->out = reinterpret_cast(out); + if (info.Length() == 3 && info[1]->IsObject()) { + v8::Local options = Nan::To(info[1]).ToLocalChecked(); + v8::Local propName = Nan::New("returnPlainObjects").ToLocalChecked(); + if (Nan::Has(options, propName).FromJust()) { + baton->returnPlainObjects = Nan::Get(options, propName).ToLocalChecked()->IsTrue(); + } else { + baton->returnPlainObjects = false; + } + } else { + baton->returnPlainObjects = false; + } baton->walk = Nan::ObjectWrap::Unwrap(info.This())->GetValue(); - - Nan::Callback *callback = new Nan::Callback(Local::Cast(info[1])); + Nan::Callback *callback = new Nan::Callback(Local::Cast(info[1]->IsFunction() ? info[1] : info[2])); CommitWalkWorker *worker = new CommitWalkWorker(baton, callback); - worker->SaveToPersistent("fastWalk", info.This()); + worker->SaveToPersistent("commitWalk", info.This()); Nan::AsyncQueueWorker(worker); return; @@ -27,6 +152,7 @@ NAN_METHOD(GitRevwalk::CommitWalk) { void GitRevwalk::CommitWalkWorker::Execute() { giterr_clear(); + std::vector *out = reinterpret_cast *>(baton->out); for (int i = 0; i < baton->max_count; i++) { git_oid next_commit_id; baton->error_code = git_revwalk_next(&next_commit_id, baton->walk); @@ -41,12 +167,12 @@ void GitRevwalk::CommitWalkWorker::Execute() { baton->error = git_error_dup(giterr_last()); } - while (baton->out->size()) { - git_commit_free(baton->out->back()); - baton->out->pop_back(); + while (out->size()) { + delete out->back(); + out->pop_back(); } - delete baton->out; + delete out; baton->out = NULL; return; @@ -60,39 +186,37 @@ void GitRevwalk::CommitWalkWorker::Execute() { baton->error = git_error_dup(giterr_last()); } - while (baton->out->size()) { - git_commit_free(baton->out->back()); - baton->out->pop_back(); + while (out->size()) { + delete out->back(); + out->pop_back(); } - delete baton->out; + delete out; baton->out = NULL; return; } - baton->out->push_back(commit); + out->push_back(new CommitModel(commit, baton->returnPlainObjects)); } } void GitRevwalk::CommitWalkWorker::HandleOKCallback() { if (baton->out != NULL) { - unsigned int size = baton->out->size(); + std::vector *out = reinterpret_cast *>(baton->out); + unsigned int size = out->size(); Local result = Nan::New(size); for (unsigned int i = 0; i < size; i++) { - git_commit *commit = baton->out->at(i); + CommitModel *commitModel = out->at(i); Nan::Set( result, Nan::New(i), - GitCommit::New( - commit, - true, - Nan::To(GitRepository::New(git_commit_owner(commit), true)).ToLocalChecked() - ) + commitModel->toJavascript() ); + delete commitModel; } - delete baton->out; + delete out; Local argv[2] = { Nan::Null(), diff --git a/generate/templates/templates/class_header.h b/generate/templates/templates/class_header.h index fce17e58c..746692e9e 100644 --- a/generate/templates/templates/class_header.h +++ b/generate/templates/templates/class_header.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "async_baton.h" #include "nodegit_wrapper.h" From d7c9860bb2b8a75b6046fa58cd5c03835ea54d63 Mon Sep 17 00:00:00 2001 From: Tyler Ang-Wanek Date: Thu, 26 Sep 2019 12:02:44 -0700 Subject: [PATCH 2/2] Use const qualifier more; use static_cast for void * --- generate/templates/manual/revwalk/commit_walk.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/generate/templates/manual/revwalk/commit_walk.cc b/generate/templates/manual/revwalk/commit_walk.cc index c230550f2..bef5bc889 100644 --- a/generate/templates/manual/revwalk/commit_walk.cc +++ b/generate/templates/manual/revwalk/commit_walk.cc @@ -21,7 +21,7 @@ class CommitModel { signedData({ 0, 0, 0 }) { if (fetchSignature) { - int error = git_commit_extract_signature( + const int error = git_commit_extract_signature( &signature, &signedData, git_commit_owner(commit), @@ -33,7 +33,7 @@ class CommitModel { } } - size_t parentCount = git_commit_parentcount(commit); + const size_t parentCount = git_commit_parentcount(commit); parentIds.reserve(parentCount); for (size_t parentIndex = 0; parentIndex < parentCount; ++parentIndex) { parentIds.push_back(git_oid_tostr_s(git_commit_parent_id(commit, parentIndex))); @@ -128,7 +128,7 @@ NAN_METHOD(GitRevwalk::CommitWalk) { baton->max_count = Nan::To(info[0]).FromJust(); std::vector *out = new std::vector; out->reserve(baton->max_count); - baton->out = reinterpret_cast(out); + baton->out = static_cast(out); if (info.Length() == 3 && info[1]->IsObject()) { v8::Local options = Nan::To(info[1]).ToLocalChecked(); v8::Local propName = Nan::New("returnPlainObjects").ToLocalChecked(); @@ -152,7 +152,7 @@ NAN_METHOD(GitRevwalk::CommitWalk) { void GitRevwalk::CommitWalkWorker::Execute() { giterr_clear(); - std::vector *out = reinterpret_cast *>(baton->out); + std::vector *out = static_cast *>(baton->out); for (int i = 0; i < baton->max_count; i++) { git_oid next_commit_id; baton->error_code = git_revwalk_next(&next_commit_id, baton->walk); @@ -203,8 +203,8 @@ void GitRevwalk::CommitWalkWorker::Execute() { void GitRevwalk::CommitWalkWorker::HandleOKCallback() { if (baton->out != NULL) { - std::vector *out = reinterpret_cast *>(baton->out); - unsigned int size = out->size(); + std::vector *out = static_cast *>(baton->out); + const unsigned int size = out->size(); Local result = Nan::New(size); for (unsigned int i = 0; i < size; i++) { CommitModel *commitModel = out->at(i);