Skip to content
This repository was archived by the owner on Nov 26, 2019. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions generate/input/libgit2-supplement.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@
"isPrototypeMethod": false,
"group": "clone"
},
"git_worktree_add": {
"isManual": true,
"cFile": "generate/templates/manual/worktree/worktree_add.cc",
"isAsync": true,
"isPrototypeMethod": false,
"group": "worktree"
},
"git_commit_extract_signature": {
"args": [
{
Expand Down
213 changes: 213 additions & 0 deletions generate/templates/manual/worktree/worktree_add.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
NAN_METHOD(GitWorktree::Add) {

if (info.Length() == 0 || !info[0]->IsObject()) {
return Nan::ThrowError("Repository repo is required.");
}

if (info.Length() == 1 || !info[1]->IsString()) {
return Nan::ThrowError("String name is required.");
}

if (info.Length() == 2 || !info[2]->IsString()) {
return Nan::ThrowError("String path is required.");
}

if (info.Length() == 3 || !info[3]->IsObject()) {
return Nan::ThrowError("WorktreeAddOptions opts is required.");
}

if (info.Length() == 4 || !info[4]->IsFunction()) {
return Nan::ThrowError("Callback is required and must be a Function.");
}

AddBaton* baton = new AddBaton;

baton->error_code = GIT_OK;
baton->error = NULL;

// start convert_from_v8 block
git_repository * from_repo = NULL;
from_repo = Nan::ObjectWrap::Unwrap<GitRepository>(info[0]->ToObject())->GetValue();
// end convert_from_v8 block
baton->repo = from_repo;
// start convert_from_v8 block
const char * from_name = NULL;

String::Utf8Value name(info[1]->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
baton->name = from_name;
// start convert_from_v8 block
const char * from_path = NULL;

String::Utf8Value path(info[2]->ToString());
// malloc with one extra byte so we can add the terminating null character C-strings expect:
from_path = (const char *) malloc(path.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_path, *path, path.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_path) + path.length()), 0, 1);
// end convert_from_v8 block
baton->path = from_path;
// start convert_from_v8 block
// Create a NULL git_worktree_add_options so that libgit2 will
// use a default options.
const git_worktree_add_options* from_opts = NULL;
// end convert_from_v8 block
baton->opts = from_opts;

Nan::Callback *callback = new Nan::Callback(v8::Local<Function>::Cast(info[4]));
AddWorker *worker = new AddWorker(baton, callback);

if (!info[0]->IsUndefined() && !info[0]->IsNull())
worker->SaveToPersistent("repo", info[0]->ToObject());
if (!info[1]->IsUndefined() && !info[1]->IsNull())
worker->SaveToPersistent("name", info[1]->ToObject());
if (!info[2]->IsUndefined() && !info[2]->IsNull())
worker->SaveToPersistent("path", info[2]->ToObject());
// Completely ignore info[3].
// if (!info[3]->IsUndefined() && !info[3]->IsNull())
// worker->SaveToPersistent("opts", info[3]->ToObject());

AsyncLibgit2QueueWorker(worker);
return;
}

void GitWorktree::AddWorker::Execute() {
git_error_clear();

{
LockMaster lockMaster(
/*asyncAction: */true
,baton->repo
,baton->name
,baton->path
,baton->opts
);

int result = git_worktree_add(
&baton->out,baton->repo,baton->name,baton->path,baton->opts );

baton->error_code = result;

if (result != GIT_OK && git_error_last() != NULL) {
baton->error = git_error_dup(git_error_last());
}

}
}

void GitWorktree::AddWorker::HandleOKCallback() {
if (baton->error_code == GIT_OK) {
v8::Local<v8::Value> to;
// start convert_to_v8 block
if (baton->out != NULL) {
v8::Local<v8::Array> owners = Nan::New<Array>(0);
Nan::Set(owners, Nan::New<v8::Number>(owners->Length()), this->GetFromPersistent("repo")->ToObject());
to = GitWorktree::New(
baton->out,
true
, owners
);
}
else {
to = Nan::Null();
}
// end convert_to_v8 block
v8::Local<v8::Value> result = to;

v8::Local<v8::Value> argv[2] = {
Nan::Null(),
result
};
callback->Call(2, argv, async_resource);
} else {
if (baton->error) {
v8::Local<v8::Object> err;
if (baton->error->message) {
err = Nan::Error(baton->error->message)->ToObject();
} else {
err = Nan::Error("Method add has thrown an error.")->ToObject();
}
err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code));
err->Set(Nan::New("errorFunction").ToLocalChecked(), Nan::New("Worktree.add").ToLocalChecked());
v8::Local<v8::Value> argv[1] = {
err
};
callback->Call(1, argv, async_resource);
if (baton->error->message)
free((void *)baton->error->message);
free((void *)baton->error);
} else if (baton->error_code < 0) {
std::queue< v8::Local<v8::Value> > workerArguments;
workerArguments.push(GetFromPersistent("repo"));
workerArguments.push(GetFromPersistent("name"));
workerArguments.push(GetFromPersistent("path"));
workerArguments.push(GetFromPersistent("opts"));
bool callbackFired = false;
while(!workerArguments.empty()) {
v8::Local<v8::Value> 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<v8::Object> nodeObj = node->ToObject();
v8::Local<v8::Value> checkValue = GetPrivate(nodeObj, Nan::New("NodeGitPromiseError").ToLocalChecked());

if (!checkValue.IsEmpty() && !checkValue->IsNull() && !checkValue->IsUndefined()) {
v8::Local<v8::Value> argv[1] = {
checkValue->ToObject()
};
callback->Call(1, argv, async_resource);
callbackFired = true;
break;
}

v8::Local<v8::Array> properties = nodeObj->GetPropertyNames();
for (unsigned int propIndex = 0; propIndex < properties->Length(); ++propIndex) {
v8::Local<v8::String> propName = properties->Get(propIndex)->ToString();
v8::Local<v8::Value> nodeToQueue = nodeObj->Get(propName);
if (!nodeToQueue->IsUndefined()) {
workerArguments.push(nodeToQueue);
}
}
}

if (!callbackFired) {
v8::Local<v8::Object> err = Nan::Error("Method add has thrown an error.")->ToObject();
err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code));
err->Set(Nan::New("errorFunction").ToLocalChecked(), Nan::New("Worktree.add").ToLocalChecked());
v8::Local<v8::Value> argv[1] = {
err
};
callback->Call(1, argv, async_resource);
}
} else {
callback->Call(0, NULL, async_resource);
}

}


