From e20451698e5d2038d735926ddbbe43ef21735dde Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Mon, 24 Jul 2017 11:41:07 -0700 Subject: [PATCH 01/35] removed node v4 tests --- .travis.yml | 3 --- appveyor.yml | 1 - 2 files changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ef6f06fc2..862d1eb6c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,15 +13,12 @@ sudo: false env: matrix: - - export NODE_VERSION="4" TARGET_ARCH="x64" - export NODE_VERSION="6.5" TARGET_ARCH="x64" - export NODE_VERSION="7.4" TARGET_ARCH="x64" matrix: fast_finish: true include: - - os: linux - env: export NODE_VERSION="4" TARGET_ARCH="ia32" - os: linux env: export NODE_VERSION="6.5" TARGET_ARCH="ia32" - os: linux diff --git a/appveyor.yml b/appveyor.yml index 5f7172f5c..9ffa0bd02 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,7 +27,6 @@ environment: GYP_MSVS_VERSION: 2013 matrix: # Node.js - - nodejs_version: "4" - nodejs_version: "6" - nodejs_version: "7" From cdfd81a9a556acd86dcbd2b0bdbbc4d9219acc5f Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Wed, 19 Jul 2017 16:25:05 -0700 Subject: [PATCH 02/35] Bump libgit2 to maintenance v0.26 --- vendor/libgit2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/libgit2 b/vendor/libgit2 index 9e76f2c72..3c1308d8c 160000 --- a/vendor/libgit2 +++ b/vendor/libgit2 @@ -1 +1 @@ -Subproject commit 9e76f2c72bb562aba6f72b95216bc4e885a46551 +Subproject commit 3c1308d8c1afa74d5da76ff1d3b2106d352ed36f From 4e34797a88070dd3fc23422a9f8518db14f62bb0 Mon Sep 17 00:00:00 2001 From: Mohseen Mukaddam Date: Thu, 1 Jun 2017 15:55:11 -0700 Subject: [PATCH 03/35] Adding filters to generator template AsyncBatonWithNoResults wip 2 --- generate/input/callbacks.json | 96 ++++++++++ generate/input/descriptor.json | 26 +-- generate/input/libgit2-supplement.json | 65 +++++-- generate/scripts/generateJson.js | 12 +- generate/scripts/helpers.js | 10 +- .../templates/manual/include/async_baton.h | 36 ++++ .../templates/partials/field_accessors.cc | 176 +++++++++++------- .../templates/templates/struct_content.cc | 17 +- generate/templates/templates/struct_header.h | 35 +++- 9 files changed, 353 insertions(+), 120 deletions(-) diff --git a/generate/input/callbacks.json b/generate/input/callbacks.json index 999ccd57f..5fe947aa5 100644 --- a/generate/input/callbacks.json +++ b/generate/input/callbacks.json @@ -311,6 +311,102 @@ "error": -1 } }, + "git_filter_apply_fn": { + "args": [ + { + "name": "self", + "cType": "git_filter *" + }, + { + "name": "payload", + "cType": "void **" + }, + { + "name": "to", + "cType": "git_buf *" + }, + { + "name": "from", + "cType": "const git_buf *" + }, + { + "name": "src", + "cType": "const git_filter_source *" + } + ], + "return": { + "type": "int", + "noResults": -30, + "success": 0, + "error": -1 + } + }, + "git_filter_check_fn": { + "args": [ + { + "name": "self", + "cType": "git_filter *" + }, + { + "name": "payload", + "cType": "void **" + }, + { + "name": "src", + "cType": "const git_filter_source *" + }, + { + "name": "attr_values", + "cType": "const char **" + } + ], + "return": { + "type": "int", + "noResults": -30, + "success": 0, + "error": -1 + } + }, + "git_filter_cleanup_fn": { + "args": [ + { + "name": "self", + "cType": "git_filter *" + }, + { + "name": "payload", + "cType": "void *" + } + ], + "return": { + "type": "void" + } + }, + "git_filter_init_fn": { + "args": [ + { + "name": "self", + "cType": "git_filter *" + } + ], + "return": { + "type": "int", + "noResults": 0, + "success": 0, + "error": -1 + } + }, + "git_filter_shutdown_fn": { + "args": [ + { + "name": "self", + "cType": "git_filter *" + } + ], + "return": { + "type": "void" + } + }, "git_index_matched_path_cb": { "args": [ { diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index d33298c30..4691ff9fe 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -879,6 +879,7 @@ } }, "filter": { + "hasConstructor": true, "functions": { "git_filter_list_apply_to_blob": { "ignore": true @@ -920,30 +921,21 @@ "ignore": true } }, + "cDependencies": [ + "git2/sys/filter.h" + ], "fields": { - "initialize": { - "ignore": true - }, - "shutdown": { - "ignore": true - }, - "check": { - "ignore": true - }, - "apply": { - "ignore": true - }, - "cleanup": { + "stream": { "ignore": true } - }, + } + }, + "filter_source": { + "ignore": false, "cDependencies": [ "git2/sys/filter.h" ] }, - "filter_source": { - "ignore": true - }, "graph": { "functions": { "git_graph_ahead_behind": { diff --git a/generate/input/libgit2-supplement.json b/generate/input/libgit2-supplement.json index 52bb45651..a8ca22130 100644 --- a/generate/input/libgit2-supplement.json +++ b/generate/input/libgit2-supplement.json @@ -273,6 +273,17 @@ "git_annotated_commit_lookup" ] ], + [ + "filter_source", + [ + "git_filter_source_repo", + "git_filter_source_path", + "git_filter_source_filemode", + "git_filter_source_id", + "git_filter_source_mode", + "git_filter_source_flags" + ] + ], [ "odb_object", [ @@ -422,33 +433,27 @@ }, { "type": "git_filter_init_fn", - "name": "initialize", - "ignore": true + "name": "initialize" }, { "type": "git_filter_shutdown_fn", - "name": "shutdown", - "ignore": true + "name": "shutdown" }, { "type": "git_filter_check_fn", - "name": "check", - "ignore": true + "name": "check" }, { "type": "git_filter_apply_fn", - "name": "apply", - "ignore": true + "name": "apply" }, { "type": "git_filter_stream_fn", - "name": "stream", - "ignore": true + "name": "stream" }, { "type": "git_filter_cleanup_fn", - "name": "cleanup", - "ignore": true + "name": "cleanup" } ] } @@ -765,14 +770,26 @@ "git_annotated_commit_lookup" ] }, - "odb": { + "filter": { "functions": [ - "git_odb_object_data", - "git_odb_object_dup", - "git_odb_object_free", - "git_odb_object_id", - "git_odb_object_size", - "git_odb_object_type" + "git_filter_list_apply_to_blob", + "git_filter_list_apply_to_data", + "git_filter_list_apply_to_file", + "git_filter_list_contains", + "git_filter_list_free", + "git_filter_list_length", + "git_filter_list_load", + "git_filter_list_new", + "git_filter_list_push", + "git_filter_list_stream_blob", + "git_filter_list_stream_data", + "git_filter_list_stream_file", + "git_filter_source_filemode", + "git_filter_source_flags", + "git_filter_source_id", + "git_filter_source_mode", + "git_filter_source_path", + "git_filter_source_repo" ] }, "merge": { @@ -784,6 +801,16 @@ "git_merge_head_id" ] }, + "odb": { + "functions": [ + "git_odb_object_data", + "git_odb_object_dup", + "git_odb_object_free", + "git_odb_object_id", + "git_odb_object_size", + "git_odb_object_type" + ] + }, "reflog": { "functions": [ "git_reflog_entry_committer", diff --git a/generate/scripts/generateJson.js b/generate/scripts/generateJson.js index 323247e13..784f58df8 100644 --- a/generate/scripts/generateJson.js +++ b/generate/scripts/generateJson.js @@ -61,6 +61,7 @@ module.exports = function generateJson() { // Split each type from the array into classes/structs and enums // each entry is of type ['name', {definingobject}] libgit2.types.forEach(function(current) { + console.log(current[1]); current[1].typeName = current[0]; // just log these out to a file for fun @@ -106,6 +107,7 @@ module.exports = function generateJson() { }, {}).valueOf(); // decorate the definitions with required data to build the C++ files + //TODO: add self ref tag here types.forEach(function(typeDef) { var typeName = typeDef.typeName; typeDef.cType = typeName; @@ -169,9 +171,18 @@ module.exports = function generateJson() { } }; + var addSelfReferentialField = function(prop){ + if (helpers.isSelfReferential(prop.type)) { + prop.isSelfReferential = true; + def.isExtendedStruct = true; + } + }; + def.fields.forEach(addDependencies); + def.fields.forEach(addSelfReferentialField); def.functions.forEach(addDependencies); + Object.keys(dependencies).forEach(function (dependencyFilename) { def.dependencies.push("../include/" + dependencyFilename + ".h"); }); @@ -183,7 +194,6 @@ module.exports = function generateJson() { fn.cppClassName = def.cppClassName; }); }); - // Process enums _(enums).forEach(function(enumerable) { output.some(function(obj) { diff --git a/generate/scripts/helpers.js b/generate/scripts/helpers.js index 48b651355..08d12eb6e 100644 --- a/generate/scripts/helpers.js +++ b/generate/scripts/helpers.js @@ -1,4 +1,5 @@ -var callbackTypePattern = /\s*_cb/; +var callbackTypePattern = /\s*_(cb|fn)/, + selfReferentialTypePattern = /\s*_fn/; var utils = require("./utils"); var _ = require("lodash"); @@ -10,6 +11,9 @@ var callbackDefs = require("../input/callbacks.json"); var descriptor = require("../input/descriptor.json"); var libgit2 = require("../input/libgit2-docs.json"); +let funcs = Object.keys(libgit2.functions); +console.log(funcs.filter(item => item.includes('filter'))); + var cTypes = libgit2.groups.map(function(group) { return group[0];}); var cTypeMappings = { @@ -93,6 +97,10 @@ var Helpers = { && ~cbField.name.indexOf(payloadName.replace("_payload", "")); }, + isSelfReferential: function(cType){ + return selfReferentialTypePattern.test(cType); + }, + getLibgitType: function(normalizedType, types) { var libgitType; diff --git a/generate/templates/manual/include/async_baton.h b/generate/templates/manual/include/async_baton.h index 5f6874102..0e6d64b6a 100644 --- a/generate/templates/manual/include/async_baton.h +++ b/generate/templates/manual/include/async_baton.h @@ -60,4 +60,40 @@ struct AsyncBatonWithResult : public AsyncBaton { } }; +struct AsyncBatonWithNoResult : public AsyncBaton { + /* ResultT result; + ResultT defaultResult;*/ // result returned if the callback doesn't return anything valid + void (*onCompletion)(AsyncBaton *); + + void Done() { + if (onCompletion) { + onCompletion(this); + } else { + // signal completion + uv_sem_post(&semaphore); + } + } + + void ExecuteAsync(ThreadPool::Callback asyncCallback, void (*onCompletion)(AsyncBaton *) = NULL) { + this->onCompletion = onCompletion; + if (!onCompletion) { + uv_sem_init(&semaphore, 0); + } + + { + LockMaster::TemporaryUnlock temporaryUnlock; + + libgit2ThreadPool.ExecuteReverseCallback(asyncCallback, this); + + if (!onCompletion) { + // wait for completion + uv_sem_wait(&semaphore); + uv_sem_destroy(&semaphore); + } + } + + return; + } +}; + #endif diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index ea5bb5db1..debda98b4 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -109,11 +109,20 @@ {% if field.isCallbackFunction %} {{ cppClassName }}* {{ cppClassName }}::{{ field.name }}_getInstanceFromBaton({{ field.name|titleCase }}Baton* baton) { - return static_cast<{{ cppClassName }}*>(baton->{% each field.args|argsInfo as arg %} - {% if arg.payload == true %}{{arg.name}}{% elsif arg.lastArg %}{{arg.name}}{% endif %} - {% endeach %}); + {% if isExtendedStruct %} + return static_cast<{{ cppClassName }}*>((({{cType}}_extended *)baton->self)->payload); + {% else %} + return static_cast<{{ cppClassName }}*>(baton-> + {% each field.args|argsInfo as arg %} + {% if arg.payload == true %} + {{arg.name}} + {% elsif arg.lastArg %} + {{arg.name}} + {% endif %} + {% endeach %}); + {% endif %} } - + {{ field.return.type }} {{ cppClassName }}::{{ field.name }}_cppCallback ( {% each field.args|argsInfo as arg %} {{ arg.cType }} {{ arg.name}}{% if not arg.lastArg %},{% endif %} @@ -127,21 +136,34 @@ {% endeach %} {{ cppClassName }}* instance = {{ field.name }}_getInstanceFromBaton(baton); - - {{ field.return.type }} result; - - if (instance->{{ field.name }}.WillBeThrottled()) { - result = baton->defaultResult; - delete baton; - } else if (instance->{{ field.name }}.ShouldWaitForResult()) { - result = baton->ExecuteAsync({{ field.name }}_async); - delete baton; - } else { - result = baton->defaultResult; - baton->ExecuteAsync({{ field.name }}_async, deleteBaton); - } - return result; + + {% if field.return.type == "void" %} + if (instance->{{ field.name }}.WillBeThrottled()) { + delete baton; + } else if (instance->{{ field.name }}.ShouldWaitForResult()) { + baton->ExecuteAsync({{ field.name }}_async); + delete baton; + } else { + baton->ExecuteAsync({{ field.name }}_async, deleteBaton); + } + return; + {% else %} + {{ field.return.type }} result; + + if (instance->{{ field.name }}.WillBeThrottled()) { + result = baton->defaultResult; + delete baton; + } else if (instance->{{ field.name }}.ShouldWaitForResult()) { + result = baton->ExecuteAsync({{ field.name }}_async); + delete baton; + } else { + result = baton->defaultResult; + baton->ExecuteAsync({{ field.name }}_async, deleteBaton); + } + return result; + {% endif %} } + void {{ cppClassName }}::{{ field.name }}_async(void *untypedBaton) { Nan::HandleScope scope; @@ -150,11 +172,12 @@ {{ cppClassName }}* instance = {{ field.name }}_getInstanceFromBaton(baton); if (instance->{{ field.name }}.GetCallback()->IsEmpty()) { - {% if field.return.type == "int" %} + {% if field.return.type == "void" %} + baton->Done(); + {% else %} baton->result = baton->defaultResult; // no results acquired + baton->Done(); {% endif %} - - baton->Done(); return; } @@ -173,8 +196,12 @@ v8::Local argv[{{ field.args|jsArgsCount }}] = { {% each field.args|argsInfo as arg %} {% if arg.name == "payload" %} - {%-- payload is always the last arg --%} - Nan::New(instance->{{ fields|payloadFor field.name }}) + {% if isExtendedStruct %} + Nan::New((({{cType}}_extended *)instance)->payload), + {% else %} + {%-- payload is always the last arg --%} + Nan::New(instance->{{ fields|payloadFor field.name }}), + {% endif %} {% elsif arg.isJsArg %} {% if arg.isEnum %} Nan::New((int)baton->{{ arg.name }}), @@ -198,40 +225,10 @@ if(PromiseCompletion::ForwardIfPromise(result, baton, {{ cppClassName }}::{{ field.name }}_promiseCompleted)) { return; } - - {% each field|returnsInfo false true as _return %} - if (result.IsEmpty() || result->IsNativeError()) { - baton->result = {{ field.return.error }}; - } - else if (!result->IsNull() && !result->IsUndefined()) { - {% if _return.isOutParam %} - {{ _return.cppClassName }}* wrapper = Nan::ObjectWrap::Unwrap<{{ _return.cppClassName }}>(result->ToObject()); - wrapper->selfFreeing = false; - - *baton->{{ _return.name }} = wrapper->GetValue(); - baton->result = {{ field.return.success }}; - {% else %} - if (result->IsNumber()) { - baton->result = (int)result->ToNumber()->Value(); - } - else { - baton->result = baton->defaultResult; - } - {% endif %} - } - else { - baton->result = baton->defaultResult; - } - {% endeach %} - baton->Done(); - } - - void {{ cppClassName }}::{{ field.name }}_promiseCompleted(bool isFulfilled, AsyncBaton *_baton, v8::Local result) { - Nan::HandleScope scope; - - {{ field.name|titleCase }}Baton* baton = static_cast<{{ field.name|titleCase }}Baton*>(_baton); - - if (isFulfilled) { + //TODO: fix for void cases + {% if field.return.type == "void" %} + baton->Done(); + {% else %} {% each field|returnsInfo false true as _return %} if (result.IsEmpty() || result->IsNativeError()) { baton->result = {{ field.return.error }}; @@ -247,7 +244,7 @@ if (result->IsNumber()) { baton->result = (int)result->ToNumber()->Value(); } - else{ + else { baton->result = baton->defaultResult; } {% endif %} @@ -256,18 +253,59 @@ baton->result = baton->defaultResult; } {% endeach %} - } - else { - // promise was rejected - {{ cppClassName }}* instance = static_cast<{{ cppClassName }}*>(baton->{% each field.args|argsInfo as arg %} - {% if arg.payload == true %}{{arg.name}}{% elsif arg.lastArg %}{{arg.name}}{% endif %} - {% endeach %}); - v8::Local parent = instance->handle(); - SetPrivate(parent, Nan::New("NodeGitPromiseError").ToLocalChecked(), result); + baton->Done(); + {% endif %} + } - baton->result = {{ field.return.error }}; - } - baton->Done(); + void {{ cppClassName }}::{{ field.name }}_promiseCompleted(bool isFulfilled, AsyncBaton *_baton, v8::Local result) { + Nan::HandleScope scope; + + {{ field.name|titleCase }}Baton* baton = static_cast<{{ field.name|titleCase }}Baton*>(_baton); + {% if field.return.type == "void" %} + baton->Done(); + {% else %} + if (isFulfilled) { + {% each field|returnsInfo false true as _return %} + if (result.IsEmpty() || result->IsNativeError()) { + baton->result = {{ field.return.error }}; + } + else if (!result->IsNull() && !result->IsUndefined()) { + {% if _return.isOutParam %} + {{ _return.cppClassName }}* wrapper = Nan::ObjectWrap::Unwrap<{{ _return.cppClassName }}>(result->ToObject()); + wrapper->selfFreeing = false; + + *baton->{{ _return.name }} = wrapper->GetValue(); + baton->result = {{ field.return.success }}; + {% else %} + if (result->IsNumber()) { + baton->result = (int)result->ToNumber()->Value(); + } + else{ + baton->result = baton->defaultResult; + } + {% endif %} + } + else { + baton->result = baton->defaultResult; + } + {% endeach %} + } + else { + // promise was rejected + {% if isExtendedStruct %} + {{ cppClassName }}* instance = static_cast<{{ cppClassName }}*>((({{cType}}_extended *)baton->self)->payload); + {% else %} + {{ cppClassName }}* instance = static_cast<{{ cppClassName }}*>(baton->{% each field.args|argsInfo as arg %} + {% if arg.payload == true %}{{arg.name}}{% elsif arg.lastArg %}{{arg.name}}{% endif %} + {% endeach %}); + {% endif %} + v8::Local parent = instance->handle(); + SetPrivate(parent, Nan::New("NodeGitPromiseError").ToLocalChecked(), result); + + baton->result = {{ field.return.error }}; + } + baton->Done(); + {% endif %} } {% endif %} {% endif %} diff --git a/generate/templates/templates/struct_content.cc b/generate/templates/templates/struct_content.cc index c6f9e5b91..5f8f88727 100644 --- a/generate/templates/templates/struct_content.cc +++ b/generate/templates/templates/struct_content.cc @@ -54,9 +54,13 @@ using namespace std; {% if not field.ignore %} {% if not field.isEnum %} {% if field.isCallbackFunction %} - if (this->{{ field.name }}.HasCallback()) { - this->raw->{{ fields|payloadFor field.name }} = NULL; - } + if (this->{{ field.name }}.HasCallback()) { + {% if isExtendedStruct %} + (({{ cType }}_extended *)this->raw)->payload = NULL; + {% else %} + this->raw->{{ fields|payloadFor field.name }} = NULL; + {% endif %} + } {% endif %} {% endif %} {% endif %} @@ -79,7 +83,12 @@ void {{ cppClassName }}::ConstructFields() { // Set the static method call and set the payload for this function to be // the current instance this->raw->{{ field.name }} = NULL; - this->raw->{{ fields|payloadFor field.name }} = (void *)this; + //TODO: solve this problem + {% if isExtendedStruct %} + (({{ cType }}_extended *)this->raw)->payload = (void *)this; + {% else %} + this->raw->{{ fields|payloadFor field.name }} = (void *)this; + {% endif %} {% elsif field.payloadFor %} v8::Local {{ field.name }} = Nan::Undefined(); diff --git a/generate/templates/templates/struct_header.h b/generate/templates/templates/struct_header.h index 94fd3bc0f..15a3a260e 100644 --- a/generate/templates/templates/struct_header.h +++ b/generate/templates/templates/struct_header.h @@ -24,7 +24,12 @@ using namespace node; using namespace v8; {%partial traits .%} - +{% if isExtendedStruct %} +struct {{ cType }}_extended { + {{ cType }} raw; + void* payload; +}; +{% endif %} class {{ cppClassName }} : public NodeGitWrapper<{{ cppClassName }}Traits> { // grant full access to base class friend class NodeGitWrapper<{{ cppClassName }}Traits>; @@ -46,15 +51,27 @@ class {{ cppClassName }} : public NodeGitWrapper<{{ cppClassName }}Traits> { static void {{ field.name }}_async(void *baton); static void {{ field.name }}_promiseCompleted(bool isFulfilled, AsyncBaton *_baton, v8::Local result); - struct {{ field.name|titleCase }}Baton : public AsyncBatonWithResult<{{ field.return.type }}> { - {% each field.args|argsInfo as arg %} - {{ arg.cType }} {{ arg.name}}; - {% endeach %} + {% if field.return.type == 'void' %} + struct {{ field.name|titleCase }}Baton : public AsyncBatonWithNoResult{ + {% each field.args|argsInfo as arg %} + {{ arg.cType }} {{ arg.name }}; + {% endeach %} + + {{ field.name|titleCase }}Baton() + : AsyncBatonWithNoResult() { + } + }; + {% else %} + struct {{ field.name|titleCase }}Baton : public AsyncBatonWithResult<{{ field.return.type }}> { + {% each field.args|argsInfo as arg %} + {{ arg.cType }} {{ arg.name }}; + {% endeach %} - {{ field.name|titleCase }}Baton(const {{ field.return.type }} &defaultResult) - : AsyncBatonWithResult<{{ field.return.type }}>(defaultResult) { - } - }; + {{ field.name|titleCase }}Baton(const {{ field.return.type }} &defaultResult) + : AsyncBatonWithResult<{{ field.return.type }}>(defaultResult) { + } + }; + {% endif %} static {{ cppClassName }} * {{ field.name }}_getInstanceFromBaton ( {{ field.name|titleCase }}Baton *baton); {% endif %} From f4f7a4dd4065ebdeffb603defc6b115e83181c62 Mon Sep 17 00:00:00 2001 From: Mohseen Mukaddam Date: Tue, 6 Jun 2017 13:29:51 -0700 Subject: [PATCH 04/35] Adding Filter registration, clean build, passing test Build + test register complete filter init test wip --- generate/input/descriptor.json | 16 ++ generate/input/libgit2-supplement.json | 11 +- .../templates/partials/field_accessors.cc | 16 +- .../templates/templates/struct_content.cc | 13 +- lib/filter_registry.js | 20 +++ test/tests/filter.js | 168 ++++++++++++++++++ 6 files changed, 230 insertions(+), 14 deletions(-) create mode 100644 lib/filter_registry.js create mode 100644 test/tests/filter.js diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index 4691ff9fe..c4b430a35 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -879,6 +879,7 @@ } }, "filter": { + "selfFreeing": false, "hasConstructor": true, "functions": { "git_filter_list_apply_to_blob": { @@ -930,6 +931,21 @@ } } }, + "filter_registry": { + "functions": { + "git_filter_register": { + "jsFunctionName": "register", + "args": { + "filter": { + "isSelf": false + } + } + }, + "git_filter_unregister": { + "jsFunctionName": "unregister" + } + } + }, "filter_source": { "ignore": false, "cDependencies": [ diff --git a/generate/input/libgit2-supplement.json b/generate/input/libgit2-supplement.json index a8ca22130..4f66dec4a 100644 --- a/generate/input/libgit2-supplement.json +++ b/generate/input/libgit2-supplement.json @@ -273,6 +273,13 @@ "git_annotated_commit_lookup" ] ], + [ + "filter_registry", + [ + "git_filter_register", + "git_filter_unregister" + ] + ], [ "filter_source", [ @@ -447,10 +454,6 @@ "type": "git_filter_apply_fn", "name": "apply" }, - { - "type": "git_filter_stream_fn", - "name": "stream" - }, { "type": "git_filter_cleanup_fn", "name": "cleanup" diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index debda98b4..3c034b1a4 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -195,12 +195,11 @@ v8::Local argv[{{ field.args|jsArgsCount }}] = { {% each field.args|argsInfo as arg %} - {% if arg.name == "payload" %} + {% if arg.cppClassName == "String" %} {% if isExtendedStruct %} - Nan::New((({{cType}}_extended *)instance)->payload), + Nan::New(*baton->{{ arg.name }}).ToLocalChecked(), {% else %} - {%-- payload is always the last arg --%} - Nan::New(instance->{{ fields|payloadFor field.name }}), + Nan::New(baton->{{ arg.name }}).ToLocalChecked(), {% endif %} {% elsif arg.isJsArg %} {% if arg.isEnum %} @@ -210,8 +209,13 @@ {% elsif arg.cType == "size_t" %} // HACK: NAN should really have an overload for Nan::New to support size_t Nan::New((unsigned int)baton->{{ arg.name }}), - {% elsif arg.cppClassName == 'String' %} - Nan::New(baton->{{ arg.name }}).ToLocalChecked(), + {% elsif arg.name == "payload" %} + {% if isExtendedStruct %} + Nan::New((({{cType}}_extended *)instance)->payload), + {% else %} + {%-- payload is always the last arg --%} + Nan::New(instance->{{ fields|payloadFor field.name }}), + {% endif %} {% else %} Nan::New(baton->{{ arg.name }}), {% endif %} diff --git a/generate/templates/templates/struct_content.cc b/generate/templates/templates/struct_content.cc index 5f8f88727..9840cfe4f 100644 --- a/generate/templates/templates/struct_content.cc +++ b/generate/templates/templates/struct_content.cc @@ -35,9 +35,15 @@ using namespace std; {% if ignoreInit == true %} this->raw = new {{ cType }}; {% else %} - {{ cType }} wrappedValue = {{ cType|upper }}_INIT; - this->raw = ({{ cType }}*) malloc(sizeof({{ cType }})); - memcpy(this->raw, &wrappedValue, sizeof({{ cType }})); + {% if isExtendedStruct %} + {{ cType }}_extended wrappedValue = {{ cType|upper }}_INIT; + this->raw = ({{ cType }}*) malloc(sizeof({{ cType }}_extended)); + memcpy(this->raw, &wrappedValue, sizeof({{ cType }}_extended)); + {% else %} + {{ cType }} wrappedValue = {{ cType|upper }}_INIT; + this->raw = ({{ cType }}*) malloc(sizeof({{ cType }})); + memcpy(this->raw, &wrappedValue, sizeof({{ cType }})); + {% endif %} {% endif %} this->ConstructFields(); @@ -83,7 +89,6 @@ void {{ cppClassName }}::ConstructFields() { // Set the static method call and set the payload for this function to be // the current instance this->raw->{{ field.name }} = NULL; - //TODO: solve this problem {% if isExtendedStruct %} (({{ cType }}_extended *)this->raw)->payload = (void *)this; {% else %} diff --git a/lib/filter_registry.js b/lib/filter_registry.js new file mode 100644 index 000000000..d8d41b2d0 --- /dev/null +++ b/lib/filter_registry.js @@ -0,0 +1,20 @@ +var NodeGit = require("../"); +var normalizeOptions = NodeGit.Utils.normalizeOptions; + +var FilterRegistry = NodeGit.FilterRegistry; + +var _register = FilterRegistry.register; + +// Override FilterRegistry.register to normalize Filter +FilterRegistry.register = function(name, filter, priority) { + filter = normalizeOptions(filter, NodeGit.Filter); + console.log("[DEBUG] Filter: ", filter); + if(filter.check && filter.apply) { + return _register(name, filter, priority); + } + else { + console.log( + "ERROR: please provide check and (apply or stream) callbacks for filter"); + return null; + } +}; diff --git a/test/tests/filter.js b/test/tests/filter.js new file mode 100644 index 000000000..933e0a314 --- /dev/null +++ b/test/tests/filter.js @@ -0,0 +1,168 @@ +var assert = require("assert"), + promisify = require("promisify-node"), + fse = promisify(require("fs-extra")), + path = require("path"), + local = path.join.bind(path, __dirname); + +describe.only("Filter", function() { + var NodeGit = require("../../"); + + var emptyRepoPath = local("../repos/empty"), + filterName = "psuedo_filter", + // newRepoPath = local("../repos/newrepo"), + Registry = NodeGit.FilterRegistry, + Checkout = NodeGit.Checkout, + Repository = NodeGit.Repository, + Attr = NodeGit.Attr, + Status = NodeGit.Status, + reposPath = local("../repos/workdir"); + + beforeEach(function() { + var test = this; + + return Repository.open(reposPath) + .then(function(repository) { + test.repository = repository; + }) + .then(function() { + return Repository.open(emptyRepoPath); + }) + .then(function(emptyRepo) { + test.emptyRepo = emptyRepo; + }); + }); + + afterEach(function() { + //Unregistering the filter to avoid GIT_EEXISTS + Registry.unregister(filterName); + }); + + it("Registering filter for the first time", function() { + // registering custom filter + var result = Registry.register(filterName, { + initialize: function() { + console.log("inside INIT"); + }, + apply: function() { + console.log("inside APPLY"); + }, + stream: function() { + console.log("inside STREAM"); + }, + check: function(){ + console.log("inside CHECK"); + } + }, 0); + assert.strictEqual(result, 0); + }); + + it("Registering filter and re-registering same filter", function() { + // registering custom filter + var result = Registry.register(filterName, { + initialize: function() { + console.log("inside INIT"); + }, + apply: function() { + console.log("inside APPLY"); + }, + stream: function() { + console.log("inside STREAM"); + }, + check: function(){ + console.log("inside CHECK"); + } + }, 0); + assert.strictEqual(result, 0); + + result = Registry.register(filterName, { + initialize: function() { + console.log("inside INIT"); + }, + apply: function() { + console.log("inside APPLY"); + }, + stream: function() { + console.log("inside STREAM"); + }, + check: function(){ + console.log("inside CHECK"); + } + }, 0); + assert.strictEqual(result, -4); + }); + + it("Testing Initialize callback", function() { + var test = this, + testFilePath = path.join(reposPath, "package.json"), + flags = Status.SHOW.INDEX_AND_WORKDIR; + + // registering custom filter + var result = Registry.register(filterName, { + initialize: function() { + console.log("inside INIT"); + }, + apply: function() { + console.log("inside APPLY"); + }, + stream: function() { + console.log("inside STREAM"); + }, + check: function(){ + console.log("inside CHECK"); + } + }, 0); + + assert.strictEqual(result, 0); + + // creating .gitattributes + var gitattributeFilePromise = fse.writeFile( + path.join(reposPath, ".gitattributes"), + "* filter="+ filterName +" diff=lfs merge=lfs -text", { + encoding: "utf-8", + }); + //creating test file that will be used to trigger custom filter + var testFilePromise = fse.writeFile( + testFilePath, + "initial text", { + encoding: "utf-8", + }); + + Attr.cacheFlush(this.repository); + + // setup complete, testing initialize of custom filter + return Promise.all([gitattributeFilePromise, testFilePromise]) + // create necessary files + .then(function() { + return Attr.get( + test.repository, + flags, + path.join(reposPath, ".gitattributes"), + "filter"); + }) + // check attribute values + .then(function(data) { + console.log("data: ", data); + assert.strictEqual(data, filterName); + }) + // modify file + .then(function() { + return fse.writeFile(testFilePath, + "Modified Content", + { + encoding: "utf-8" + }); + }) + // perform checkout, which should trigger filter + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + console.log("Post checkout"); + }); + }); + +}); From 3844f98ab3bfcdee5be6360d5d8206d5122d66c2 Mon Sep 17 00:00:00 2001 From: Mohseen Mukaddam Date: Fri, 9 Jun 2017 12:09:12 -0700 Subject: [PATCH 05/35] Added Filter callback support Adding subtract filter + refactoring template code to eliminate new self() in cc code filter registry update + templating changes --- generate/scripts/generateNativeCode.js | 1 + generate/templates/filters/args_info.js | 6 + generate/templates/filters/subtract.js | 3 + .../templates/partials/field_accessors.cc | 53 ++- lib/filter_registry.js | 32 +- test/tests/filter.js | 379 ++++++++++++------ 6 files changed, 339 insertions(+), 135 deletions(-) create mode 100644 generate/templates/filters/subtract.js diff --git a/generate/scripts/generateNativeCode.js b/generate/scripts/generateNativeCode.js index a82bef4e5..cc4e5255e 100644 --- a/generate/scripts/generateNativeCode.js +++ b/generate/scripts/generateNativeCode.js @@ -68,6 +68,7 @@ module.exports = function generateNativeCode() { replace: require("../templates/filters/replace"), returnsCount: require("../templates/filters/returns_count"), returnsInfo: require("../templates/filters/returns_info"), + subtract: require("../templates/filters/subtract"), titleCase: require("../templates/filters/title_case"), toBool: require('../templates/filters/to_bool'), unPointer: require("../templates/filters/un_pointer"), diff --git a/generate/templates/filters/args_info.js b/generate/templates/filters/args_info.js index 1382c67d6..72f3854aa 100644 --- a/generate/templates/filters/args_info.js +++ b/generate/templates/filters/args_info.js @@ -15,9 +15,15 @@ module.exports = function(args) { if (cArg === args.length -1) { arg.lastArg = true; + arg.firstArg = false; + } + else if(cArg === 0){ + arg.firstArg = true; + arg.lastArg = false; } else { arg.lastArg = false; + arg.firstArg = false; } arg.cArg = cArg; diff --git a/generate/templates/filters/subtract.js b/generate/templates/filters/subtract.js new file mode 100644 index 000000000..36d0f59de --- /dev/null +++ b/generate/templates/filters/subtract.js @@ -0,0 +1,3 @@ +module.exports = function(value, other) { + return (value - other); +}; diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index 3c034b1a4..48288f9f0 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -188,19 +188,47 @@ {% if arg.cType == "const char *" %} if (baton->{{ arg.name }} == NULL) { baton->{{ arg.name }} = ""; + } + {% elsif arg.cppClassName == "String" %} + v8::Local src; + if (baton->{{ arg.name }} == NULL) { + src = Nan::Null(); + } + else { + src = Nan::New(*baton->{{ arg.name }}).ToLocalChecked(); } {% endif %} {% endif %} {% endeach %} - v8::Local argv[{{ field.args|jsArgsCount }}] = { - {% each field.args|argsInfo as arg %} - {% if arg.cppClassName == "String" %} - {% if isExtendedStruct %} - Nan::New(*baton->{{ arg.name }}).ToLocalChecked(), - {% else %} - Nan::New(baton->{{ arg.name }}).ToLocalChecked(), + {% if field.isSelfReferential %} + v8::Local argv[{{ field.args|jsArgsCount|subtract 1 }}] = { + {% else %} + v8::Local argv[{{ field.args|jsArgsCount }}] = { + {% endif %} + {% each field.args|argsInfo as arg %} + {% if field.isSelfReferential %} + {% if not arg.firstArg %} + {% if field.args|jsArgsCount|subtract 1|or 0 %} + {% if arg.cppClassName == "String" %} + src, + {% elsif arg.isJsArg %} + {% if arg.isEnum %} + Nan::New((int)baton->{{ arg.name }}), + {% elsif arg.isLibgitType %} + {{ arg.cppClassName }}::New(baton->{{ arg.name }}, false), + {% elsif arg.cType == "size_t" %} + Nan::New((unsigned int)baton->{{ arg.name }}), + {% elsif arg.name == "payload" %} + {% else %} + Nan::New(baton->{{ arg.name }}), + {% endif %} + {% endif %} {% endif %} + {% endif %} + {% else %} + {% if arg.cppClassName == "String" %} + Nan::New(baton->{{ arg.name }}).ToLocalChecked(), {% elsif arg.isJsArg %} {% if arg.isEnum %} Nan::New((int)baton->{{ arg.name }}), @@ -210,21 +238,16 @@ // HACK: NAN should really have an overload for Nan::New to support size_t Nan::New((unsigned int)baton->{{ arg.name }}), {% elsif arg.name == "payload" %} - {% if isExtendedStruct %} - Nan::New((({{cType}}_extended *)instance)->payload), - {% else %} - {%-- payload is always the last arg --%} - Nan::New(instance->{{ fields|payloadFor field.name }}), - {% endif %} {% else %} Nan::New(baton->{{ arg.name }}), {% endif %} {% endif %} - {% endeach %} + {% endif %} + {% endeach %} }; Nan::TryCatch tryCatch; - v8::Local result = instance->{{ field.name }}.GetCallback()->Call({{ field.args|jsArgsCount }}, argv); + v8::Local result = instance->{{ field.name }}.GetCallback()->Call({{ field.args|jsArgsCount|subtract 1 }}, argv); if(PromiseCompletion::ForwardIfPromise(result, baton, {{ cppClassName }}::{{ field.name }}_promiseCompleted)) { return; diff --git a/lib/filter_registry.js b/lib/filter_registry.js index d8d41b2d0..6908c465e 100644 --- a/lib/filter_registry.js +++ b/lib/filter_registry.js @@ -4,17 +4,45 @@ var normalizeOptions = NodeGit.Utils.normalizeOptions; var FilterRegistry = NodeGit.FilterRegistry; var _register = FilterRegistry.register; +var _unregister = FilterRegistry.unregister; + +// // hold onto the scope of our filters until unregister is called +var filtersByName = {}; + +// register should add filter by name to dict and return // Override FilterRegistry.register to normalize Filter FilterRegistry.register = function(name, filter, priority) { + // setting default value of attributes + if(filter.attributes === undefined) { + filter.attributes = ""; + } + filter = normalizeOptions(filter, NodeGit.Filter); - console.log("[DEBUG] Filter: ", filter); + + if (filtersByName[name] === undefined) { + filtersByName[name] = filter; + } + + console.log("filtersByName[Register]: ", filtersByName); + + if(filter.check && filter.apply) { return _register(name, filter, priority); } else { console.log( - "ERROR: please provide check and (apply or stream) callbacks for filter"); + "ERROR: please provide check and apply callbacks for filter"); return null; } }; + +FilterRegistry.unregister = function(name){ + if (filtersByName[name] !== undefined) { + delete filtersByName[name]; + } + + console.log("filtersByName[Unregister]: ", filtersByName); + + return _unregister(name); +}; diff --git a/test/tests/filter.js b/test/tests/filter.js index 933e0a314..45dcf5f81 100644 --- a/test/tests/filter.js +++ b/test/tests/filter.js @@ -4,7 +4,7 @@ var assert = require("assert"), path = require("path"), local = path.join.bind(path, __dirname); -describe.only("Filter", function() { +describe("Filter", function() { var NodeGit = require("../../"); var emptyRepoPath = local("../repos/empty"), @@ -37,132 +37,275 @@ describe.only("Filter", function() { Registry.unregister(filterName); }); - it("Registering filter for the first time", function() { - // registering custom filter - var result = Registry.register(filterName, { - initialize: function() { - console.log("inside INIT"); - }, - apply: function() { - console.log("inside APPLY"); - }, - stream: function() { - console.log("inside STREAM"); - }, - check: function(){ - console.log("inside CHECK"); - } - }, 0); - assert.strictEqual(result, 0); + describe.only("Register and unregister", function(){ + it("Registering filter for the first time", function() { + // registering custom filter + var result = Registry.register(filterName, { + initialize: function() { + console.log("inside INIT"); + }, + apply: function() { + console.log("inside APPLY"); + }, + stream: function() { + console.log("inside STREAM"); + }, + check: function(){ + console.log("inside CHECK"); + } + }, 0); + assert.strictEqual(result, 0); + }); + + it("Registering filter and re-registering same filter", function() { + // registering custom filter + var result = Registry.register(filterName, { + initialize: function() { + console.log("inside INIT"); + }, + apply: function() { + console.log("inside APPLY"); + }, + stream: function() { + console.log("inside STREAM"); + }, + check: function(){ + console.log("inside CHECK"); + } + }, 0); + assert.strictEqual(result, 0); + + result = Registry.register(filterName, { + initialize: function() { + console.log("inside INIT"); + }, + apply: function() { + console.log("inside APPLY"); + }, + stream: function() { + console.log("inside STREAM"); + }, + check: function(){ + console.log("inside CHECK"); + } + }, 0); + assert.strictEqual(result, -4); + }); + }); - it("Registering filter and re-registering same filter", function() { - // registering custom filter - var result = Registry.register(filterName, { - initialize: function() { - console.log("inside INIT"); - }, - apply: function() { - console.log("inside APPLY"); - }, - stream: function() { - console.log("inside STREAM"); - }, - check: function(){ - console.log("inside CHECK"); - } - }, 0); - assert.strictEqual(result, 0); - - result = Registry.register(filterName, { - initialize: function() { - console.log("inside INIT"); - }, - apply: function() { - console.log("inside APPLY"); - }, - stream: function() { - console.log("inside STREAM"); - }, - check: function(){ - console.log("inside CHECK"); - } - }, 0); - assert.strictEqual(result, -4); + describe("Initialize callback", function(){ + + it.only("Testing Initialize callback", function() { + var test = this, + testFilePath = path.join(reposPath, "package.json"), + flags = Status.SHOW.INDEX_AND_WORKDIR; + + // registering custom filter + var result = Registry.register(filterName, { + initialize: function() { + console.log("inside INIT"); + }, + apply: function() { + console.log("inside APPLY"); + }, + check: function(){ + console.log("inside CHECK"); + return 0; + } + }, 0); + + assert.strictEqual(result, 0); + + // creating .gitattributes + var gitattributeFilePromise = fse.writeFile( + path.join(reposPath, ".gitattributes"), + "* filter="+ filterName +" diff=lfs merge=lfs -text", { + encoding: "utf-8", + }); + //creating test file that will be used to trigger custom filter + var testFilePromise = fse.writeFile( + testFilePath, + "initial text", { + encoding: "utf-8", + }); + + Attr.cacheFlush(this.repository); + + // setup complete, testing initialize of custom filter + return Promise.all([gitattributeFilePromise, testFilePromise]) + // create necessary files + .then(function() { + return Attr.get( + test.repository, + flags, + path.join(reposPath, ".gitattributes"), + "filter"); + }) + // check attribute values + .then(function(data) { + console.log("data: ", data); + assert.strictEqual(data, filterName); + }) + // modify file + .then(function() { + return fse.writeFile(testFilePath, + "Modified Content", + { + encoding: "utf-8" + }); + }) + // perform checkout, which should trigger filter + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + console.log("Post checkout"); + }); + }); + }); - it("Testing Initialize callback", function() { - var test = this, - testFilePath = path.join(reposPath, "package.json"), - flags = Status.SHOW.INDEX_AND_WORKDIR; - - // registering custom filter - var result = Registry.register(filterName, { - initialize: function() { - console.log("inside INIT"); - }, - apply: function() { - console.log("inside APPLY"); - }, - stream: function() { - console.log("inside STREAM"); - }, - check: function(){ - console.log("inside CHECK"); - } - }, 0); - - assert.strictEqual(result, 0); + describe("Shutdown callback", function(){ + + it("Testing shutdown callback", function(){ + var result = Registry.register(filterName, { + initialize: function() { + console.log("inside INIT"); + return 0; + }, + apply: function() { + console.log("inside APPLY"); + }, + stream: function() { + console.log("inside STREAM"); + }, + check: function(){ + console.log("inside CHECK"); + return 0; + }, + shutdown: function(){ + console.log("inside SHUTDOWN"); + return 0; + } + }, 0); + assert.strictEqual(result, 0); + + result = Registry.unregister(filterName); + assert.strictEqual(result, 0); + }); - // creating .gitattributes - var gitattributeFilePromise = fse.writeFile( - path.join(reposPath, ".gitattributes"), - "* filter="+ filterName +" diff=lfs merge=lfs -text", { - encoding: "utf-8", + // TODO: shutdown is supposed to work even if + // intialize call back is not provided/call not made + it("Testing shutdown callback with initialize callback", function(){ + var result = Registry.register(filterName, { + apply: function() { + console.log("inside APPLY"); + }, + stream: function() { + console.log("inside STREAM"); + }, + check: function(){ + console.log("inside CHECK"); + return 0; + }, + shutdown: function(){ + console.log("inside SHUTDOWN"); + return 0; + } + }, 0); + assert.strictEqual(result, 0); + + result = Registry.unregister(filterName); + // somewhere here test the result of the shutdown callback + assert.strictEqual(result, 0); }); - //creating test file that will be used to trigger custom filter - var testFilePromise = fse.writeFile( - testFilePath, - "initial text", { - encoding: "utf-8", + + }); + + describe("Check Callback", function(){ + + it("Normal check usage", function(){ + var result = Registry.register(filterName, { + initialize: function() { + console.log("inside INIT"); + return 0; + }, + apply: function() { + console.log("inside APPLY"); + }, + stream: function() { + console.log("inside STREAM"); + }, + check: function(){ + console.log("inside CHECK"); + return 0; + }, + shutdown: function(){ + console.log("inside SHUTDOWN"); + return 0; + } + }, 0); + assert.strictEqual(result, 0); + // do some action like change package.json + // checkout -> clean -> to odb + assert.strictEqual(result, 0); }); - Attr.cacheFlush(this.repository); + it( + "GIT_PASSTHROUGH should be returned" + + " if filter is not to be applied", function(){ + var result = Registry.register(filterName, { + initialize: function() { + console.log("inside INIT"); + return 0; + }, + apply: function() { + console.log("inside APPLY"); + }, + stream: function() { + console.log("inside STREAM"); + }, + check: function(){ + console.log("inside CHECK"); + return 0; + }, + shutdown: function(){ + console.log("inside SHUTDOWN"); + return 0; + } + }, 0); + assert.strictEqual(result, 0); + /* + do some action like change package.json + the filter should return GIT_PASSTHROUGH + verify -> apply callback should get -30 or anything except 0 + check if contents of file modified are not changed and staged? + */ + }); + }); - // setup complete, testing initialize of custom filter - return Promise.all([gitattributeFilePromise, testFilePromise]) - // create necessary files - .then(function() { - return Attr.get( - test.repository, - flags, - path.join(reposPath, ".gitattributes"), - "filter"); - }) - // check attribute values - .then(function(data) { - console.log("data: ", data); - assert.strictEqual(data, filterName); - }) - // modify file - .then(function() { - return fse.writeFile(testFilePath, - "Modified Content", - { - encoding: "utf-8" - }); - }) - // perform checkout, which should trigger filter - .then(function() { - var opts = { - checkoutStrategy: Checkout.STRATEGY.FORCE, - paths: "package.json" - }; - return Checkout.head(test.repository, opts); - }) - .then(function() { - console.log("Post checkout"); - }); + describe("Apply Callback", function(){ + it("Verify apply callback", function(){ + /* + register filter + make changes -> checkout + verify return value from apply + verify changes + */ + }); + it("Verify apply callback did not work", function(){ + /* + register filter + make changes -> checkout + verify return value from apply as GIT_PASSTHROUGH + verify changes + */ + }); }); }); From 172e4ad3d34e94e31922ad399b7820b0ca09175f Mon Sep 17 00:00:00 2001 From: Mohseen Mukaddam Date: Mon, 19 Jun 2017 15:39:42 -0700 Subject: [PATCH 06/35] Transition to manual templates working filters!! (for now) --- generate/input/descriptor.json | 15 -- generate/input/libgit2-supplement.json | 7 - generate/scripts/generateNativeCode.js | 1 + generate/templates/filters/unsigned.js | 3 + .../manual/include/filter_registry.h | 41 ++++ .../templates/manual/src/filter_registry.cc | 157 ++++++++++++++ .../templates/partials/field_accessors.cc | 4 +- generate/templates/templates/binding.gyp | 3 +- generate/templates/templates/nodegit.cc | 2 + generate/templates/templates/nodegit.js | 4 + lib/filter_registry.js | 6 - test/tests/filter.js | 205 +++++++++++------- 12 files changed, 336 insertions(+), 112 deletions(-) create mode 100644 generate/templates/filters/unsigned.js create mode 100644 generate/templates/manual/include/filter_registry.h create mode 100644 generate/templates/manual/src/filter_registry.cc diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index c4b430a35..bf6a67d7e 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -931,21 +931,6 @@ } } }, - "filter_registry": { - "functions": { - "git_filter_register": { - "jsFunctionName": "register", - "args": { - "filter": { - "isSelf": false - } - } - }, - "git_filter_unregister": { - "jsFunctionName": "unregister" - } - } - }, "filter_source": { "ignore": false, "cDependencies": [ diff --git a/generate/input/libgit2-supplement.json b/generate/input/libgit2-supplement.json index 4f66dec4a..12cfe7b2a 100644 --- a/generate/input/libgit2-supplement.json +++ b/generate/input/libgit2-supplement.json @@ -273,13 +273,6 @@ "git_annotated_commit_lookup" ] ], - [ - "filter_registry", - [ - "git_filter_register", - "git_filter_unregister" - ] - ], [ "filter_source", [ diff --git a/generate/scripts/generateNativeCode.js b/generate/scripts/generateNativeCode.js index cc4e5255e..30fc52707 100644 --- a/generate/scripts/generateNativeCode.js +++ b/generate/scripts/generateNativeCode.js @@ -72,6 +72,7 @@ module.exports = function generateNativeCode() { titleCase: require("../templates/filters/title_case"), toBool: require('../templates/filters/to_bool'), unPointer: require("../templates/filters/un_pointer"), + setUnsigned: require("../templates/filters/unsigned"), upper: require("../templates/filters/upper") }; diff --git a/generate/templates/filters/unsigned.js b/generate/templates/filters/unsigned.js new file mode 100644 index 000000000..a46078331 --- /dev/null +++ b/generate/templates/filters/unsigned.js @@ -0,0 +1,3 @@ +module.exports = function(value) { + return value < 0 ? 0 : value; +}; diff --git a/generate/templates/manual/include/filter_registry.h b/generate/templates/manual/include/filter_registry.h new file mode 100644 index 000000000..48632e44d --- /dev/null +++ b/generate/templates/manual/include/filter_registry.h @@ -0,0 +1,41 @@ +// This is a generated file, modify: generate/templates/templates/class_header.h + +#ifndef GITFILTERREGISTRY_H +#define GITFILTERREGISTRY_H +#include +#include +#include +#include + +#include "async_baton.h" +#include "nodegit_wrapper.h" +#include "promise_completion.h" + +extern "C" { +#include +} + +#include "../include/typedefs.h" + +#include "../include/filter.h" + +using namespace node; +using namespace v8; + + +class GitFilterRegistry : public + Nan::ObjectWrap +{ + public: + static void InitializeComponent (v8::Local target); + + static Nan::Persistent persistentHandle; + + private: + + static NAN_METHOD(GitFilterRegister); + + static NAN_METHOD(GitFilterUnregister); +}; + +#endif diff --git a/generate/templates/manual/src/filter_registry.cc b/generate/templates/manual/src/filter_registry.cc new file mode 100644 index 000000000..68dae3ecc --- /dev/null +++ b/generate/templates/manual/src/filter_registry.cc @@ -0,0 +1,157 @@ +// This is a generated file, modify: generate/templates/templates/class_content.cc + +#include +#include + +extern "C" { + #include + } + +#include "../include/nodegit.h" +#include "../include/lock_master.h" +#include "../include/functions/copy.h" +#include "../include/filter_registry.h" +#include "nodegit_wrapper.cc" +#include "../include/async_libgit2_queue_worker.h" + +#include "../include/filter.h" + +#include + +using namespace std; +using namespace v8; +using namespace node; + +Nan::Persistent GitFilterRegistry::persistentHandle; + +// #pragma unmanaged +void GitFilterRegistry::InitializeComponent(v8::Local target) { + Nan::HandleScope scope; + + + v8::Local object = Nan::New(); + + Nan::SetMethod(object, "register", GitFilterRegister); + Nan::SetMethod(object, "unregister", GitFilterUnregister); + + + Nan::Set(target, Nan::New("FilterRegistry").ToLocalChecked(), object); + GitFilterRegistry::persistentHandle.Reset(object); +} +// TODO: Reset persistent handle in destructor +/* + * @param String name +* @param Filter filter +* @param Number priority +* @return Number result +*/ + +NAN_METHOD(GitFilterRegistry::GitFilterRegister) { + Nan::EscapableHandleScope scope; + + if (info.Length() == 0 || !info[0]->IsString()) { + return Nan::ThrowError("String name is required."); + } + + if (info.Length() == 1 || !info[1]->IsObject()) { + return Nan::ThrowError("Filter filter is required."); + } + + if (info.Length() == 2 || !info[2]->IsNumber()) { + return Nan::ThrowError("Number priority is required."); + } + + // start convert_from_v8 block + const char * from_name = NULL; + + String::Utf8Value name(info[0]->ToString()); + // malloc with one extra byte so we can add the terminating null character C-strings expect: + from_name = (const char *) malloc(name.length() + 1); + // copy the characters from the nodejs string into our C-string (used instead of strdup or strcpy because nulls in + // the middle of strings are valid coming from nodejs): + memcpy((void *)from_name, *name, name.length()); + // ensure the final byte of our new string is null, extra casts added to ensure compatibility with various C types + // used in the nodejs binding generation: + memset((void *)(((char *)from_name) + name.length()), 0, 1); + // end convert_from_v8 block + // start convert_from_v8 block + git_filter * from_filter = NULL; + from_filter = Nan::ObjectWrap::Unwrap(info[1]->ToObject())->GetValue(); + // end convert_from_v8 block + // start convert_from_v8 block + int from_priority; + from_priority = (int) info[2]->ToNumber()->Value(); + // end convert_from_v8 block + bool result = GitFilterRegistry::persistentHandle.IsEmpty(); + Nan::New(GitFilterRegistry::persistentHandle)->Set(info[0]->ToString(), info[1]->ToObject()); + // Nan::Persistent testSample = GitFilterRegistry::persistentHandle; + // Nan::New(GitFilterRegistry::persistentHandle)->Set(name, info.This()); + // Nan::Set(GitFilterRegistry::persistentHandle, name, info.This()); + v8::Local temp = Nan::New(GitFilterRegistry::persistentHandle); + // v8::Local key = Nan::New("omg").ToLocalChecked(); + v8::Local key = info[0]->ToString(); + v8::Maybe result2 = Nan::Has(temp, key); + // New(GitFilterRegistry::persistentHandle)->Set(name, in) + // v8::New(persistentHandle).Set(name, info.This()); + // v8::Local testObject = Nan::New(GitFilterRegistry::persistentHandle); + // testObject->Set(name, from_filter); + // Nan::Set(testObject, Nan::New("omg").ToLocalChecked(), info[1]->ToObject()); + + // v8::Local testObject2 = Nan::New(GitFilterRegistry::persistentHandle); + // Nan::MaybeLocal res1 = Nan::Get(testObject2, Nan::New("omg").ToLocalChecked()); + + giterr_clear(); + + { + LockMaster lockMaster(/*asyncAction: */false, from_name, from_filter); + + int result = git_filter_register(from_name, from_filter, from_priority); + + v8::Local to; + // start convert_to_v8 block + to = Nan::New(result); + // end convert_to_v8 block + return info.GetReturnValue().Set(scope.Escape(to)); + } +} + +/* +* @param String name +* @return Number result +*/ + +NAN_METHOD(GitFilterRegistry::GitFilterUnregister) { + Nan::EscapableHandleScope scope; + + if (info.Length() == 0 || !info[0]->IsString()) { + return Nan::ThrowError("String name is required."); + } + + // start convert_from_v8 block + const char * from_name = NULL; + + String::Utf8Value name(info[0]->ToString()); + // malloc with one extra byte so we can add the terminating null character C-strings expect: + from_name = (const char *) malloc(name.length() + 1); + // copy the characters from the nodejs string into our C-string (used instead of strdup or strcpy because nulls in + // the middle of strings are valid coming from nodejs): + memcpy((void *)from_name, *name, name.length()); + // ensure the final byte of our new string is null, extra casts added to ensure compatibility with various C types + // used in the nodejs binding generation: + memset((void *)(((char *)from_name) + name.length()), 0, 1); + // end convert_from_v8 block + + giterr_clear(); + + { + LockMaster lockMaster(/*asyncAction: */false, from_name); + + int result = git_filter_unregister(from_name); + + v8::Local to; + // start convert_to_v8 block + to = Nan::New(result); + // end convert_to_v8 block + return info.GetReturnValue().Set(scope.Escape(to)); + } +} diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index 48288f9f0..3c5d4615f 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -202,7 +202,7 @@ {% endeach %} {% if field.isSelfReferential %} - v8::Local argv[{{ field.args|jsArgsCount|subtract 1 }}] = { + v8::Local argv[{{ field.args|jsArgsCount|subtract 2| setUnsigned }}] = { {% else %} v8::Local argv[{{ field.args|jsArgsCount }}] = { {% endif %} @@ -247,7 +247,7 @@ }; Nan::TryCatch tryCatch; - v8::Local result = instance->{{ field.name }}.GetCallback()->Call({{ field.args|jsArgsCount|subtract 1 }}, argv); + v8::Local result = instance->{{ field.name }}.GetCallback()->Call({{ field.args|jsArgsCount|subtract 2| setUnsigned }}, argv); if(PromiseCompletion::ForwardIfPromise(result, baton, {{ cppClassName }}::{{ field.name }}_promiseCompleted)) { return; diff --git a/generate/templates/templates/binding.gyp b/generate/templates/templates/binding.gyp index 69e2042ad..a448a4a5f 100644 --- a/generate/templates/templates/binding.gyp +++ b/generate/templates/templates/binding.gyp @@ -10,7 +10,7 @@ "variables": { "coverage%": 0 }, - + "sources": [ "src/async_baton.cc", "src/lock_master.cc", @@ -22,6 +22,7 @@ "src/functions/free.cc", "src/convenient_patch.cc", "src/convenient_hunk.cc", + "src/filter_registry.cc", "src/str_array_converter.cc", "src/thread_pool.cc", {% each %} diff --git a/generate/templates/templates/nodegit.cc b/generate/templates/templates/nodegit.cc index 9f392cabc..e81bbb85f 100644 --- a/generate/templates/templates/nodegit.cc +++ b/generate/templates/templates/nodegit.cc @@ -21,6 +21,7 @@ {% endeach %} #include "../include/convenient_patch.h" #include "../include/convenient_hunk.h" +#include "../include/filter_registry.h" #if (NODE_MODULE_VERSION > 48) v8::Local GetPrivate(v8::Local object, @@ -140,6 +141,7 @@ extern "C" void init(v8::Local target) { ConvenientHunk::InitializeComponent(target); ConvenientPatch::InitializeComponent(target); + GitFilterRegistry::InitializeComponent(target); NODE_SET_METHOD(target, "enableThreadSafety", LockMasterEnable); NODE_SET_METHOD(target, "setThreadSafetyStatus", LockMasterSetStatus); diff --git a/generate/templates/templates/nodegit.js b/generate/templates/templates/nodegit.js index 84bc558b8..8b2baa030 100644 --- a/generate/templates/templates/nodegit.js +++ b/generate/templates/templates/nodegit.js @@ -58,6 +58,8 @@ _ConvenientPatch.prototype.hunks = promisify(_ConvenientPatch_hunks); var _ConvenientHunk = rawApi.ConvenientHunk; var _ConvenientHunk_lines = _ConvenientHunk.prototype.lines; _ConvenientHunk.prototype.lines = promisify(_ConvenientHunk_lines); + +var _FilterRegistry = rawApi.FilterRegistry; /* jshint ignore:end */ // Set the exports prototype to the raw API. @@ -86,6 +88,8 @@ require("./status_file"); require("./enums.js"); // Import extensions +// [Manual] extensions +importExtension("filter_registry"); {% each %} {% if type != "enum" %} importExtension("{{ filename }}"); diff --git a/lib/filter_registry.js b/lib/filter_registry.js index 6908c465e..67549170a 100644 --- a/lib/filter_registry.js +++ b/lib/filter_registry.js @@ -24,9 +24,6 @@ FilterRegistry.register = function(name, filter, priority) { filtersByName[name] = filter; } - console.log("filtersByName[Register]: ", filtersByName); - - if(filter.check && filter.apply) { return _register(name, filter, priority); } @@ -41,8 +38,5 @@ FilterRegistry.unregister = function(name){ if (filtersByName[name] !== undefined) { delete filtersByName[name]; } - - console.log("filtersByName[Unregister]: ", filtersByName); - return _unregister(name); }; diff --git a/test/tests/filter.js b/test/tests/filter.js index 45dcf5f81..f8f230670 100644 --- a/test/tests/filter.js +++ b/test/tests/filter.js @@ -29,6 +29,13 @@ describe("Filter", function() { }) .then(function(emptyRepo) { test.emptyRepo = emptyRepo; + }) + .then(function() { + return fse.writeFile( + path.join(reposPath, ".gitattributes"), + "* filter="+ filterName +" diff=lfs merge=lfs -text", { + encoding: "utf-8", + }); }); }); @@ -37,7 +44,7 @@ describe("Filter", function() { Registry.unregister(filterName); }); - describe.only("Register and unregister", function(){ + describe("Register and unregister", function(){ it("Registering filter for the first time", function() { // registering custom filter var result = Registry.register(filterName, { @@ -95,79 +102,33 @@ describe("Filter", function() { }); describe("Initialize callback", function(){ - - it.only("Testing Initialize callback", function() { - var test = this, - testFilePath = path.join(reposPath, "package.json"), - flags = Status.SHOW.INDEX_AND_WORKDIR; - - // registering custom filter + /* TODO: first setup and check init callback + * , based on what it's supposed to do + */ + it.only("Testing initialize callback", function() { + // test if anything has changed and appy something, then check var result = Registry.register(filterName, { initialize: function() { console.log("inside INIT"); + return 0; }, apply: function() { console.log("inside APPLY"); }, + stream: function() { + console.log("inside STREAM"); + }, check: function(){ console.log("inside CHECK"); return 0; + }, + shutdown: function(){ + console.log("inside SHUTDOWN"); + return 0; } }, 0); - assert.strictEqual(result, 0); - - // creating .gitattributes - var gitattributeFilePromise = fse.writeFile( - path.join(reposPath, ".gitattributes"), - "* filter="+ filterName +" diff=lfs merge=lfs -text", { - encoding: "utf-8", - }); - //creating test file that will be used to trigger custom filter - var testFilePromise = fse.writeFile( - testFilePath, - "initial text", { - encoding: "utf-8", - }); - - Attr.cacheFlush(this.repository); - - // setup complete, testing initialize of custom filter - return Promise.all([gitattributeFilePromise, testFilePromise]) - // create necessary files - .then(function() { - return Attr.get( - test.repository, - flags, - path.join(reposPath, ".gitattributes"), - "filter"); - }) - // check attribute values - .then(function(data) { - console.log("data: ", data); - assert.strictEqual(data, filterName); - }) - // modify file - .then(function() { - return fse.writeFile(testFilePath, - "Modified Content", - { - encoding: "utf-8" - }); - }) - // perform checkout, which should trigger filter - .then(function() { - var opts = { - checkoutStrategy: Checkout.STRATEGY.FORCE, - paths: "package.json" - }; - return Checkout.head(test.repository, opts); - }) - .then(function() { - console.log("Post checkout"); - }); }); - }); describe("Shutdown callback", function(){ @@ -229,7 +190,9 @@ describe("Filter", function() { describe("Check Callback", function(){ - it("Normal check usage", function(){ + it( + "GIT_PASSTHROUGH should be returned" + + " if filter is not to be applied", function(){ var result = Registry.register(filterName, { initialize: function() { console.log("inside INIT"); @@ -251,41 +214,121 @@ describe("Filter", function() { } }, 0); assert.strictEqual(result, 0); - // do some action like change package.json - // checkout -> clean -> to odb - assert.strictEqual(result, 0); + /* + do some action like change package.json + the filter should return GIT_PASSTHROUGH + verify -> apply callback should get -30 or anything except 0 + check if contents of file modified are not changed and staged? + */ }); - it( - "GIT_PASSTHROUGH should be returned" + - " if filter is not to be applied", function(){ + it.only("Testing check callback", function() { + var test = this, + testFilePath = path.join(reposPath, "package.json"), + flags = Status.SHOW.INDEX_AND_WORKDIR; + + // registering custom filter var result = Registry.register(filterName, { initialize: function() { console.log("inside INIT"); - return 0; }, apply: function() { console.log("inside APPLY"); }, - stream: function() { - console.log("inside STREAM"); - }, check: function(){ console.log("inside CHECK"); return 0; - }, - shutdown: function(){ - console.log("inside SHUTDOWN"); - return 0; } }, 0); + assert.strictEqual(result, 0); - /* - do some action like change package.json - the filter should return GIT_PASSTHROUGH - verify -> apply callback should get -30 or anything except 0 - check if contents of file modified are not changed and staged? - */ + + // creating .gitattributes + /*var gitattributeFilePromise = fse.writeFile( + path.join(reposPath, ".gitattributes"), + "* filter="+ filterName +" diff=lfs merge=lfs -text", { + encoding: "utf-8", + });*/ + //creating test file that will be used to trigger custom filter + Attr.cacheFlush(this.repository); + /*var testFilePromise = fse.writeFile( + testFilePath, + "initial text", { + encoding: "utf-8", + });*/ + + return fse.writeFile( + testFilePath, + "initial text", { + encoding: "utf-8", + }) + .then(function() { + return Attr.get( + test.repository, + flags, + path.join(reposPath, ".gitattributes"), + "filter"); + }) + // check attribute values + .then(function(data) { + console.log("data: ", data); + assert.strictEqual(data, filterName); + }) + // modify file + .then(function() { + return fse.writeFile(testFilePath, + "Modified Content", + { + encoding: "utf-8" + }); + }) + // perform checkout, which should trigger filter + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + console.log("Post checkout"); + }); + + + /*// setup complete, testing initialize of custom filter + return Promise.all([gitattributeFilePromise, testFilePromise]) + // create necessary files + .then(function() { + return Attr.get( + test.repository, + flags, + path.join(reposPath, ".gitattributes"), + "filter"); + }) + // check attribute values + .then(function(data) { + console.log("data: ", data); + assert.strictEqual(data, filterName); + }) + // modify file + .then(function() { + return fse.writeFile(testFilePath, + "Modified Content", + { + encoding: "utf-8" + }); + }) + // perform checkout, which should trigger filter + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + console.log("Post checkout"); + });*/ }); }); From 60c1866ebcf88087dee03c135f52080a44b0236b Mon Sep 17 00:00:00 2001 From: Mohseen Mukaddam Date: Mon, 26 Jun 2017 13:36:50 -0700 Subject: [PATCH 07/35] Added Async functionality Reached Async Land adding error handling testing commit + apply callback fixed field_accessor template on windows --- generate/scripts/generateJson.js | 1 - .../manual/include/filter_registry.h | 44 + .../templates/manual/src/filter_registry.cc | 300 ++++++- generate/templates/partials/async_function.cc | 23 +- .../templates/partials/field_accessors.cc | 12 +- generate/templates/templates/nodegit.js | 6 + lib/filter_registry.js | 37 +- test/tests/filter.js | 793 +++++++++++++----- 8 files changed, 924 insertions(+), 292 deletions(-) diff --git a/generate/scripts/generateJson.js b/generate/scripts/generateJson.js index 784f58df8..bba4ca0fe 100644 --- a/generate/scripts/generateJson.js +++ b/generate/scripts/generateJson.js @@ -61,7 +61,6 @@ module.exports = function generateJson() { // Split each type from the array into classes/structs and enums // each entry is of type ['name', {definingobject}] libgit2.types.forEach(function(current) { - console.log(current[1]); current[1].typeName = current[0]; // just log these out to a file for fun diff --git a/generate/templates/manual/include/filter_registry.h b/generate/templates/manual/include/filter_registry.h index 48632e44d..a46d84d3d 100644 --- a/generate/templates/manual/include/filter_registry.h +++ b/generate/templates/manual/include/filter_registry.h @@ -36,6 +36,50 @@ class GitFilterRegistry : public static NAN_METHOD(GitFilterRegister); static NAN_METHOD(GitFilterUnregister); + + struct FilterBaton { + const git_error* error; + git_filter *filter; + char *filter_name; + int filter_priority; + int error_code; + }; + + struct SimpleFilterBaton { + const git_error* error; + char *filter_name; + int error_code; + }; + + class RegisterWorker : public Nan::AsyncWorker { + public: + RegisterWorker( + FilterBaton *_baton, + Nan::Callback *callback + ) : Nan::AsyncWorker(callback) + , baton(_baton) {}; + ~RegisterWorker() {}; + void Execute(); + void HandleOKCallback(); + + private: + FilterBaton *baton; + }; + + class UnRegisterWorker : public Nan::AsyncWorker { + public: + UnRegisterWorker( + SimpleFilterBaton *_baton, + Nan::Callback *callback + ) : Nan::AsyncWorker(callback) + , baton(_baton) {}; + ~UnRegisterWorker() {}; + void Execute(); + void HandleOKCallback(); + + private: + SimpleFilterBaton *baton; + }; }; #endif diff --git a/generate/templates/manual/src/filter_registry.cc b/generate/templates/manual/src/filter_registry.cc index 68dae3ecc..23abdaa83 100644 --- a/generate/templates/manual/src/filter_registry.cc +++ b/generate/templates/manual/src/filter_registry.cc @@ -61,6 +61,9 @@ NAN_METHOD(GitFilterRegistry::GitFilterRegister) { return Nan::ThrowError("Number priority is required."); } + if (info.Length() == 3 || !info[3]->IsFunction()) { + return Nan::ThrowError("Callback is required and must be a Function."); + } // start convert_from_v8 block const char * from_name = NULL; @@ -73,46 +76,138 @@ NAN_METHOD(GitFilterRegistry::GitFilterRegister) { // ensure the final byte of our new string is null, extra casts added to ensure compatibility with various C types // used in the nodejs binding generation: memset((void *)(((char *)from_name) + name.length()), 0, 1); - // end convert_from_v8 block - // start convert_from_v8 block - git_filter * from_filter = NULL; + + FilterBaton *baton = new FilterBaton; + + git_filter *from_filter = NULL; from_filter = Nan::ObjectWrap::Unwrap(info[1]->ToObject())->GetValue(); - // end convert_from_v8 block - // start convert_from_v8 block + + baton->filter = from_filter; + baton->filter_name = (char *) malloc(name.length() + 1); + strcpy(baton->filter_name, from_name); + baton->error_code = GIT_OK; + int from_priority; from_priority = (int) info[2]->ToNumber()->Value(); - // end convert_from_v8 block + + baton->filter_priority = from_priority; + + /* This will delete the filter name from persistent handle */ bool result = GitFilterRegistry::persistentHandle.IsEmpty(); Nan::New(GitFilterRegistry::persistentHandle)->Set(info[0]->ToString(), info[1]->ToObject()); - // Nan::Persistent testSample = GitFilterRegistry::persistentHandle; - // Nan::New(GitFilterRegistry::persistentHandle)->Set(name, info.This()); - // Nan::Set(GitFilterRegistry::persistentHandle, name, info.This()); - v8::Local temp = Nan::New(GitFilterRegistry::persistentHandle); - // v8::Local key = Nan::New("omg").ToLocalChecked(); + + v8::Local handleRef = Nan::New(GitFilterRegistry::persistentHandle); v8::Local key = info[0]->ToString(); - v8::Maybe result2 = Nan::Has(temp, key); - // New(GitFilterRegistry::persistentHandle)->Set(name, in) - // v8::New(persistentHandle).Set(name, info.This()); - // v8::Local testObject = Nan::New(GitFilterRegistry::persistentHandle); - // testObject->Set(name, from_filter); - // Nan::Set(testObject, Nan::New("omg").ToLocalChecked(), info[1]->ToObject()); + v8::Maybe result2 = Nan::Has(handleRef, key); - // v8::Local testObject2 = Nan::New(GitFilterRegistry::persistentHandle); - // Nan::MaybeLocal res1 = Nan::Get(testObject2, Nan::New("omg").ToLocalChecked()); + Nan::Callback *callback = new Nan::Callback(Local::Cast(info[3])); + RegisterWorker *worker = new RegisterWorker(baton, callback); + worker->SaveToPersistent("filter_name", info[0]->ToObject()); + worker->SaveToPersistent("filter_priority", info[2]->ToObject()); + + AsyncLibgit2QueueWorker(worker); + return; +} +// no v8 in execute +void GitFilterRegistry::RegisterWorker::Execute() { + giterr_clear(); { - LockMaster lockMaster(/*asyncAction: */false, from_name, from_filter); + LockMaster lockMaster(/*asyncAction: */true, baton->filter_name, baton->filter); + int result = git_filter_register(baton->filter_name, baton->filter, baton->filter_priority); + baton->error_code = result; - int result = git_filter_register(from_name, from_filter, from_priority); - - v8::Local to; - // start convert_to_v8 block - to = Nan::New(result); - // end convert_to_v8 block - return info.GetReturnValue().Set(scope.Escape(to)); + if (result != GIT_OK && giterr_last() != NULL) { + baton->error = git_error_dup(giterr_last()); + } + } +} + +void GitFilterRegistry::RegisterWorker::HandleOKCallback() { + if (baton->error_code == GIT_OK) { + v8::Local result = Nan::New(baton->error_code); + v8::Local argv[2] = { + Nan::Null(), + result + }; + callback->Call(2, argv); + } else { + if (baton->error) { + v8::Local err; + if (baton->error->message) { + err = Nan::Error(baton->error->message)->ToObject(); + } else { + err = Nan::Error("Method register has thrown an error.")->ToObject(); + } + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); + v8::Local argv[1] = { + err + }; + callback->Call(1, argv); + if (baton->error->message) + free((void *)baton->error->message); + free((void *)baton->error); + } else if (baton->error_code < 0) { + std::queue< v8::Local > workerArguments; + workerArguments.push(GetFromPersistent("filter_name")); + workerArguments.push(GetFromPersistent("filter_priority")); + + bool callbackFired = false; + while(!workerArguments.empty()) { + v8::Local node = workerArguments.front(); + workerArguments.pop(); + + if ( + !node->IsObject() + || node->IsArray() + || node->IsBooleanObject() + || node->IsDate() + || node->IsFunction() + || node->IsNumberObject() + || node->IsRegExp() + || node->IsStringObject() + ) { + continue; + } + + v8::Local nodeObj = node->ToObject(); + v8::Local checkValue = GetPrivate(nodeObj, Nan::New("NodeGitPromiseError").ToLocalChecked()); + + if (!checkValue.IsEmpty() && !checkValue->IsNull() && !checkValue->IsUndefined()) { + v8::Local argv[1] = { + checkValue->ToObject() + }; + callback->Call(1, argv); + callbackFired = true; + break; + } + + v8::Local properties = nodeObj->GetPropertyNames(); + for (unsigned int propIndex = 0; propIndex < properties->Length(); ++propIndex) { + v8::Local propName = properties->Get(propIndex)->ToString(); + v8::Local nodeToQueue = nodeObj->Get(propName); + if (!nodeToQueue->IsUndefined()) { + workerArguments.push(nodeToQueue); + } + } + } + + if (!callbackFired) { + v8::Local err = Nan::Error("Method register has thrown an error.")->ToObject(); + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); + v8::Local argv[1] = { + err + }; + callback->Call(1, argv); + } + } else { + callback->Call(0, NULL); + } } + delete baton; + return; } /* @@ -127,7 +222,10 @@ NAN_METHOD(GitFilterRegistry::GitFilterUnregister) { return Nan::ThrowError("String name is required."); } - // start convert_from_v8 block + if (info.Length() == 1 || !info[1]->IsFunction()) { + return Nan::ThrowError("Callback is required and must be a Function."); + } + const char * from_name = NULL; String::Utf8Value name(info[0]->ToString()); @@ -139,12 +237,22 @@ NAN_METHOD(GitFilterRegistry::GitFilterUnregister) { // ensure the final byte of our new string is null, extra casts added to ensure compatibility with various C types // used in the nodejs binding generation: memset((void *)(((char *)from_name) + name.length()), 0, 1); - // end convert_from_v8 block - - giterr_clear(); + + SimpleFilterBaton *baton = new SimpleFilterBaton; + baton->filter_name = (char *) malloc(name.length() + 1); + strcpy(baton->filter_name, from_name); + baton->error_code = GIT_OK; + + /* Setting up Async Worker */ + Nan::Callback *callback = new Nan::Callback(Local::Cast(info[1])); + UnRegisterWorker *worker = new UnRegisterWorker(baton, callback); + + worker->SaveToPersistent("filter_name", info[0]); + + /*giterr_clear(); { - LockMaster lockMaster(/*asyncAction: */false, from_name); + LockMaster lockMaster(false, from_name); int result = git_filter_unregister(from_name); @@ -153,5 +261,133 @@ NAN_METHOD(GitFilterRegistry::GitFilterUnregister) { to = Nan::New(result); // end convert_to_v8 block return info.GetReturnValue().Set(scope.Escape(to)); + }*/ + // Remove persistent reference for given filter + /*v8::Local handleRef = Nan::New(GitFilterRegistry::persistentHandle); + Nan::Maybe _delete_result = Nan::Delete(handleRef, info[0]->ToString()); + + Nan::Maybe result3 = Nan::Has(handleRef, info[0]->ToString()); + + if(!GitFilterRegistry::persistentHandle.IsEmpty()){ + printf("not empty\n"); + GitFilterRegistry::persistentHandle.Reset(); + } else { + printf("empty\n"); + }*/ + + AsyncLibgit2QueueWorker(worker); + return; +} + +// no v8 in execute +void GitFilterRegistry::UnRegisterWorker::Execute() { + + giterr_clear(); + + { + LockMaster lockMaster(/*asyncAction: */true, baton->filter_name); + int result = git_filter_unregister(baton->filter_name); + baton->error_code = result; + + if (result != GIT_OK && giterr_last() != NULL) { + baton->error = git_error_dup(giterr_last()); + } + } + /*// Remove persistent reference for given filter + *v8::Local handleRef = Nan::New(GitFilterRegistry::persistentHandle); + Nan::Maybe _delete_result = Nan::Delete(handleRef, info[0]->ToString()); + + Nan::Maybe result3 = Nan::Has(handleRef, info[0]->ToString()); + + if(!GitFilterRegistry::persistentHandle.IsEmpty()){ + printf("not empty\n"); + GitFilterRegistry::persistentHandle.Reset(); + } else { + printf("empty\n"); + }*/ +} + +void GitFilterRegistry::UnRegisterWorker::HandleOKCallback() { + + if (baton->error_code == GIT_OK) { + v8::Local result = Nan::New(baton->error_code); + v8::Local argv[2] = { + Nan::Null(), + result + }; + callback->Call(2, argv); + } else { + if (baton->error) { + v8::Local err; + if (baton->error->message) { + err = Nan::Error(baton->error->message)->ToObject(); + } else { + err = Nan::Error("Method register has thrown an error.")->ToObject(); + } + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); + v8::Local argv[1] = { + err + }; + callback->Call(1, argv); + if (baton->error->message) + free((void *)baton->error->message); + free((void *)baton->error); + } else if (baton->error_code < 0) { + std::queue< v8::Local > workerArguments; + workerArguments.push(GetFromPersistent("filter_name")); + + bool callbackFired = false; + while(!workerArguments.empty()) { + v8::Local node = workerArguments.front(); + workerArguments.pop(); + + if ( + !node->IsObject() + || node->IsArray() + || node->IsBooleanObject() + || node->IsDate() + || node->IsFunction() + || node->IsNumberObject() + || node->IsRegExp() + || node->IsStringObject() + ) { + continue; + } + + v8::Local nodeObj = node->ToObject(); + v8::Local checkValue = GetPrivate(nodeObj, Nan::New("NodeGitPromiseError").ToLocalChecked()); + + if (!checkValue.IsEmpty() && !checkValue->IsNull() && !checkValue->IsUndefined()) { + v8::Local argv[1] = { + checkValue->ToObject() + }; + callback->Call(1, argv); + callbackFired = true; + break; + } + + v8::Local properties = nodeObj->GetPropertyNames(); + for (unsigned int propIndex = 0; propIndex < properties->Length(); ++propIndex) { + v8::Local propName = properties->Get(propIndex)->ToString(); + v8::Local nodeToQueue = nodeObj->Get(propName); + if (!nodeToQueue->IsUndefined()) { + workerArguments.push(nodeToQueue); + } + } + } + + if (!callbackFired) { + v8::Local err = Nan::Error("Method register has thrown an error.")->ToObject(); + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); + v8::Local argv[1] = { + err + }; + callback->Call(1, argv); + } + } else { + callback->Call(0, NULL); + } } + delete baton; + return; } diff --git a/generate/templates/partials/async_function.cc b/generate/templates/partials/async_function.cc index b8e19ddb0..34c3e7bb3 100644 --- a/generate/templates/partials/async_function.cc +++ b/generate/templates/partials/async_function.cc @@ -16,9 +16,13 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) { {{ cppFunctionName }}_globalPayload* globalPayload = new {{ cppFunctionName }}_globalPayload; {%endif%} {%if arg.cppClassName == "GitBuf" %} - baton->{{arg.name}} = ({{ arg.cType }})malloc(sizeof({{ arg.cType|replace '*' '' }}));; - baton->{{arg.name}}->ptr = NULL; - baton->{{arg.name}}->size = baton->{{arg.name}}->asize = 0; + {%if cppFunctionName == "Set"%} + baton->{{arg.name}} = Nan::ObjectWrap::Unwrap<{{ arg.cppClassName }}>(info.This())->GetValue(); + {%else%} + baton->{{arg.name}} = ({{ arg.cType }})malloc(sizeof({{ arg.cType|replace '*' '' }})); + baton->{{arg.name}}->ptr = NULL; + baton->{{arg.name}}->size = baton->{{arg.name}}->asize = 0; + {%endif%} {%endif%} {%endeach%} @@ -57,7 +61,11 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) { {%endif%} {%endif%} {%elsif arg.shouldAlloc %} - baton->{{ arg.name }} = ({{ arg.cType }})malloc(sizeof({{ arg.cType|replace '*' '' }})); + {%if arg.cppClassName == "GitBuf" %} + {%else%} + // culprit found + baton->{{ arg.name }} = ({{ arg.cType }})malloc(sizeof({{ arg.cType|replace '*' '' }})); + {%endif%} {%endif%} {%endeach%} @@ -273,8 +281,11 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { delete ({{ cppFunctionName}}_globalPayload*)baton->{{ arg.name }}; {%endif%} {%if arg.cppClassName == "GitBuf" %} - git_buf_free(baton->{{ arg.name }}); - free((void *)baton->{{ arg.name }}); + {%if cppFunctionName == "Set" %} + {%else%} + git_buf_free(baton->{{ arg.name }}); + free((void *)baton->{{ arg.name }}); + {%endif%} {%endif%} {%endeach%} diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index 3c5d4615f..f330f0462 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -202,7 +202,11 @@ {% endeach %} {% if field.isSelfReferential %} - v8::Local argv[{{ field.args|jsArgsCount|subtract 2| setUnsigned }}] = { + {% if field.args|jsArgsCount|subtract 2| setUnsigned == 0 %} + v8::Local *argv = NULL; + {% else %} + v8::Local argv[{{ field.args|jsArgsCount|subtract 2| setUnsigned }}] = { + {% endif %} {% else %} v8::Local argv[{{ field.args|jsArgsCount }}] = { {% endif %} @@ -244,7 +248,11 @@ {% endif %} {% endif %} {% endeach %} - }; + {% if not field.isSelfReferential %} + }; + {% elsif field.args|jsArgsCount|subtract 2| setUnsigned > 0 %} + }; + {% endif %} Nan::TryCatch tryCatch; v8::Local result = instance->{{ field.name }}.GetCallback()->Call({{ field.args|jsArgsCount|subtract 2| setUnsigned }}, argv); diff --git a/generate/templates/templates/nodegit.js b/generate/templates/templates/nodegit.js index 8b2baa030..246f5b26b 100644 --- a/generate/templates/templates/nodegit.js +++ b/generate/templates/templates/nodegit.js @@ -60,6 +60,12 @@ var _ConvenientHunk_lines = _ConvenientHunk.prototype.lines; _ConvenientHunk.prototype.lines = promisify(_ConvenientHunk_lines); var _FilterRegistry = rawApi.FilterRegistry; +var _FilterRegistry_register = _FilterRegistry.register; +_FilterRegistry.register = promisify(_FilterRegistry_register); + +var _FilterRegistry_unregister = _FilterRegistry.unregister; +_FilterRegistry.unregister = promisify(_FilterRegistry_unregister); + /* jshint ignore:end */ // Set the exports prototype to the raw API. diff --git a/lib/filter_registry.js b/lib/filter_registry.js index 67549170a..bdf9f4ffa 100644 --- a/lib/filter_registry.js +++ b/lib/filter_registry.js @@ -6,13 +6,9 @@ var FilterRegistry = NodeGit.FilterRegistry; var _register = FilterRegistry.register; var _unregister = FilterRegistry.unregister; -// // hold onto the scope of our filters until unregister is called -var filtersByName = {}; - // register should add filter by name to dict and return - // Override FilterRegistry.register to normalize Filter -FilterRegistry.register = function(name, filter, priority) { +FilterRegistry.register = function(name, filter, priority, callback) { // setting default value of attributes if(filter.attributes === undefined) { filter.attributes = ""; @@ -20,23 +16,28 @@ FilterRegistry.register = function(name, filter, priority) { filter = normalizeOptions(filter, NodeGit.Filter); - if (filtersByName[name] === undefined) { - filtersByName[name] = filter; - } - if(filter.check && filter.apply) { - return _register(name, filter, priority); + return _register(name, filter, priority) + .then(function(result) { + if(typeof callback === "function") { + callback(null, result); + } + return result; + }, callback); } else { - console.log( - "ERROR: please provide check and apply callbacks for filter"); - return null; + return callback(new Error( + "ERROR: please provide check and apply callbacks for filter" + )); } }; -FilterRegistry.unregister = function(name){ - if (filtersByName[name] !== undefined) { - delete filtersByName[name]; - } - return _unregister(name); +FilterRegistry.unregister = function(name, callback){ + return _unregister(name) + .then(function(result) { + if(typeof callback === "function") { + callback(null, result); + } + return result; + }, callback); }; diff --git a/test/tests/filter.js b/test/tests/filter.js index f8f230670..5ec300dcf 100644 --- a/test/tests/filter.js +++ b/test/tests/filter.js @@ -6,16 +6,69 @@ var assert = require("assert"), describe("Filter", function() { var NodeGit = require("../../"); + // var Buffer = NodeGit.Buf; + // var FilterSource = NodeGit.FilterSource; - var emptyRepoPath = local("../repos/empty"), - filterName = "psuedo_filter", - // newRepoPath = local("../repos/newrepo"), - Registry = NodeGit.FilterRegistry, - Checkout = NodeGit.Checkout, - Repository = NodeGit.Repository, - Attr = NodeGit.Attr, - Status = NodeGit.Status, - reposPath = local("../repos/workdir"); + var emptyRepoPath = local("../repos/empty"); + var filterName = "psuedo_filter"; + var Registry = NodeGit.FilterRegistry; + var Checkout = NodeGit.Checkout; + var Repository = NodeGit.Repository; + // Attr = NodeGit.Attr, + // Status = NodeGit.Status, + var reposPath = local("../repos/workdir"); + + var packageJsonPath = path.join(reposPath, "package.json"); + var readmePath = path.join(reposPath, "README.md"); + + function commitFile(repo, fileName, fileContent, commitMessage) { + var index; + var treeOid; + var parent; + + return fse.writeFile(path.join(repo.workdir(), fileName), fileContent) + .then(function() { + return repo.refreshIndex(); + }) + .then(function(indexResult) { + index = indexResult; + }) + .then(function() { + return index.addByPath(fileName); + }) + .then(function() { + return index.write(); + }) + .then(function() { + return index.writeTree(); + }) + .then(function(oidResult) { + treeOid = oidResult; + return NodeGit.Reference.nameToId(repo, "HEAD"); + }) + .then(function(head) { + return repo.getCommit(head); + }) + .then(function(parentResult) { + parent = parentResult; + return Promise.all([ + NodeGit.Signature.create("Foo Bar", "foo@bar.com", 123456789, 60), + NodeGit.Signature.create("Foo A Bar", "foo@bar.com", 987654321, 90) + ]); + }) + .then(function(signatures) { + var author = signatures[0]; + var committer = signatures[1]; + + return repo.createCommit( + "HEAD", + author, + committer, + "message", + treeOid, + [parent]); + }); + } beforeEach(function() { var test = this; @@ -31,9 +84,10 @@ describe("Filter", function() { test.emptyRepo = emptyRepo; }) .then(function() { + // FIXME: updated * wildcard to *.md -> update test cases return fse.writeFile( path.join(reposPath, ".gitattributes"), - "* filter="+ filterName +" diff=lfs merge=lfs -text", { + "*.md filter="+ filterName +" diff=lfs merge=lfs -text", { encoding: "utf-8", }); }); @@ -41,284 +95,573 @@ describe("Filter", function() { afterEach(function() { //Unregistering the filter to avoid GIT_EEXISTS - Registry.unregister(filterName); + return Registry.unregister(filterName) + .then(function(error_code){ + if(error_code) { + console.log("Error code: ", error_code); + } + }) + .catch(function(error) { + if (error.errno !== -3) { + throw new Error(error); + } + }); }); - describe("Register and unregister", function(){ + describe("Register and Unregister (now callback)", function(){ it("Registering filter for the first time", function() { + // registering custom filter - var result = Registry.register(filterName, { - initialize: function() { - console.log("inside INIT"); - }, + return Registry.register(filterName, { apply: function() { - console.log("inside APPLY"); - }, - stream: function() { - console.log("inside STREAM"); + // console.log("inside APPLY"); + return; }, check: function(){ - console.log("inside CHECK"); + // console.log("inside CHECK"); + return; } - }, 0); - assert.strictEqual(result, 0); + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }); }); it("Registering filter and re-registering same filter", function() { // registering custom filter - var result = Registry.register(filterName, { - initialize: function() { - console.log("inside INIT"); - }, + return Registry.register(filterName, { apply: function() { - console.log("inside APPLY"); - }, - stream: function() { - console.log("inside STREAM"); - }, - check: function(){ - console.log("inside CHECK"); - } - }, 0); - assert.strictEqual(result, 0); - - result = Registry.register(filterName, { - initialize: function() { - console.log("inside INIT"); - }, - apply: function() { - console.log("inside APPLY"); - }, - stream: function() { - console.log("inside STREAM"); + return; }, check: function(){ - console.log("inside CHECK"); + return; } - }, 0); - assert.strictEqual(result, -4); + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + return; + }) + .then(function() { + return Registry.register(filterName, { + apply: function() { + return; + }, + check: function(){ + return; + } + }, 0); + }) + .catch(function(error) { + assert.strictEqual(error.errno, -4); + }); }); - }); describe("Initialize callback", function(){ - /* TODO: first setup and check init callback - * , based on what it's supposed to do - */ - it.only("Testing initialize callback", function() { + + it("Testing initialize callback", function() { + var test = this; // test if anything has changed and appy something, then check - var result = Registry.register(filterName, { + return Registry.register(filterName, { initialize: function() { - console.log("inside INIT"); + fse.writeFileSync( + readmePath, + "Initialized", { + encoding: "utf-8" + } + ); return 0; }, apply: function() { - console.log("inside APPLY"); - }, - stream: function() { - console.log("inside STREAM"); + return; }, - check: function(){ - console.log("inside CHECK"); - return 0; - }, - shutdown: function(){ - console.log("inside SHUTDOWN"); - return 0; + check: function() { + return -30; } - }, 0); - assert.strictEqual(result, 0); + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }) + .then(function() { + //assert the package json does not contain Initialized TEXT + var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), + readmeContent = fse.readFileSync(readmePath, "utf-8"); + + assert.notEqual(packageContent, ""); + assert.notEqual(readmeContent, "Initialized"); + }) + .then(function() { + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", + }); + }) + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + var postInitializeReadmeContents = fse.readFileSync( + readmePath, "utf-8"); + + assert.strictEqual( + postInitializeReadmeContents, "Initialized"); + }); }); }); describe("Shutdown callback", function(){ it("Testing shutdown callback", function(){ - var result = Registry.register(filterName, { - initialize: function() { - console.log("inside INIT"); - return 0; - }, + var test = this; + return Registry.register(filterName, { apply: function() { - console.log("inside APPLY"); - }, - stream: function() { - console.log("inside STREAM"); + return; }, check: function(){ - console.log("inside CHECK"); - return 0; + return -30; }, shutdown: function(){ - console.log("inside SHUTDOWN"); - return 0; + fse.writeFileSync( + readmePath, + "Shutdown", { + encoding: "utf-8" + } + ); } - }, 0); - assert.strictEqual(result, 0); + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }) + .then(function() { + var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), + readmeContent = fse.readFileSync(readmePath, "utf-8"); - result = Registry.unregister(filterName); - assert.strictEqual(result, 0); + assert.notEqual(packageContent, ""); + assert.notEqual(readmeContent, "Shutdown"); + }) + .then(function() { + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", + }); + }) + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + return Registry.unregister(filterName); + }) + .then(function() { + var postUnregisterReadmeContent = fse.readFileSync( + readmePath, "utf-8"); + + assert.strictEqual( + postUnregisterReadmeContent, "Shutdown"); + }); }); - // TODO: shutdown is supposed to work even if - // intialize call back is not provided/call not made - it("Testing shutdown callback with initialize callback", function(){ - var result = Registry.register(filterName, { + it("Testing shutdown callback without initialize callback", function(){ + var test = this; + return Registry.register(filterName, { apply: function() { - console.log("inside APPLY"); - }, - stream: function() { - console.log("inside STREAM"); + return; }, check: function(){ - console.log("inside CHECK"); - return 0; + return -30; }, shutdown: function(){ - console.log("inside SHUTDOWN"); - return 0; + fse.writeFileSync( + readmePath, + "Shutdown", { + encoding: "utf-8" + } + ); } - }, 0); - assert.strictEqual(result, 0); + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }) + .then(function() { + var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), + readmeContent = fse.readFileSync(readmePath, "utf-8"); - result = Registry.unregister(filterName); - // somewhere here test the result of the shutdown callback - assert.strictEqual(result, 0); + assert.notEqual(packageContent, ""); + assert.notEqual(readmeContent, "Shutdown"); + }) + .then(function() { + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", + }); + }) + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + return Registry.unregister(filterName); + }) + .then(function() { + var postUnregisterReadmeContent = fse.readFileSync( + readmePath, "utf-8"); + + assert.strictEqual( + postUnregisterReadmeContent, "Shutdown"); + }); }); }); - describe("Check Callback", function(){ + describe("Check and Apply callback", function(){ it( - "GIT_PASSTHROUGH should be returned" + - " if filter is not to be applied", function(){ - var result = Registry.register(filterName, { - initialize: function() { - console.log("inside INIT"); - return 0; - }, + "if GIT_PASSTHROUGH is returned" + + " filter should not to be applied", function(){ + var test = this; + + return Registry.register(filterName, { apply: function() { - console.log("inside APPLY"); + fse.writeFileSync( + readmePath, + "Filter Applied", { + encoding: "utf-8" + } + ); }, - stream: function() { - console.log("inside STREAM"); + check: function() { + return -30; + } + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }) + .then(function() { + //assert the package json does not contain Initialized TEXT + var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), + readmeContent = fse.readFileSync(readmePath, "utf-8"); + + assert.notStrictEqual(packageContent, ""); + assert.notStrictEqual(readmeContent, "Filter Applied"); + }) + .then(function() { + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", + }); + }) + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + var postInitializeReadmeContents = fse.readFileSync( + readmePath, "utf-8"); + + assert.notStrictEqual( + postInitializeReadmeContents, "Filter Applied" + ); + }); + + }); + + it("if GIT_OK is passed, filter should be applied", function() { + var test = this; + + return Registry.register(filterName, { + apply: function() { + fse.writeFileSync( + readmePath, + "Filter Applied", { + encoding: "utf-8" + } + ); }, - check: function(){ - console.log("inside CHECK"); + check: function() { + return 0; + } + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }) + .then(function() { + //assert the package json does not contain Initialized TEXT + var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), + readmeContent = fse.readFileSync(readmePath, "utf-8"); + + assert.notStrictEqual(packageContent, ""); + assert.notStrictEqual(readmeContent, "Filter Applied"); + }) + .then(function() { + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", + }); + }) + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + var postInitializeReadmeContents = fse.readFileSync( + readmePath, "utf-8"); + + assert.strictEqual( + postInitializeReadmeContents, "Filter Applied" + ); + }); + }); + + it("if GIT_PASSTHROUGH is returned from Apply callback", function() { + var test = this; + + var tempBuffer = new Buffer("some new fancy filter", "utf8"); + console.log("tempBuffer: ", tempBuffer); + + // check the contents of to inside of apply + //call back and check if the to structure is + //being poulated v/s just being null + return Registry.register(filterName, { + apply: function(to, from, source) { + // console.log("To: ", to.ptr()); + // console.log("From: ", from.ptr()); + // to.ptr = "some random text 2"; + // console.log("To: ", to.ptr()); + // console.log("[changed]From: ", from.ptr()); + // console.log("Source: ", source); + fse.writeFileSync( + readmePath, + "Filter Applied", { + encoding: "utf-8" + } + ); return 0; }, - shutdown: function(){ - console.log("inside SHUTDOWN"); + check: function() { return 0; + }, + cleanup: function() { + // console.log("Inside CLEANUP"); + return; } - }, 0); - assert.strictEqual(result, 0); - /* - do some action like change package.json - the filter should return GIT_PASSTHROUGH - verify -> apply callback should get -30 or anything except 0 - check if contents of file modified are not changed and staged? - */ + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }) + .then(function() { + //assert the package json does not contain Initialized TEXT + var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), + readmeContent = fse.readFileSync(readmePath, "utf-8"); + + assert.notStrictEqual(packageContent, ""); + assert.notStrictEqual(readmeContent, "Filter Applied"); + }) + .then(function() { + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", + }); + }) + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + var postInitializeReadmeContents = fse.readFileSync( + readmePath, "utf-8"); + + assert.strictEqual( + postInitializeReadmeContents, "Filter Applied" + ); + }); }); - it.only("Testing check callback", function() { - var test = this, - testFilePath = path.join(reposPath, "package.json"), - flags = Status.SHOW.INDEX_AND_WORKDIR; + it.only("using buffers to control data flow inside filter", function() { + var test = this; - // registering custom filter - var result = Registry.register(filterName, { - initialize: function() { - console.log("inside INIT"); - }, - apply: function() { - console.log("inside APPLY"); + return Registry.register(filterName, { + apply: function(to, from, source) { + var tempBuffer = new Buffer("fancy filter", "utf8"); + // console.log("tempBuffer: ", tempBuffer); + + // console.log("To: ", to.ptr()); + // console.log("From: ", from.ptr()); + var newTo = to.set(tempBuffer, 12) + .then(function(buf) { + // console.log("buffer: ", buf); + return buf; + }); + return newTo.then(function(ret) { + console.log("To[New]: ", to.ptr()); + return 0; + }); }, - check: function(){ - console.log("inside CHECK"); + check: function() { return 0; + }, + cleanup: function() { + return; } - }, 0); - - assert.strictEqual(result, 0); - - // creating .gitattributes - /*var gitattributeFilePromise = fse.writeFile( - path.join(reposPath, ".gitattributes"), - "* filter="+ filterName +" diff=lfs merge=lfs -text", { - encoding: "utf-8", - });*/ - //creating test file that will be used to trigger custom filter - Attr.cacheFlush(this.repository); - /*var testFilePromise = fse.writeFile( - testFilePath, - "initial text", { - encoding: "utf-8", - });*/ - - return fse.writeFile( - testFilePath, - "initial text", { - encoding: "utf-8", - }) - .then(function() { - return Attr.get( - test.repository, - flags, - path.join(reposPath, ".gitattributes"), - "filter"); - }) - // check attribute values - .then(function(data) { - console.log("data: ", data); - assert.strictEqual(data, filterName); - }) - // modify file - .then(function() { - return fse.writeFile(testFilePath, - "Modified Content", - { - encoding: "utf-8" + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }) + .then(function() { + var readmeContent = fse.readFileSync(readmePath, "utf-8"); + assert.notStrictEqual(readmeContent, "testing commit contents"); + }) + .then(function() { + return commitFile(test.repository, "README.md", + "testing commit contents", + "test commit"); + }) + .then(function() { + var postInitializeReadmeContents = fse.readFileSync( + readmePath, "utf-8"); + + assert.strictEqual( + postInitializeReadmeContents, "testing commit contents" + ); }); - }) - // perform checkout, which should trigger filter - .then(function() { - var opts = { - checkoutStrategy: Checkout.STRATEGY.FORCE, - paths: "package.json" - }; - return Checkout.head(test.repository, opts); - }) - .then(function() { - console.log("Post checkout"); - }); + }); + }); + describe("Cleanup callback", function() { + it("Cleanup callback is called after" + + " filter has been applied", function() { + var test = this; + // test if anything has changed and appy something, then check + return Registry.register(filterName, { + initialize: function() { + fse.writeFileSync( + readmePath, + "Initialized", { + encoding: "utf-8" + } + ); + return 0; + }, + apply: function() { + return 0; + }, + check: function() { + return 0; + }, + cleanup: function() { + fse.writeFileSync( + readmePath, + "Cleaned Up", { + encoding: "utf-8" + } + ); + } + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }) + .then(function() { + //assert the package json does not contain Initialized TEXT + var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), + readmeContent = fse.readFileSync(readmePath, "utf-8"); - /*// setup complete, testing initialize of custom filter - return Promise.all([gitattributeFilePromise, testFilePromise]) - // create necessary files + assert.notEqual(packageContent, ""); + assert.notEqual(readmeContent, "Initialized"); + }) + .then(function() { + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", + }); + }) + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) .then(function() { - return Attr.get( - test.repository, - flags, - path.join(reposPath, ".gitattributes"), - "filter"); + var postInitializeReadmeContents = fse.readFileSync( + readmePath, "utf-8"); + + assert.strictEqual( + postInitializeReadmeContents, "Cleaned Up"); + }); + }); + + it("Cleanup callback should not be called if" + + " Check callback returns GIT_PASSTHROUGH", function() { + var test = this; + // test if anything has changed and appy something, then check + return Registry.register(filterName, { + initialize: function() { + fse.writeFileSync( + readmePath, + "Initialized", { + encoding: "utf-8" + } + ); + return 0; + }, + apply: function() { + return 0; + }, + check: function() { + return -30; + }, + cleanup: function() { + fse.writeFileSync( + readmePath, + "Cleaned Up", { + encoding: "utf-8" + } + ); + } + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); }) - // check attribute values - .then(function(data) { - console.log("data: ", data); - assert.strictEqual(data, filterName); + .then(function() { + //assert the package json does not contain Initialized TEXT + var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), + readmeContent = fse.readFileSync(readmePath, "utf-8"); + + assert.notEqual(packageContent, ""); + assert.notEqual(readmeContent, "Initialized"); }) - // modify file .then(function() { - return fse.writeFile(testFilePath, - "Modified Content", - { - encoding: "utf-8" + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", }); }) - // perform checkout, which should trigger filter .then(function() { var opts = { checkoutStrategy: Checkout.STRATEGY.FORCE, @@ -327,28 +670,12 @@ describe("Filter", function() { return Checkout.head(test.repository, opts); }) .then(function() { - console.log("Post checkout"); - });*/ - }); - }); + var postInitializeReadmeContents = fse.readFileSync( + readmePath, "utf-8"); - describe("Apply Callback", function(){ - it("Verify apply callback", function(){ - /* - register filter - make changes -> checkout - verify return value from apply - verify changes - */ - }); - it("Verify apply callback did not work", function(){ - /* - register filter - make changes -> checkout - verify return value from apply as GIT_PASSTHROUGH - verify changes - */ - }); + assert.notStrictEqual( + postInitializeReadmeContents, "Cleaned Up"); + }); + }); }); - }); From 339799e89ce3c144fc21cd4783ffb846ca880513 Mon Sep 17 00:00:00 2001 From: Mohseen Mukaddam Date: Thu, 6 Jul 2017 15:05:30 -0700 Subject: [PATCH 08/35] Added more unit tests implementing checks in test suite added more filter tests lol CRLF Added more unit tests --- test/tests/filter.js | 822 +++++++++++++++++++++++++------------------ 1 file changed, 487 insertions(+), 335 deletions(-) diff --git a/test/tests/filter.js b/test/tests/filter.js index 5ec300dcf..70a5ea0b0 100644 --- a/test/tests/filter.js +++ b/test/tests/filter.js @@ -6,25 +6,32 @@ var assert = require("assert"), describe("Filter", function() { var NodeGit = require("../../"); - // var Buffer = NodeGit.Buf; - // var FilterSource = NodeGit.FilterSource; var emptyRepoPath = local("../repos/empty"); var filterName = "psuedo_filter"; var Registry = NodeGit.FilterRegistry; var Checkout = NodeGit.Checkout; var Repository = NodeGit.Repository; - // Attr = NodeGit.Attr, - // Status = NodeGit.Status, var reposPath = local("../repos/workdir"); var packageJsonPath = path.join(reposPath, "package.json"); var readmePath = path.join(reposPath, "README.md"); + var GIT_PASSTHROUGH = -30; + + var mockFilter = { + apply: function() { + return; + }, + check: function(){ + return; + } + }; + function commitFile(repo, fileName, fileContent, commitMessage) { - var index; - var treeOid; - var parent; + let index; + let treeOid; + let parent; return fse.writeFile(path.join(repo.workdir(), fileName), fileContent) .then(function() { @@ -57,14 +64,14 @@ describe("Filter", function() { ]); }) .then(function(signatures) { - var author = signatures[0]; - var committer = signatures[1]; + let author = signatures[0]; + let committer = signatures[1]; return repo.createCommit( "HEAD", author, committer, - "message", + commitMessage, treeOid, [parent]); }); @@ -76,101 +83,177 @@ describe("Filter", function() { return Repository.open(reposPath) .then(function(repository) { test.repository = repository; - }) - .then(function() { return Repository.open(emptyRepoPath); }) .then(function(emptyRepo) { test.emptyRepo = emptyRepo; - }) - .then(function() { - // FIXME: updated * wildcard to *.md -> update test cases return fse.writeFile( path.join(reposPath, ".gitattributes"), - "*.md filter="+ filterName +" diff=lfs merge=lfs -text", { + "*.md filter="+ filterName +" -text", { encoding: "utf-8", }); }); }); afterEach(function() { - //Unregistering the filter to avoid GIT_EEXISTS return Registry.unregister(filterName) - .then(function(error_code){ - if(error_code) { - console.log("Error code: ", error_code); - } - }) .catch(function(error) { - if (error.errno !== -3) { - throw new Error(error); + switch(error) { + case -1: + throw new Error("Cannot unregister filter"); + // case -3: + // throw new Error('Cannot find filter to unregister'); + default: + return; } }); }); - describe("Register and Unregister (now callback)", function(){ - it("Registering filter for the first time", function() { + describe("Register", function() { + var secondFilter = "hellofilter"; + + after(function(done) { + return Registry.unregister(secondFilter) + .then(function() { + done(); + }); + }); + + it("can register a filter", function() { + return Registry.register(filterName, mockFilter, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }); + }); + + it("can register multiple filters", function() { + return Registry.register(filterName, mockFilter, 0) + .then(function(result) { + assert.strictEqual(result, 0); + return Registry.register(secondFilter, mockFilter, 1); + }) + .then(function(result) { + assert.strictEqual(result, 0); + }); + }); + + it("cannot register the same filter twice", function() { + return Registry.register(filterName, mockFilter, 0) + .then(function(result) { + assert.strictEqual(result, 0); + return Registry.register(filterName, mockFilter, 0); + }) + .catch(function(error) { + assert.strictEqual(error.errno, -4); + }); + }); + }); + + describe("Unregister", function() { + beforeEach(function() { + return Registry.register(filterName, mockFilter, 0); + }); + + it("can unregister the filter", function() { + return Registry.unregister(filterName) + .then(function(result) { + assert.strictEqual(result, 0); + }); + }); + + it("cannot unregister the filter twice", function() { + return Registry.unregister(filterName) + .then(function(result) { + assert.strictEqual(result, 0); + return Registry.unregister(filterName); + }) + .then(function(result) { + assert.fail(result, -3, "Should not have unregistered successfully"); + }) + .catch(function(error) { + assert.strictEqual(error.errno, -3); + }); + }); + }); - // registering custom filter + describe("Initialize", function(){ + it("initializes successfully", function() { + var test = this; + var initialized = false; return Registry.register(filterName, { + initialize: function() { + initialized = true; + return 0; + }, apply: function() { - // console.log("inside APPLY"); return; }, - check: function(){ - // console.log("inside CHECK"); - return; + check: function() { + return -30; } }, 0) .then(function(result) { assert.strictEqual(result, 0); + }) + .then(function() { + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout"); + }) + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + assert.strictEqual(initialized, true); }); }); - it("Registering filter and re-registering same filter", function() { - // registering custom filter + it("initializes successfully even on garbage collect", function() { + var test = this; + var initialized = false; return Registry.register(filterName, { + initialize: function() { + initialized = true; + return 0; + }, apply: function() { return; }, - check: function(){ - return; + check: function() { + return -30; } }, 0) - .then(function(result) { - assert.strictEqual(result, 0); - return; - }) - .then(function() { - return Registry.register(filterName, { - apply: function() { - return; - }, - check: function(){ - return; - } - }, 0); - }) - .catch(function(error) { - assert.strictEqual(error.errno, -4); - }); + .then(function(result) { + assert.strictEqual(result, 0); + global.gc(); + + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout"); + }) + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + assert.strictEqual(initialized, true); + }); }); - }); - describe("Initialize callback", function(){ - - it("Testing initialize callback", function() { + it("does not initialize successfully", function() { var test = this; - // test if anything has changed and appy something, then check + var initialized = false; return Registry.register(filterName, { initialize: function() { - fse.writeFileSync( - readmePath, - "Initialized", { - encoding: "utf-8" - } - ); - return 0; + initialized = true; + return -1; }, apply: function() { return; @@ -182,20 +265,10 @@ describe("Filter", function() { .then(function(result) { assert.strictEqual(result, 0); }) - .then(function() { - //assert the package json does not contain Initialized TEXT - var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), - readmeContent = fse.readFileSync(readmePath, "utf-8"); - - assert.notEqual(packageContent, ""); - assert.notEqual(readmeContent, "Initialized"); - }) .then(function() { return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + "Changing content to trigger checkout"); }) .then(function() { var opts = { @@ -204,20 +277,19 @@ describe("Filter", function() { }; return Checkout.head(test.repository, opts); }) - .then(function() { - var postInitializeReadmeContents = fse.readFileSync( - readmePath, "utf-8"); - - assert.strictEqual( - postInitializeReadmeContents, "Initialized"); + .then(function(head) { + assert.fail(head, undefined, "Should not have actually checked out"); + }) + .catch(function(error) { + assert.strictEqual(initialized, true); }); }); }); - describe("Shutdown callback", function(){ - - it("Testing shutdown callback", function(){ + describe("Shutdown", function() { + it("filter successfully shuts down", function() { var test = this; + var shutdown = false; return Registry.register(filterName, { apply: function() { return; @@ -226,25 +298,49 @@ describe("Filter", function() { return -30; }, shutdown: function(){ - fse.writeFileSync( - readmePath, - "Shutdown", { - encoding: "utf-8" - } - ); + shutdown = true; } }, 0) .then(function(result) { assert.strictEqual(result, 0); + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", + }); }) .then(function() { - var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), - readmeContent = fse.readFileSync(readmePath, "utf-8"); - - assert.notEqual(packageContent, ""); - assert.notEqual(readmeContent, "Shutdown"); + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); }) .then(function() { + return Registry.unregister(filterName); + }) + .then(function(result) { + assert.strictEqual(result, 0); + assert.strictEqual(shutdown, true); + }); + }); + + it("filter successfully shuts down on garbage collect", function() { + var test = this; + var shutdown = false; + return Registry.register(filterName, { + apply: function() { + return; + }, + check: function(){ + return -30; + }, + shutdown: function(){ + shutdown = true; + } + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); return fse.writeFile( packageJsonPath, "Changing content to trigger checkout", { @@ -259,19 +355,18 @@ describe("Filter", function() { return Checkout.head(test.repository, opts); }) .then(function() { + global.gc(); return Registry.unregister(filterName); }) - .then(function() { - var postUnregisterReadmeContent = fse.readFileSync( - readmePath, "utf-8"); - - assert.strictEqual( - postUnregisterReadmeContent, "Shutdown"); + .then(function(result) { + assert.strictEqual(result, 0); + assert.strictEqual(shutdown, true); }); }); - it("Testing shutdown callback without initialize callback", function(){ + it("shutdown completes even if there is an error", function() { var test = this; + var shutdown = false; return Registry.register(filterName, { apply: function() { return; @@ -280,25 +375,12 @@ describe("Filter", function() { return -30; }, shutdown: function(){ - fse.writeFileSync( - readmePath, - "Shutdown", { - encoding: "utf-8" - } - ); + shutdown = true; + throw new Error("I failed"); } }, 0) .then(function(result) { assert.strictEqual(result, 0); - }) - .then(function() { - var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), - readmeContent = fse.readFileSync(readmePath, "utf-8"); - - assert.notEqual(packageContent, ""); - assert.notEqual(readmeContent, "Shutdown"); - }) - .then(function() { return fse.writeFile( packageJsonPath, "Changing content to trigger checkout", { @@ -315,49 +397,67 @@ describe("Filter", function() { .then(function() { return Registry.unregister(filterName); }) - .then(function() { - var postUnregisterReadmeContent = fse.readFileSync( - readmePath, "utf-8"); - - assert.strictEqual( - postUnregisterReadmeContent, "Shutdown"); + .then(function(result) { + assert.strictEqual(result, 0); + assert.strictEqual(shutdown, true); + }) + .catch(function(error) { + assert.fail(error, null, "The operation should not have failed"); }); }); - }); - describe("Check and Apply callback", function(){ + describe("Apply", function() { + var message = "some new fancy filter"; + var length = message.length; + var tempBuffer = new Buffer(message, "utf-8"); - it( - "if GIT_PASSTHROUGH is returned" + - " filter should not to be applied", function(){ + it("should not apply when check returns GIT_PASSTHROUGH", function(){ var test = this; + var applied = false; return Registry.register(filterName, { apply: function() { - fse.writeFileSync( - readmePath, - "Filter Applied", { - encoding: "utf-8" - } - ); + applied = true; }, check: function() { - return -30; + return GIT_PASSTHROUGH; } }, 0) .then(function(result) { assert.strictEqual(result, 0); + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", + }); }) .then(function() { - //assert the package json does not contain Initialized TEXT - var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), - readmeContent = fse.readFileSync(readmePath, "utf-8"); - - assert.notStrictEqual(packageContent, ""); - assert.notStrictEqual(readmeContent, "Filter Applied"); + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); }) .then(function() { + assert.notStrictEqual(applied, true); + }); + }); + + it("should apply filter when check succeeds", function() { + var test = this; + var applied = true; + + return Registry.register(filterName, { + apply: function() { + applied = true; + }, + check: function() { + return 0; + } + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); return fse.writeFile( packageJsonPath, "Changing content to trigger checkout", { @@ -372,27 +472,19 @@ describe("Filter", function() { return Checkout.head(test.repository, opts); }) .then(function() { - var postInitializeReadmeContents = fse.readFileSync( - readmePath, "utf-8"); - - assert.notStrictEqual( - postInitializeReadmeContents, "Filter Applied" - ); + assert.strictEqual(applied, true); }); - }); - it("if GIT_OK is passed, filter should be applied", function() { + it("does not apply when GIT_PASSTHROUGH is returned", function() { var test = this; - + return Registry.register(filterName, { - apply: function() { - fse.writeFileSync( - readmePath, - "Filter Applied", { - encoding: "utf-8" - } - ); + apply: function(to, from, source) { + return to.set(tempBuffer, length) + .then(function() { + return GIT_PASSTHROUGH; + }); }, check: function() { return 0; @@ -402,19 +494,12 @@ describe("Filter", function() { assert.strictEqual(result, 0); }) .then(function() { - //assert the package json does not contain Initialized TEXT - var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), - readmeContent = fse.readFileSync(readmePath, "utf-8"); + var readmeContent = fse.readFileSync(packageJsonPath, "utf-8"); + assert.notStrictEqual(readmeContent, message); - assert.notStrictEqual(packageContent, ""); - assert.notStrictEqual(readmeContent, "Filter Applied"); - }) - .then(function() { return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + "Changing content to trigger checkout"); }) .then(function() { var opts = { @@ -427,67 +512,72 @@ describe("Filter", function() { var postInitializeReadmeContents = fse.readFileSync( readmePath, "utf-8"); - assert.strictEqual( - postInitializeReadmeContents, "Filter Applied" - ); + assert.notStrictEqual(postInitializeReadmeContents, message); }); }); - it("if GIT_PASSTHROUGH is returned from Apply callback", function() { + it("applies the filter data on checkout", function() { var test = this; - - var tempBuffer = new Buffer("some new fancy filter", "utf8"); - console.log("tempBuffer: ", tempBuffer); - // check the contents of to inside of apply - //call back and check if the to structure is - //being poulated v/s just being null return Registry.register(filterName, { apply: function(to, from, source) { - // console.log("To: ", to.ptr()); - // console.log("From: ", from.ptr()); - // to.ptr = "some random text 2"; - // console.log("To: ", to.ptr()); - // console.log("[changed]From: ", from.ptr()); - // console.log("Source: ", source); - fse.writeFileSync( - readmePath, - "Filter Applied", { - encoding: "utf-8" - } - ); - return 0; + return to.set(tempBuffer, length) + .then(function(buf) { + return 0; + }); }, - check: function() { + check: function(src, attr) { return 0; - }, - cleanup: function() { - // console.log("Inside CLEANUP"); - return; } }, 0) .then(function(result) { assert.strictEqual(result, 0); }) .then(function() { - //assert the package json does not contain Initialized TEXT - var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), - readmeContent = fse.readFileSync(readmePath, "utf-8"); + var readmeContent = fse.readFileSync(readmePath, "utf-8"); + assert.notStrictEqual(readmeContent, message); + fse.writeFileSync(readmePath, "whoa", "utf8"); - assert.notStrictEqual(packageContent, ""); - assert.notStrictEqual(readmeContent, "Filter Applied"); + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: ["README.md"] + }; + return Checkout.head(test.repository, opts); }) .then(function() { - return fse.writeFile( - packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + var postInitializeReadmeContents = fse.readFileSync( + readmePath, "utf-8"); + + assert.strictEqual(postInitializeReadmeContents, message); + }); + }); + + it("applies the filter data on checkout with gc", function() { + var test = this; + + return Registry.register(filterName, { + apply: function(to, from, source) { + return to.set(tempBuffer, length) + .then(function(buf) { + return 0; + }); + }, + check: function(src, attr) { + return 0; + } + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); }) .then(function() { + var readmeContent = fse.readFileSync(readmePath, "utf-8"); + assert.notStrictEqual(readmeContent, message); + fse.writeFileSync(readmePath, "whoa", "utf8"); + global.gc(); + var opts = { checkoutStrategy: Checkout.STRATEGY.FORCE, - paths: "package.json" + paths: ["README.md"] }; return Checkout.head(test.repository, opts); }) @@ -495,34 +585,22 @@ describe("Filter", function() { var postInitializeReadmeContents = fse.readFileSync( readmePath, "utf-8"); - assert.strictEqual( - postInitializeReadmeContents, "Filter Applied" - ); + assert.strictEqual(postInitializeReadmeContents, message); }); }); - it.only("using buffers to control data flow inside filter", function() { + it("applies the filter data on commit", function() { var test = this; return Registry.register(filterName, { apply: function(to, from, source) { - var tempBuffer = new Buffer("fancy filter", "utf8"); - // console.log("tempBuffer: ", tempBuffer); - - // console.log("To: ", to.ptr()); - // console.log("From: ", from.ptr()); - var newTo = to.set(tempBuffer, 12) + return to.set(tempBuffer, length) .then(function(buf) { - // console.log("buffer: ", buf); - return buf; + return 0; }); - return newTo.then(function(ret) { - console.log("To[New]: ", to.ptr()); - return 0; - }); }, - check: function() { - return 0; + check: function(src, attr) { + return src.path() === "README.md" ? 0 : GIT_PASSTHROUGH; }, cleanup: function() { return; @@ -540,142 +618,216 @@ describe("Filter", function() { "testing commit contents", "test commit"); }) - .then(function() { + .then(function(oid) { + return test.repository.getHeadCommit(); + }) + .then(function(commit) { var postInitializeReadmeContents = fse.readFileSync( readmePath, "utf-8"); assert.strictEqual( postInitializeReadmeContents, "testing commit contents" ); + assert.strictEqual(commit.message(), "test commit"); + + return commit.getEntry("README.md"); + }) + .then(function(entry) { + assert.strictEqual(entry.isBlob(), true); + return entry.getBlob(); + }) + .then(function(blob) { + assert.strictEqual(blob.toString(), message); }); }); - }); - describe("Cleanup callback", function() { - it("Cleanup callback is called after" + - " filter has been applied", function() { - var test = this; - // test if anything has changed and appy something, then check - return Registry.register(filterName, { - initialize: function() { - fse.writeFileSync( - readmePath, - "Initialized", { - encoding: "utf-8" - } - ); - return 0; - }, - apply: function() { - return 0; - }, - check: function() { - return 0; - }, - cleanup: function() { - fse.writeFileSync( - readmePath, - "Cleaned Up", { - encoding: "utf-8" - } - ); - } - }, 0) + it("applies the filter data on commit with gc", function() { + var test = this; + + return Registry.register(filterName, { + apply: function(to, from, source) { + return to.set(tempBuffer, length) + .then(function(buf) { + return 0; + }); + }, + check: function(src, attr) { + return src.path() === "README.md" ? 0 : GIT_PASSTHROUGH; + }, + cleanup: function() { + return; + } + }, 0) .then(function(result) { + global.gc(); assert.strictEqual(result, 0); }) .then(function() { - //assert the package json does not contain Initialized TEXT - var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), - readmeContent = fse.readFileSync(readmePath, "utf-8"); - - assert.notEqual(packageContent, ""); - assert.notEqual(readmeContent, "Initialized"); + var readmeContent = fse.readFileSync(readmePath, "utf-8"); + assert.notStrictEqual(readmeContent, "testing commit contents"); }) .then(function() { - return fse.writeFile( - packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + return commitFile(test.repository, "README.md", + "testing commit contents", + "test commit"); }) - .then(function() { - var opts = { - checkoutStrategy: Checkout.STRATEGY.FORCE, - paths: "package.json" - }; - return Checkout.head(test.repository, opts); + .then(function(oid) { + global.gc(); + return test.repository.getHeadCommit(); }) - .then(function() { + .then(function(commit) { var postInitializeReadmeContents = fse.readFileSync( readmePath, "utf-8"); assert.strictEqual( - postInitializeReadmeContents, "Cleaned Up"); - }); - }); - - it("Cleanup callback should not be called if" + - " Check callback returns GIT_PASSTHROUGH", function() { - var test = this; - // test if anything has changed and appy something, then check - return Registry.register(filterName, { - initialize: function() { - fse.writeFileSync( - readmePath, - "Initialized", { - encoding: "utf-8" - } - ); - return 0; - }, - apply: function() { - return 0; - }, - check: function() { - return -30; - }, - cleanup: function() { - fse.writeFileSync( - readmePath, - "Cleaned Up", { - encoding: "utf-8" - } - ); - } - }, 0) - .then(function(result) { - assert.strictEqual(result, 0); - }) - .then(function() { - //assert the package json does not contain Initialized TEXT - var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), - readmeContent = fse.readFileSync(readmePath, "utf-8"); + postInitializeReadmeContents, "testing commit contents" + ); + assert.strictEqual(commit.message(), "test commit"); + global.gc(); - assert.notEqual(packageContent, ""); - assert.notEqual(readmeContent, "Initialized"); + return commit.getEntry("README.md"); }) - .then(function() { - return fse.writeFile( - packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + .then(function(entry) { + assert.strictEqual(entry.isBlob(), true); + return entry.getBlob(); }) - .then(function() { - var opts = { - checkoutStrategy: Checkout.STRATEGY.FORCE, - paths: "package.json" - }; - return Checkout.head(test.repository, opts); - }) - .then(function() { - var postInitializeReadmeContents = fse.readFileSync( - readmePath, "utf-8"); + .then(function(blob) { + assert.strictEqual(blob.toString(), message); + }); + }); + }); + + describe("Cleanup", function() { + it("is called successfully", function() { + var test = this; + var cleaned = false; + return Registry.register(filterName, { + initialize: function() { + return 0; + }, + apply: function() { + return 0; + }, + check: function() { + return 0; + }, + cleanup: function() { + cleaned = true; + } + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }) + .then(function() { + var packageContent = fse.readFileSync(packageJsonPath, "utf-8"); + assert.notEqual(packageContent, ""); - assert.notStrictEqual( - postInitializeReadmeContents, "Cleaned Up"); + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", }); - }); + }) + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + assert.strictEqual(cleaned, true); + }); + }); + + it("is called successfully with gc", function() { + var test = this; + var cleaned = false; + return Registry.register(filterName, { + initialize: function() { + return 0; + }, + apply: function() { + return 0; + }, + check: function() { + return 0; + }, + cleanup: function() { + cleaned = true; + } + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }) + .then(function() { + var packageContent = fse.readFileSync(packageJsonPath, "utf-8"); + assert.notEqual(packageContent, ""); + + global.gc(); + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", + }); + }) + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "package.json" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + assert.strictEqual(cleaned, true); + }); + }); + + it("is not called when apply returns GIT_PASSTHROUGH", function() { + var test = this; + var cleaned = false; + + return Registry.register(filterName, { + initialize: function() { + return 0; + }, + apply: function() { + return GIT_PASSTHROUGH; + }, + check: function() { + return 0; + }, + cleanup: function() { + cleaned = true; + } + }, 0) + .then(function(result) { + assert.strictEqual(result, 0); + }) + .then(function() { + var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), + readmeContent = fse.readFileSync(readmePath, "utf-8"); + + assert.notEqual(packageContent, ""); + assert.notEqual(readmeContent, "Initialized"); + }) + .then(function() { + return fse.writeFile( + packageJsonPath, + "Changing content to trigger checkout", { + encoding: "utf-8", + }); + }) + .then(function() { + var opts = { + checkoutStrategy: Checkout.STRATEGY.FORCE, + paths: "README.md" + }; + return Checkout.head(test.repository, opts); + }) + .then(function() { + assert.notStrictEqual(cleaned, true); + }); + }); }); }); From 718e101eb2d1f6166963b422b406c97e945cb2e7 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Tue, 11 Jul 2017 15:07:06 -0700 Subject: [PATCH 09/35] Fixed field_accessors template --- generate/templates/partials/async_function.cc | 1 - .../templates/partials/field_accessors.cc | 21 +++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/generate/templates/partials/async_function.cc b/generate/templates/partials/async_function.cc index 34c3e7bb3..20813136d 100644 --- a/generate/templates/partials/async_function.cc +++ b/generate/templates/partials/async_function.cc @@ -63,7 +63,6 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) { {%elsif arg.shouldAlloc %} {%if arg.cppClassName == "GitBuf" %} {%else%} - // culprit found baton->{{ arg.name }} = ({{ arg.cType }})malloc(sizeof({{ arg.cType|replace '*' '' }})); {%endif%} {%endif%} diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index f330f0462..f0ecc0350 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -215,7 +215,8 @@ {% if not arg.firstArg %} {% if field.args|jsArgsCount|subtract 1|or 0 %} {% if arg.cppClassName == "String" %} - src, + {%-- src is always the last arg --%} + src {% elsif arg.isJsArg %} {% if arg.isEnum %} Nan::New((int)baton->{{ arg.name }}), @@ -224,6 +225,7 @@ {% elsif arg.cType == "size_t" %} Nan::New((unsigned int)baton->{{ arg.name }}), {% elsif arg.name == "payload" %} + {%-- skip, filters should not have a payload --%} {% else %} Nan::New(baton->{{ arg.name }}), {% endif %} @@ -231,8 +233,9 @@ {% endif %} {% endif %} {% else %} - {% if arg.cppClassName == "String" %} - Nan::New(baton->{{ arg.name }}).ToLocalChecked(), + {% if arg.name == "payload" %} + {%-- payload is always the last arg --%} + Nan::New(instance->{{ fields|payloadFor field.name }}) {% elsif arg.isJsArg %} {% if arg.isEnum %} Nan::New((int)baton->{{ arg.name }}), @@ -241,7 +244,8 @@ {% elsif arg.cType == "size_t" %} // HACK: NAN should really have an overload for Nan::New to support size_t Nan::New((unsigned int)baton->{{ arg.name }}), - {% elsif arg.name == "payload" %} + {% elsif arg.cppClassName == "String" %} + Nan::New(baton->{{ arg.name }}).ToLocalChecked(), {% else %} Nan::New(baton->{{ arg.name }}), {% endif %} @@ -255,12 +259,17 @@ {% endif %} Nan::TryCatch tryCatch; - v8::Local result = instance->{{ field.name }}.GetCallback()->Call({{ field.args|jsArgsCount|subtract 2| setUnsigned }}, argv); + + {% if field.isSelfReferential %} + v8::Local result = instance->{{ field.name }}.GetCallback()->Call({{ field.args|jsArgsCount|subtract 2| setUnsigned }}, argv); + {% else %} + v8::Local result = instance->{{ field.name }}.GetCallback()->Call({{ field.args|jsArgsCount }}, argv); + {% endif %} if(PromiseCompletion::ForwardIfPromise(result, baton, {{ cppClassName }}::{{ field.name }}_promiseCompleted)) { return; } - //TODO: fix for void cases + {% if field.return.type == "void" %} baton->Done(); {% else %} From 8c6d2a513afbf522d392367193acad36c2ebe93f Mon Sep 17 00:00:00 2001 From: Mohseen Mukaddam Date: Wed, 12 Jul 2017 16:49:40 -0700 Subject: [PATCH 10/35] Fixing rouge console logs and bugs in tests --- generate/scripts/helpers.js | 3 --- test/tests/filter.js | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/generate/scripts/helpers.js b/generate/scripts/helpers.js index 08d12eb6e..9b7baa2cb 100644 --- a/generate/scripts/helpers.js +++ b/generate/scripts/helpers.js @@ -11,9 +11,6 @@ var callbackDefs = require("../input/callbacks.json"); var descriptor = require("../input/descriptor.json"); var libgit2 = require("../input/libgit2-docs.json"); -let funcs = Object.keys(libgit2.functions); -console.log(funcs.filter(item => item.includes('filter'))); - var cTypes = libgit2.groups.map(function(group) { return group[0];}); var cTypeMappings = { diff --git a/test/tests/filter.js b/test/tests/filter.js index 70a5ea0b0..ad29ef8c4 100644 --- a/test/tests/filter.js +++ b/test/tests/filter.js @@ -783,7 +783,7 @@ describe("Filter", function() { }); }); - it("is not called when apply returns GIT_PASSTHROUGH", function() { + it("is not called when check returns GIT_PASSTHROUGH", function() { var test = this; var cleaned = false; @@ -792,10 +792,10 @@ describe("Filter", function() { return 0; }, apply: function() { - return GIT_PASSTHROUGH; + return 0; }, check: function() { - return 0; + return GIT_PASSTHROUGH; }, cleanup: function() { cleaned = true; From d9527b317f39f7120ec90f2e6e2587d4b9687178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=A5=BA?= Date: Fri, 28 Jul 2017 09:33:23 +0800 Subject: [PATCH 11/35] Add CI build config for node stable version --- .travis.yml | 13 ++++++++----- appveyor.yml | 7 ++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 862d1eb6c..2b317c86e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,16 +13,19 @@ sudo: false env: matrix: - - export NODE_VERSION="6.5" TARGET_ARCH="x64" + - export NODE_VERSION="stable" TARGET_ARCH="x64" - export NODE_VERSION="7.4" TARGET_ARCH="x64" + - export NODE_VERSION="6.5" TARGET_ARCH="x64" matrix: fast_finish: true include: - os: linux - env: export NODE_VERSION="6.5" TARGET_ARCH="ia32" + env: export NODE_VERSION="stable" TARGET_ARCH="ia32" - os: linux env: export NODE_VERSION="7.4" TARGET_ARCH="ia32" + - os: linux + env: export NODE_VERSION="6.5" TARGET_ARCH="ia32" git: depth: 1 @@ -63,7 +66,7 @@ before_install: fi install: - - npm install; + - travis_retry npm install; # This is a random private key used purely for testing. before_script: @@ -78,9 +81,9 @@ before_script: script: if [ -z "$TRAVIS_TAG" ] && [ $TRAVIS_OS_NAME == "linux" ] && [ $NODE_VERSION == "6" ]; then - npm test && npm run cov && npm run coveralls; + travis_retry npm test && npm run cov && npm run coveralls; else - npm test; + travis_retry npm test; fi after_success: diff --git a/appveyor.yml b/appveyor.yml index 9ffa0bd02..c25c50ebb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,8 +27,9 @@ environment: GYP_MSVS_VERSION: 2013 matrix: # Node.js - - nodejs_version: "6" + - nodejs_version: "stable" - nodejs_version: "7" + - nodejs_version: "6" matrix: fast_finish: true @@ -39,12 +40,12 @@ install: - ps: Start-Process c:\projects\nodegit\vendor\pageant.exe c:\projects\nodegit\vendor\private.ppk - npm install -g npm - cmd: npm install -g node-gyp - - npm install + - appveyor-retry call npm install test_script: - node --version - npm --version - - cmd: npm test + - appveyor-retry call npm test on_success: - IF %APPVEYOR_REPO_TAG%==true npm install -g node-pre-gyp From f913d50a9e2fbe6861a3837d113bed8f4198fda2 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Mon, 31 Jul 2017 09:51:33 -0700 Subject: [PATCH 12/35] Exposed libgit2 git_branch_remote_name method --- generate/input/descriptor.json | 31 +++++++++++++++++++++++++++- generate/input/libgit2-docs.json | 35 +++++++++++++++++++++++++++++++- lib/branch.js | 19 +++++++++++++++++ test/tests/branch.js | 22 ++++++++++++++++++++ 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 lib/branch.js diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index d33298c30..4bf70fbb3 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -202,6 +202,32 @@ "git_branch_next": { "ignore": true }, + "git_branch_remote_name": { + "cppFunctionName": "RemoteName", + "jsFunctionName": "remoteName", + "isAsync": true, + "args": { + "out": { + "isReturn": true, + "cppClassName": "GitBuf", + "jsClassName": "Buffer", + "cType": "git_buf *" + }, + "repo": { + "cppClassName": "GitRepository", + "jsClassName": "Repo", + "cType": "git_repository *" + }, + "canonical_branch_name": { + "cppClassName": "String", + "jsClassName": "String", + "cType": "const char *" + } + }, + "return": { + "isErrorCode": true + } + }, "git_branch_set_upstream": { "isAsync": true, "args": { @@ -221,7 +247,10 @@ "isErrorCode": true } } - } + }, + "dependencies": [ + "../include/buf.h" + ] }, "buf": { "functions": { diff --git a/generate/input/libgit2-docs.json b/generate/input/libgit2-docs.json index 48099e8b0..fb9f175af 100644 --- a/generate/input/libgit2-docs.json +++ b/generate/input/libgit2-docs.json @@ -2632,6 +2632,38 @@ "comments": "

