Skip to content

Commit a2388e3

Browse files
committed
git_filter_list has a complex owner scenario and requires adjustments
I know we will need this in the future for merge drivers and the like. But for now, this will at least show how it could be done.
1 parent 2e5451f commit a2388e3

2 files changed

Lines changed: 240 additions & 0 deletions

File tree

generate/input/libgit2-supplement.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@
144144
"isErrorCode": true
145145
}
146146
},
147+
"git_filter_list_load": {
148+
"isManual": true,
149+
"cFile": "generate/templates/manual/filter_list/load.cc",
150+
"isAsync": true,
151+
"isPrototypeMethod": false,
152+
"group": "filter_list"
153+
},
147154
"git_patch_convenient_from_diff": {
148155
"args": [
149156
{
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
/*
2+
* @param Repository repo
3+
* @param Blob blob
4+
* @param String path
5+
* @param Number mode
6+
* @param Number flags
7+
* @param FilterList callback
8+
*/
9+
NAN_METHOD(GitFilterList::Load) {
10+
if (info.Length() == 0 || !info[0]->IsObject()) {
11+
return Nan::ThrowError("Repository repo is required.");
12+
}
13+
14+
if (info.Length() == 2 || !info[2]->IsString()) {
15+
return Nan::ThrowError("String path is required.");
16+
}
17+
18+
if (info.Length() == 3 || !info[3]->IsNumber()) {
19+
return Nan::ThrowError("Number mode is required.");
20+
}
21+
22+
if (info.Length() == 4 || !info[4]->IsNumber()) {
23+
return Nan::ThrowError("Number flags is required.");
24+
}
25+
26+
if (info.Length() == 5 || !info[5]->IsFunction()) {
27+
return Nan::ThrowError("Callback is required and must be a Function.");
28+
}
29+
30+
LoadBaton *baton = new LoadBaton;
31+
32+
baton->error_code = GIT_OK;
33+
baton->error = NULL;
34+
35+
// start convert_from_v8 block
36+
git_repository *from_repo = NULL;
37+
from_repo =
38+
Nan::ObjectWrap::Unwrap<GitRepository>(info[0]->ToObject())->GetValue();
39+
// end convert_from_v8 block
40+
baton->repo = from_repo;
41+
// start convert_from_v8 block
42+
git_blob *from_blob = NULL;
43+
if (info[1]->IsObject()) {
44+
from_blob =
45+
Nan::ObjectWrap::Unwrap<GitBlob>(info[1]->ToObject())->GetValue();
46+
} else {
47+
from_blob = 0;
48+
}
49+
// end convert_from_v8 block
50+
baton->blob = from_blob;
51+
// start convert_from_v8 block
52+
const char *from_path = NULL;
53+
54+
String::Utf8Value path(info[2]->ToString());
55+
// malloc with one extra byte so we can add the terminating null character
56+
// C-strings expect:
57+
from_path = (const char *)malloc(path.length() + 1);
58+
// copy the characters from the nodejs string into our C-string (used instead
59+
// of strdup or strcpy because nulls in the middle of strings are valid coming
60+
// from nodejs):
61+
memcpy((void *)from_path, *path, path.length());
62+
// ensure the final byte of our new string is null, extra casts added to
63+
// ensure compatibility with various C types used in the nodejs binding
64+
// generation:
65+
memset((void *)(((char *)from_path) + path.length()), 0, 1);
66+
// end convert_from_v8 block
67+
baton->path = from_path;
68+
// start convert_from_v8 block
69+
git_filter_mode_t from_mode;
70+
from_mode = (git_filter_mode_t)(int)info[3].As<v8::Number>()->Value();
71+
// end convert_from_v8 block
72+
baton->mode = from_mode;
73+
// start convert_from_v8 block
74+
uint32_t from_flags;
75+
from_flags = (uint32_t)info[4].As<v8::Number>()->Value();
76+
// end convert_from_v8 block
77+
baton->flags = from_flags;
78+
79+
Nan::Callback *callback =
80+
new Nan::Callback(v8::Local<Function>::Cast(info[5]));
81+
LoadWorker *worker = new LoadWorker(baton, callback);
82+
83+
if (!info[0]->IsUndefined() && !info[0]->IsNull())
84+
worker->SaveToPersistent("repo", info[0]->ToObject());
85+
if (!info[1]->IsUndefined() && !info[1]->IsNull())
86+
worker->SaveToPersistent("blob", info[1]->ToObject());
87+
if (!info[2]->IsUndefined() && !info[2]->IsNull())
88+
worker->SaveToPersistent("path", info[2]->ToObject());
89+
if (!info[3]->IsUndefined() && !info[3]->IsNull())
90+
worker->SaveToPersistent("mode", info[3]->ToObject());
91+
if (!info[4]->IsUndefined() && !info[4]->IsNull())
92+
worker->SaveToPersistent("flags", info[4]->ToObject());
93+
94+
AsyncLibgit2QueueWorker(worker);
95+
return;
96+
}
97+
98+
void GitFilterList::LoadWorker::Execute() {
99+
giterr_clear();
100+
101+
{
102+
LockMaster lockMaster(
103+
/*asyncAction: */ true, baton->repo, baton->blob, baton->path);
104+
105+
int result = git_filter_list_load(&baton->filters, baton->repo, baton->blob,
106+
baton->path, baton->mode, baton->flags);
107+
108+
baton->error_code = result;
109+
110+
if (result != GIT_OK && giterr_last() != NULL) {
111+
baton->error = git_error_dup(giterr_last());
112+
}
113+
}
114+
}
115+
116+
void GitFilterList::LoadWorker::HandleOKCallback() {
117+
if (baton->error_code == GIT_OK) {
118+
v8::Local<v8::Value> to;
119+
// start convert_to_v8 block
120+
121+
if (baton->filters != NULL) {
122+
// GitFilterList baton->filters
123+
v8::Local<v8::Array> owners = Nan::New<Array>(0);
124+
v8::Local<v8::Object> filterRegistry = Nan::New(GitFilterRegistry::persistentHandle);
125+
v8::Local<v8::Array> propertyNames = filterRegistry->GetPropertyNames();
126+
127+
Nan::Set(
128+
owners,
129+
Nan::New<Number>(0),
130+
this->GetFromPersistent("repo")->ToObject()
131+
);
132+
133+
for (uint32_t index = 0; index < propertyNames->Length(); ++index) {
134+
v8::Local<v8::String> propertyName = propertyNames->Get(index)->ToString();
135+
String::Utf8Value propertyNameAsUtf8Value(propertyName);
136+
const char *propertyNameAsCString = *propertyNameAsUtf8Value;
137+
138+
bool isNotMethodOnRegistry = strcmp("register", propertyNameAsCString)
139+
&& strcmp("unregister", propertyNameAsCString);
140+
if (isNotMethodOnRegistry && git_filter_list_contains(baton->filters, propertyNameAsCString)) {
141+
Nan::Set(
142+
owners,
143+
Nan::New<Number>(owners->Length()),
144+
filterRegistry->Get(propertyName)
145+
);
146+
}
147+
}
148+
149+
to = GitFilterList::New(baton->filters, true, owners->ToObject());
150+
} else {
151+
to = Nan::Null();
152+
}
153+
154+
// end convert_to_v8 block
155+
v8::Local<v8::Value> result = to;
156+
157+
v8::Local<v8::Value> argv[2] = {Nan::Null(), result};
158+
callback->Call(2, argv, async_resource);
159+
} else {
160+
if (baton->error) {
161+
v8::Local<v8::Object> err;
162+
if (baton->error->message) {
163+
err = Nan::Error(baton->error->message)->ToObject();
164+
} else {
165+
err = Nan::Error("Method load has thrown an error.")->ToObject();
166+
}
167+
err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code));
168+
err->Set(Nan::New("errorFunction").ToLocalChecked(),
169+
Nan::New("FilterList.load").ToLocalChecked());
170+
v8::Local<v8::Value> argv[1] = {err};
171+
callback->Call(1, argv, async_resource);
172+
if (baton->error->message)
173+
free((void *)baton->error->message);
174+
free((void *)baton->error);
175+
} else if (baton->error_code < 0) {
176+
std::queue<v8::Local<v8::Value>> workerArguments;
177+
workerArguments.push(GetFromPersistent("repo"));
178+
workerArguments.push(GetFromPersistent("blob"));
179+
workerArguments.push(GetFromPersistent("path"));
180+
workerArguments.push(GetFromPersistent("mode"));
181+
workerArguments.push(GetFromPersistent("flags"));
182+
bool callbackFired = false;
183+
while (!workerArguments.empty()) {
184+
v8::Local<v8::Value> node = workerArguments.front();
185+
workerArguments.pop();
186+
187+
if (!node->IsObject() || node->IsArray() || node->IsBooleanObject() ||
188+
node->IsDate() || node->IsFunction() || node->IsNumberObject() ||
189+
node->IsRegExp() || node->IsStringObject()) {
190+
continue;
191+
}
192+
193+
v8::Local<v8::Object> nodeObj = node->ToObject();
194+
v8::Local<v8::Value> checkValue = GetPrivate(
195+
nodeObj, Nan::New("NodeGitPromiseError").ToLocalChecked());
196+
197+
if (!checkValue.IsEmpty() && !checkValue->IsNull() &&
198+
!checkValue->IsUndefined()) {
199+
v8::Local<v8::Value> argv[1] = {checkValue->ToObject()};
200+
callback->Call(1, argv, async_resource);
201+
callbackFired = true;
202+
break;
203+
}
204+
205+
v8::Local<v8::Array> properties = nodeObj->GetPropertyNames();
206+
for (unsigned int propIndex = 0; propIndex < properties->Length();
207+
++propIndex) {
208+
v8::Local<v8::String> propName =
209+
properties->Get(propIndex)->ToString();
210+
v8::Local<v8::Value> nodeToQueue = nodeObj->Get(propName);
211+
if (!nodeToQueue->IsUndefined()) {
212+
workerArguments.push(nodeToQueue);
213+
}
214+
}
215+
}
216+
217+
if (!callbackFired) {
218+
v8::Local<v8::Object> err =
219+
Nan::Error("Method load has thrown an error.")->ToObject();
220+
err->Set(Nan::New("errno").ToLocalChecked(),
221+
Nan::New(baton->error_code));
222+
err->Set(Nan::New("errorFunction").ToLocalChecked(),
223+
Nan::New("FilterList.load").ToLocalChecked());
224+
v8::Local<v8::Value> argv[1] = {err};
225+
callback->Call(1, argv, async_resource);
226+
}
227+
} else {
228+
callback->Call(0, NULL, async_resource);
229+
}
230+
}
231+
232+
delete baton;
233+
}

0 commit comments

Comments
 (0)