/* * Copyright 2013, Tim Branyen @tbranyen * @author Michael Robinson @codeofinterest * * Dual licensed under the MIT and GPL licenses. */ #include #include #include #include "git2.h" #include "cvv8/v8-convert.hpp" #include "../include/reference.h" #include "../include/signature.h" #include "../include/repo.h" #include "../include/oid.h" #include "../include/tree.h" #include "../include/commit.h" #include "../include/error.h" #include "../include/functions/utilities.h" #include "../include/functions/string.h" using namespace v8; using namespace cvv8; using namespace node; void GitCommit::Initialize(Handle target) { HandleScope scope; Local tpl = FunctionTemplate::New(New); tpl->InstanceTemplate()->SetInternalFieldCount(1); tpl->SetClassName(String::NewSymbol("Commit")); NODE_SET_PROTOTYPE_METHOD(tpl, "lookup", Lookup); NODE_SET_PROTOTYPE_METHOD(tpl, "oid", Oid); NODE_SET_PROTOTYPE_METHOD(tpl, "message", Message); NODE_SET_PROTOTYPE_METHOD(tpl, "time", Time); NODE_SET_PROTOTYPE_METHOD(tpl, "offset", Offset); NODE_SET_PROTOTYPE_METHOD(tpl, "author", Author); NODE_SET_PROTOTYPE_METHOD(tpl, "committer", Committer); NODE_SET_PROTOTYPE_METHOD(tpl, "tree", Tree); NODE_SET_PROTOTYPE_METHOD(tpl, "parents", Parents); NODE_SET_PROTOTYPE_METHOD(tpl, "free", Free); constructor_template = Persistent::New(tpl->GetFunction()); target->Set(String::NewSymbol("Commit"), constructor_template); } git_commit* GitCommit::GetValue() { return this->commit; } void GitCommit::SetValue(git_commit* commit) { this->commit = commit; } void GitCommit::SetOid(git_oid* oid) { this->oid = oid; } Handle GitCommit::New(const Arguments& args) { HandleScope scope; GitCommit *commit = new GitCommit(); commit->Wrap(args.This()); return scope.Close(args.This()); } Handle GitCommit::Free(const Arguments& args) { HandleScope scope; GitCommit *commit = ObjectWrap::Unwrap(args.This()); git_commit_free(commit->commit); commit->commit = NULL; return Undefined(); } Handle GitCommit::Lookup(const Arguments& args) { HandleScope scope; if(args.Length() == 0 || !args[0]->IsObject()) { return ThrowException(Exception::Error(String::New("Repo is required and must be an Object."))); } if(args.Length() == 1 || !(args[1]->IsObject() || args[1]->IsString())) { return ThrowException(Exception::Error(String::New("Oid is required and must be an Object or String"))); } if(args.Length() == 2 || !args[2]->IsFunction()) { return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } LookupBaton *baton = new LookupBaton; baton->request.data = baton; baton->error = NULL; baton->repo = ObjectWrap::Unwrap(args[0]->ToObject())->GetValue(); if (args[1]->IsObject()) { baton->rawOid = ObjectWrap::Unwrap(args[1]->ToObject())->GetValue(); } else { baton->sha = stringArgToString(args[1]->ToString()); } baton->callback = Persistent::New(Local::Cast(args[2])); uv_queue_work(uv_default_loop(), &baton->request, LookupWork, (uv_after_work_cb)LookupAfterWork); return Undefined(); } void GitCommit::LookupWork(uv_work_t *req) { LookupBaton *baton = static_cast(req->data); if (!baton->sha.empty()) { int returnCode = git_oid_fromstr(&baton->rawOid, baton->sha.c_str()); if (returnCode != GIT_OK) { baton->error = giterr_last(); return; } } baton->rawCommit = NULL; int returnCode = git_commit_lookup(&baton->rawCommit, baton->repo, &baton->rawOid); if (returnCode != GIT_OK) { baton->error = giterr_last(); } } void GitCommit::LookupAfterWork(uv_work_t *req) { HandleScope scope; LookupBaton *baton = static_cast(req->data); if (success(baton->error, baton->callback)) { Local commit = GitCommit::constructor_template->NewInstance(); GitCommit *commitInstance = ObjectWrap::Unwrap(commit); commitInstance->SetValue(baton->rawCommit); commitInstance->SetOid(&baton->rawOid); Handle argv[2] = { Local::New(Null()), commit }; TryCatch try_catch; baton->callback->Call(Context::GetCurrent()->Global(), 2, argv); if (try_catch.HasCaught()) { node::FatalException(try_catch); } } delete req; } Handle GitCommit::Oid(const Arguments& args) { HandleScope scope; Local oid = GitOid::constructor_template->NewInstance(); GitOid *oidInstance = ObjectWrap::Unwrap(oid); oidInstance->SetValue(*const_cast(ObjectWrap::Unwrap(args.This())->oid)); return scope.Close(oid); } Handle GitCommit::Message(const Arguments& args) { HandleScope scope; if(args.Length() == 0 || !args[0]->IsFunction()) { return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } MessageBaton* baton = new MessageBaton; baton->request.data = baton; baton->rawCommit = ObjectWrap::Unwrap(args.This())->GetValue(); baton->callback = Persistent::New(Local::Cast(args[0])); uv_queue_work(uv_default_loop(), &baton->request, MessageWork, (uv_after_work_cb)MessageAfterWork); return Undefined(); } void GitCommit::MessageWork(uv_work_t* req) { MessageBaton *baton = static_cast(req->data); baton->message = git_commit_message(baton->rawCommit); } void GitCommit::MessageAfterWork(uv_work_t* req) { HandleScope scope; MessageBaton *baton = static_cast(req->data); Handle argv[2] = { Local::New(Null()), String::New(baton->message.c_str()) }; TryCatch try_catch; baton->callback->Call(Context::GetCurrent()->Global(), 2, argv); if (try_catch.HasCaught()) { node::FatalException(try_catch); } delete req; } Handle GitCommit::Time(const Arguments& args) { HandleScope scope; if(args.Length() == 0 || !args[0]->IsFunction()) { return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } TimeBaton* baton = new TimeBaton; baton->request.data = baton; baton->rawCommit = ObjectWrap::Unwrap(args.This())->GetValue(); baton->callback = Persistent::New(Local::Cast(args[0])); uv_queue_work(uv_default_loop(), &baton->request, TimeWork, (uv_after_work_cb)TimeAfterWork); return Undefined(); } void GitCommit::TimeWork(uv_work_t* req) { TimeBaton *baton = static_cast(req->data); baton->time = git_commit_time(baton->rawCommit); } void GitCommit::TimeAfterWork(uv_work_t* req) { HandleScope scope; TimeBaton *baton = static_cast(req->data); Handle argv[2] = { Local::New(Null()), Integer::New(baton->time) }; TryCatch try_catch; baton->callback->Call(Context::GetCurrent()->Global(), 2, argv); if (try_catch.HasCaught()) { node::FatalException(try_catch); } delete req; } Handle GitCommit::Offset(const Arguments& args) { HandleScope scope; if(args.Length() == 0 || !args[0]->IsFunction()) { return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } OffsetBaton* baton = new OffsetBaton; baton->request.data = baton; baton->rawCommit = ObjectWrap::Unwrap(args.This())->GetValue(); baton->callback = Persistent::New(Local::Cast(args[0])); uv_queue_work(uv_default_loop(), &baton->request, OffsetWork, (uv_after_work_cb)OffsetAfterWork); return Undefined(); } void GitCommit::OffsetWork(uv_work_t* req) { OffsetBaton *baton = static_cast(req->data); baton->offset = git_commit_time_offset(baton->rawCommit); } void GitCommit::OffsetAfterWork(uv_work_t* req) { HandleScope scope; OffsetBaton *baton = static_cast(req->data); Handle argv[2] = { Local::New(Null()), Integer::New(baton->offset) }; TryCatch try_catch; baton->callback->Call(Context::GetCurrent()->Global(), 2, argv); if (try_catch.HasCaught()) { node::FatalException(try_catch); } delete req; } Handle GitCommit::Author(const Arguments& args) { HandleScope scope; if(args.Length() == 0 || !args[0]->IsFunction()) { return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } SignatureBaton* baton = new SignatureBaton; baton->request.data = baton; baton->rawCommit = ObjectWrap::Unwrap(args.This())->GetValue(); baton->callback = Persistent::New(Local::Cast(args[0])); uv_queue_work(uv_default_loop(), &baton->request, AuthorWork, (uv_after_work_cb)AuthorAfterWork); return Undefined(); } void GitCommit::AuthorWork(uv_work_t* req) { SignatureBaton *baton = static_cast(req->data); baton->rawSignature = git_commit_author(baton->rawCommit); } void GitCommit::AuthorAfterWork(uv_work_t* req) { HandleScope scope; SignatureBaton *baton = static_cast(req->data); Local signature = GitSignature::constructor_template->NewInstance(); GitSignature *signatureInstance = ObjectWrap::Unwrap(signature); signatureInstance->SetValue(const_cast(baton->rawSignature)); Handle argv[2] = { Local::New(Null()), signature }; TryCatch try_catch; baton->callback->Call(Context::GetCurrent()->Global(), 2, argv); if (try_catch.HasCaught()) { node::FatalException(try_catch); } delete req; } Handle GitCommit::Committer(const Arguments& args) { HandleScope scope; if(args.Length() == 0 || !args[0]->IsFunction()) { return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } SignatureBaton* baton = new SignatureBaton; baton->request.data = baton; baton->rawCommit = ObjectWrap::Unwrap(args.This())->GetValue(); baton->callback = Persistent::New(Local::Cast(args[0])); uv_queue_work(uv_default_loop(), &baton->request, CommitterWork, (uv_after_work_cb)CommitterAfterWork); return Undefined(); } void GitCommit::CommitterWork(uv_work_t* req) { SignatureBaton *baton = static_cast(req->data); baton->rawSignature = git_commit_committer(baton->rawCommit); } void GitCommit::CommitterAfterWork(uv_work_t* req) { HandleScope scope; SignatureBaton *baton = static_cast(req->data); Local signature = GitSignature::constructor_template->NewInstance(); GitSignature *signatureInstance = ObjectWrap::Unwrap(signature); signatureInstance->SetValue(const_cast(baton->rawSignature)); Handle argv[2] = { Local::New(Null()), signature }; TryCatch try_catch; baton->callback->Call(Context::GetCurrent()->Global(), 2, argv); if (try_catch.HasCaught()) { node::FatalException(try_catch); } delete req; } Handle GitCommit::Tree(const Arguments& args) { HandleScope scope; if(args.Length() == 0 || !args[0]->IsFunction()) { return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } TreeBaton* baton = new TreeBaton; baton->request.data = baton; baton->error = NULL; baton->rawTree = NULL; baton->rawCommit = ObjectWrap::Unwrap(args.This())->GetValue(); baton->callback = Persistent::New(Local::Cast(args[0])); uv_queue_work(uv_default_loop(), &baton->request, TreeWork, (uv_after_work_cb)TreeAfterWork); return Undefined(); } void GitCommit::TreeWork(uv_work_t* req) { TreeBaton* baton = static_cast(req->data); int returnCode = git_commit_tree(&baton->rawTree, baton->rawCommit); if (returnCode != GIT_OK) { baton->error = giterr_last(); } } void GitCommit::TreeAfterWork(uv_work_t* req) { HandleScope scope; TreeBaton* baton = static_cast(req->data); if (success(baton->error, baton->callback)) { Local tree = GitTree::constructor_template->NewInstance(); GitTree *treeInstance = ObjectWrap::Unwrap(tree); treeInstance->SetValue(baton->rawTree); Handle argv[2] = { Local::New(Null()), tree }; TryCatch try_catch; baton->callback->Call(Context::GetCurrent()->Global(), 2, argv); if (try_catch.HasCaught()) { node::FatalException(try_catch); } } delete req; } Handle GitCommit::Parents(const Arguments& args) { HandleScope scope; if(args.Length() == 0 && !args[0]->IsFunction()) { return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } ParentsBaton* baton = new ParentsBaton; baton->request.data = baton; baton->error = NULL; baton->rawCommit = ObjectWrap::Unwrap(args.This())->GetValue(); baton->callback = Persistent::New(Local::Cast(args[0])); uv_queue_work(uv_default_loop(), &baton->request, ParentsWork, (uv_after_work_cb)ParentsAfterWork); return Undefined(); } void GitCommit::ParentsWork(uv_work_t* req) { ParentsBaton* baton = static_cast(req->data); int parentCount = git_commit_parentcount(baton->rawCommit); while (parentCount > 0) { git_commit* rawParentCommit = NULL; int parentIndex = parentCount -1; int returnCode = git_commit_parent(&rawParentCommit, baton->rawCommit, parentIndex); if (returnCode != GIT_OK) { baton->error = giterr_last(); return; } const git_oid* rawParentOid = git_commit_id(rawParentCommit); Parent* parent = new Parent; parent->rawCommit = rawParentCommit; parent->rawOid = rawParentOid; baton->parents.push_back(parent); parentCount--; } } void GitCommit::ParentsAfterWork(uv_work_t* req) { HandleScope scope; ParentsBaton* baton = static_cast(req->data); if (success(baton->error, baton->callback)) { std::vector > parents; for(std::vector::iterator parentIterator = baton->parents.begin(); parentIterator != baton->parents.end(); ++parentIterator) { Parent *parentData = (*parentIterator); Local parent = GitCommit::constructor_template->NewInstance(); GitCommit *parentInstance = ObjectWrap::Unwrap(parent); parentInstance->SetValue(parentData->rawCommit); parentInstance->SetOid(const_cast(parentData->rawOid)); parents.push_back(parent); } Handle argv[2] = { Local::New(Null()), cvv8::CastToJS(parents) }; TryCatch try_catch; baton->callback->Call(Context::GetCurrent()->Global(), 2, argv); if (try_catch.HasCaught()) { node::FatalException(try_catch); } } delete req; } Persistent GitCommit::constructor_template;