The name of the branch matches the definition of the name for git_branch_lookup. That is, if the returned name is given to git_branch_lookup() then the reference is returned that was given to this function.

\n", "group": "branch" }, + "git_branch_remote_name": { + "type": "function", + "file": "branch.h", + "line": 274, + "lineto": 277, + "args": [ + { + "name": "out", + "type": "git_buf *", + "comment": "where the name is stored." + }, + { + "name": "repo", + "type": "git_respository *", + "comment": "the repo to check." + }, + { + "name": "canonical_branch_name", + "type": "const char *", + "comment": "the ref name of the branch" + } + ], + "argline": "git_buf *out, git_repository *repo, const char *canonical_branch_name", + "sig": "git_buf *::git_repository *::const char *", + "return": { + "type": "int", + "comment": " 0 on success; otherwise an error code (e.g., if the\n ref is no local or remote branch)." + }, + "description": "

Return the name of the given remote branch.

\n", + "comments": "

\n", + "group": "branch" + }, "git_branch_upstream": { "type": "function", "file": "branch.h", @@ -36087,6 +36119,7 @@ "git_branch_name", "git_branch_next", "git_branch_set_upstream", + "git_branch_remote_name", "git_branch_upstream" ] ], @@ -37149,4 +37182,4 @@ "ex/HEAD/tag.html" ] ] -} \ No newline at end of file +} diff --git a/lib/branch.js b/lib/branch.js new file mode 100644 index 000000000..bc4b23443 --- /dev/null +++ b/lib/branch.js @@ -0,0 +1,19 @@ +var NodeGit = require("../"); +var Branch = NodeGit.Branch; + +var _remoteName = Branch.remoteName; + +/** + * Retrieve the Branch's Remote Name as a String. + * + * @async + * @param {Repository} repo The repo to get the remote name from + * @param {String} the refname of the branch + * @return {String} remote name as a string. + */ +Branch.remoteName = function(repo, remoteRef) { + return _remoteName.call(this, repo, remoteRef) + .then(function(remoteNameBuffer) { + return remoteNameBuffer.toString(); + }); +}; diff --git a/test/tests/branch.js b/test/tests/branch.js index 8d587c019..3900e4242 100644 --- a/test/tests/branch.js +++ b/test/tests/branch.js @@ -11,6 +11,7 @@ describe("Branch", function() { var branchName2 = "test-branch2"; var fullBranchName = "refs/heads/" + branchName; var fullBranchName2 = "refs/heads/" + branchName2; + var remoteName = "origin"; var upstreamName = "origin/master"; var fullUpstreamName = "refs/remotes/origin/master"; var nonHeadCommit = "c82fb078a192ea221c9f1093c64321c60d64aa0d"; @@ -85,6 +86,27 @@ describe("Branch", function() { }); }); + it("can get the remote name of a branch", function() { + var repo = this.repository; + + return NodeGit.Branch.remoteName(repo, fullUpstreamName) + .then(function(remoteNameToTest) { + assert.equal(remoteNameToTest, remoteName); + }); + }); + + it("cannot get remote name from a non-remote branch", function() { + var repo = this.repository; + + return NodeGit.Branch.remoteName(repo, fullBranchName) + .then(function() { + assert.fail("The ref should not have been a remote"); + }) + .catch(function(err) { + assert.strictEqual(err.errno, -1); + }); + }); + it("can rename a branch", function() { var branch = this.branch; From debcf21e478db6219ba0aa72b95c83fb616b699d Mon Sep 17 00:00:00 2001 From: Mohseen Mukaddam Date: Wed, 26 Jul 2017 14:08:25 -0700 Subject: [PATCH 13/35] Updating with requested changes and refactors --- generate/scripts/generateJson.js | 1 - generate/templates/filters/args_info.js | 14 +- generate/templates/filters/subtract.js | 2 +- .../templates/manual/include/async_baton.h | 2 - .../manual/include/filter_registry.h | 38 +- .../templates/manual/src/filter_registry.cc | 318 +++----------- .../templates/partials/field_accessors.cc | 26 +- generate/templates/templates/binding.gyp | 1 - generate/templates/templates/struct_header.h | 2 +- lib/filter_registry.js | 25 +- test/tests/filter.js | 397 +++++++++--------- 11 files changed, 320 insertions(+), 506 deletions(-) diff --git a/generate/scripts/generateJson.js b/generate/scripts/generateJson.js index bba4ca0fe..49a2795c2 100644 --- a/generate/scripts/generateJson.js +++ b/generate/scripts/generateJson.js @@ -106,7 +106,6 @@ module.exports = function generateJson() { }, {}).valueOf(); // decorate the definitions with required data to build the C++ files - //TODO: add self ref tag here types.forEach(function(typeDef) { var typeName = typeDef.typeName; typeDef.cType = typeName; diff --git a/generate/templates/filters/args_info.js b/generate/templates/filters/args_info.js index 72f3854aa..0c05c30eb 100644 --- a/generate/templates/filters/args_info.js +++ b/generate/templates/filters/args_info.js @@ -13,18 +13,8 @@ module.exports = function(args) { jsArg++; } - if (cArg === args.length -1) { - arg.lastArg = true; - arg.firstArg = false; - } - else if(cArg === 0){ - arg.firstArg = true; - arg.lastArg = false; - } - else { - arg.lastArg = false; - arg.firstArg = false; - } + arg.lastArg = cArg === args.length - 1; + arg.firstArg = !arg.lastArg && cArg === 0; arg.cArg = cArg; arg.isCppClassStringOrArray = ~["String", "Array"].indexOf(arg.cppClassName); diff --git a/generate/templates/filters/subtract.js b/generate/templates/filters/subtract.js index 36d0f59de..6329f2e2c 100644 --- a/generate/templates/filters/subtract.js +++ b/generate/templates/filters/subtract.js @@ -1,3 +1,3 @@ module.exports = function(value, other) { - return (value - other); + return value - other; }; diff --git a/generate/templates/manual/include/async_baton.h b/generate/templates/manual/include/async_baton.h index 0e6d64b6a..f8373cd0d 100644 --- a/generate/templates/manual/include/async_baton.h +++ b/generate/templates/manual/include/async_baton.h @@ -61,8 +61,6 @@ struct AsyncBatonWithResult : public AsyncBaton { }; struct AsyncBatonWithNoResult : public AsyncBaton { - /* ResultT result; - ResultT defaultResult;*/ // result returned if the callback doesn't return anything valid void (*onCompletion)(AsyncBaton *); void Done() { diff --git a/generate/templates/manual/include/filter_registry.h b/generate/templates/manual/include/filter_registry.h index a46d84d3d..b75938218 100644 --- a/generate/templates/manual/include/filter_registry.h +++ b/generate/templates/manual/include/filter_registry.h @@ -1,5 +1,3 @@ -// This is a generated file, modify: generate/templates/templates/class_header.h - #ifndef GITFILTERREGISTRY_H #define GITFILTERREGISTRY_H #include @@ -23,11 +21,9 @@ using namespace node; using namespace v8; -class GitFilterRegistry : public - Nan::ObjectWrap -{ +class GitFilterRegistry : public Nan::ObjectWrap { public: - static void InitializeComponent (v8::Local target); + static void InitializeComponent(v8::Local target); static Nan::Persistent persistentHandle; @@ -37,48 +33,42 @@ class GitFilterRegistry : public static NAN_METHOD(GitFilterUnregister); - struct FilterBaton { - const git_error* error; + struct FilterRegisterBaton { + const git_error *error; git_filter *filter; char *filter_name; int filter_priority; int error_code; }; - struct SimpleFilterBaton { - const git_error* error; + struct FilterUnregisterBaton { + const git_error *error; char *filter_name; int error_code; }; class RegisterWorker : public Nan::AsyncWorker { public: - RegisterWorker( - FilterBaton *_baton, - Nan::Callback *callback - ) : Nan::AsyncWorker(callback) - , baton(_baton) {}; + RegisterWorker(FilterRegisterBaton *_baton, Nan::Callback *callback) + : Nan::AsyncWorker(callback), baton(_baton) {}; ~RegisterWorker() {}; void Execute(); void HandleOKCallback(); private: - FilterBaton *baton; + FilterRegisterBaton *baton; }; - class UnRegisterWorker : public Nan::AsyncWorker { + class UnregisterWorker : public Nan::AsyncWorker { public: - UnRegisterWorker( - SimpleFilterBaton *_baton, - Nan::Callback *callback - ) : Nan::AsyncWorker(callback) - , baton(_baton) {}; - ~UnRegisterWorker() {}; + UnregisterWorker(FilterUnregisterBaton *_baton, Nan::Callback *callback) + : Nan::AsyncWorker(callback), baton(_baton) {}; + ~UnregisterWorker() {}; void Execute(); void HandleOKCallback(); private: - SimpleFilterBaton *baton; + FilterUnregisterBaton *baton; }; }; diff --git a/generate/templates/manual/src/filter_registry.cc b/generate/templates/manual/src/filter_registry.cc index 23abdaa83..a44e4ae70 100644 --- a/generate/templates/manual/src/filter_registry.cc +++ b/generate/templates/manual/src/filter_registry.cc @@ -1,11 +1,9 @@ -// This is a generated file, modify: generate/templates/templates/class_content.cc - #include #include extern "C" { #include - } +} #include "../include/nodegit.h" #include "../include/lock_master.h" @@ -15,8 +13,6 @@ extern "C" { #include "../include/async_libgit2_queue_worker.h" #include "../include/filter.h" - -#include using namespace std; using namespace v8; @@ -28,23 +24,14 @@ Nan::Persistent GitFilterRegistry::persistentHandle; void GitFilterRegistry::InitializeComponent(v8::Local target) { Nan::HandleScope scope; - v8::Local object = Nan::New(); Nan::SetMethod(object, "register", GitFilterRegister); Nan::SetMethod(object, "unregister", GitFilterUnregister); - Nan::Set(target, Nan::New("FilterRegistry").ToLocalChecked(), object); GitFilterRegistry::persistentHandle.Reset(object); } -// TODO: Reset persistent handle in destructor -/* - * @param String name -* @param Filter filter -* @param Number priority -* @return Number result -*/ NAN_METHOD(GitFilterRegistry::GitFilterRegister) { Nan::EscapableHandleScope scope; @@ -64,42 +51,21 @@ NAN_METHOD(GitFilterRegistry::GitFilterRegister) { if (info.Length() == 3 || !info[3]->IsFunction()) { return Nan::ThrowError("Callback is required and must be a Function."); } - // start convert_from_v8 block - const char * from_name = NULL; + FilterRegisterBaton *baton = new FilterRegisterBaton; + + baton->filter = Nan::ObjectWrap::Unwrap(info[1]->ToObject())->GetValue(); String::Utf8Value name(info[0]->ToString()); - // malloc with one extra byte so we can add the terminating null character C-strings expect: - from_name = (const char *) malloc(name.length() + 1); - // copy the characters from the nodejs string into our C-string (used instead of strdup or strcpy because nulls in - // the middle of strings are valid coming from nodejs): - memcpy((void *)from_name, *name, name.length()); - // ensure the final byte of our new string is null, extra casts added to ensure compatibility with various C types - // used in the nodejs binding generation: - memset((void *)(((char *)from_name) + name.length()), 0, 1); - - FilterBaton *baton = new FilterBaton; - - git_filter *from_filter = NULL; - from_filter = Nan::ObjectWrap::Unwrap(info[1]->ToObject())->GetValue(); - baton->filter = from_filter; - baton->filter_name = (char *) malloc(name.length() + 1); - strcpy(baton->filter_name, from_name); - baton->error_code = GIT_OK; - - int from_priority; - from_priority = (int) info[2]->ToNumber()->Value(); + baton->filter_name = (char *)malloc(name.length() + 1); + memcpy((void *)baton->filter_name, *name, name.length()); + memset((void *)(((char *)baton->filter_name) + name.length()), 0, 1); - baton->filter_priority = from_priority; - - /* This will delete the filter name from persistent handle */ - bool result = GitFilterRegistry::persistentHandle.IsEmpty(); + baton->error_code = GIT_OK; + baton->filter_priority = (int)info[2]->ToNumber()->Value(); + Nan::New(GitFilterRegistry::persistentHandle)->Set(info[0]->ToString(), info[1]->ToObject()); - v8::Local handleRef = Nan::New(GitFilterRegistry::persistentHandle); - v8::Local key = info[0]->ToString(); - v8::Maybe result2 = Nan::Has(handleRef, key); - Nan::Callback *callback = new Nan::Callback(Local::Cast(info[3])); RegisterWorker *worker = new RegisterWorker(baton, callback); @@ -109,9 +75,8 @@ NAN_METHOD(GitFilterRegistry::GitFilterRegister) { AsyncLibgit2QueueWorker(worker); return; } -// no v8 in execute + void GitFilterRegistry::RegisterWorker::Execute() { - giterr_clear(); { @@ -133,87 +98,37 @@ void GitFilterRegistry::RegisterWorker::HandleOKCallback() { result }; callback->Call(2, argv); - } else { - if (baton->error) { - v8::Local err; - if (baton->error->message) { - err = Nan::Error(baton->error->message)->ToObject(); - } else { - err = Nan::Error("Method register has thrown an error.")->ToObject(); - } - err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); - v8::Local argv[1] = { - err - }; - callback->Call(1, argv); - if (baton->error->message) - free((void *)baton->error->message); - free((void *)baton->error); - } else if (baton->error_code < 0) { - std::queue< v8::Local > workerArguments; - workerArguments.push(GetFromPersistent("filter_name")); - workerArguments.push(GetFromPersistent("filter_priority")); - - bool callbackFired = false; - while(!workerArguments.empty()) { - v8::Local node = workerArguments.front(); - workerArguments.pop(); - - if ( - !node->IsObject() - || node->IsArray() - || node->IsBooleanObject() - || node->IsDate() - || node->IsFunction() - || node->IsNumberObject() - || node->IsRegExp() - || node->IsStringObject() - ) { - continue; - } - - v8::Local nodeObj = node->ToObject(); - v8::Local checkValue = GetPrivate(nodeObj, Nan::New("NodeGitPromiseError").ToLocalChecked()); - - if (!checkValue.IsEmpty() && !checkValue->IsNull() && !checkValue->IsUndefined()) { - v8::Local argv[1] = { - checkValue->ToObject() - }; - callback->Call(1, argv); - callbackFired = true; - break; - } - - v8::Local properties = nodeObj->GetPropertyNames(); - for (unsigned int propIndex = 0; propIndex < properties->Length(); ++propIndex) { - v8::Local propName = properties->Get(propIndex)->ToString(); - v8::Local nodeToQueue = nodeObj->Get(propName); - if (!nodeToQueue->IsUndefined()) { - workerArguments.push(nodeToQueue); - } - } - } - - if (!callbackFired) { - v8::Local err = Nan::Error("Method register has thrown an error.")->ToObject(); - err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); - v8::Local argv[1] = { - err - }; - callback->Call(1, argv); - } + } + else if (baton->error) { + v8::Local err; + if (baton->error->message) { + err = Nan::Error(baton->error->message)->ToObject(); } else { - callback->Call(0, NULL); + err = Nan::Error("Method register has thrown an error.")->ToObject(); } + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); + v8::Local argv[1] = { + err + }; + callback->Call(1, argv); + if (baton->error->message) + free((void *)baton->error->message); + free((void *)baton->error); + } + else if (baton->error_code < 0) { + v8::Local err = Nan::Error("Method register has thrown an error.")->ToObject(); + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); + v8::Local argv[1] = { + err + }; + callback->Call(1, argv); + } + else { + callback->Call(0, NULL); } delete baton; return; } - -/* -* @param String name -* @return Number result -*/ NAN_METHOD(GitFilterRegistry::GitFilterUnregister) { Nan::EscapableHandleScope scope; @@ -226,62 +141,26 @@ NAN_METHOD(GitFilterRegistry::GitFilterUnregister) { return Nan::ThrowError("Callback is required and must be a Function."); } - const char * from_name = NULL; - + FilterUnregisterBaton *baton = new FilterUnregisterBaton; String::Utf8Value name(info[0]->ToString()); - // malloc with one extra byte so we can add the terminating null character C-strings expect: - from_name = (const char *) malloc(name.length() + 1); - // copy the characters from the nodejs string into our C-string (used instead of strdup or strcpy because nulls in - // the middle of strings are valid coming from nodejs): - memcpy((void *)from_name, *name, name.length()); - // ensure the final byte of our new string is null, extra casts added to ensure compatibility with various C types - // used in the nodejs binding generation: - memset((void *)(((char *)from_name) + name.length()), 0, 1); - - SimpleFilterBaton *baton = new SimpleFilterBaton; - baton->filter_name = (char *) malloc(name.length() + 1); - strcpy(baton->filter_name, from_name); + + baton->filter_name = (char *)malloc(name.length() + 1); + memcpy((void *)baton->filter_name, *name, name.length()); + memset((void *)(((char *)baton->filter_name) + name.length()), 0, 1); + baton->error_code = GIT_OK; /* Setting up Async Worker */ Nan::Callback *callback = new Nan::Callback(Local::Cast(info[1])); - UnRegisterWorker *worker = new UnRegisterWorker(baton, callback); + UnregisterWorker *worker = new UnregisterWorker(baton, callback); worker->SaveToPersistent("filter_name", info[0]); - /*giterr_clear(); - - { - LockMaster lockMaster(false, from_name); - - int result = git_filter_unregister(from_name); - - v8::Local to; - // start convert_to_v8 block - to = Nan::New(result); - // end convert_to_v8 block - return info.GetReturnValue().Set(scope.Escape(to)); - }*/ - // Remove persistent reference for given filter - /*v8::Local handleRef = Nan::New(GitFilterRegistry::persistentHandle); - Nan::Maybe _delete_result = Nan::Delete(handleRef, info[0]->ToString()); - - Nan::Maybe result3 = Nan::Has(handleRef, info[0]->ToString()); - - if(!GitFilterRegistry::persistentHandle.IsEmpty()){ - printf("not empty\n"); - GitFilterRegistry::persistentHandle.Reset(); - } else { - printf("empty\n"); - }*/ - AsyncLibgit2QueueWorker(worker); return; } -// no v8 in execute -void GitFilterRegistry::UnRegisterWorker::Execute() { - +void GitFilterRegistry::UnregisterWorker::Execute() { giterr_clear(); { @@ -293,22 +172,9 @@ void GitFilterRegistry::UnRegisterWorker::Execute() { baton->error = git_error_dup(giterr_last()); } } - /*// Remove persistent reference for given filter - *v8::Local handleRef = Nan::New(GitFilterRegistry::persistentHandle); - Nan::Maybe _delete_result = Nan::Delete(handleRef, info[0]->ToString()); - - Nan::Maybe result3 = Nan::Has(handleRef, info[0]->ToString()); - - if(!GitFilterRegistry::persistentHandle.IsEmpty()){ - printf("not empty\n"); - GitFilterRegistry::persistentHandle.Reset(); - } else { - printf("empty\n"); - }*/ } -void GitFilterRegistry::UnRegisterWorker::HandleOKCallback() { - +void GitFilterRegistry::UnregisterWorker::HandleOKCallback() { if (baton->error_code == GIT_OK) { v8::Local result = Nan::New(baton->error_code); v8::Local argv[2] = { @@ -316,77 +182,33 @@ void GitFilterRegistry::UnRegisterWorker::HandleOKCallback() { result }; callback->Call(2, argv); - } else { - if (baton->error) { - v8::Local err; - if (baton->error->message) { - err = Nan::Error(baton->error->message)->ToObject(); - } else { - err = Nan::Error("Method register has thrown an error.")->ToObject(); - } - err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); - v8::Local argv[1] = { - err - }; - callback->Call(1, argv); - if (baton->error->message) - free((void *)baton->error->message); - free((void *)baton->error); - } else if (baton->error_code < 0) { - std::queue< v8::Local > workerArguments; - workerArguments.push(GetFromPersistent("filter_name")); - - bool callbackFired = false; - while(!workerArguments.empty()) { - v8::Local node = workerArguments.front(); - workerArguments.pop(); - - if ( - !node->IsObject() - || node->IsArray() - || node->IsBooleanObject() - || node->IsDate() - || node->IsFunction() - || node->IsNumberObject() - || node->IsRegExp() - || node->IsStringObject() - ) { - continue; - } - - v8::Local nodeObj = node->ToObject(); - v8::Local checkValue = GetPrivate(nodeObj, Nan::New("NodeGitPromiseError").ToLocalChecked()); - - if (!checkValue.IsEmpty() && !checkValue->IsNull() && !checkValue->IsUndefined()) { - v8::Local argv[1] = { - checkValue->ToObject() - }; - callback->Call(1, argv); - callbackFired = true; - break; - } - - v8::Local properties = nodeObj->GetPropertyNames(); - for (unsigned int propIndex = 0; propIndex < properties->Length(); ++propIndex) { - v8::Local propName = properties->Get(propIndex)->ToString(); - v8::Local nodeToQueue = nodeObj->Get(propName); - if (!nodeToQueue->IsUndefined()) { - workerArguments.push(nodeToQueue); - } - } - } - - if (!callbackFired) { - v8::Local err = Nan::Error("Method register has thrown an error.")->ToObject(); - err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); - v8::Local argv[1] = { - err - }; - callback->Call(1, argv); - } + } + else if (baton->error) { + v8::Local err; + if (baton->error->message) { + err = Nan::Error(baton->error->message)->ToObject(); } else { - callback->Call(0, NULL); + err = Nan::Error("Method register has thrown an error.")->ToObject(); } + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); + v8::Local argv[1] = { + err + }; + callback->Call(1, argv); + if (baton->error->message) + free((void *)baton->error->message); + free((void *)baton->error); + } + else if (baton->error_code < 0) { + v8::Local err = Nan::Error("Method unregister has thrown an error.")->ToObject(); + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); + v8::Local argv[1] = { + err + }; + callback->Call(1, argv); + } + else { + callback->Call(0, NULL); } delete baton; return; diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index f0ecc0350..480adc76f 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -172,12 +172,10 @@ {{ cppClassName }}* instance = {{ field.name }}_getInstanceFromBaton(baton); if (instance->{{ field.name }}.GetCallback()->IsEmpty()) { - {% if field.return.type == "void" %} - baton->Done(); - {% else %} + {% if field.return.type == "int" %} baton->result = baton->defaultResult; // no results acquired - baton->Done(); {% endif %} + baton->Done(); return; } @@ -186,17 +184,17 @@ {%-- Do nothing --%} {% elsif arg.isJsArg %} {% if arg.cType == "const char *" %} - if (baton->{{ arg.name }} == NULL) { - baton->{{ arg.name }} = ""; - } + if (baton->{{ arg.name }} == NULL) { + baton->{{ arg.name }} = ""; + } {% elsif arg.cppClassName == "String" %} - v8::Local src; - if (baton->{{ arg.name }} == NULL) { - src = Nan::Null(); - } - else { - src = Nan::New(*baton->{{ arg.name }}).ToLocalChecked(); - } + v8::Local src; + if (baton->{{ arg.name }} == NULL) { + src = Nan::Null(); + } + else { + src = Nan::New(*baton->{{ arg.name }}).ToLocalChecked(); + } {% endif %} {% endif %} {% endeach %} diff --git a/generate/templates/templates/binding.gyp b/generate/templates/templates/binding.gyp index a448a4a5f..1be9be490 100644 --- a/generate/templates/templates/binding.gyp +++ b/generate/templates/templates/binding.gyp @@ -10,7 +10,6 @@ "variables": { "coverage%": 0 }, - "sources": [ "src/async_baton.cc", "src/lock_master.cc", diff --git a/generate/templates/templates/struct_header.h b/generate/templates/templates/struct_header.h index 15a3a260e..4d2ec2af5 100644 --- a/generate/templates/templates/struct_header.h +++ b/generate/templates/templates/struct_header.h @@ -52,7 +52,7 @@ class {{ cppClassName }} : public NodeGitWrapper<{{ cppClassName }}Traits> { static void {{ field.name }}_async(void *baton); static void {{ field.name }}_promiseCompleted(bool isFulfilled, AsyncBaton *_baton, v8::Local result); {% if field.return.type == 'void' %} - struct {{ field.name|titleCase }}Baton : public AsyncBatonWithNoResult{ + struct {{ field.name|titleCase }}Baton : public AsyncBatonWithNoResult { {% each field.args|argsInfo as arg %} {{ arg.cType }} {{ arg.name }}; {% endeach %} diff --git a/lib/filter_registry.js b/lib/filter_registry.js index bdf9f4ffa..76dfba573 100644 --- a/lib/filter_registry.js +++ b/lib/filter_registry.js @@ -10,32 +10,31 @@ var _unregister = FilterRegistry.unregister; // Override FilterRegistry.register to normalize Filter FilterRegistry.register = function(name, filter, priority, callback) { // setting default value of attributes - if(filter.attributes === undefined) { + if (filter.attributes === undefined) { filter.attributes = ""; } filter = normalizeOptions(filter, NodeGit.Filter); - if(filter.check && filter.apply) { - return _register(name, filter, priority) - .then(function(result) { - if(typeof callback === "function") { - callback(null, result); - } - return result; - }, callback); - } - else { + if (!filter.check || !filter.apply) { return callback(new Error( "ERROR: please provide check and apply callbacks for filter" )); } + + return _register(name, filter, priority) + .then(function(result) { + if (typeof callback === "function") { + callback(null, result); + } + return result; + }, callback); }; -FilterRegistry.unregister = function(name, callback){ +FilterRegistry.unregister = function(name, callback) { return _unregister(name) .then(function(result) { - if(typeof callback === "function") { + if (typeof callback === "function") { callback(null, result); } return result; diff --git a/test/tests/filter.js b/test/tests/filter.js index ad29ef8c4..1db1c9ecb 100644 --- a/test/tests/filter.js +++ b/test/tests/filter.js @@ -1,8 +1,8 @@ -var assert = require("assert"), - promisify = require("promisify-node"), - fse = promisify(require("fs-extra")), - path = require("path"), - local = path.join.bind(path, __dirname); +var assert = require("assert"); +var promisify = require("promisify-node"); +var fse = promisify(require("fs-extra")); +var path = require("path"); +var local = path.join.bind(path, __dirname); describe("Filter", function() { var NodeGit = require("../../"); @@ -16,16 +16,10 @@ describe("Filter", function() { var packageJsonPath = path.join(reposPath, "package.json"); var readmePath = path.join(reposPath, "README.md"); - - var GIT_PASSTHROUGH = -30; var mockFilter = { - apply: function() { - return; - }, - check: function(){ - return; - } + apply: function() {}, + check: function() {} }; function commitFile(repo, fileName, fileContent, commitMessage) { @@ -34,47 +28,48 @@ describe("Filter", function() { let parent; return fse.writeFile(path.join(repo.workdir(), fileName), fileContent) - .then(function() { - return repo.refreshIndex(); - }) - .then(function(indexResult) { - index = indexResult; - }) - .then(function() { - return index.addByPath(fileName); - }) - .then(function() { - return index.write(); - }) - .then(function() { - return index.writeTree(); - }) - .then(function(oidResult) { - treeOid = oidResult; - return NodeGit.Reference.nameToId(repo, "HEAD"); - }) - .then(function(head) { - return repo.getCommit(head); - }) - .then(function(parentResult) { - parent = parentResult; - return Promise.all([ - NodeGit.Signature.create("Foo Bar", "foo@bar.com", 123456789, 60), - NodeGit.Signature.create("Foo A Bar", "foo@bar.com", 987654321, 90) - ]); - }) - .then(function(signatures) { - let author = signatures[0]; - let committer = signatures[1]; - - return repo.createCommit( - "HEAD", - author, - committer, - commitMessage, - treeOid, - [parent]); - }); + .then(function() { + return repo.refreshIndex(); + }) + .then(function(indexResult) { + index = indexResult; + }) + .then(function() { + return index.addByPath(fileName); + }) + .then(function() { + return index.write(); + }) + .then(function() { + return index.writeTree(); + }) + .then(function(oidResult) { + treeOid = oidResult; + return NodeGit.Reference.nameToId(repo, "HEAD"); + }) + .then(function(head) { + return repo.getCommit(head); + }) + .then(function(parentResult) { + parent = parentResult; + return Promise.all([ + NodeGit.Signature.create("Foo Bar", "foo@bar.com", 123456789, 60), + NodeGit.Signature.create("Foo A Bar", "foo@bar.com", 987654321, 90) + ]); + }) + .then(function(signatures) { + let author = signatures[0]; + let committer = signatures[1]; + + return repo.createCommit( + "HEAD", + author, + committer, + commitMessage, + treeOid, + [parent] + ); + }); } beforeEach(function() { @@ -89,22 +84,17 @@ describe("Filter", function() { test.emptyRepo = emptyRepo; return fse.writeFile( path.join(reposPath, ".gitattributes"), - "*.md filter="+ filterName +" -text", { - encoding: "utf-8", - }); + "*.md filter=" + filterName + " -text", + { encoding: "utf-8" } + ); }); }); afterEach(function() { return Registry.unregister(filterName) .catch(function(error) { - switch(error) { - case -1: - throw new Error("Cannot unregister filter"); - // case -3: - // throw new Error('Cannot find filter to unregister'); - default: - return; + if (error === NodeGit.Error.CODE.ERROR) { + throw new Error("Cannot unregister filter"); } }); }); @@ -122,29 +112,29 @@ describe("Filter", function() { it("can register a filter", function() { return Registry.register(filterName, mockFilter, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); }); }); it("can register multiple filters", function() { return Registry.register(filterName, mockFilter, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); return Registry.register(secondFilter, mockFilter, 1); }) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); }); }); it("cannot register the same filter twice", function() { return Registry.register(filterName, mockFilter, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); return Registry.register(filterName, mockFilter, 0); }) .catch(function(error) { - assert.strictEqual(error.errno, -4); + assert.strictEqual(error.errno, NodeGit.Error.CODE.EEXISTS); }); }); }); @@ -157,21 +147,21 @@ describe("Filter", function() { it("can unregister the filter", function() { return Registry.unregister(filterName) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); }); }); it("cannot unregister the filter twice", function() { return Registry.unregister(filterName) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); return Registry.unregister(filterName); }) .then(function(result) { - assert.fail(result, -3, "Should not have unregistered successfully"); + assert.fail("Should not have unregistered successfully"); }) .catch(function(error) { - assert.strictEqual(error.errno, -3); + assert.strictEqual(error.errno, NodeGit.Error.CODE.ENOTFOUND); }); }); }); @@ -183,22 +173,21 @@ describe("Filter", function() { return Registry.register(filterName, { initialize: function() { initialized = true; - return 0; - }, - apply: function() { - return; + return NodeGit.Error.CODE.OK; }, + apply: function() {}, check: function() { - return -30; + return NodeGit.Error.CODE.PASSTHROUGH; } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); }) .then(function() { return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout"); + "Changing content to trigger checkout" + ); }) .then(function() { var opts = { @@ -218,22 +207,21 @@ describe("Filter", function() { return Registry.register(filterName, { initialize: function() { initialized = true; - return 0; - }, - apply: function() { - return; + return NodeGit.Error.CODE.OK; }, + apply: function() {}, check: function() { - return -30; + return NodeGit.Error.CODE.PASSTHROUGH; } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); global.gc(); return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout"); + "Changing content to trigger checkout" + ); }) .then(function() { var opts = { @@ -253,22 +241,21 @@ describe("Filter", function() { return Registry.register(filterName, { initialize: function() { initialized = true; - return -1; - }, - apply: function() { - return; + return NodeGit.Error.CODE.ERROR; }, + apply: function() {}, check: function() { - return -30; + return NodeGit.Error.CODE.PASSTHROUGH; } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); }) .then(function() { return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout"); + "Changing content to trigger checkout" + ); }) .then(function() { var opts = { @@ -291,23 +278,21 @@ describe("Filter", function() { var test = this; var shutdown = false; return Registry.register(filterName, { - apply: function() { - return; - }, + apply: function() {}, check: function(){ - return -30; + return NodeGit.Error.CODE.PASSTHROUGH; }, shutdown: function(){ shutdown = true; } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + "Changing content to trigger checkout", + { encoding: "utf-8" } + ); }) .then(function() { var opts = { @@ -320,7 +305,7 @@ describe("Filter", function() { return Registry.unregister(filterName); }) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); assert.strictEqual(shutdown, true); }); }); @@ -329,23 +314,21 @@ describe("Filter", function() { var test = this; var shutdown = false; return Registry.register(filterName, { - apply: function() { - return; - }, + apply: function() {}, check: function(){ - return -30; + return NodeGit.Error.CODE.PASSTHROUGH; }, shutdown: function(){ shutdown = true; } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + "Changing content to trigger checkout", + { encoding: "utf-8" } + ); }) .then(function() { var opts = { @@ -359,7 +342,7 @@ describe("Filter", function() { return Registry.unregister(filterName); }) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); assert.strictEqual(shutdown, true); }); }); @@ -368,11 +351,9 @@ describe("Filter", function() { var test = this; var shutdown = false; return Registry.register(filterName, { - apply: function() { - return; - }, + apply: function() {}, check: function(){ - return -30; + return NodeGit.Error.CODE.PASSTHROUGH; }, shutdown: function(){ shutdown = true; @@ -380,12 +361,12 @@ describe("Filter", function() { } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + "Changing content to trigger checkout", + { encoding: "utf-8" } + ); }) .then(function() { var opts = { @@ -398,7 +379,7 @@ describe("Filter", function() { return Registry.unregister(filterName); }) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); assert.strictEqual(shutdown, true); }) .catch(function(error) { @@ -421,16 +402,16 @@ describe("Filter", function() { applied = true; }, check: function() { - return GIT_PASSTHROUGH; + return NodeGit.Error.CODE.PASSTHROUGH; } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + "Changing content to trigger checkout", + { encoding: "utf-8" } + ); }) .then(function() { var opts = { @@ -453,16 +434,16 @@ describe("Filter", function() { applied = true; }, check: function() { - return 0; + return NodeGit.Error.CODE.OK; } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + "Changing content to trigger checkout", + { encoding: "utf-8" } + ); }) .then(function() { var opts = { @@ -483,23 +464,27 @@ describe("Filter", function() { apply: function(to, from, source) { return to.set(tempBuffer, length) .then(function() { - return GIT_PASSTHROUGH; + return NodeGit.Error.CODE.PASSTHROUGH; }); }, check: function() { - return 0; + return NodeGit.Error.CODE.OK; } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); }) .then(function() { - var readmeContent = fse.readFileSync(packageJsonPath, "utf-8"); + var readmeContent = fse.readFileSync( + packageJsonPath, + "utf-8" + ); assert.notStrictEqual(readmeContent, message); return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout"); + "Changing content to trigger checkout" + ); }) .then(function() { var opts = { @@ -510,7 +495,9 @@ describe("Filter", function() { }) .then(function() { var postInitializeReadmeContents = fse.readFileSync( - readmePath, "utf-8"); + readmePath, + "utf-8" + ); assert.notStrictEqual(postInitializeReadmeContents, message); }); @@ -523,18 +510,21 @@ describe("Filter", function() { apply: function(to, from, source) { return to.set(tempBuffer, length) .then(function(buf) { - return 0; + return NodeGit.Error.CODE.OK; }); }, check: function(src, attr) { - return 0; + return NodeGit.Error.CODE.OK; } }, 0) .then(function(result) { assert.strictEqual(result, 0); }) .then(function() { - var readmeContent = fse.readFileSync(readmePath, "utf-8"); + var readmeContent = fse.readFileSync( + readmePath, + "utf-8" + ); assert.notStrictEqual(readmeContent, message); fse.writeFileSync(readmePath, "whoa", "utf8"); @@ -546,7 +536,9 @@ describe("Filter", function() { }) .then(function() { var postInitializeReadmeContents = fse.readFileSync( - readmePath, "utf-8"); + readmePath, + "utf-8" + ); assert.strictEqual(postInitializeReadmeContents, message); }); @@ -559,18 +551,21 @@ describe("Filter", function() { apply: function(to, from, source) { return to.set(tempBuffer, length) .then(function(buf) { - return 0; + return NodeGit.Error.CODE.OK; }); }, check: function(src, attr) { - return 0; + return NodeGit.Error.CODE.OK; } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); }) .then(function() { - var readmeContent = fse.readFileSync(readmePath, "utf-8"); + var readmeContent = fse.readFileSync( + readmePath, + "utf-8" + ); assert.notStrictEqual(readmeContent, message); fse.writeFileSync(readmePath, "whoa", "utf8"); global.gc(); @@ -583,7 +578,9 @@ describe("Filter", function() { }) .then(function() { var postInitializeReadmeContents = fse.readFileSync( - readmePath, "utf-8"); + readmePath, + "utf-8" + ); assert.strictEqual(postInitializeReadmeContents, message); }); @@ -596,34 +593,39 @@ describe("Filter", function() { apply: function(to, from, source) { return to.set(tempBuffer, length) .then(function(buf) { - return 0; + return NodeGit.Error.CODE.OK; }); }, check: function(src, attr) { - return src.path() === "README.md" ? 0 : GIT_PASSTHROUGH; + return src.path() === "README.md" ? + 0 : NodeGit.Error.CODE.PASSTHROUGH; }, - cleanup: function() { - return; - } + cleanup: function() {} }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); }) .then(function() { - var readmeContent = fse.readFileSync(readmePath, "utf-8"); + var readmeContent = fse.readFileSync( + readmePath, + "utf-8" + ); assert.notStrictEqual(readmeContent, "testing commit contents"); }) .then(function() { return commitFile(test.repository, "README.md", "testing commit contents", - "test commit"); + "test commit" + ); }) .then(function(oid) { return test.repository.getHeadCommit(); }) .then(function(commit) { var postInitializeReadmeContents = fse.readFileSync( - readmePath, "utf-8"); + readmePath, + "utf-8" + ); assert.strictEqual( postInitializeReadmeContents, "testing commit contents" @@ -648,28 +650,31 @@ describe("Filter", function() { apply: function(to, from, source) { return to.set(tempBuffer, length) .then(function(buf) { - return 0; + return NodeGit.Error.CODE.OK; }); }, check: function(src, attr) { - return src.path() === "README.md" ? 0 : GIT_PASSTHROUGH; + return src.path() === "README.md" ? + 0 : NodeGit.Error.CODE.PASSTHROUGH; }, - cleanup: function() { - return; - } + cleanup: function() {} }, 0) .then(function(result) { global.gc(); - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); }) .then(function() { - var readmeContent = fse.readFileSync(readmePath, "utf-8"); + var readmeContent = fse.readFileSync( + readmePath, + "utf-8" + ); assert.notStrictEqual(readmeContent, "testing commit contents"); }) .then(function() { return commitFile(test.repository, "README.md", "testing commit contents", - "test commit"); + "test commit" + ); }) .then(function(oid) { global.gc(); @@ -677,7 +682,9 @@ describe("Filter", function() { }) .then(function(commit) { var postInitializeReadmeContents = fse.readFileSync( - readmePath, "utf-8"); + readmePath, + "utf-8" + ); assert.strictEqual( postInitializeReadmeContents, "testing commit contents" @@ -703,30 +710,33 @@ describe("Filter", function() { var cleaned = false; return Registry.register(filterName, { initialize: function() { - return 0; + return NodeGit.Error.CODE.OK; }, apply: function() { - return 0; + return NodeGit.Error.CODE.OK; }, check: function() { - return 0; + return NodeGit.Error.CODE.OK; }, cleanup: function() { cleaned = true; } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); }) .then(function() { - var packageContent = fse.readFileSync(packageJsonPath, "utf-8"); + var packageContent = fse.readFileSync( + packageJsonPath, + "utf-8" + ); assert.notEqual(packageContent, ""); return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + "Changing content to trigger checkout", + { encoding: "utf-8" } + ); }) .then(function() { var opts = { @@ -745,31 +755,34 @@ describe("Filter", function() { var cleaned = false; return Registry.register(filterName, { initialize: function() { - return 0; + return NodeGit.Error.CODE.OK; }, apply: function() { - return 0; + return NodeGit.Error.CODE.OK; }, check: function() { - return 0; + return NodeGit.Error.CODE.OK; }, cleanup: function() { cleaned = true; } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); }) .then(function() { - var packageContent = fse.readFileSync(packageJsonPath, "utf-8"); + var packageContent = fse.readFileSync( + packageJsonPath, + "utf-8" + ); assert.notEqual(packageContent, ""); global.gc(); return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + "Changing content to trigger checkout", + { encoding: "utf-8" } + ); }) .then(function() { var opts = { @@ -789,24 +802,30 @@ describe("Filter", function() { return Registry.register(filterName, { initialize: function() { - return 0; + return NodeGit.Error.CODE.OK; }, apply: function() { - return 0; + return NodeGit.Error.CODE.OK; }, check: function() { - return GIT_PASSTHROUGH; + return NodeGit.Error.CODE.PASSTHROUGH; }, cleanup: function() { cleaned = true; } }, 0) .then(function(result) { - assert.strictEqual(result, 0); + assert.strictEqual(result, NodeGit.Error.CODE.OK); }) .then(function() { - var packageContent = fse.readFileSync(packageJsonPath, "utf-8"), - readmeContent = fse.readFileSync(readmePath, "utf-8"); + var packageContent = fse.readFileSync( + packageJsonPath, + "utf-8" + ); + var readmeContent = fse.readFileSync( + readmePath, + "utf-8" + ); assert.notEqual(packageContent, ""); assert.notEqual(readmeContent, "Initialized"); @@ -814,9 +833,9 @@ describe("Filter", function() { .then(function() { return fse.writeFile( packageJsonPath, - "Changing content to trigger checkout", { - encoding: "utf-8", - }); + "Changing content to trigger checkout", + { encoding: "utf-8" } + ); }) .then(function() { var opts = { From 945b09d79f4b34a7e709287acbed660bdc33e802 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Wed, 2 Aug 2017 15:23:44 -0700 Subject: [PATCH 14/35] Convert git_status_file to an async method --- generate/input/descriptor.json | 1 + generate/templates/partials/async_function.cc | 11 ++++ lib/repository.js | 65 +++++++++++++------ 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index 1e9aeaf8b..659a63403 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -2241,6 +2241,7 @@ "isAsync": false }, "git_status_file": { + "isAsync": true, "args": { "status_flags": { "isReturn": true diff --git a/generate/templates/partials/async_function.cc b/generate/templates/partials/async_function.cc index 20813136d..ca4bd8d47 100644 --- a/generate/templates/partials/async_function.cc +++ b/generate/templates/partials/async_function.cc @@ -10,6 +10,11 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) { baton->error_code = GIT_OK; baton->error = NULL; + {%if cppClassName == "GitStatus" %} + {%if cppFunctionName == "File" %} + baton->status_flags = (unsigned int *)malloc(sizeof(unsigned int)); + {%endif%} + {%endif%} {%each args|argsInfo as arg %} {%if arg.globalPayload %} @@ -260,6 +265,12 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { {%endeach%} } + {%if cppClassName == "GitStatus" %} + {%if cppFunctionName == "File" %} + free((void *)baton->status_flags); + {%endif%} + {%endif%} + {%each args|argsInfo as arg %} {%if arg.isCppClassStringOrArray %} {%if arg.freeFunctionName %} diff --git a/lib/repository.js b/lib/repository.js index 90be1d91c..3c4dcbda4 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -150,15 +150,15 @@ function getPathHunks(repo, index, filePath, isStaged, additionalDiffOptions) { }); }) .then(function(diff) { - if (!(NodeGit.Status.file(repo, filePath) & - NodeGit.Status.STATUS.WT_MODIFIED) && - !(NodeGit.Status.file(repo, filePath) & - NodeGit.Status.STATUS.INDEX_MODIFIED)) { - return Promise.reject - ("Selected staging is only available on modified files."); - } - - return diff.patches(); + return NodeGit.Status.file(repo, filePath) + .then(function(status) { + if (!(status & NodeGit.Status.STATUS.WT_MODIFIED) && + !(status & NodeGit.Status.STATUS.INDEX_MODIFIED)) { + return Promise.reject + ("Selected staging is only available on modified files."); + } + return diff.patches(); + }); }) .then(function(patches) { var pathPatch = patches.filter(function(patch) { @@ -1636,17 +1636,42 @@ Repository.prototype.stageFilemode = }) .then(function(diff) { var origLength = filePaths.length; - filePaths = filePaths.filter(function(p) { - return ( - (NodeGit.Status.file(repo, p) & NodeGit.Status.STATUS.WT_MODIFIED) || - (NodeGit.Status.file(repo, p) & NodeGit.Status.STATUS.INDEX_MODIFIED) - ); - }); - if (filePaths.length === 0 && origLength > 0) { - return Promise.reject - ("Selected staging is only available on modified files."); - } - return diff.patches(); + var fileFilterPromises = fp.map(function(p) { + return NodeGit.Status.file(repo, p) + .then(function(status) { + return { + path: p, + filter: ( + (status & NodeGit.Status.STATUS.WT_MODIFIED) || + (status & NodeGit.Status.STATUS.INDEX_MODIFIED) + ) + }; + }); + }, filePaths); + + return Promise.all(fileFilterPromises) + .then(function(results) { + filePaths = fp.flow([ + fp.filter(function(filterResult) { + return filterResult.filter; + }), + fp.map(function(filterResult) { + return filterResult.path; + }) + ])(results); + + if (filePaths.length === 0 && origLength > 0) { + return Promise.reject + ("Selected staging is only available on modified files."); + } + return diff.patches(); + }); +// filePaths = filePaths.filter(function(p) { +// return ( +// (NodeGit.Status.file(repo, p) & NodeGit.Status.STATUS.WT_MODIFIED) || +// (NodeGit.Status.file(repo, p) & NodeGit.Status.STATUS.INDEX_MODIFIED) +// ); +// }); }) .then(function(patches) { var pathPatches = patches.filter(function(patch) { From 54a278624740fdc4e049556d15010432080919d1 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Wed, 2 Aug 2017 15:29:03 -0700 Subject: [PATCH 15/35] removed comments --- lib/repository.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/repository.js b/lib/repository.js index 3c4dcbda4..a5a0012fa 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -1666,12 +1666,6 @@ Repository.prototype.stageFilemode = } return diff.patches(); }); -// filePaths = filePaths.filter(function(p) { -// return ( -// (NodeGit.Status.file(repo, p) & NodeGit.Status.STATUS.WT_MODIFIED) || -// (NodeGit.Status.file(repo, p) & NodeGit.Status.STATUS.INDEX_MODIFIED) -// ); -// }); }) .then(function(patches) { var pathPatches = patches.filter(function(patch) { From 89c34899db978b618ff49a3b286595bd993d4927 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Tue, 8 Aug 2017 08:19:28 -0700 Subject: [PATCH 16/35] BREAKING: Made Merge.merge async --- generate/input/descriptor.json | 22 ++++++++++++++++++++++ test/tests/merge.js | 4 +--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index 659a63403..234b91e3c 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -1268,13 +1268,35 @@ "merge": { "functions": { "git_merge": { + "isAsync": true, "args": { + "repo": { + "cppClassName": "GitRepository", + "cType": "git_repository *", + "jsClassName": "Repo" + }, "their_heads": { "cType": "const git_annotated_commit **", "cppClassName": "Array", "jsClassName": "Array", "arrayElementCppClassName": "GitAnnotatedCommit" + }, + "their_heads_len": { + "cType": "size_t", + "cppClassName": "Number", + "jsClassName": "Number" + }, + "merge_opts": { + "cType": "git_merge_options *", + "cppClassName": "GitMergeOptions" + }, + "checkout_opts": { + "cType": "git_checkout_options *", + "cppClassName": "GitCheckoutOptions" } + }, + "return": { + "isErrorCode": true } }, "git_merge_analysis": { diff --git a/test/tests/merge.js b/test/tests/merge.js index 66728bdb9..86531aa2c 100644 --- a/test/tests/merge.js +++ b/test/tests/merge.js @@ -1539,9 +1539,7 @@ describe("Merge", function() { .then(function(theirAnnotatedCommit) { return NodeGit.Merge(repository, theirAnnotatedCommit); }) - .then(function(result) { - assert.equal(result, 0); - + .then(function() { assert.equal(repository.state(), NodeGit.Repository.STATE.MERGE); // verify the convenience method From 9927174ba75cb48e55896126778f203b82c39488 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Tue, 8 Aug 2017 12:11:57 -0700 Subject: [PATCH 17/35] updated rebase.commit to be async --- generate/input/descriptor.json | 7 ++++++ lib/rebase.js | 14 ++++++++++++ lib/repository.js | 42 +++++++++++++++++++--------------- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index 234b91e3c..be711db91 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -1681,8 +1681,12 @@ "rebase": { "functions": { "git_rebase_commit": { + "isAsync": true, "args": { "id": { + "cType": "git_oid *", + "cppClassName": "GitOid", + "jsClassName": "Oid", "isReturn": true, "shouldAlloc": true }, @@ -1695,6 +1699,9 @@ "message": { "isOptional": true } + }, + "return": { + "isErrorCode": true } }, "git_rebase_finish": { diff --git a/lib/rebase.js b/lib/rebase.js index 22ca72c7d..1c112f051 100644 --- a/lib/rebase.js +++ b/lib/rebase.js @@ -5,6 +5,7 @@ var shallowClone = NodeGit.Utils.shallowClone; var _init = Rebase.init; var _open = Rebase.open; +var _commit = Rebase.prototype.commit; /** * Initializes a rebase * @async @@ -83,3 +84,16 @@ Rebase.open = function(repository, options) { ); return _open(repository, options); }; + +Rebase.prototype.commit = + function(author, committer, encoding, message, callback) { + return _commit.call(this, author, committer, encoding, message) + .then(function(oid) { + if (typeof callback === "function") { + callback(null, oid); + } + + return oid; + }, callback); + }; + diff --git a/lib/repository.js b/lib/repository.js index a5a0012fa..b841097ae 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -217,23 +217,26 @@ function performRebase( function getPromise() { return rebase.next() .then(function() { - return repository.refreshIndex() - .then(function(index) { - if (index.hasConflicts()) { - throw index; - } + return repository.refreshIndex(); + }) + .then(function(index) { + if (index.hasConflicts()) { + throw index; + } - rebase.commit(null, signature); + return rebase.commit(null, signature); + }) + .then(function() { - return performRebase( - repository, - rebase, - signature, - beforeNextFn, - beforeFinishFn - ); - }); - }, function(error) { + return performRebase( + repository, + rebase, + signature, + beforeNextFn, + beforeFinishFn + ); + }) + .catch(function(error) { if (error && error.errno === NodeGit.Error.CODE.ITEROVER) { const calcRewritten = fp.flow([ fp.split("\n"), @@ -435,6 +438,7 @@ Repository.prototype.continueRebase = function( signature = signature || repo.defaultSignature(); + var rebase; return repo.refreshIndex() .then(function(index) { if (index.hasConflicts()) { @@ -443,9 +447,11 @@ Repository.prototype.continueRebase = function( return NodeGit.Rebase.open(repo); }) - .then(function(rebase) { - rebase.commit(null, signature); - + .then(function(_rebase) { + rebase = _rebase; + return rebase.commit(null, signature); + }) + .then(function(oid) { return performRebase( repo, rebase, From 0f389936116c033927f1099ef1923c063122b1f1 Mon Sep 17 00:00:00 2001 From: Mohseen Mukaddam Date: Wed, 9 Aug 2017 11:45:34 -0700 Subject: [PATCH 18/35] Converted rebase abort to async --- generate/input/descriptor.json | 16 ++++++++++++++++ lib/rebase.js | 11 +++++++++++ test/tests/rebase.js | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index be711db91..a1832cd1c 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -1729,6 +1729,22 @@ "isOptional": true } } + }, + "git_rebase_abort": { + "isAsync": true, + "args": { + "rebase": { + "cType": "git_rebase *", + "cppClassName": "GitRebase", + "jsClassName": "Rebase", + "isOptional": false, + "isSelf": true, + "isReturn": false + } + }, + "return": { + "isErrorCode": true + } } } }, diff --git a/lib/rebase.js b/lib/rebase.js index 1c112f051..8250c8663 100644 --- a/lib/rebase.js +++ b/lib/rebase.js @@ -5,6 +5,7 @@ var shallowClone = NodeGit.Utils.shallowClone; var _init = Rebase.init; var _open = Rebase.open; +var _abort = Rebase.prototype.abort; var _commit = Rebase.prototype.commit; /** * Initializes a rebase @@ -97,3 +98,13 @@ Rebase.prototype.commit = }, callback); }; +Rebase.prototype.abort = + function(callback) { + return _abort.call(this) + .then(function() { + if (typeof callback === "function") { + callback(null); + } + }, callback); + }; + diff --git a/test/tests/rebase.js b/test/tests/rebase.js index 731884f82..d121a6c0f 100644 --- a/test/tests/rebase.js +++ b/test/tests/rebase.js @@ -658,7 +658,7 @@ describe("Rebase", function() { }); }) .then(function() { - return rebase.abort(ourSignature); + return rebase.abort(); }) .then(function() { return NodeGit.Rebase.open(repository) From 766d3dda0e5f1bc7dd72573c6afdabb2db005338 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Wed, 9 Aug 2017 16:21:01 -0700 Subject: [PATCH 19/35] Fixed error in continueRebase --- lib/repository.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/repository.js b/lib/repository.js index b841097ae..42093d3db 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -449,9 +449,13 @@ Repository.prototype.continueRebase = function( }) .then(function(_rebase) { rebase = _rebase; - return rebase.commit(null, signature); + return rebase.commit(null, signature) + .catch(function() { + // we are ignoring errors. This is to prevent issues caused by making this async + return 0; + }); }) - .then(function(oid) { + .then(function() { return performRebase( repo, rebase, From 7e65c095343156b557c58441db89d2b3f72acbb4 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Thu, 10 Aug 2017 08:03:22 -0700 Subject: [PATCH 20/35] fixed linter error --- lib/repository.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/repository.js b/lib/repository.js index 42093d3db..0637cec47 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -451,7 +451,10 @@ Repository.prototype.continueRebase = function( rebase = _rebase; return rebase.commit(null, signature) .catch(function() { - // we are ignoring errors. This is to prevent issues caused by making this async + // Ignore all errors to prevent + // this routine from choking now + // that we made rebase.commit + // asynchronous return 0; }); }) From 6ded1d23b278b8165896b7d103e4a9b335b9bc1d Mon Sep 17 00:00:00 2001 From: Mohseen Mukaddam Date: Thu, 10 Aug 2017 09:55:30 -0700 Subject: [PATCH 21/35] converted commit amend to async --- generate/input/descriptor.json | 1 + 1 file changed, 1 insertion(+) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index a1832cd1c..d6506d1d6 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -402,6 +402,7 @@ "selfFreeing": true, "functions": { "git_commit_amend": { + "isAsync": true, "args": { "author": { "isOptional": true From 63f4db04626503ae99ea3ae2b6b785eaea81897c Mon Sep 17 00:00:00 2001 From: Mohseen Mukaddam Date: Thu, 10 Aug 2017 16:50:02 -0700 Subject: [PATCH 22/35] Converting git_reflog_write to async --- generate/input/descriptor.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index d6506d1d6..563ae0eb0 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -1844,6 +1844,17 @@ "needsForwardDeclaration": false, "ignore": true }, + "reflog": { + "functions": { + "git_reflog_write": { + "isAsync": true, + "isSelf": true, + "return": { + "isErrorCode": true + } + } + } + }, "reflog_entry": { "functions": { "git_reflog_entry_id_new": { From 080e8aafe7354010f08cce842256070c313160ee Mon Sep 17 00:00:00 2001 From: Mohseen Mukaddam Date: Fri, 11 Aug 2017 13:51:28 -0700 Subject: [PATCH 23/35] babel cli fix for travis --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5becdd1c1..686c8357d 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "host": "https://nodegit.s3.amazonaws.com/nodegit/nodegit/" }, "scripts": { - "babel": "babel --presets es2015 -d ./dist ./lib", + "babel": "babel --presets es2015 -d dist lib", "cov": "npm run cppcov && npm run filtercov && npm run mergecov", "coveralls": "cat ./test/coverage/merged.lcov | coveralls", "cppcov": "mkdir -p test/coverage/cpp && ./lcov-1.10/bin/lcov --gcov-tool /usr/bin/gcov-4.9 --capture --directory build/Release/obj.target/nodegit/src --output-file test/coverage/cpp/lcov_full.info", From 34a9e594ffcc3e4324325b3b4af7a340964c6fd2 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Mon, 14 Aug 2017 08:08:14 -0700 Subject: [PATCH 24/35] Reverted unnecessary babel changes. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 686c8357d..5becdd1c1 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "host": "https://nodegit.s3.amazonaws.com/nodegit/nodegit/" }, "scripts": { - "babel": "babel --presets es2015 -d dist lib", + "babel": "babel --presets es2015 -d ./dist ./lib", "cov": "npm run cppcov && npm run filtercov && npm run mergecov", "coveralls": "cat ./test/coverage/merged.lcov | coveralls", "cppcov": "mkdir -p test/coverage/cpp && ./lcov-1.10/bin/lcov --gcov-tool /usr/bin/gcov-4.9 --capture --directory build/Release/obj.target/nodegit/src --output-file test/coverage/cpp/lcov_full.info", From 2e32eeb14f0e6c0b5e9afdef5387bc05d2188e2f Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Tue, 15 Aug 2017 14:52:41 -0700 Subject: [PATCH 25/35] Fixed status_file special case --- generate/input/descriptor.json | 3 ++- generate/templates/partials/async_function.cc | 11 ----------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index 563ae0eb0..1290486d9 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -2301,7 +2301,8 @@ "isAsync": true, "args": { "status_flags": { - "isReturn": true + "isReturn": true, + "shouldAlloc": true }, "return": { "isErrorCode": true diff --git a/generate/templates/partials/async_function.cc b/generate/templates/partials/async_function.cc index ca4bd8d47..20813136d 100644 --- a/generate/templates/partials/async_function.cc +++ b/generate/templates/partials/async_function.cc @@ -10,11 +10,6 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) { baton->error_code = GIT_OK; baton->error = NULL; - {%if cppClassName == "GitStatus" %} - {%if cppFunctionName == "File" %} - baton->status_flags = (unsigned int *)malloc(sizeof(unsigned int)); - {%endif%} - {%endif%} {%each args|argsInfo as arg %} {%if arg.globalPayload %} @@ -265,12 +260,6 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { {%endeach%} } - {%if cppClassName == "GitStatus" %} - {%if cppFunctionName == "File" %} - free((void *)baton->status_flags); - {%endif%} - {%endif%} - {%each args|argsInfo as arg %} {%if arg.isCppClassStringOrArray %} {%if arg.freeFunctionName %} From f39bf863c123ff77cf85f51edc766313bdfd07c8 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Tue, 15 Aug 2017 15:01:49 -0700 Subject: [PATCH 26/35] removed old callback style code --- lib/rebase.js | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/lib/rebase.js b/lib/rebase.js index 8250c8663..eb0957081 100644 --- a/lib/rebase.js +++ b/lib/rebase.js @@ -87,24 +87,11 @@ Rebase.open = function(repository, options) { }; Rebase.prototype.commit = - function(author, committer, encoding, message, callback) { - return _commit.call(this, author, committer, encoding, message) - .then(function(oid) { - if (typeof callback === "function") { - callback(null, oid); - } - - return oid; - }, callback); + function(author, committer, encoding, message) { + return _commit.call(this, author, committer, encoding, message); }; -Rebase.prototype.abort = - function(callback) { - return _abort.call(this) - .then(function() { - if (typeof callback === "function") { - callback(null); - } - }, callback); +Rebase.prototype.abort = function() { + return _abort.call(this); }; From 3b548992f5cccd5c560d1460b8bf9253157408f0 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Tue, 15 Aug 2017 15:10:18 -0700 Subject: [PATCH 27/35] Formatting; removed unnecessary return of 0 --- lib/rebase.js | 11 +++++------ lib/repository.js | 1 - 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/rebase.js b/lib/rebase.js index eb0957081..28882ea6c 100644 --- a/lib/rebase.js +++ b/lib/rebase.js @@ -86,12 +86,11 @@ Rebase.open = function(repository, options) { return _open(repository, options); }; -Rebase.prototype.commit = - function(author, committer, encoding, message) { - return _commit.call(this, author, committer, encoding, message); - }; +Rebase.prototype.commit = function(author, committer, encoding, message) { + return _commit.call(this, author, committer, encoding, message); +}; Rebase.prototype.abort = function() { - return _abort.call(this); - }; + return _abort.call(this); +}; diff --git a/lib/repository.js b/lib/repository.js index 0637cec47..bcf8591c7 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -455,7 +455,6 @@ Repository.prototype.continueRebase = function( // this routine from choking now // that we made rebase.commit // asynchronous - return 0; }); }) .then(function() { From a48779bc7293f0927cc5b87f93cd569ad17d2484 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Thu, 13 Jul 2017 12:41:20 -0700 Subject: [PATCH 28/35] Added blob methods and converted to async --- generate/input/descriptor.json | 52 ++++- test/tests/blob.js | 397 +++++++++++++++++++++++++++++++++ test/tests/diff.js | 9 +- 3 files changed, 453 insertions(+), 5 deletions(-) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index 1290486d9..7d1953de8 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -130,7 +130,7 @@ "selfFreeing": true, "functions": { "git_blob_create_frombuffer": { - "isAsync": false, + "isAsync": true, "args": { "id": { "isReturn": true @@ -141,11 +141,59 @@ } } }, + "git_blob_create_fromworkdir": { + "isAsync": true, + "args": { + "id": { + "isReturn": true + } + }, + "return": { + "isErrorCode": true + } + }, + "git_blob_create_fromdisk": { + "isAsync": true, + "args": { + "id": { + "isReturn": true + } + }, + "return": { + "isErrorCode": true + } + }, "git_blob_create_fromchunks": { "ignore": true }, "git_blob_filtered_content": { - "ignore": true + "isAsync": true, + "isPrototypeMethod": false, + "args": { + "out": { + "isReturn": true, + "cppClassName": "GitBuf", + "jsClassName": "Buffer" + }, + "blob": { + "cppClassName": "GitBlob", + "jsClassName": "Blob", + "isSelf": false + }, + "as_path": { + "cppClassName": "String", + "jsClassName": "String", + "cType": "const char *" + }, + "check_for_binary_data": { + "cppClassName": "Number", + "jsClassName": "Number", + "cType": "int" + } + }, + "return": { + "isErrorCode": true + } }, "git_blob_id": { "return": { diff --git a/test/tests/blob.js b/test/tests/blob.js index 342cb2578..a6c466995 100644 --- a/test/tests/blob.js +++ b/test/tests/blob.js @@ -1,17 +1,69 @@ var assert = require("assert"); var path = require("path"); var local = path.join.bind(path, __dirname); +var promisify = require("promisify-node"); +var fse = promisify("fs-extra"); describe("Blob", function() { var NodeGit = require("../../"); var Oid = NodeGit.Oid; var Repository = NodeGit.Repository; + var Blob = NodeGit.Blob; var FileMode = NodeGit.TreeEntry.FILEMODE; var reposPath = local("../repos/workdir"); var oid = "111dd657329797f6165f52f5085f61ac976dcf04"; + function commitFile(repo, fileName, fileContent, commitMessage) { + var index; + var treeOid; + var parent; + + return fse.writeFile(path.join(repo.workdir(), fileName), fileContent) + .then(function() { + return repo.refreshIndex(); + }) + .then(function(indexResult) { + index = indexResult; + }) + .then(function() { + return index.addByPath(fileName); + }) + .then(function() { + return index.write(); + }) + .then(function() { + return index.writeTree(); + }) + .then(function(oidResult) { + treeOid = oidResult; + return NodeGit.Reference.nameToId(repo, "HEAD"); + }) + .then(function(head) { + return repo.getCommit(head); + }) + .then(function(parentResult) { + parent = parentResult; + return Promise.all([ + NodeGit.Signature.create("Foo Bar", "foo@bar.com", 123456789, 60), + NodeGit.Signature.create("Foo A Bar", "foo@bar.com", 987654321, 90) + ]); + }) + .then(function(signatures) { + var author = signatures[0]; + var committer = signatures[1]; + + return repo.createCommit( + "HEAD", + author, + committer, + commitMessage, + treeOid, + [parent]); + }); + } + beforeEach(function() { var test = this; @@ -50,4 +102,349 @@ describe("Blob", function() { assert.equal(blob.id().toString(), oid); }); }); + + describe("createFromBuffer", function() { + it("creates a new blob from the buffer", function() { + var content = "This is a new buffer"; + var buf = new Buffer(content, content.length); + var test = this; + + return Blob.createFromBuffer(test.repository, buf, content.length) + .then(function(oid) { + return test.repository.getBlob(oid); + }) + .then(function(newBlob) { + assert.equal(newBlob.toString(), content); + }); + }); + + it("creates blob with content equal to length", function() { + var content = "This is a new buffer"; + var buf = new Buffer(content, content.length); + var test = this; + + return Blob.createFromBuffer(test.repository, buf, 2) + .then(function(oid) { + return test.repository.getBlob(oid); + }) + .then(function(newBlob) { + assert.equal(newBlob.toString(), "Th"); + }); + }); + + it("throws an error when repository is null", function() { + return Blob.createFromBuffer(null, null, 0) + .catch(function(error) { + assert.strictEqual(error.message, "Repository repo is required."); + }); + }); + + it("throws an error when buffer is null", function() { + var test = this; + return Blob.createFromBuffer(test.repository, null) + .catch(function(error) { + assert.strictEqual(error.message, "Buffer buffer is required."); + }); + }); + + it("throws an error when no length is provided", function() { + var test = this; + return Blob.createFromBuffer(test.repository, new Buffer("testing")) + .catch(function(error) { + assert.strictEqual(error.message, "Number len is required."); + }); + }); + }); + + describe("createFromDisk", function() { + var fileName = path.join(reposPath, "testFile.zzz"); + var fileContent = "this is my file content"; + + beforeEach(function() { + return fse.writeFile(fileName, fileContent); + }); + + afterEach(function() { + return fse.unlink(fileName); + }); + + it("creates a new blob from the file", function() { + var test = this; + + return Blob.createFromDisk(test.repository, fileName) + .then(function(oid) { + return test.repository.getBlob(oid); + }) + .then(function(newBlob) { + assert.equal(newBlob.toString(), fileContent); + }); + }); + + it("throws an error when the file cannot be found", function() { + var test = this; + + return Blob.createFromDisk(test.repository, "aaaaaaaaaa") + .catch(function(error) { + assert.equal(error.errno, -3); + }); + }); + + it("throws an error when repository is null", function() { + return Blob.createFromDisk(null, null, 0) + .catch(function(error) { + assert.strictEqual(error.message, "Repository repo is required."); + }); + }); + + it("throws an error when path is null", function() { + var test = this; + return Blob.createFromDisk(test.repository, null) + .catch(function(error) { + assert.strictEqual(error.message, "String path is required."); + }); + }); + }); + + describe("createFromWorkdir", function() { + it("creates a blob from the file", function() { + var fileName = "package.json"; + var filePath = path.join(reposPath, "package.json"); + var test = this; + + return fse.readFile(filePath) + .then(function(content) { + test.content = content.toString(); + return Blob.createFromWorkdir(test.repository, fileName); + }) + .then(function(oid) { + return test.repository.getBlob(oid); + }) + .then(function(newBlob) { + assert.equal(newBlob.toString(), test.content); + }); + }); + + it("throws an error when the file cannot be found", function() { + var test = this; + + return Blob.createFromWorkdir(test.repository, "thisisabadfile.jpg") + .catch(function(error) { + assert.equal(error.errno, -3); + }); + }); + + it("throws an error when repository is null", function() { + return Blob.createFromWorkdir(null, null, 0) + .catch(function(error) { + assert.strictEqual(error.message, "Repository repo is required."); + }); + }); + + it("throws an error when path is null", function() { + var test = this; + return Blob.createFromWorkdir(test.repository, null) + .catch(function(error) { + assert + .strictEqual(error.message, "String relative_path is required."); + }); + }); + }); + + describe("filteredContent", function() { + var attrFileName = ".gitattributes"; + var filter = "* text eol=crlf"; + var lineEndingRegex = /\r\n|\r|\n/; + var newFileName = "testfile.test"; + + it("retrieves the filtered content", function() { + var test = this; + + return commitFile( + test.repository, + attrFileName, + filter, + "added gitattributes") + .then(function() { + return commitFile( + test.repository, + newFileName, + "this\nis\nfun\guys", + "added LF ending file"); + }) + .then(function(oid) { + return test.repository.getCommit(oid); + }) + .then(function(commit) { + test.filteredCommit = commit; + return commit.getEntry(newFileName); + }) + .then(function(entry) { + return entry.getBlob(); + }) + .then(function(lfBlob) { + test.lfBlob = lfBlob; + var ending = test.lfBlob.toString().match(lineEndingRegex); + assert.strictEqual(ending[0], "\n"); + + return Blob.filteredContent( + test.lfBlob, + newFileName, + 0); + }) + .then(function(content) { + var ending = content.match(lineEndingRegex); + assert.strictEqual(ending[0], "\r\n"); + assert.notStrictEqual(content, test.blob.toString()); + }); + }); + + it("returns non-binary filtered content when checking binary", function() { + var test = this; + + return commitFile( + test.repository, + attrFileName, + filter, + "added gitattributes") + .then(function() { + return commitFile( + test.repository, + newFileName, + "this\nis\nfun\guys", + "added LF ending file"); + }) + .then(function(oid) { + return test.repository.getCommit(oid); + }) + .then(function(commit) { + test.filteredCommit = commit; + return commit.getEntry(newFileName); + }) + .then(function(entry) { + return entry.getBlob(); + }) + .then(function(lfBlob) { + test.lfBlob = lfBlob; + var ending = test.lfBlob.toString().match(lineEndingRegex); + assert.strictEqual(ending[0], "\n"); + + return Blob.filteredContent( + test.lfBlob, + newFileName, + 1); + }) + .then(function(content) { + var ending = content.match(lineEndingRegex); + assert.strictEqual(ending[0], "\r\n"); + assert.notStrictEqual(content, test.blob.toString()); + }); + }); + + it("returns nothing when checking binary blob", function() { + var test = this; + var binary = new Buffer(new Uint8Array([1,2,3,4,5,6])); + + return commitFile( + test.repository, + attrFileName, + filter, + "added gitattributes") + .then(function() { + return commitFile( + test.repository, + newFileName, + binary, + "binary content"); + }) + .then(function(oid) { + return test.repository.getCommit(oid); + }) + .then(function(commit) { + test.filteredCommit = commit; + return commit.getEntry(newFileName); + }) + .then(function(entry) { + return entry.getBlob(); + }) + .then(function(bblob) { + test.bblob = bblob; + assert.equal(true, bblob.isBinary()); + + return Blob.filteredContent( + test.bblob, + newFileName, + 1); + }) + .then(function(content) { + assert.strictEqual(content, ""); + }); + }); + + it("returns blob when not checking binary on binary blob", function() { + var test = this; + var binary = new Buffer(new Uint8Array([1,2,3,4,5,6])); + + return commitFile( + test.repository, + attrFileName, + filter, + "added gitattributes") + .then(function() { + return commitFile( + test.repository, + newFileName, + binary, + "binary content"); + }) + .then(function(oid) { + return test.repository.getCommit(oid); + }) + .then(function(commit) { + test.filteredCommit = commit; + return commit.getEntry(newFileName); + }) + .then(function(entry) { + return entry.getBlob(); + }) + .then(function(bblob) { + test.bblob = bblob; + assert.equal(true, bblob.isBinary()); + + return Blob.filteredContent( + test.bblob, + newFileName, + 0); + }) + .then(function(content) { + assert.strictEqual(content, binary.toString()); + }); + }); + + it("throws an error when the blob is null", function() { + return Blob.filteredContent(null, "", 0) + .catch(function(err) { + assert.strictEqual( + err.message, + "Blob blob is required."); + }); + }); + + it("throws an error when the path is null", function() { + var test = this; + return Blob.filteredContent(test.blob, null, 0) + .catch(function(err) { + assert.strictEqual(err.message, "String as_path is required."); + }); + }); + + it("throws an error when the flag is undefined", function() { + var test = this; + return Blob.filteredContent(test.blob, "") + .catch(function(err) { + assert.strictEqual( + err.message, + "Number check_for_binary_data is required."); + }); + }); + }); }); diff --git a/test/tests/diff.js b/test/tests/diff.js index 43d14a3ec..fdad25354 100644 --- a/test/tests/diff.js +++ b/test/tests/diff.js @@ -247,10 +247,13 @@ describe("Diff", function() { function(done) { var evilString = "Unicode’s fun!\nAnd it’s good for you!\n"; var buffer = new Buffer(evilString); - var oid = Blob.createFromBuffer(this.repository, buffer, buffer.length); - Blob.lookup(this.repository, oid) + var test = this; + Blob.createFromBuffer(test.repository, buffer, buffer.length) + .then(function(oid) { + return Blob.lookup(test.repository, oid); + }) .then(function(blob) { - blob.repo = this.repository; + blob.repo = test.repository; return Diff.blobToBuffer( blob, null, From d7eff48e14def704f623ca075515ac4d989400ed Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Tue, 25 Jul 2017 14:52:54 -0700 Subject: [PATCH 29/35] Fixed test and made repo blob method return a promise --- lib/repository.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/repository.js b/lib/repository.js index bcf8591c7..33adcc498 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -511,8 +511,8 @@ Repository.prototype.createBranch = function(name, commit, force) { * @param {Buffer} buffer * @return {Oid} */ -Repository.prototype.createBlobFromBuffer = function(buffer, callback) { - return Blob.createFromBuffer(this, buffer, buffer.length, callback); +Repository.prototype.createBlobFromBuffer = function(buffer) { + return Blob.createFromBuffer(this, buffer, buffer.length); }; /** @@ -1784,9 +1784,9 @@ Repository.prototype.stageLines = .then(function(newContent) { var newContentBuffer = new Buffer(newContent); - var newOid = repo.createBlobFromBuffer(newContentBuffer); - return repo.getBlob(newOid); + return repo.createBlobFromBuffer(newContentBuffer); }) + .then(newOid => repo.getBlob(newOid)) .then(function(newBlob) { var entry = index.getByPath(filePath, 0); entry.id = newBlob.id(); From be3955eba3718cb6306b61396c39be97f9e70714 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Tue, 25 Jul 2017 16:26:31 -0700 Subject: [PATCH 30/35] Fixed unit tests --- test/tests/blob.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/tests/blob.js b/test/tests/blob.js index a6c466995..004136147 100644 --- a/test/tests/blob.js +++ b/test/tests/blob.js @@ -3,6 +3,7 @@ var path = require("path"); var local = path.join.bind(path, __dirname); var promisify = require("promisify-node"); var fse = promisify("fs-extra"); +var exec = require("../../utils/execPromise"); describe("Blob", function() { var NodeGit = require("../../"); @@ -14,6 +15,7 @@ describe("Blob", function() { var reposPath = local("../repos/workdir"); var oid = "111dd657329797f6165f52f5085f61ac976dcf04"; + var previousCommitOid = ""; function commitFile(repo, fileName, fileContent, commitMessage) { var index; @@ -64,6 +66,16 @@ describe("Blob", function() { }); } + before(function() { + return Repository.open(reposPath) + .then(function(repository) { + return repository.getHeadCommit(); + }) + .then(function(commit) { + previousCommitOid = commit.id(); + }); + }); + beforeEach(function() { var test = this; @@ -78,6 +90,17 @@ describe("Blob", function() { }); }); + after(function() { + console.log("cleaning"); + return exec("git clean -xdf", {cwd: reposPath}) + .then(function() { + return exec("git checkout master", {cwd: reposPath}); + }) + .then(function() { + return exec("git reset --hard " + previousCommitOid, {cwd: reposPath}); + }); + }); + it("can provide content as a buffer", function() { var contents = this.blob.content(); From c87633eae89bf5c615ee2689dd755e01941f3667 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Tue, 25 Jul 2017 16:33:55 -0700 Subject: [PATCH 31/35] removed console.log --- test/tests/blob.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/tests/blob.js b/test/tests/blob.js index 004136147..70543323c 100644 --- a/test/tests/blob.js +++ b/test/tests/blob.js @@ -91,7 +91,6 @@ describe("Blob", function() { }); after(function() { - console.log("cleaning"); return exec("git clean -xdf", {cwd: reposPath}) .then(function() { return exec("git checkout master", {cwd: reposPath}); From ff97c4beff1a29b47685e2e838c35f608c545bd4 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Mon, 31 Jul 2017 07:35:10 -0700 Subject: [PATCH 32/35] style fixes --- test/tests/blob.js | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/test/tests/blob.js b/test/tests/blob.js index 70543323c..a4299cee4 100644 --- a/test/tests/blob.js +++ b/test/tests/blob.js @@ -62,7 +62,8 @@ describe("Blob", function() { committer, commitMessage, treeOid, - [parent]); + [parent] + ); }); } @@ -291,7 +292,8 @@ describe("Blob", function() { test.repository, newFileName, "this\nis\nfun\guys", - "added LF ending file"); + "added LF ending file" + ); }) .then(function(oid) { return test.repository.getCommit(oid); @@ -311,7 +313,8 @@ describe("Blob", function() { return Blob.filteredContent( test.lfBlob, newFileName, - 0); + 0 + ); }) .then(function(content) { var ending = content.match(lineEndingRegex); @@ -333,7 +336,8 @@ describe("Blob", function() { test.repository, newFileName, "this\nis\nfun\guys", - "added LF ending file"); + "added LF ending file" + ); }) .then(function(oid) { return test.repository.getCommit(oid); @@ -353,7 +357,8 @@ describe("Blob", function() { return Blob.filteredContent( test.lfBlob, newFileName, - 1); + 1 + ); }) .then(function(content) { var ending = content.match(lineEndingRegex); @@ -376,7 +381,8 @@ describe("Blob", function() { test.repository, newFileName, binary, - "binary content"); + "binary content" + ); }) .then(function(oid) { return test.repository.getCommit(oid); @@ -395,7 +401,8 @@ describe("Blob", function() { return Blob.filteredContent( test.bblob, newFileName, - 1); + 1 + ); }) .then(function(content) { assert.strictEqual(content, ""); @@ -416,7 +423,8 @@ describe("Blob", function() { test.repository, newFileName, binary, - "binary content"); + "binary content" + ); }) .then(function(oid) { return test.repository.getCommit(oid); @@ -435,7 +443,8 @@ describe("Blob", function() { return Blob.filteredContent( test.bblob, newFileName, - 0); + 0 + ); }) .then(function(content) { assert.strictEqual(content, binary.toString()); @@ -447,7 +456,8 @@ describe("Blob", function() { .catch(function(err) { assert.strictEqual( err.message, - "Blob blob is required."); + "Blob blob is required." + ); }); }); @@ -465,7 +475,8 @@ describe("Blob", function() { .catch(function(err) { assert.strictEqual( err.message, - "Number check_for_binary_data is required."); + "Number check_for_binary_data is required." + ); }); }); }); From cdfad45b16638b68cc6709773dcc784753986933 Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Wed, 16 Aug 2017 07:53:20 -0700 Subject: [PATCH 33/35] renamed bblob to binaryBlob --- test/tests/blob.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/tests/blob.js b/test/tests/blob.js index a4299cee4..dce4ce619 100644 --- a/test/tests/blob.js +++ b/test/tests/blob.js @@ -394,12 +394,12 @@ describe("Blob", function() { .then(function(entry) { return entry.getBlob(); }) - .then(function(bblob) { - test.bblob = bblob; - assert.equal(true, bblob.isBinary()); + .then(function(binaryBlob) { + test.binaryBlob = binaryBlob; + assert.equal(true, binaryBlob.isBinary()); return Blob.filteredContent( - test.bblob, + test.binaryBlob, newFileName, 1 ); @@ -436,12 +436,12 @@ describe("Blob", function() { .then(function(entry) { return entry.getBlob(); }) - .then(function(bblob) { - test.bblob = bblob; - assert.equal(true, bblob.isBinary()); + .then(function(binaryBlob) { + test.binaryBlob = binaryBlob; + assert.equal(true, binaryBlob.isBinary()); return Blob.filteredContent( - test.bblob, + test.binaryBlob, newFileName, 0 ); From c9e2bcc32ad1582b3bfa3cb3c03a9acc3feadda1 Mon Sep 17 00:00:00 2001 From: Tyler Wanek Date: Wed, 16 Aug 2017 12:22:35 -0700 Subject: [PATCH 34/35] 0.20.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5becdd1c1..268d00f86 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nodegit", "description": "Node.js libgit2 asynchronous native bindings", - "version": "0.19.0", + "version": "0.20.0", "homepage": "http://nodegit.org", "keywords": [ "libgit2", From c6adb86dd1799fdc05ab07b2a282edd76844a44e Mon Sep 17 00:00:00 2001 From: Tyler Wanek Date: Wed, 16 Aug 2017 13:24:43 -0700 Subject: [PATCH 35/35] Bump to 0.20.0 with changelog --- CHANGELOG.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++-- README.md | 4 +-- 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 516919bed..0d8fdc98a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,86 @@ # Change Log +## v0.20.0 [(2017-08-16)](https://github.com/nodegit/nodegit/releases/tag/v0.20.0) + +[Full Changelog](https://github.com/nodegit/nodegit/compare/v0.19.0...v0.20.0) + +#### Summary of changes outside of libgit2 bump: + - [BREAKING: Added blob methods and converted to async #1327](https://github.com/nodegit/nodegit/pull/1327) + - [BREAKING: Convert sync methods to async methods #1348](https://github.com/nodegit/nodegit/pull/1348) + - [Exposed libgit2 git_branch_remote_name method #1340](https://github.com/nodegit/nodegit/pull/1340) + - [Adding git_filter support in nodegit #1331](https://github.com/nodegit/nodegit/pull/1331) + - [Add CI build config for node stable version #1337](https://github.com/nodegit/nodegit/pull/1337) + - [removed node v4 tests #1330](https://github.com/nodegit/nodegit/pull/1330) + +#### Included merged libgti2 PRs: + - [Include fixups #4288](https://github.com/libgit2/libgit2/pull/4288) + - [Docs: Fix inline comments for git_diff_hunk #4330](https://github.com/libgit2/libgit2/pull/4330) + - [oid: use memcmp in git_oid__hashcmp #4328](https://github.com/libgit2/libgit2/pull/4328) + - [sha1_lookup: drop sha1_entry_pos function #4327](https://github.com/libgit2/libgit2/pull/4327) + - [sha1_position: convert do-while to while #4326](https://github.com/libgit2/libgit2/pull/4326) + - [patch_generate: represent buffers as void pointers #4304](https://github.com/libgit2/libgit2/pull/4304) + - [Remove unused 'sys/remote.h' header #4323](https://github.com/libgit2/libgit2/pull/4323) + - [tests: rebase::submodule: verify initialization method calls #4320](https://github.com/libgit2/libgit2/pull/4320) + - [tests: rewrite rebase-submodule .gitmodule file #4275](https://github.com/libgit2/libgit2/pull/4275) + - [tsort: remove idempotent conditional assignment #4314](https://github.com/libgit2/libgit2/pull/4314) + - [Build with patched libcurl #4317](https://github.com/libgit2/libgit2/pull/4317) + - [win32: provide fast-path for retrying filesystem operations #4311](https://github.com/libgit2/libgit2/pull/4311) + - [Configuration file fixes with includes #4250](https://github.com/libgit2/libgit2/pull/4250) + - [Patch ID calculation #4272](https://github.com/libgit2/libgit2/pull/4272) + - [signature: don't leave a dangling pointer to the strings on parse failure #4306](https://github.com/libgit2/libgit2/pull/4306) + - [git_reset_*: pass parameters as const pointers #4287](https://github.com/libgit2/libgit2/pull/4287) + - [tests: config: fix missing declaration causing error #4291](https://github.com/libgit2/libgit2/pull/4291) + - [Convert port with htons() in p_getaddrinfo() #4280](https://github.com/libgit2/libgit2/pull/4280) + - [Out of tree builds #4235](https://github.com/libgit2/libgit2/pull/4235) + - [cmake: Permit disabling external http-parser #4278](https://github.com/libgit2/libgit2/pull/4278) + - [merge: fix potential free of uninitialized memory #4277](https://github.com/libgit2/libgit2/pull/4277) + - [merge: perform exact rename detection in linear time #4202](https://github.com/libgit2/libgit2/pull/4202) + - [travis: upgrade container to Ubuntu 14.04 #4211](https://github.com/libgit2/libgit2/pull/4211) + - [Fix template dir empty string #4273](https://github.com/libgit2/libgit2/pull/4273) + - [adding GIT_FILTER_VERSION to GIT_FILTER_INIT as part of convention #4267](https://github.com/libgit2/libgit2/pull/4267) + - [travis: replace use of deprecated homebrew/dupes tap #4268](https://github.com/libgit2/libgit2/pull/4268) + - [Test improvements #4269](https://github.com/libgit2/libgit2/pull/4269) + - [Read prefix tests #4265](https://github.com/libgit2/libgit2/pull/4265) + - [Allow creation of a configuration object in an in-memory repository #4263](https://github.com/libgit2/libgit2/pull/4263) + - [travis: install openssl explicitly #4266](https://github.com/libgit2/libgit2/pull/4266) + - [smart_protocol: fix parsing of server ACK responses #4261](https://github.com/libgit2/libgit2/pull/4261) + - [odb_read_prefix: reset error in backends loop #4264](https://github.com/libgit2/libgit2/pull/4264) + - [Update version number to 0.26 #4262](https://github.com/libgit2/libgit2/pull/4262) + - [CHANGELOG: add various changes introduced since v0.25 #4254](https://github.com/libgit2/libgit2/pull/4254) + - [Ensure packfiles with different contents have different names #4088](https://github.com/libgit2/libgit2/pull/4088) + - [Update to forced checkout and untracked files #4260](https://github.com/libgit2/libgit2/pull/4260) + - [settings: rename `GIT_OPT_ENABLE_SYNCHRONOUS_OBJECT_CREATION` #4259](https://github.com/libgit2/libgit2/pull/4259) + - [Buffer growing cleanups #4255](https://github.com/libgit2/libgit2/pull/4255) + - [Coverity fixes #4253](https://github.com/libgit2/libgit2/pull/4253) + - [SHA1DC update #4258](https://github.com/libgit2/libgit2/pull/4258) + - [Fix path computations for compressed index entries #4236](https://github.com/libgit2/libgit2/pull/4236) + - [(Temporarily) disable UNC tests #4256](https://github.com/libgit2/libgit2/pull/4256) + - [fix build with libressl #4251](https://github.com/libgit2/libgit2/pull/4251) + - [Fix issue with directory glob ignore in subdirectories #4239](https://github.com/libgit2/libgit2/pull/4239) + - [Submodule working directory #4243](https://github.com/libgit2/libgit2/pull/4243) + - [Introduce home directory expansion function for config files, attribute files #4179](https://github.com/libgit2/libgit2/pull/4179) + - [Fix proxy auto detect not utilizing callbacks #4097](https://github.com/libgit2/libgit2/pull/4097) + - [git_repository_set_head: use tag name in reflog #4174](https://github.com/libgit2/libgit2/pull/4174) + - [revparse: support open-ended ranges #4231](https://github.com/libgit2/libgit2/pull/4231) + - [Fix GCC warnings #4240](https://github.com/libgit2/libgit2/pull/4240) + - [Update README: VS -> VSTS #4238](https://github.com/libgit2/libgit2/pull/4238) + - [tests: repo: fix repo discovery tests on overlayfs #4232](https://github.com/libgit2/libgit2/pull/4232) + - [libssh2 shutdown #4229](https://github.com/libgit2/libgit2/pull/4229) + - [WIP: squash some memleaks #4226](https://github.com/libgit2/libgit2/pull/4226) + - [Verify object hashes #4197](https://github.com/libgit2/libgit2/pull/4197) + - [transport: provide a getter for the proxy options #4206](https://github.com/libgit2/libgit2/pull/4206) + - [Debian HTTPS feature test failure #4216](https://github.com/libgit2/libgit2/pull/4216) + - [Do not free config when creating remote #4224](https://github.com/libgit2/libgit2/pull/4224) + - [socket_stream: continue to next addrinfo on socket creation failure #4219](https://github.com/libgit2/libgit2/pull/4219) + - [Honor read-only flag when writing to config backends #4217](https://github.com/libgit2/libgit2/pull/4217) + - [diff_parse: free object instead of its pointer #4215](https://github.com/libgit2/libgit2/pull/4215) + +#### Included non-merged libgit2 PRs: + + - [Parallelize checkout_create_the_new for ntfs perf gains #4205](https://github.com/libgit2/libgit2/pull/4205) + - [negotiate always fails via libcurl #4126](https://github.com/libgit2/libgit2/pull/4126) + + ## v0.19.0 [(2017-04-20)](https://github.com/nodegit/nodegit/releases/tag/v0.19.0) [Full Changelog](https://github.com/nodegit/nodegit/compare/v0.18.0...v0.19.0) @@ -81,7 +162,7 @@ - `ontoSha` The sha that we rebased onto - `originalHeadName` The name of the branch that we rebased - `originalHeadSha` The sha of the branch that was rebased - - `rewitten` which is an array of sha pairs that contain which contain what the commit sha was before the rebase and what the commit sha is after the rebase + - `rewitten` which is an array of sha pairs that contain which contain what the commit sha was before the rebase and what the commit sha is after the rebase ### Summary of Changes from bumping libgit2 to 43275f5 @@ -140,7 +221,7 @@ In this release we had added support for Node v7 and latest Electron. We have removed support for Node v0.12 and v5. -We are also deprecating nw.js support since it is currently broken, no one in the current team uses it and we would not be able to currently support nw.js in an effective manner with a good user experience. +We are also deprecating nw.js support since it is currently broken, no one in the current team uses it and we would not be able to currently support nw.js in an effective manner with a good user experience. ### Now building against shared libcurl lib diff --git a/README.md b/README.md index 029378eb9..3a9ee8b80 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ NodeGit -**Stable (libgit2#master): 0.19.0** -**Stable (libgit2@0.24): 0.14.1** +**Stable (libgit2#master): 0.20.0** +**Stable (libgit2@v0.26.0): 0.26.0** ## Have a problem? Come chat with us! ##