diff --git a/.gitignore b/.gitignore index 052792737..64ce99175 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ /build/ /test/coverage/ /test/repos/ -/test/test/repos/ +/test/test/ /src/ /include/ /lib/enums.js diff --git a/example/create-new-repo.js b/example/create-new-repo.js index c934476d9..91be1ea54 100644 --- a/example/create-new-repo.js +++ b/example/create-new-repo.js @@ -14,37 +14,29 @@ var index; fse.ensureDir(path.resolve(__dirname, repoDir)) .then(function() { - console.log('a'); return nodegit.Repository.init(path.resolve(__dirname, repoDir), 0); }) .then(function(repo) { - console.log('b'); repository = repo; return fse.writeFile(path.join(repository.workdir(), fileName), fileContent); }) .then(function(){ - console.log('c'); return repository.openIndex(); }) .then(function(idx) { - console.log('d'); index = idx; return index.read(1); }) .then(function() { - console.log('e'); return index.addByPath(fileName); }) .then(function() { - console.log('f'); return index.write(); }) .then(function() { - console.log('g'); return index.writeTree(); }) .then(function(oid) { - console.log('j'); var author = nodegit.Signature.create("Scott Chacon", "schacon@gmail.com", 123456789, 60); var committer = nodegit.Signature.create("Scott A Chacon", "scott@github.com", 987654321, 90); diff --git a/example/details-for-tree-entry.js b/example/details-for-tree-entry.js index c17c6d065..2197fed6f 100644 --- a/example/details-for-tree-entry.js +++ b/example/details-for-tree-entry.js @@ -7,8 +7,7 @@ var path = require('path'); nodegit.Repository.open(path.resolve(__dirname, '../.git')) .then(function(repo) { - return repo.getTree( - nodegit.Oid.fromString("e1b0c7ea57bfc5e30ec279402a98168a27838ac9")) + return repo.getTree("e1b0c7ea57bfc5e30ec279402a98168a27838ac9") .then(function(tree) { var treeEntry = tree.entryByIndex(0); diff --git a/example/fetch.js b/example/fetch.js index 927a2b8db..4b5471874 100644 --- a/example/fetch.js +++ b/example/fetch.js @@ -2,10 +2,7 @@ var nodegit = require('../'); var path = require('path'); nodegit.Repository.open(path.resolve(__dirname, '../.git')).then(function(repo) { - return nodegit.Remote.load(repo, "origin"); -}).then(function(remote) { - remote.connect(0); - return remote.download(); + return repo.fetch("origin"); }) .done(function() { console.log("It worked!"); diff --git a/generate/combyne/filters/is_oid.js b/generate/combyne/filters/is_oid.js new file mode 100644 index 000000000..1d13f700f --- /dev/null +++ b/generate/combyne/filters/is_oid.js @@ -0,0 +1,3 @@ +module.exports = function(arg) { + return arg.cppClassName == "GitOid" && !arg.isSelf && !arg.isReturn; +}; diff --git a/generate/combyne/partials/async_function.cc b/generate/combyne/partials/async_function.cc index 0197c4281..95f26fdf2 100644 --- a/generate/combyne/partials/async_function.cc +++ b/generate/combyne/partials/async_function.cc @@ -1,9 +1,8 @@ -{% partial doc . %} +{%partial doc .%} NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) { NanScope(); - {% partial guardArguments . %} - + {%partial guardArguments .%} if (args.Length() == {{args|jsArgsCount}} || !args[{{args|jsArgsCount}}]->IsFunction()) { return NanThrowError("Callback is required and must be a Function."); } @@ -13,85 +12,90 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) { baton->error_code = GIT_OK; baton->error = NULL; - {% each args|argsInfo as arg %} - {% if not arg.isReturn %} - {% if arg.isSelf %} - baton->{{ arg.name }} = ObjectWrap::Unwrap<{{ arg.cppClassName }}>(args.This())->GetValue(); - {% elsif arg.name %} - {% partial convertFromV8 arg %} - {% if not arg.isPayload %} - baton->{{ arg.name }} = from_{{ arg.name }}; - {% endif %} - {% endif %} - {% elsif arg.shouldAlloc %} - baton->{{ arg.name }} = ({{ arg.cType }})malloc(sizeof({{ arg.cType|replace '*' '' }})); - {% endif %} - {% endeach %} + {%each args|argsInfo as arg %} + {%if not arg.isReturn %} + {%if arg.isSelf %} + baton->{{ arg.name }} = ObjectWrap::Unwrap<{{ arg.cppClassName }}>(args.This())->GetValue(); + {%elsif arg.name %} + {%partial convertFromV8 arg%} + {%if not arg.isPayload %} + baton->{{ arg.name }} = from_{{ arg.name }}; + {%if arg | isOid %} + baton->{{ arg.name }}NeedsFree = args[{{ arg.jsArg }}]->IsString(); + {%endif%} + {%endif%} + {%endif%} + {%elsif arg.shouldAlloc %} + baton->{{ arg.name }} = ({{ arg.cType }})malloc(sizeof({{ arg.cType|replace '*' '' }})); + {%endif%} + {%endeach%} NanCallback *callback = new NanCallback(Local::Cast(args[{{args|jsArgsCount}}])); {{ cppFunctionName }}Worker *worker = new {{ cppFunctionName }}Worker(baton, callback); - {% each args|argsInfo as arg %} - {% if not arg.isReturn %} - {% if arg.isSelf %} + {%each args|argsInfo as arg %} + {%if not arg.isReturn %} + {%if arg.isSelf %} worker->SaveToPersistent("{{ arg.name }}", args.This()); - {% else %} + {%else%} if (!args[{{ arg.jsArg }}]->IsUndefined() && !args[{{ arg.jsArg }}]->IsNull()) worker->SaveToPersistent("{{ arg.name }}", args[{{ arg.jsArg }}]->ToObject()); - {% endif %} - {% endif %} - {% endeach %} + {%endif%} + {%endif%} + {%endeach%} NanAsyncQueueWorker(worker); NanReturnUndefined(); } -// startexecute {{ cppFunctionName }} void {{ cppClassName }}::{{ cppFunctionName }}Worker::Execute() { - {% if .|hasReturnType %} - {{ return.cType }} result = {{ cFunctionName }} - {% else %} - {{ cFunctionName }} - {% endif %} - ( - - {% each .args|argsInfo as arg %} - {% if arg.isReturn|and arg.cType|isDoublePointer %}&{% endif %}baton->{{ arg.name }}{% if not arg.lastArg %},{% endif %} - {% endeach %} - ); - - {% if return.isErrorCode %} - baton->error_code = result; - - if (result != GIT_OK && giterr_last() != NULL) { - baton->error = git_error_dup(giterr_last()); - } - {% elsif not return.cType == 'void' %} - baton->result = result; - {% endif %} + {%if .|hasReturnType %} + {{ return.cType }} result = {{ cFunctionName }}( + {%else%} + {{ cFunctionName }}( + {%endif%} + {%-- Insert Function Arguments --%} + {%each args|argsInfo as arg %} + {%-- turn the pointer into a ref --%} + {%if arg.isReturn|and arg.cType|isDoublePointer %}&{%endif%}baton->{{ arg.name }}{%if not arg.lastArg %},{%endif%} + + {%endeach%} + ); + + {%if return.isErrorCode %} + baton->error_code = result; + + if (result != GIT_OK && giterr_last() != NULL) { + baton->error = git_error_dup(giterr_last()); + } + + {%elsif not return.cType == 'void' %} + + baton->result = result; + + {%endif%} } -// done void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { TryCatch try_catch; if (baton->error_code == GIT_OK) { - {% if not .|returnsCount %} + {%if not .|returnsCount %} Handle result = NanUndefined(); - {% else %} + {%else%} Handle to; - {% if .|returnsCount > 1 %} + {%if .|returnsCount > 1 %} Handle result = NanNew(); - {% endif %} - {% each .|returnsInfo 0 1 as _return %} - {% partial convertToV8 _return %} - {% if .|returnsCount > 1 %} + {%endif%} + {%each .|returnsInfo 0 1 as _return %} + {%partial convertToV8 _return %} + {%if .|returnsCount > 1 %} result->Set(NanNew("{{ _return.returnNameOrName }}"), to); - {% endif %} - {% endeach %} - {% if .|returnsCount == 1 %} + {%endif%} + {%endeach%} + {%if .|returnsCount == 1 %} Handle result = to; - {% endif %} - {% endif %} + {%endif%} + {%endif%} Handle argv[2] = { NanNull(), result @@ -110,26 +114,30 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { callback->Call(0, NULL); } - {% each args as arg %} - {% if arg.shouldAlloc %} + {%each args as arg %} + {%if arg.shouldAlloc %} free((void*)baton->{{ arg.name }}); - {% endif %} - {% endeach %} + {%endif%} + {%endeach%} } if (try_catch.HasCaught()) { node::FatalException(try_catch); } - {% each args|argsInfo as arg %} - {% if arg.isCppClassStringOrArray %} - {% if arg.freeFunctionName %} + {%each args|argsInfo as arg %} + {%if arg.isCppClassStringOrArray %} + {%if arg.freeFunctionName %} {{ arg.freeFunctionName }}(baton->{{ arg.name }}); - {% else %} + {%else%} free((void *)baton->{{ arg.name }}); - {% endif %} - {% endif %} - {% endeach %} + {%endif%} + {%elsif arg | isOid %} + if (baton->{{ arg.name}}NeedsFree) { + free((void *)baton->{{ arg.name }}); + } + {%endif%} + {%endeach%} delete baton; } diff --git a/generate/combyne/partials/convert_from_v8.cc b/generate/combyne/partials/convert_from_v8.cc index 45128e591..638f4f016 100644 --- a/generate/combyne/partials/convert_from_v8.cc +++ b/generate/combyne/partials/convert_from_v8.cc @@ -1,53 +1,87 @@ -{% if not isPayload %} +{%if not isPayload %} +// start convert_from_v8 block {{ cType }} from_{{ name }}; - {% if isOptional %} - if (args[{{ jsArg }}]->Is{{ cppClassName|cppToV8 }}()) { - {% endif %} + {%if isOptional | or isBoolean %} - {% if cppClassName == 'String' %} + if (args[{{ jsArg }}]->Is{{ cppClassName|cppToV8 }}()) { + {%endif%} + {%if cppClassName == 'String'%} - String::Utf8Value {{ name }}(args[{{ jsArg }}]->ToString()); - from_{{ name }} = ({{ cType }}) strdup(*{{ name }}); + String::Utf8Value {{ name }}(args[{{ jsArg }}]->ToString()); + from_{{ name }} = ({{ cType }}) strdup(*{{ name }}); + {%elsif cppClassName == 'Wrapper'%} - {% elsif cppClassName == 'Wrapper' %} + String::Utf8Value {{ name }}(args[{{ jsArg }}]->ToString()); + from_{{ name }} = ({{ cType }}) strdup(*{{ name }}); + {%elsif cppClassName == 'Array'%} - String::Utf8Value {{ name }}(args[{{ jsArg }}]->ToString()); - from_{{ name }} = ({{ cType }}) strdup(*{{ name }}); + Array *tmp_{{ name }} = Array::Cast(*args[{{ jsArg }}]); + from_{{ name }} = ({{ cType }})malloc(tmp_{{ name }}->Length() * sizeof({{ cType|replace '**' '*' }})); + for (unsigned int i = 0; i < tmp_{{ name }}->Length(); i++) { + {%-- + // FIXME: should recursively call convertFromv8. + --%} + from_{{ name }}[i] = ObjectWrap::Unwrap<{{ arrayElementCppClassName }}>(tmp_{{ name }}->Get(NanNew(static_cast(i)))->ToObject())->GetValue(); + } + {%elsif cppClassName == 'Function'%} + {%elsif cppClassName == 'Buffer'%} - {% elsif cppClassName == 'Array' %} + from_{{ name }} = Buffer::Data(args[{{ jsArg }}]->ToObject()); + {%elsif cppClassName|isV8Value %} - Array *tmp_{{ name }} = Array::Cast(*args[{{ jsArg }}]); - from_{{ name }} = ({{ cType }})malloc(tmp_{{ name }}->Length() * sizeof({{ cType|replace '**' '*' }})); - for (unsigned int i = 0; i < tmp_{{ name }}->Length(); i++) { + {%if cType|isPointer %} + *from_{{ name }} = ({{ cType|unPointer }}) {{ cast }} {%if isEnum %}(int){%endif%} args[{{ jsArg }}]->To{{ cppClassName }}()->Value(); + {%else%} + from_{{ name }} = ({{ cType }}) {{ cast }} {%if isEnum %}(int){%endif%} args[{{ jsArg }}]->To{{ cppClassName }}()->Value(); + {%endif%} + {%elsif cppClassName == 'GitOid'%} + if (args[{{ jsArg }}]->IsString()) { + // Try and parse in a string to a git_oid + String::Utf8Value oidString(args[{{ jsArg }}]->ToString()); + git_oid *oidOut = (git_oid *)malloc(sizeof(git_oid)); - {%-- FIXME: should recursively call convertFromv8. --%} - from_{{ name }}[i] = ObjectWrap::Unwrap<{{ arrayElementCppClassName }}>(tmp_{{ name }}->Get(NanNew(static_cast(i)))->ToObject())->GetValue(); - } - {% elsif cppClassName == 'Function' %} - - {% elsif cppClassName == 'Buffer' %} - - from_{{ name }} = Buffer::Data(args[{{ jsArg }}]->ToObject()); - - {% elsif cppClassName|isV8Value %} - {% if cType|isPointer %} - *from_{{ name }} = ({{ cType|unPointer }}) {{ cast }} {% if isEnum %}(int){% endif %} args[{{ jsArg }}]->To{{ cppClassName }}()->Value(); - {% else %} - from_{{ name }} = ({{ cType }}) {{ cast }} {% if isEnum %}(int){% endif %} args[{{ jsArg }}]->To{{ cppClassName }}()->Value(); - {% endif %} - {% else %} - {% if cType|isDoublePointer %} - from_{{ name }} = ObjectWrap::Unwrap<{{ cppClassName }}>(args[{{ jsArg }}]->ToObject())->GetRefValue(); - {% else %} - from_{{ name }} = ObjectWrap::Unwrap<{{ cppClassName }}>(args[{{ jsArg }}]->ToObject())->GetValue(); - {% endif %} - {% endif %} - - {% if isOptional %} - } - else { - from_{{ name }} = 0; + if (git_oid_fromstr(oidOut, (const char *) strdup(*oidString)) != GIT_OK) { + free(oidOut); + + if (giterr_last()) { + return NanThrowError(giterr_last()->message); + } else { + return NanThrowError("Unknown Error"); + } } - {% endif %} -{% endif %} + {%if cType|isDoublePointer %} + from_{{ name }} = &oidOut; + {%else%} + from_{{ name }} = oidOut; + {%endif%} + } + else { + {%if cType|isDoublePointer %} + from_{{ name }} = ObjectWrap::Unwrap<{{ cppClassName }}>(args[{{ jsArg }}]->ToObject())->GetRefValue(); + {%else%} + from_{{ name }} = ObjectWrap::Unwrap<{{ cppClassName }}>(args[{{ jsArg }}]->ToObject())->GetValue(); + {%endif%} + } + {%else%} + {%if cType|isDoublePointer %} + from_{{ name }} = ObjectWrap::Unwrap<{{ cppClassName }}>(args[{{ jsArg }}]->ToObject())->GetRefValue(); + {%else%} + from_{{ name }} = ObjectWrap::Unwrap<{{ cppClassName }}>(args[{{ jsArg }}]->ToObject())->GetValue(); + {%endif%} + {%endif%} + + {%if isBoolean %} + } + else { + from_{{ name }} = args[{{ jsArg }}]->IsTrue() ? 1 : 0; + } + {%elsif isOptional %} + } + else { + from_{{ name }} = 0; + } + + {%endif%} +// end convert_from_v8 block +{%endif%} diff --git a/generate/combyne/partials/guard_arguments.cc b/generate/combyne/partials/guard_arguments.cc index 278c5c27a..5179ce908 100644 --- a/generate/combyne/partials/guard_arguments.cc +++ b/generate/combyne/partials/guard_arguments.cc @@ -1,9 +1,19 @@ -{% each args|argsInfo as arg %} - {% if arg.isJsArg %} - {% if not arg.isOptional %} - if (args.Length() == {{arg.jsArg}} || !args[{{arg.jsArg}}]->Is{{arg.cppClassName|cppToV8}}()) { - return NanThrowError("{{arg.jsClassName}} {{arg.name}} is required."); - } - {% endif %} - {% endif %} -{% endeach %} + +{%each args|argsInfo as arg%} + {%if arg.isJsArg%} + {%if not arg.isOptional%} + {%if arg | isOid %} + if (args.Length() == {{arg.jsArg}} + || (!args[{{arg.jsArg}}]->IsObject() && !args[{{arg.jsArg}}]->IsString())) { + return NanThrowError("{{arg.jsClassName}} {{arg.name}} is required."); + } + + {%else%} + if (args.Length() == {{arg.jsArg}} || !args[{{arg.jsArg}}]->Is{{arg.cppClassName|cppToV8}}()) { + return NanThrowError("{{arg.jsClassName}} {{arg.name}} is required."); + } + + {%endif%} + {%endif%} + {%endif%} +{%endeach%} diff --git a/generate/combyne/partials/sync_function.cc b/generate/combyne/partials/sync_function.cc index df627de3b..243c1654e 100644 --- a/generate/combyne/partials/sync_function.cc +++ b/generate/combyne/partials/sync_function.cc @@ -1,86 +1,93 @@ -{% partial doc . %} + +{%partial doc .%} NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) { NanEscapableScope(); - {% partial guardArguments . %} - - {% each .|returnsInfo 'true' as _return %} - {% if _return.shouldAlloc %} - {{ _return.cType }}{{ _return.name }} = ({{ _return.cType }})malloc(sizeof({{ _return.cType|unPointer }})); - {% else %} - {{ _return.cType|unPointer }} {{ _return.name }} = {{ _return.cType|unPointer|defaultValue }}; - {% endif %} - {% endeach %} + {%partial guardArguments .%} - {% each args|argsInfo as arg %} - {% if not arg.isSelf %} - {% if not arg.isReturn %} - {% partial convertFromV8 arg %} - {% endif %} - {% endif %} - {% endeach %} + {%each .|returnsInfo 'true' as _return %} + {%if _return.shouldAlloc %} + {{ _return.cType }}{{ _return.name }} = ({{ _return.cType }})malloc(sizeof({{ _return.cType|unPointer }})); + {%else%} + {{ _return.cType|unPointer }} {{ _return.name }} = {{ _return.cType|unPointer|defaultValue }}; + {%endif%} + {%endeach%} - {% if .|hasReturns %} - {{ return.cType }} result = - {% endif %} - {{ cFunctionName }}( - {% each args|argsInfo as arg %} - {% if arg.isReturn %} - {% if not arg.shouldAlloc %}&{% endif %} - {% endif %} - {% if arg.isSelf %} - ObjectWrap::Unwrap<{{ arg.cppClassName }}>(args.This())->GetValue() - {% elsif arg.isReturn %} - {{ arg.name }} - {% else %} - from_{{ arg.name }} - {% endif %} + {%each args|argsInfo as arg %} + {%if not arg.isSelf %} + {%if not arg.isReturn %} + {%partial convertFromV8 arg %} + {%endif%} + {%endif%} + {%endeach%} - {% if not arg.lastArg %},{% endif %} - {% endeach %} - ); +{%if .|hasReturns %} + {{ return.cType }} result = {%endif%}{{ cFunctionName }}( + {%each args|argsInfo as arg %} + {%if arg.isReturn %} + {%if not arg.shouldAlloc %}&{%endif%} + {%endif%} + {%if arg.isSelf %} +ObjectWrap::Unwrap<{{ arg.cppClassName }}>(args.This())->GetValue() + {%elsif arg.isReturn %} +{{ arg.name }} + {%else%} +from_{{ arg.name }} + {%endif%} + {%if not arg.lastArg %},{%endif%} + {%endeach%} + ); +{%if return.isErrorCode %} + if (result != GIT_OK) { + {%each args|argsInfo as arg %} + {%if arg.shouldAlloc %} + free({{ arg.name }}); + {%elsif arg | isOid %} + if (args[{{ arg.jsArg }}]->IsString()) { + free({{ arg.name }}); + } + {%endif%} + {%endeach%} - {% if return.isErrorCode %} - if (result != GIT_OK) { - {% each args|argsInfo as arg %} - {% if arg.shouldAlloc %} - free({{ arg.name }}); - {% endif %} - {% endeach %} + if (giterr_last()) { + return NanThrowError(giterr_last()->message); + } else { + return NanThrowError("Unknown Error"); + } + } +{%endif%} - if (giterr_last()) { - return NanThrowError(giterr_last()->message); - } else { - return NanThrowError("Unknown Error"); - } - } - {% endif %} +{%each args|argsInfo as arg %} + {%if arg | isOid %} + if (args[{{ arg.jsArg }}]->IsString()) { + free(&from_{{ arg.name }}); + } + {%endif%} +{%endeach%} - {% if not .|returnsCount %} - NanReturnUndefined(); - {% else %} - {% if return.cType | isPointer %} +{%if not .|returnsCount %} + NanReturnUndefined(); +{%else%} + {%if return.cType | isPointer %} // null checks on pointers - if (!result) { - NodeGitPsueodoNanReturnEscapingValue(NanUndefined()); - } - {% endif %} - - Handle to; - {% if .|returnsCount > 1 %} - Handle toReturn = NanNew(); - {% endif %} - - {% each .|returnsInfo as _return %} - {% partial convertToV8 _return %} - {% if .|returnsCount > 1 %} - toReturn->Set(NanNew("{{ _return.returnNameOrName }}"), to); - {% endif %} - {% endeach %} + if (!result) { + NodeGitPsueodoNanReturnEscapingValue(NanUndefined()); + } + {%endif%} - {% if .|returnsCount == 1 %} - NodeGitPsueodoNanReturnEscapingValue(to); - {% else %} - NodeGitPsueodoNanReturnEscapingValue(toReturn); - {% endif %} - {% endif %} + Handle to; + {%if .|returnsCount > 1 %} + Handle toReturn = NanNew(); + {%endif%} + {%each .|returnsInfo as _return %} + {%partial convertToV8 _return %} + {%if .|returnsCount > 1 %} + toReturn->Set(NanNew("{{ _return.returnNameOrName }}"), to); + {%endif%} + {%endeach%} + {%if .|returnsCount == 1 %} + NodeGitPsueodoNanReturnEscapingValue(to); + {%else%} + NodeGitPsueodoNanReturnEscapingValue(toReturn); + {%endif%} +{%endif%} } diff --git a/generate/combyne/templates/class_header.h b/generate/combyne/templates/class_header.h index 0e23d702f..d438e0317 100644 --- a/generate/combyne/templates/class_header.h +++ b/generate/combyne/templates/class_header.h @@ -5,26 +5,26 @@ #include extern "C" { - #include - {% each cDependencies as dependency %} - #include <{{ dependency }}> - {% endeach %} +#include +{%each cDependencies as dependency %} +#include <{{ dependency }}> +{%endeach%} } -{% each dependencies as dependency %} - #include "{{ dependency }}" -{% endeach %} - -{% if needsForwardDeclaration %} - // Forward declaration. - struct {{ cType }} { - {% each fields as field %} - {% if not field.ignore %} - {{ field.structType|or field.cType }} {{ field.structName|or field.name }}; - {% endif %} - {% endeach %} - }; -{% endif %} +{%each dependencies as dependency%} +#include "{{ dependency }}" +{%endeach%} + +{%if needsForwardDeclaration %} +// Forward declaration. +struct {{ cType }} { + {%each fields as field%} + {%if not field.ignore%} + {{ field.structType|or field.cType }} {{ field.structName|or field.name }}; + {%endif%} + {%endeach%} +}; +{%endif%} using namespace node; using namespace v8; @@ -35,70 +35,69 @@ class {{ cppClassName }} : public ObjectWrap { static Persistent constructor_template; static void InitializeComponent (Handle target); - {% if cType %} - {{ cType }} *GetValue(); - {{ cType }} **GetRefValue(); - - static Handle New(void *raw, bool selfFreeing); - - {% endif %} + {%if cType%} + {{ cType }} *GetValue(); + {{ cType }} **GetRefValue(); + static Handle New(void *raw, bool selfFreeing); + {%endif%} bool selfFreeing; private: - {% if cType %} - {{ cppClassName }}({{ cType }} *raw, bool selfFreeing); - ~{{ cppClassName }}(); - {% endif %} + {%if cType%} + {{ cppClassName }}({{ cType }} *raw, bool selfFreeing); + ~{{ cppClassName }}(); + {%endif%} static NAN_METHOD(New); - {% each fields as field %} - {% if not field.ignore %} - static NAN_METHOD({{ field.cppFunctionName }}); - {% endif %} - {% endeach %} - - {% each functions as function %} - {% if not function.ignore %} - {% if function.isAsync %} - - struct {{ function.cppFunctionName }}Baton { - int error_code; - const git_error* error; - {% each function.args as arg %} - {% if arg.isReturn %} - {{ arg.cType|replace "**" "*" }} {{ arg.name }}; - {% else %} - {{ arg.cType }} {{ arg.name }}; - {% endif %} - {% endeach %} - }; - - class {{ function.cppFunctionName }}Worker : public NanAsyncWorker { - public: - {{ function.cppFunctionName }}Worker( - {{ function.cppFunctionName }}Baton *_baton, - NanCallback *callback - ) : NanAsyncWorker(callback) - , baton(_baton) {}; - ~{{ function.cppFunctionName }}Worker() {}; - void Execute(); - void HandleOKCallback(); - - private: - {{ function.cppFunctionName }}Baton *baton; - - }; - {% endif %} - - static NAN_METHOD({{ function.cppFunctionName }}); - {% endif %} - {% endeach %} - - {% if cType %} - {{ cType }} *raw; - {% endif %} + {%each fields as field%} + {%if not field.ignore%} + static NAN_METHOD({{ field.cppFunctionName }}); + {%endif%} + {%endeach%} + + {%each functions as function%} + {%if not function.ignore%} + {%if function.isAsync%} + + struct {{ function.cppFunctionName }}Baton { + int error_code; + const git_error* error; + {%each function.args as arg%} + {%if arg.isReturn%} + {{ arg.cType|replace "**" "*" }} {{ arg.name }}; + {%else%} + {{ arg.cType }} {{ arg.name }}; + {%if arg | isOid %} + bool {{ arg.name }}NeedsFree; + {%endif%} + {%endif%} + {%endeach%} + }; + class {{ function.cppFunctionName }}Worker : public NanAsyncWorker { + public: + {{ function.cppFunctionName }}Worker( + {{ function.cppFunctionName }}Baton *_baton, + NanCallback *callback + ) : NanAsyncWorker(callback) + , baton(_baton) {}; + ~{{ function.cppFunctionName }}Worker() {}; + void Execute(); + void HandleOKCallback(); + + private: + {{ function.cppFunctionName }}Baton *baton; + }; + {%endif%} + + static NAN_METHOD({{ function.cppFunctionName }}); + {%endif%} + {%endeach%} + + {%if cType%} + {{ cType }} *raw; + {%endif%} }; #endif diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index d28660112..eeff8f1ba 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -1068,6 +1068,13 @@ "git_remote_default_branch": { "ignore": true }, + "git_remote_fetch": { + "args": { + "reflog_message": { + "isOptional": true + } + } + }, "git_remote_get_fetch_refspecs": { "ignore": true }, @@ -1156,6 +1163,9 @@ }, "signature": { "functions": { + "git_signature_default": { + "isAsync": false + }, "git_signature_new": { "isAsync": false }, diff --git a/generate/scripts/generateNativeCode.js b/generate/scripts/generateNativeCode.js index 8ee98f74c..0960ec357 100644 --- a/generate/scripts/generateNativeCode.js +++ b/generate/scripts/generateNativeCode.js @@ -62,6 +62,7 @@ module.exports = function() { isV8Value: require("../combyne/filters/is_v8_value"), isPointer: require("../combyne/filters/is_pointer"), isDoublePointer: require("../combyne/filters/is_double_pointer"), + isOid: require("../combyne/filters/is_oid"), unPointer: require("../combyne/filters/un_pointer"), payloadFor: require("../combyne/filters/payload_for"), hasReturnType: require("../combyne/filters/has_return_type"), diff --git a/lib/blob.js b/lib/blob.js index 4f8527273..842f2e114 100644 --- a/lib/blob.js +++ b/lib/blob.js @@ -1,8 +1,18 @@ var NodeGit = require("../"); var TreeEntry = require("./tree_entry"); +var LookupWrapper = require("./util/lookupWrapper"); var Blob = NodeGit.Blob; +/** +* Retrieves the blob pointed to by the oid +* @param {Repository} repo The repo that the blob lives in +* @param {String|Oid|Blob} id The blob to lookup +* @param {Function} callback +* @return {Blob} +*/ +Blob.lookup = LookupWrapper(Blob); + /** * Retrieve the content of the Blob. * diff --git a/lib/commit.js b/lib/commit.js index 55cebfb45..9a8a9a4fe 100644 --- a/lib/commit.js +++ b/lib/commit.js @@ -1,9 +1,19 @@ var events = require("events"); var Promise = require("nodegit-promise"); var NodeGit = require("../"); +var LookupWrapper = require("./util/lookupWrapper"); var Commit = NodeGit.Commit; +/** + * Retrieves the commit pointed to by the oid + * @param {Repository} repo The repo that the commit lives in + * @param {String|Oid|Commit} id The commit to lookup + * @param {Function} callback + * @return {Commit} + */ +Commit.lookup = LookupWrapper(Commit); + /** * Retrieve the SHA. * @return {String} diff --git a/lib/merge.js b/lib/merge.js index cd96c88ce..fb9a8b0b5 100644 --- a/lib/merge.js +++ b/lib/merge.js @@ -1,5 +1,6 @@ var NodeGit = require("../"); var normalizeOptions = require("./util/normalize_options"); +var Promise = require("nodegit-promise"); var Merge = NodeGit.Merge; var mergeCommits = Merge.commits; @@ -16,7 +17,12 @@ var mergeCommits = Merge.commits; Merge.commits = function(repo, ourCommit, theirCommit, options) { options = normalizeOptions(options, NodeGit.MergeOptions); - return mergeCommits.call(this, repo, ourCommit, theirCommit, options); + return Promise.all([ + repo.getCommit(ourCommit), + repo.getCommit(theirCommit) + ]).then(function(commits) { + return mergeCommits.call(this, repo, commits[0], commits[1], options); + }); }; module.exports = Merge; diff --git a/lib/odb.js b/lib/odb.js index 12e7c82c1..72d26af52 100644 --- a/lib/odb.js +++ b/lib/odb.js @@ -1,12 +1,9 @@ var git = require("../"); -var normalizeOid = require("./util/normalize_oid"); var Odb = git.Odb; var read = Odb.prototype.read; Odb.prototype.read = function(oid, callback) { - oid = normalizeOid(oid); - return read.call(this, oid).then(function(odbObject) { if (typeof callback === "function") { callback(null, odbObject); diff --git a/lib/reference.js b/lib/reference.js index eab158eb0..cb308c017 100644 --- a/lib/reference.js +++ b/lib/reference.js @@ -1,8 +1,18 @@ var NodeGit = require("../"); +var LookupWrapper = require("./util/lookupWrapper"); var Reference = NodeGit.Reference; var Branch = NodeGit.Branch; +/** +* Retrieves the reference pointed to by the oid +* @param {Repository} repo The repo that the reference lives in +* @param {String|Reference} id The reference to lookup +* @param {Function} callback +* @return {Reference} +*/ +Reference.lookup = LookupWrapper(Reference); + /** * Returns true if this reference is valid * @return {Boolean} diff --git a/lib/repository.js b/lib/repository.js index f42314724..42e91419d 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -1,5 +1,4 @@ var NodeGit = require("../"); -var normalizeOid = require("./util/normalize_oid"); var Blob = require("./blob"); var Tree = require("./tree"); var Tag = require("./tag"); @@ -56,12 +55,14 @@ function(name, commit, force, signature, logMessage) { /** * Look up a branch * - * @param {String} name Branch name, e.g. "master" + * @param {String|Ref} name Branch name, e.g. "master" or Branch Ref * @param {Function} callback * @return {Ref} */ Repository.prototype.getBranch = function(name, callback) { - name = ~name.indexOf("refs/heads/") ? name : "refs/heads/" + name; + name = (name instanceof Reference || + ~name.indexOf("refs/heads/")) ? name + : "refs/heads/" + name; return this.getReference(name).then(function(reference) { if (typeof callback === "function") { @@ -75,7 +76,7 @@ Repository.prototype.getBranch = function(name, callback) { /** * Look up a branch's most recent commit. * - * @param {String} name Branch name, e.g. "master" + * @param {String|Ref} name Branch name, e.g. "master" or Branch Ref * @param {Function} callback * @return {Commit} */ @@ -94,19 +95,12 @@ Repository.prototype.getBranchCommit = function(name, callback) { }; /** - * Lists out the remotes in the given repository. - * - * @param {Function} Optional callback - * @return {Object} Promise object. + * Gets the branch that HEAD currently points to + * Is an alias to head() + * @return {Reference} */ -Repository.prototype.getRemotes = function(callback) { - return Remote.list(this).then(function(remotes) { - if (typeof callback === "function") { - callback(null, remotes); - } - - return remotes; - }, callback); +Repository.prototype.getCurrentBranch = function() { + return this.head(); }; /** @@ -194,8 +188,6 @@ Repository.prototype.getReferenceNames = function(type, callback) { * @return {Commit} */ Repository.prototype.getCommit = function(oid, callback) { - oid = normalizeOid(oid); - var repository = this; return Commit.lookup(repository, oid).then(function(commit) { @@ -217,7 +209,6 @@ Repository.prototype.getCommit = function(oid, callback) { * @return {Blob} */ Repository.prototype.getBlob = function(oid, callback) { - oid = normalizeOid(oid); var repository = this; return Blob.lookup(repository, oid).then(function(blob) { @@ -239,8 +230,6 @@ Repository.prototype.getBlob = function(oid, callback) { * @return {Tree} */ Repository.prototype.getTree = function(oid, callback) { - oid = normalizeOid(oid); - var repository = this; return Tree.lookup(repository, oid).then(function(tree) { @@ -262,8 +251,6 @@ Repository.prototype.getTree = function(oid, callback) { * @return {Tag} */ Repository.prototype.getTag = function(oid, callback) { - oid = normalizeOid(oid); - var repository = this; return Tag.lookup(repository, oid).then(function(reference) { @@ -326,6 +313,20 @@ Repository.prototype.getMasterCommit = function(callback) { return this.getBranchCommit("master", callback); }; +/** + * Retrieve the commit that HEAD is currently pointing to + * + * @param {Function} callback + * @return {Commit} + */ +Repository.prototype.getHeadCommit = function(callback) { + var repo = this; + + return Reference.nameToId(repo, "HEAD").then(function(head) { + return repo.getCommit(head, callback); + }); +}; + /** * Create a commit * @@ -341,40 +342,40 @@ Repository.prototype.getMasterCommit = function(callback) { Repository.prototype.createCommit = function( updateRef, author, committer, message, tree, parents, callback) { - var createCommit = null; var repo = this; + var promises = []; - if (tree instanceof Tree) { - createCommit = Promise.all([ - Commit.create( - repo, - updateRef, - author, - committer, - null /* use default message encoding */, - message, - tree, - parents.length, - parents - ) - ]); - } else { - createCommit = this.getTree(tree).then(function(tree) { - return Commit.create( - repo, - updateRef, - author, - committer, - null /* use default message encoding */, - message, - tree, - parents.length, - parents - ); - }); - } + parents = parents || []; + + promises.push(repo.getTree(tree)); + + parents.forEach(function(parent) { + promises.push(repo.getCommit(parent)); + }); + + return Promise.all(promises).then(function(results) { + tree = results[0]; + + // Get the normalized values for our input into the function + var parentsLength = parents.length; + parents = []; - return createCommit.then(function(commit) { + for (var i = 0; i < parentsLength; i++) { + parents.push(results[i + 1]); + } + + return Commit.create( + repo, + updateRef, + author, + committer, + null /* use default message encoding */, + message, + tree, + parents.length, + parents + ); + }).then(function(commit) { if (typeof callback === "function") { callback(null, commit); } @@ -383,6 +384,48 @@ Repository.prototype.createCommit = function( }, callback); }; +/** + * Creates a new commit on HEAD from the list of passed in files + * @param {Array} filesToAdd + * @param {Signature} author + * @param {Signature} committer + * @param {String} message + * @param {Function} callback + * @return {Oid} The oid of the new commit + */ +Repository.prototype.createCommitOnHead = function( + filesToAdd, + author, + committer, + message, + callback){ + var repo = this; + + return repo.openIndex().then(function(index) { + index.read(true); + + filesToAdd.forEach(function(filePath) { + index.addByPath(filePath); + }); + + index.write(); + + return index.writeTree(); + }).then(function(treeOid) { + + return repo.getHeadCommit().then(function(parent) { + return repo.createCommit( + "HEAD", + author, + committer, + message, + treeOid, + [parent], + callback); + }); + }, callback); +}; + /** * Create a blob from a buffer * @@ -408,4 +451,171 @@ Repository.prototype.treeBuilder = function() { return builder; }; +/** + * Gets the default signature for the default user and now timestamp + * @return {Signature} + */ +Repository.prototype.defaultSignature = function() { + return NodeGit.Signature.default(this); +}; + +/** +* Lists out the remotes in the given repository. +* +* @param {Function} Optional callback +* @return {Object} Promise object. +*/ +Repository.prototype.getRemotes = function(callback) { + return Remote.list(this).then(function(remotes) { + if (typeof callback === "function") { + callback(null, remotes); + } + + return remotes; + }, callback); +}; + +/** + * Gets a remote from the repo + * + * @param {String|Remote} remote + * @param {Function} callback + * @return {Remote} The remote object + */ +Repository.prototype.getRemote = function(remote, callback) { + if (remote instanceof NodeGit.Remote) { + return Promise.resolve(remote).then(function(remoteObj) { + if (typeof callback === "function") { + callback(null, remoteObj); + } + + return remoteObj; + }, callback); + } + + return NodeGit.Remote.load(this, remote).then(function(remoteObj) { + if (typeof callback === "function") { + callback(null, remoteObj); + } + + return remoteObj; + }, callback); +}; + +/** + * Fetches from a remote + * + * @param {String|Remote} remote + */ +Repository.prototype.fetch = function(remote) { + var repo = this; + + return repo.getRemote(remote).then(function(remote) { + return remote.fetch(repo.defaultSignature()); + }); +}; + +/** + * Fetches from all remotes + */ +Repository.prototype.fetchAll = function() { + var repo = this; + + return repo.getRemotes(function(remotes) { + var fetchPromises = []; + + remotes.forEach(function(remote) { + fetchPromises.push(repo.fetch(remote)); + }); + + return Promise.all(fetchPromises); + }); +}; + +/** + * Merge a branch onto another branch + * + * @param {String|Ref} from + * @param {String|Ref} to + * @return {Oid|Index} A commit id for a succesful merge or an index for a + * merge with conflicts + */ +Repository.prototype.mergeBranches = function(to, from, signature) { + var repo = this; + var fromBranch; + var toBranch; + + signature = signature || repo.defaultSignature(); + + return Promise.all([ + repo.getBranch(to), + repo.getBranch(from) + ]).then(function(branches) { + toBranch = branches[0]; + fromBranch = branches[1]; + + return Promise.all([ + repo.getBranchCommit(toBranch), + repo.getBranchCommit(fromBranch) + ]); + }).then(function(branchCommits) { + var toCommitOid = branchCommits[0].toString(); + var fromCommitOid = branchCommits[1].toString(); + + return NodeGit.Merge.base(repo, toCommitOid, fromCommitOid) + .then(function(baseCommit) { + if (baseCommit.toString() == fromCommitOid) { + // The commit we're merging to is already in our history. + // nothing to do so just return the commit the branch is on + return toCommitOid; + } + else if (baseCommit.toString() == toCommitOid) { + // fast forward + var message = + "Fast forward branch " + + toBranch.shorthand() + + " to branch " + + fromBranch.shorthand(); + + return toBranch.setTarget( + fromCommitOid, + signature, + message) + .then(function() { + return fromCommitOid; + }); + } + else { + // We have to merge. Lets do it! + return NodeGit.Merge.commits(repo, toCommitOid, fromCommitOid) + .then(function(index) { + // if we have conflicts then throw the index + if (index.hasConflicts()) { + throw index; + } + + // No conflicts so just go ahead with the merge + index.write(); + return index.writeTreeTo(repo); + }).then(function(oid) { + var message = + "Merged " + + fromBranch.shorthand() + + " into " + + toBranch.shorthand(); + console.log(message); + + return repo.createCommit( + toBranch.name(), + signature, + signature, + message, + oid, + [toCommitOid, fromCommitOid]); + }); + } + }); + }); +}; + module.exports = Repository; diff --git a/lib/revwalk.js b/lib/revwalk.js index cf4875bc4..37e24d9f6 100644 --- a/lib/revwalk.js +++ b/lib/revwalk.js @@ -1,6 +1,4 @@ var NodeGit = require("../"); -var normalizeOid = require("./util/normalize_oid"); - var Revwalk = NodeGit.Revwalk; var oldSorting = Revwalk.prototype.sorting; @@ -30,8 +28,6 @@ Revwalk.prototype.sorting = function() { * @return {Commit} */ Revwalk.prototype.walk = function(oid, callback) { - oid = normalizeOid(oid); - var revwalk = this; this.push(oid); diff --git a/lib/tag.js b/lib/tag.js index ebbe71af6..2a6c51f90 100644 --- a/lib/tag.js +++ b/lib/tag.js @@ -1,5 +1,15 @@ var git = require("../"); +var LookupWrapper = require("./util/lookupWrapper"); var Tag = git.Tag; +/** +* Retrieves the tag pointed to by the oid +* @param {Repository} repo The repo that the tag lives in +* @param {String|Oid|Tag} id The tag to lookup +* @param {Function} callback +* @return {Tag} +*/ +Tag.lookup = LookupWrapper(Tag); + module.exports = Tag; diff --git a/lib/tree.js b/lib/tree.js index 9abb4662d..ca35af90a 100644 --- a/lib/tree.js +++ b/lib/tree.js @@ -3,6 +3,16 @@ var Tree = git.Tree; var Treebuilder = git.Treebuilder; var Diff = git.Diff; var events = require("events"); +var LookupWrapper = require("./util/lookupWrapper"); + +/** +* Retrieves the tree pointed to by the oid +* @param {Repository} repo The repo that the tree lives in +* @param {String|Oid|Tree} id The tree to lookup +* @param {Function} callback +* @return {Tree} +*/ +Tree.lookup = LookupWrapper(Tree); /** * Diff two trees diff --git a/lib/util/lookupWrapper.js b/lib/util/lookupWrapper.js new file mode 100644 index 000000000..a0c66ffec --- /dev/null +++ b/lib/util/lookupWrapper.js @@ -0,0 +1,37 @@ +var Promise = require("nodegit-promise"); + +/** +* Wraps a method so that you can pass in either a string, OID or the object +* itself and you will always get back a promise that resolves to the object. +* @param {Object} objectType The object type that you're expecting to receive. +* @param {Function} lookupFunction The function to do the lookup for the +* object. Defaults to `objectType.lookup`. +* @return {Function} +*/ +module.exports = function(objectType, lookupFunction) { + lookupFunction = lookupFunction || objectType.lookup; + + return function(repo, id, callback) { + if (id instanceof objectType) { + return Promise.resolve(id).then(function(obj) { + obj.repo = repo; + + if (typeof callback === "function") { + callback(null, obj); + } + + return obj; + }, callback); + } + + return lookupFunction(repo, id).then(function(obj) { + obj.repo = repo; + + if (typeof callback === "function") { + callback(null, obj); + } + + return obj; + }, callback); + }; +}; diff --git a/lib/util/normalize_oid.js b/lib/util/normalize_oid.js deleted file mode 100644 index f08efcc07..000000000 --- a/lib/util/normalize_oid.js +++ /dev/null @@ -1,18 +0,0 @@ -var NodeGit = require("../../"); - -/** - * Normalize an identifier to always be an OID instance. - * - * @param {String, Object} oid - The oid string or instance. - * @return {Object} An Oid instance. - */ -function normalizeOid(oid) { - try { - return typeof oid === "string" ? NodeGit.Oid.fromString(oid) : oid; - } - catch (ex) { - return null; - } -} - -module.exports = normalizeOid; diff --git a/package.json b/package.json index c39c1afbe..a495da515 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "lint": "jshint lib test/tests", "cov": "node test", "mocha": "mocha test/runner test/tests", + "mochaDebug": "mocha --debug-brk test/runner test/tests", "test": "npm run lint && npm run cov", "generateJson": "node generate/scripts/generateJson", "generateNativeCode": "node generate/scripts/generateNativeCode", diff --git a/test/tests/blob.js b/test/tests/blob.js index 06856cc03..c3d8f61ff 100644 --- a/test/tests/blob.js +++ b/test/tests/blob.js @@ -5,6 +5,7 @@ describe("Blob", function() { var reposPath = path.resolve("test/repos/workdir/.git"); var oid = "111dd657329797f6165f52f5085f61ac976dcf04"; + var Oid = require("../../lib/oid"); var Repository = require("../../lib/repository"); var FileMode = require("../../lib/tree_entry").FILEMODE; @@ -36,4 +37,11 @@ describe("Blob", function() { it("can determine if a blob is not a binary", function() { assert.equal(this.blob.filemode(), FileMode.BLOB); }); + + it("can get a blob with an Oid object", function() { + var oidObject = Oid.fromString(oid); + this.repository.getBlob(oidObject).then(function(blob) { + assert.equal(this.blob.id().toString(), oid); + }); + }); }); diff --git a/test/tests/merge.js b/test/tests/merge.js index 72b3d9c74..b66eeb03f 100644 --- a/test/tests/merge.js +++ b/test/tests/merge.js @@ -129,6 +129,230 @@ describe("Merge", function() { }); }); + it("can fast-forward using the convenience method", function() { + var ourFileName = "ourNewFile.txt"; + var theirFileName = "theirNewFile.txt"; + + var ourFileContent = "I like Toll Roads. I have an EZ-Pass!"; + var theirFileContent = "I'm skeptical about Toll Roads"; + + var ourSignature = nodegit.Signature.create + ("Ron Paul", "RonPaul@TollRoadsRBest.info", 123456789, 60); + var theirSignature = nodegit.Signature.create + ("Greg Abbott", "Gregggg@IllTollYourFace.us", 123456789, 60); + + var repository = this.repository; + var ourCommit; + var theirCommit; + var ourBranch; + var theirBranch; + + return fse.writeFile( + path.join(repository.workdir(), ourFileName), + ourFileContent) + // Load up the repository index and make our initial commit to HEAD + .then(function() { + return repository.openIndex() + .then(function(index) { + index.read(1); + index.addByPath(ourFileName); + index.write(); + + return index.writeTree(); + }); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "11ead82b1135b8e240fb5d61e703312fb9cc3d6a"); + + return repository.createCommit("HEAD", ourSignature, + ourSignature, "we made a commit", oid, []); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "91a183f87842ebb7a9b08dad8bc2473985796844"); + + return repository.getCommit(commitOid).then(function(commit) { + ourCommit = commit; + }).then(function() { + return repository.createBranch(ourBranchName, commitOid) + .then(function(branch) { + ourBranch = branch; + return repository.createBranch(theirBranchName, commitOid); + }); + }); + }) + .then(function(branch) { + theirBranch = branch; + return fse.writeFile(path.join(repository.workdir(), theirFileName), + theirFileContent); + }) + .then(function() { + return repository.openIndex() + .then(function(index) { + index.read(1); + index.addByPath(theirFileName); + index.write(); + + return index.writeTree(); + }); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "76631cb5a290dafe2959152626bb90f2a6d8ec94"); + + return repository.createCommit(theirBranch.name(), theirSignature, + theirSignature, "they made a commit", oid, [ourCommit]); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "0e9231d489b3f4303635fc4b0397830da095e7e7"); + + return repository.getCommit(commitOid).then(function(commit) { + theirCommit = commit; + }); + }) + .then(function() { + return repository.mergeBranches(ourBranchName, theirBranchName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "0e9231d489b3f4303635fc4b0397830da095e7e7"); + + return repository.getBranchCommit(ourBranchName) + .then(function(branchCommit) { + assert.equal(oid.toString(), branchCommit.toString()); + }); + }); + }); + + it("can merge cleanly using the convenience method", function() { + var initialFileName = "initialFile.txt"; + var ourFileName = "ourNewFile.txt"; + var theirFileName = "theirNewFile.txt"; + + var initialFileContent = "I'd like to drive somewhere"; + var ourFileContent = "I like Toll Roads. I have an EZ-Pass!"; + var theirFileContent = "I'm skeptical about Toll Roads"; + + var ourSignature = nodegit.Signature.create + ("Ron Paul", "RonPaul@TollRoadsRBest.info", 123456789, 60); + var theirSignature = nodegit.Signature.create + ("Greg Abbott", "Gregggg@IllTollYourFace.us", 123456789, 60); + + var repository = this.repository; + var initialCommit; + var ourCommit; + var theirCommit; + var ourBranch; + var theirBranch; + + return fse.writeFile( + path.join(repository.workdir(), initialFileName), + initialFileContent) + // Load up the repository index and make our initial commit to HEAD + .then(function() { + return repository.openIndex() + .then(function(index) { + index.read(1); + index.addByPath(initialFileName); + index.write(); + + return index.writeTree(); + }); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "21a553813e2f670815b649eef51eeadb253a5d0c"); + + return repository.createCommit("HEAD", ourSignature, + ourSignature, "initial commit", oid, []); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "af66a9c799a10a23319ee4318c8bb2021521f539"); + + return repository.getCommit(commitOid).then(function(commit) { + initialCommit = commit; + }).then(function() { + return repository.createBranch(ourBranchName, commitOid) + .then(function(branch) { + ourBranch = branch; + return repository.createBranch(theirBranchName, commitOid); + }); + }); + }) + .then(function(branch) { + theirBranch = branch; + }) + .then(function() { + return fse.writeFile(path.join(repository.workdir(), ourFileName), + ourFileContent); + }) + .then(function() { + return repository.openIndex() + .then(function(index) { + index.read(1); + index.addByPath(ourFileName); + index.write(); + + return index.writeTree(); + }); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "af60aa06b3537f75b427f6268a130c842c84a137"); + + return repository.createCommit(ourBranch.name(), ourSignature, + ourSignature, "we made a commit", oid, [initialCommit]); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "7ce31c05427659986d50abfb90c8f7db88ef4fa1"); + + return repository.getCommit(commitOid).then(function(commit) { + ourCommit = commit; + }); + }) + .then(function() { + return fse.writeFile(path.join(repository.workdir(), theirFileName), + theirFileContent); + }) + .then(function() { + return repository.openIndex() + .then(function(index) { + index.read(1); + index.addByPath(theirFileName); + index.write(); + + return index.writeTree(); + }); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "f007361737a2ca00a0e80fc2daf55064463173b4"); + + return repository.createCommit(theirBranch.name(), theirSignature, + theirSignature, "they made a commit", oid, [initialCommit]); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "b588f0eef1809226f8f7db542940749da15ae1de"); + + return repository.getCommit(commitOid).then(function(commit) { + theirCommit = commit; + }); + }) + .then(function() { + return repository.mergeBranches(ourBranchName, theirBranchName, + ourSignature); + }) + .then(function(commitId) { + assert.equal(commitId.toString(), + "5384feb481d9c29081b3a0c1478fcc24a3953efa"); + }); + }); + it("can merge 2 branchs with conflicts on a single file", function () { var baseFileContent = "All Bobs are created equal. ish.\n"; var ourFileContent = "Big Bobs are best, IMHO.\n"; diff --git a/test/tests/remote.js b/test/tests/remote.js index 1142fd192..b1bd807d8 100644 --- a/test/tests/remote.js +++ b/test/tests/remote.js @@ -88,7 +88,7 @@ describe("Remote", function() { }); }); - it("can fetch from a remote", function() { + it("can download from a remote", function() { var repo = this.repository; return Remote.load(repo, "origin") @@ -102,4 +102,13 @@ describe("Remote", function() { assert(false); }); }); + + it("can fetch from a remote", function() { + return this.repository.fetch("origin") + .then(function() { + assert(true); + }, function() { + assert(false); + }); + }); }); diff --git a/test/tests/repository.js b/test/tests/repository.js index 3d1de0fe8..c172604ff 100644 --- a/test/tests/repository.js +++ b/test/tests/repository.js @@ -52,4 +52,10 @@ describe("Repository", function() { assert.equal(remotes.strings(), "origin"); }); }); + + it("can get the current branch", function() { + return this.repository.getCurrentBranch().then(function(branch) { + assert.equal(branch.shorthand(), "master"); + }); + }); });