delete baton;
}
1 change: 0 additions & 1 deletion lib/utils/binary_info.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ function binary_info(platform, arch) {
var package_json = JSON.parse(
fs.readFileSync(path.resolve(__dirname,"../../package.json"), "utf8"));
var options = {
platform,
target_platform: platform,
target_arch: arch
};
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@elastic/nodegit",
"description": "Node.js libgit2 asynchronous native bindings",
"version": "0.25.0-alpha.13",
"version": "0.25.0-alpha.14",
"homepage": "http://github.com/elastic/nodegit",
"keywords": [
"libgit2",
Expand Down
47 changes: 47 additions & 0 deletions test/tests/worktree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
var path = require("path");
var assert = require("assert");
var local = path.join.bind(path, __dirname);

describe("Worktree", function() {
var NodeGit = require("../../");
var Repository = NodeGit.Repository;
var Worktree = NodeGit.Worktree;
var Clone = NodeGit.Clone;

var clonePath = local("../repos/clone");
var worktreePath = local("../repos/worktree");

// Set a reasonable timeout here now that our repository has grown.
this.timeout(30000);

before(function() {
var test = this;
var url = "https://github.com/nodegit/test.git";
var opts = {
fetchOpts: {
callbacks: {
certificateCheck: () => 0
}
}
};

return Clone(url, clonePath, opts).then(function(repo) {
assert.ok(repo instanceof Repository);
test.repository = repo;
});
});

it("can create worktree", function() {
return Worktree.add(this.repository, "workspace", worktreePath, {})
.then(function(wt) {
assert.ok(wt instanceof Worktree);
});
});

it("can open a worktree repository", function() {
return Repository.open(worktreePath).then(function(repo) {
assert.ok(repo instanceof Repository);
assert.ok(repo.isWorktree());
});
});
});