diff --git a/.travis.yml b/.travis.yml
index ef6f06fc2..2b317c86e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,19 +13,19 @@ sudo: false
env:
matrix:
- - export NODE_VERSION="4" TARGET_ARCH="x64"
- - 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="4" TARGET_ARCH="ia32"
- - 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
@@ -66,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:
@@ -81,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 5f7172f5c..c25c50ebb 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -27,9 +27,9 @@ environment:
GYP_MSVS_VERSION: 2013
matrix:
# Node.js
- - nodejs_version: "4"
- - nodejs_version: "6"
+ - nodejs_version: "stable"
- nodejs_version: "7"
+ - nodejs_version: "6"
matrix:
fast_finish: true
@@ -40,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
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..1e9aeaf8b 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": {
@@ -879,6 +908,8 @@
}
},
"filter": {
+ "selfFreeing": false,
+ "hasConstructor": true,
"functions": {
"git_filter_list_apply_to_blob": {
"ignore": true
@@ -920,30 +951,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-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/generate/input/libgit2-supplement.json b/generate/input/libgit2-supplement.json
index 52bb45651..12cfe7b2a 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,23 @@
},
{
"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
- },
- {
- "type": "git_filter_stream_fn",
- "name": "stream",
- "ignore": true
+ "name": "apply"
},
{
"type": "git_filter_cleanup_fn",
- "name": "cleanup",
- "ignore": true
+ "name": "cleanup"
}
]
}
@@ -765,14 +766,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 +797,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..49a2795c2 100644
--- a/generate/scripts/generateJson.js
+++ b/generate/scripts/generateJson.js
@@ -169,9 +169,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 +192,6 @@ module.exports = function generateJson() {
fn.cppClassName = def.cppClassName;
});
});
-
// Process enums
_(enums).forEach(function(enumerable) {
output.some(function(obj) {
diff --git a/generate/scripts/generateNativeCode.js b/generate/scripts/generateNativeCode.js
index a82bef4e5..30fc52707 100644
--- a/generate/scripts/generateNativeCode.js
+++ b/generate/scripts/generateNativeCode.js
@@ -68,9 +68,11 @@ 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"),
+ setUnsigned: require("../templates/filters/unsigned"),
upper: require("../templates/filters/upper")
};
diff --git a/generate/scripts/helpers.js b/generate/scripts/helpers.js
index 48b651355..9b7baa2cb 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");
@@ -93,6 +94,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/filters/args_info.js b/generate/templates/filters/args_info.js
index 1382c67d6..0c05c30eb 100644
--- a/generate/templates/filters/args_info.js
+++ b/generate/templates/filters/args_info.js
@@ -13,12 +13,8 @@ module.exports = function(args) {
jsArg++;
}
- if (cArg === args.length -1) {
- arg.lastArg = true;
- }
- else {
- arg.lastArg = 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
new file mode 100644
index 000000000..6329f2e2c
--- /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/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/async_baton.h b/generate/templates/manual/include/async_baton.h
index 5f6874102..f8373cd0d 100644
--- a/generate/templates/manual/include/async_baton.h
+++ b/generate/templates/manual/include/async_baton.h
@@ -60,4 +60,38 @@ struct AsyncBatonWithResult : public AsyncBaton {
}
};
+struct AsyncBatonWithNoResult : public AsyncBaton {
+ 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/manual/include/filter_registry.h b/generate/templates/manual/include/filter_registry.h
new file mode 100644
index 000000000..b75938218
--- /dev/null
+++ b/generate/templates/manual/include/filter_registry.h
@@ -0,0 +1,75 @@
+#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);
+
+ struct FilterRegisterBaton {
+ const git_error *error;
+ git_filter *filter;
+ char *filter_name;
+ int filter_priority;
+ int error_code;
+ };
+
+ struct FilterUnregisterBaton {
+ const git_error *error;
+ char *filter_name;
+ int error_code;
+ };
+
+ class RegisterWorker : public Nan::AsyncWorker {
+ public:
+ RegisterWorker(FilterRegisterBaton *_baton, Nan::Callback *callback)
+ : Nan::AsyncWorker(callback), baton(_baton) {};
+ ~RegisterWorker() {};
+ void Execute();
+ void HandleOKCallback();
+
+ private:
+ FilterRegisterBaton *baton;
+ };
+
+ class UnregisterWorker : public Nan::AsyncWorker {
+ public:
+ UnregisterWorker(FilterUnregisterBaton *_baton, Nan::Callback *callback)
+ : Nan::AsyncWorker(callback), baton(_baton) {};
+ ~UnregisterWorker() {};
+ void Execute();
+ void HandleOKCallback();
+
+ private:
+ FilterUnregisterBaton *baton;
+ };
+};
+
+#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..a44e4ae70
--- /dev/null
+++ b/generate/templates/manual/src/filter_registry.cc
@@ -0,0 +1,215 @@
+#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"
+
+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);
+}
+
+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.");
+ }
+
+ if (info.Length() == 3 || !info[3]->IsFunction()) {
+ return Nan::ThrowError("Callback is required and must be a Function.");
+ }
+
+ FilterRegisterBaton *baton = new FilterRegisterBaton;
+
+ baton->filter = Nan::ObjectWrap::Unwrap(info[1]->ToObject())->GetValue();
+ String::Utf8Value name(info[0]->ToString());
+
+ 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;
+ baton->filter_priority = (int)info[2]->ToNumber()->Value();
+
+ Nan::New(GitFilterRegistry::persistentHandle)->Set(info[0]->ToString(), info[1]->ToObject());
+
+ 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;
+}
+
+void GitFilterRegistry::RegisterWorker::Execute() {
+ giterr_clear();
+
+ {
+ 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;
+
+ 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) {
+ 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;
+}
+
+NAN_METHOD(GitFilterRegistry::GitFilterUnregister) {
+ Nan::EscapableHandleScope scope;
+
+ if (info.Length() == 0 || !info[0]->IsString()) {
+ return Nan::ThrowError("String name is required.");
+ }
+
+ if (info.Length() == 1 || !info[1]->IsFunction()) {
+ return Nan::ThrowError("Callback is required and must be a Function.");
+ }
+
+ FilterUnregisterBaton *baton = new FilterUnregisterBaton;
+ String::Utf8Value name(info[0]->ToString());
+
+ 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);
+
+ worker->SaveToPersistent("filter_name", info[0]);
+
+ AsyncLibgit2QueueWorker(worker);
+ return;
+}
+
+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());
+ }
+ }
+}
+
+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) {
+ 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/async_function.cc b/generate/templates/partials/async_function.cc
index b8e19ddb0..20813136d 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,10 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) {
{%endif%}
{%endif%}
{%elsif arg.shouldAlloc %}
- baton->{{ arg.name }} = ({{ arg.cType }})malloc(sizeof({{ arg.cType|replace '*' '' }}));
+ {%if arg.cppClassName == "GitBuf" %}
+ {%else%}
+ baton->{{ arg.name }} = ({{ arg.cType }})malloc(sizeof({{ arg.cType|replace '*' '' }}));
+ {%endif%}
{%endif%}
{%endeach%}
@@ -273,8 +280,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 ea5bb5db1..480adc76f 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;
@@ -153,7 +175,6 @@
{% if field.return.type == "int" %}
baton->result = baton->defaultResult; // no results acquired
{% endif %}
-
baton->Done();
return;
}
@@ -163,15 +184,53 @@
{%-- 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();
+ }
{% endif %}
{% endif %}
{% endeach %}
- v8::Local argv[{{ field.args|jsArgsCount }}] = {
- {% each field.args|argsInfo as arg %}
+ {% if field.isSelfReferential %}
+ {% 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 %}
+ {% 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 is always the last arg --%}
+ 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" %}
+ {%-- skip, filters should not have a payload --%}
+ {% else %}
+ Nan::New(baton->{{ arg.name }}),
+ {% endif %}
+ {% endif %}
+ {% endif %}
+ {% endif %}
+ {% else %}
{% if arg.name == "payload" %}
{%-- payload is always the last arg --%}
Nan::New(instance->{{ fields|payloadFor field.name }})
@@ -183,55 +242,35 @@
{% 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' %}
+ {% elsif arg.cppClassName == "String" %}
Nan::New(baton->{{ arg.name }}).ToLocalChecked(),
{% else %}
Nan::New(baton->{{ arg.name }}),
{% endif %}
{% endif %}
- {% endeach %}
- };
+ {% 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 }}, 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;
}
-
- {% 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) {
+
+ {% 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 +286,7 @@
if (result->IsNumber()) {
baton->result = (int)result->ToNumber()->Value();
}
- else{
+ else {
baton->result = baton->defaultResult;
}
{% endif %}
@@ -256,18 +295,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/binding.gyp b/generate/templates/templates/binding.gyp
index 69e2042ad..c163ae268 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",
@@ -22,6 +21,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 %}
@@ -91,9 +91,9 @@
}
],
[
- "OS=='linux' or OS=='mac'", {
+ "OS=='linux' or OS=='mac' or OS.endswith('bsd')", {
"libraries": [
- "-lcurl"
+ "/dev/null || echo)"
]
}
],
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..246f5b26b 100644
--- a/generate/templates/templates/nodegit.js
+++ b/generate/templates/templates/nodegit.js
@@ -58,6 +58,14 @@ _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;
+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.
@@ -86,6 +94,8 @@ require("./status_file");
require("./enums.js");
// Import extensions
+// [Manual] extensions
+importExtension("filter_registry");
{% each %}
{% if type != "enum" %}
importExtension("{{ filename }}");
diff --git a/generate/templates/templates/struct_content.cc b/generate/templates/templates/struct_content.cc
index c6f9e5b91..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();
@@ -54,9 +60,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 +89,11 @@ 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;
+ {% 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..4d2ec2af5 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 %}
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/lib/filter_registry.js b/lib/filter_registry.js
new file mode 100644
index 000000000..76dfba573
--- /dev/null
+++ b/lib/filter_registry.js
@@ -0,0 +1,42 @@
+var NodeGit = require("../");
+var normalizeOptions = NodeGit.Utils.normalizeOptions;
+
+var FilterRegistry = NodeGit.FilterRegistry;
+
+var _register = FilterRegistry.register;
+var _unregister = FilterRegistry.unregister;
+
+// register should add filter by name to dict and return
+// Override FilterRegistry.register to normalize Filter
+FilterRegistry.register = function(name, filter, priority, callback) {
+ // setting default value of attributes
+ if (filter.attributes === undefined) {
+ filter.attributes = "";
+ }
+
+ filter = normalizeOptions(filter, NodeGit.Filter);
+
+ 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) {
+ return _unregister(name)
+ .then(function(result) {
+ if (typeof callback === "function") {
+ callback(null, result);
+ }
+ return result;
+ }, callback);
+};
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;
diff --git a/test/tests/filter.js b/test/tests/filter.js
new file mode 100644
index 000000000..1db1c9ecb
--- /dev/null
+++ b/test/tests/filter.js
@@ -0,0 +1,852 @@
+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("../../");
+
+ var emptyRepoPath = local("../repos/empty");
+ var filterName = "psuedo_filter";
+ var Registry = NodeGit.FilterRegistry;
+ var Checkout = NodeGit.Checkout;
+ var Repository = NodeGit.Repository;
+ var reposPath = local("../repos/workdir");
+
+ var packageJsonPath = path.join(reposPath, "package.json");
+ var readmePath = path.join(reposPath, "README.md");
+
+ var mockFilter = {
+ apply: function() {},
+ check: function() {}
+ };
+
+ function commitFile(repo, fileName, fileContent, commitMessage) {
+ let index;
+ let treeOid;
+ 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]
+ );
+ });
+ }
+
+ beforeEach(function() {
+ var test = this;
+
+ return Repository.open(reposPath)
+ .then(function(repository) {
+ test.repository = repository;
+ return Repository.open(emptyRepoPath);
+ })
+ .then(function(emptyRepo) {
+ test.emptyRepo = emptyRepo;
+ return fse.writeFile(
+ path.join(reposPath, ".gitattributes"),
+ "*.md filter=" + filterName + " -text",
+ { encoding: "utf-8" }
+ );
+ });
+ });
+
+ afterEach(function() {
+ return Registry.unregister(filterName)
+ .catch(function(error) {
+ if (error === NodeGit.Error.CODE.ERROR) {
+ throw new Error("Cannot unregister filter");
+ }
+ });
+ });
+
+ 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, NodeGit.Error.CODE.OK);
+ });
+ });
+
+ it("can register multiple filters", function() {
+ return Registry.register(filterName, mockFilter, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ return Registry.register(secondFilter, mockFilter, 1);
+ })
+ .then(function(result) {
+ 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, NodeGit.Error.CODE.OK);
+ return Registry.register(filterName, mockFilter, 0);
+ })
+ .catch(function(error) {
+ assert.strictEqual(error.errno, NodeGit.Error.CODE.EEXISTS);
+ });
+ });
+ });
+
+ 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, NodeGit.Error.CODE.OK);
+ });
+ });
+
+ it("cannot unregister the filter twice", function() {
+ return Registry.unregister(filterName)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ return Registry.unregister(filterName);
+ })
+ .then(function(result) {
+ assert.fail("Should not have unregistered successfully");
+ })
+ .catch(function(error) {
+ assert.strictEqual(error.errno, NodeGit.Error.CODE.ENOTFOUND);
+ });
+ });
+ });
+
+ describe("Initialize", function(){
+ it("initializes successfully", function() {
+ var test = this;
+ var initialized = false;
+ return Registry.register(filterName, {
+ initialize: function() {
+ initialized = true;
+ return NodeGit.Error.CODE.OK;
+ },
+ apply: function() {},
+ check: function() {
+ return NodeGit.Error.CODE.PASSTHROUGH;
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ })
+ .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("initializes successfully even on garbage collect", function() {
+ var test = this;
+ var initialized = false;
+ return Registry.register(filterName, {
+ initialize: function() {
+ initialized = true;
+ return NodeGit.Error.CODE.OK;
+ },
+ apply: function() {},
+ check: function() {
+ return NodeGit.Error.CODE.PASSTHROUGH;
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ 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);
+ });
+ });
+
+ it("does not initialize successfully", function() {
+ var test = this;
+ var initialized = false;
+ return Registry.register(filterName, {
+ initialize: function() {
+ initialized = true;
+ return NodeGit.Error.CODE.ERROR;
+ },
+ apply: function() {},
+ check: function() {
+ return NodeGit.Error.CODE.PASSTHROUGH;
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ })
+ .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(head) {
+ assert.fail(head, undefined, "Should not have actually checked out");
+ })
+ .catch(function(error) {
+ assert.strictEqual(initialized, true);
+ });
+ });
+ });
+
+ describe("Shutdown", function() {
+ it("filter successfully shuts down", function() {
+ var test = this;
+ var shutdown = false;
+ return Registry.register(filterName, {
+ apply: function() {},
+ check: function(){
+ return NodeGit.Error.CODE.PASSTHROUGH;
+ },
+ shutdown: function(){
+ shutdown = true;
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ 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(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ 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() {},
+ check: function(){
+ return NodeGit.Error.CODE.PASSTHROUGH;
+ },
+ shutdown: function(){
+ shutdown = true;
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ 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() {
+ global.gc();
+ return Registry.unregister(filterName);
+ })
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ assert.strictEqual(shutdown, true);
+ });
+ });
+
+ it("shutdown completes even if there is an error", function() {
+ var test = this;
+ var shutdown = false;
+ return Registry.register(filterName, {
+ apply: function() {},
+ check: function(){
+ return NodeGit.Error.CODE.PASSTHROUGH;
+ },
+ shutdown: function(){
+ shutdown = true;
+ throw new Error("I failed");
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ 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(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ assert.strictEqual(shutdown, true);
+ })
+ .catch(function(error) {
+ assert.fail(error, null, "The operation should not have failed");
+ });
+ });
+ });
+
+ describe("Apply", function() {
+ var message = "some new fancy filter";
+ var length = message.length;
+ var tempBuffer = new Buffer(message, "utf-8");
+
+ it("should not apply when check returns GIT_PASSTHROUGH", function(){
+ var test = this;
+ var applied = false;
+
+ return Registry.register(filterName, {
+ apply: function() {
+ applied = true;
+ },
+ check: function() {
+ return NodeGit.Error.CODE.PASSTHROUGH;
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ 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.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 NodeGit.Error.CODE.OK;
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ 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(applied, true);
+ });
+ });
+
+ it("does not apply when GIT_PASSTHROUGH is returned", function() {
+ var test = this;
+
+ return Registry.register(filterName, {
+ apply: function(to, from, source) {
+ return to.set(tempBuffer, length)
+ .then(function() {
+ return NodeGit.Error.CODE.PASSTHROUGH;
+ });
+ },
+ check: function() {
+ return NodeGit.Error.CODE.OK;
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ })
+ .then(function() {
+ var readmeContent = fse.readFileSync(
+ packageJsonPath,
+ "utf-8"
+ );
+ assert.notStrictEqual(readmeContent, message);
+
+ 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() {
+ var postInitializeReadmeContents = fse.readFileSync(
+ readmePath,
+ "utf-8"
+ );
+
+ assert.notStrictEqual(postInitializeReadmeContents, message);
+ });
+ });
+
+ it("applies the filter data on checkout", function() {
+ var test = this;
+
+ return Registry.register(filterName, {
+ apply: function(to, from, source) {
+ return to.set(tempBuffer, length)
+ .then(function(buf) {
+ return NodeGit.Error.CODE.OK;
+ });
+ },
+ check: function(src, attr) {
+ return NodeGit.Error.CODE.OK;
+ }
+ }, 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");
+
+ var opts = {
+ checkoutStrategy: Checkout.STRATEGY.FORCE,
+ paths: ["README.md"]
+ };
+ return Checkout.head(test.repository, opts);
+ })
+ .then(function() {
+ 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 NodeGit.Error.CODE.OK;
+ });
+ },
+ check: function(src, attr) {
+ return NodeGit.Error.CODE.OK;
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ })
+ .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: ["README.md"]
+ };
+ return Checkout.head(test.repository, opts);
+ })
+ .then(function() {
+ var postInitializeReadmeContents = fse.readFileSync(
+ readmePath,
+ "utf-8"
+ );
+
+ assert.strictEqual(postInitializeReadmeContents, message);
+ });
+ });
+
+ it("applies the filter data on commit", function() {
+ var test = this;
+
+ return Registry.register(filterName, {
+ apply: function(to, from, source) {
+ return to.set(tempBuffer, length)
+ .then(function(buf) {
+ return NodeGit.Error.CODE.OK;
+ });
+ },
+ check: function(src, attr) {
+ return src.path() === "README.md" ?
+ 0 : NodeGit.Error.CODE.PASSTHROUGH;
+ },
+ cleanup: function() {}
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ })
+ .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(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);
+ });
+ });
+
+ 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 NodeGit.Error.CODE.OK;
+ });
+ },
+ check: function(src, attr) {
+ return src.path() === "README.md" ?
+ 0 : NodeGit.Error.CODE.PASSTHROUGH;
+ },
+ cleanup: function() {}
+ }, 0)
+ .then(function(result) {
+ global.gc();
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ })
+ .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(oid) {
+ global.gc();
+ 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");
+ global.gc();
+
+ 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", function() {
+ it("is called successfully", function() {
+ var test = this;
+ var cleaned = false;
+ return Registry.register(filterName, {
+ initialize: function() {
+ return NodeGit.Error.CODE.OK;
+ },
+ apply: function() {
+ return NodeGit.Error.CODE.OK;
+ },
+ check: function() {
+ return NodeGit.Error.CODE.OK;
+ },
+ cleanup: function() {
+ cleaned = true;
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ })
+ .then(function() {
+ var packageContent = fse.readFileSync(
+ packageJsonPath,
+ "utf-8"
+ );
+ assert.notEqual(packageContent, "");
+
+ 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 NodeGit.Error.CODE.OK;
+ },
+ apply: function() {
+ return NodeGit.Error.CODE.OK;
+ },
+ check: function() {
+ return NodeGit.Error.CODE.OK;
+ },
+ cleanup: function() {
+ cleaned = true;
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ })
+ .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 check returns GIT_PASSTHROUGH", function() {
+ var test = this;
+ var cleaned = false;
+
+ return Registry.register(filterName, {
+ initialize: function() {
+ return NodeGit.Error.CODE.OK;
+ },
+ apply: function() {
+ return NodeGit.Error.CODE.OK;
+ },
+ check: function() {
+ return NodeGit.Error.CODE.PASSTHROUGH;
+ },
+ cleanup: function() {
+ cleaned = true;
+ }
+ }, 0)
+ .then(function(result) {
+ assert.strictEqual(result, NodeGit.Error.CODE.OK);
+ })
+ .then(function() {
+ var packageContent = fse.readFileSync(
+ packageJsonPath,
+ "utf-8"
+ );
+ var 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);
+ });
+ });
+ });
+});
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
diff --git a/vendor/libgit2.gyp b/vendor/libgit2.gyp
index f00470f99..1f461d6bb 100644
--- a/vendor/libgit2.gyp
+++ b/vendor/libgit2.gyp
@@ -299,7 +299,8 @@
}],
["OS=='mac' or OS=='linux' or OS.endswith('bsd')", {
"cflags": [
- "-DGIT_CURL"
+ "-DGIT_CURL",
+ "/dev/null || echo)"
],
"defines": [
"GIT_CURL",