From e1ecafaea57ffb849528ffc7ba5d7a7cd5fb8dbf Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Sun, 16 Jul 2017 23:00:19 +0100 Subject: [PATCH 01/18] build: use pkg-config to find curl header pkgsrc (as used by NetBSD) installs package headers in non default locations. The solution is to use pkg-config to work out the correct location via CFLAGS. --- vendor/libgit2.gyp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vendor/libgit2.gyp b/vendor/libgit2.gyp index f00470f99..120be078f 100644 --- a/vendor/libgit2.gyp +++ b/vendor/libgit2.gyp @@ -27,6 +27,9 @@ "openssl/openssl.gyp:openssl", "libssh2" ], + 'cflags': [ + '/dev/null || echo "")', + ], "sources": [ "libgit2/include/git2/sys/hashsig.h", "libgit2/include/git2/sys/merge.h", From 3f2452792517152a36dc92d68fc41b8c0f5338ef Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Mon, 17 Jul 2017 08:23:11 +0100 Subject: [PATCH 02/18] Move the pkg-config logic to the Linux, BSD and OSX cflags section. This un-breaks the windows build. --- vendor/libgit2.gyp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/vendor/libgit2.gyp b/vendor/libgit2.gyp index 120be078f..1f461d6bb 100644 --- a/vendor/libgit2.gyp +++ b/vendor/libgit2.gyp @@ -27,9 +27,6 @@ "openssl/openssl.gyp:openssl", "libssh2" ], - 'cflags': [ - '/dev/null || echo "")', - ], "sources": [ "libgit2/include/git2/sys/hashsig.h", "libgit2/include/git2/sys/merge.h", @@ -302,7 +299,8 @@ }], ["OS=='mac' or OS=='linux' or OS.endswith('bsd')", { "cflags": [ - "-DGIT_CURL" + "-DGIT_CURL", + "/dev/null || echo)" ], "defines": [ "GIT_CURL", From e20451698e5d2038d735926ddbbe43ef21735dde Mon Sep 17 00:00:00 2001 From: Carson Howard Date: Mon, 24 Jul 2017 11:41:07 -0700 Subject: [PATCH 03/18] 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 04/18] 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 05/18] 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 06/18] 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 07/18] 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 08/18] 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 09/18] 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 10/18] 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 11/18] 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 12/18] 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 13/18] 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 14/18] 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 15/18] 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 7cd2f24ee8d04d9398fe57babbdb97eeab668f17 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Sun, 16 Jul 2017 23:00:19 +0100 Subject: [PATCH 16/18] build: use pkg-config to find curl header pkgsrc (as used by NetBSD) installs package headers in non default locations. The solution is to use pkg-config to work out the correct location via CFLAGS. --- vendor/libgit2.gyp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vendor/libgit2.gyp b/vendor/libgit2.gyp index f00470f99..120be078f 100644 --- a/vendor/libgit2.gyp +++ b/vendor/libgit2.gyp @@ -27,6 +27,9 @@ "openssl/openssl.gyp:openssl", "libssh2" ], + 'cflags': [ + '/dev/null || echo "")', + ], "sources": [ "libgit2/include/git2/sys/hashsig.h", "libgit2/include/git2/sys/merge.h", From 9e6e2370f39b61076453d1aa8183e3f321745d57 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Mon, 17 Jul 2017 08:23:11 +0100 Subject: [PATCH 17/18] Move the pkg-config logic to the Linux, BSD and OSX cflags section. This un-breaks the windows build. --- vendor/libgit2.gyp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/vendor/libgit2.gyp b/vendor/libgit2.gyp index 120be078f..1f461d6bb 100644 --- a/vendor/libgit2.gyp +++ b/vendor/libgit2.gyp @@ -27,9 +27,6 @@ "openssl/openssl.gyp:openssl", "libssh2" ], - 'cflags': [ - '/dev/null || echo "")', - ], "sources": [ "libgit2/include/git2/sys/hashsig.h", "libgit2/include/git2/sys/merge.h", @@ -302,7 +299,8 @@ }], ["OS=='mac' or OS=='linux' or OS.endswith('bsd')", { "cflags": [ - "-DGIT_CURL" + "-DGIT_CURL", + "/dev/null || echo)" ], "defines": [ "GIT_CURL", From 7d34e4667d119f3f2f3519236aef623816339bd2 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Sat, 5 Aug 2017 10:22:52 +0100 Subject: [PATCH 18/18] find libcurl using pkg-config --- generate/templates/templates/binding.gyp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generate/templates/templates/binding.gyp b/generate/templates/templates/binding.gyp index 1be9be490..c163ae268 100644 --- a/generate/templates/templates/binding.gyp +++ b/generate/templates/templates/binding.gyp @@ -91,9 +91,9 @@ } ], [ - "OS=='linux' or OS=='mac'", { + "OS=='linux' or OS=='mac' or OS.endswith('bsd')", { "libraries": [ - "-lcurl" + "/dev/null || echo)" ] } ],