Skip to content

Commit 4b11a46

Browse files
Merge pull request nodegit#1919 from julianmesa-gitkraken/tree-get-all-filepaths
Add getAllFilepaths function in tree object
2 parents 36c0e3f + e746e62 commit 4b11a46

File tree

3 files changed

+198
-0
lines changed

3 files changed

+198
-0
lines changed

generate/input/libgit2-supplement.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,32 @@
10131013
"type": "int"
10141014
},
10151015
"group": "status_list"
1016+
},
1017+
"git_tree_get_all_filepaths": {
1018+
"args": [
1019+
{
1020+
"name": "tree",
1021+
"type": "git_tree *"
1022+
},
1023+
{
1024+
"name": "repo",
1025+
"type": "git_repository *"
1026+
},
1027+
{
1028+
"name": "out",
1029+
"type": "std::vector<std::string> *"
1030+
}
1031+
],
1032+
"type": "function",
1033+
"isManual": true,
1034+
"cFile": "generate/templates/manual/tree/get_all_filepaths.cc",
1035+
"isAsync": true,
1036+
"isPrototypeMethod": true,
1037+
"group": "tree",
1038+
"return": {
1039+
"type": "int",
1040+
"isErrorCode": true
1041+
}
10161042
}
10171043
},
10181044
"groups": [
@@ -1223,6 +1249,12 @@
12231249
"git_status_list_new"
12241250
]
12251251
],
1252+
[
1253+
"tree",
1254+
[
1255+
"git_tree_get_all_filepaths"
1256+
]
1257+
],
12261258
[
12271259
"tree_entry",
12281260
[
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
2+
namespace TreeFilepathsHelpers {
3+
4+
int iterateTreePaths(git_repository *repo, git_tree *tree, std::vector<std::string> *paths,std::string *buffer) {
5+
size_t size = git_tree_entrycount(tree);
6+
for (size_t i = 0; i < size; i++) {
7+
const git_tree_entry *entry = git_tree_entry_byindex(tree, i);
8+
const git_filemode_t filemode = git_tree_entry_filemode(entry);
9+
if (filemode == GIT_FILEMODE_BLOB || filemode == GIT_FILEMODE_BLOB_EXECUTABLE) {
10+
paths->push_back(*buffer + std::string(git_tree_entry_name(entry)));
11+
}
12+
else if (filemode == GIT_FILEMODE_TREE) {
13+
git_tree *subtree;
14+
int error = git_tree_lookup(&subtree, repo, git_tree_entry_id(entry));
15+
if (error == GIT_OK) {
16+
size_t size = buffer->size();
17+
/* append the next entry to the path */
18+
buffer->append(git_tree_entry_name(entry));
19+
buffer->append("/");
20+
error = iterateTreePaths(repo, subtree, paths, buffer);
21+
git_tree_free(subtree);
22+
buffer->resize(size);
23+
}
24+
25+
if (error < 0 ) {
26+
return error;
27+
}
28+
29+
}
30+
}
31+
return GIT_OK;
32+
}
33+
34+
} // end anonymous namespace
35+
36+
NAN_METHOD(GitTree::GetAllFilepaths)
37+
{
38+
if (!info[info.Length() - 1]->IsFunction()) {
39+
return Nan::ThrowError("Callback is required and must be a Function.");
40+
}
41+
42+
GetAllFilepathsBaton* baton = new GetAllFilepathsBaton();
43+
44+
baton->error_code = GIT_OK;
45+
baton->error = NULL;
46+
baton->tree = Nan::ObjectWrap::Unwrap<GitTree>(info.This())->GetValue();
47+
baton->out = new std::vector<std::string>;
48+
baton->repo = git_tree_owner(baton->tree);
49+
50+
Nan::Callback *callback = new Nan::Callback(Local<Function>::Cast(info[info.Length() - 1]));
51+
std::map<std::string, std::shared_ptr<nodegit::CleanupHandle>> cleanupHandles;
52+
GetAllFilepathsWorker *worker = new GetAllFilepathsWorker(baton, callback, cleanupHandles);
53+
worker->Reference<GitTree>("tree", info.This());
54+
nodegit::Context *nodegitContext = reinterpret_cast<nodegit::Context *>(info.Data().As<External>()->Value());
55+
nodegitContext->QueueWorker(worker);
56+
57+
return;
58+
}
59+
60+
nodegit::LockMaster GitTree::GetAllFilepathsWorker::AcquireLocks() {
61+
nodegit::LockMaster lockMaster(true, baton->tree, baton->repo);
62+
return lockMaster;
63+
}
64+
65+
void GitTree::GetAllFilepathsWorker::Execute()
66+
{
67+
std::string buffer;
68+
buffer.reserve(4096);
69+
baton->error_code = TreeFilepathsHelpers::iterateTreePaths(baton->repo, baton->tree, baton->out, &buffer);
70+
if (baton->error_code != GIT_OK && git_error_last() != NULL) {
71+
baton->error = git_error_dup(git_error_last());
72+
}
73+
}
74+
75+
void GitTree::GetAllFilepathsWorker::HandleErrorCallback() {
76+
if (baton->error) {
77+
if (baton->error->message) {
78+
free((void *)baton->error->message);
79+
}
80+
81+
free((void *)baton->error);
82+
}
83+
84+
delete baton->out;
85+
86+
delete baton;
87+
}
88+
89+
void GitTree::GetAllFilepathsWorker::HandleOKCallback()
90+
{
91+
if (baton->error_code == GIT_OK) {
92+
std::vector<std::string> &paths = *(baton->out);
93+
v8::Local<v8::Array> result = Nan::New<v8::Array>(paths.size());
94+
for (unsigned int i = 0; i < paths.size(); i++) {
95+
Nan::Set(result, i, Nan::New<v8::String>(paths[i]).ToLocalChecked());
96+
}
97+
98+
v8::Local<v8::Value> argv[2] = {Nan::Null(), result};
99+
callback->Call(2, argv, async_resource);
100+
}
101+
else
102+
{
103+
if (baton->error)
104+
{
105+
Local<v8::Object> err;
106+
if (baton->error->message) {
107+
err = Nan::To<v8::Object>(Nan::Error(baton->error->message)).ToLocalChecked();
108+
} else {
109+
err = Nan::To<v8::Object>(Nan::Error("Method getAllFilepaths has thrown an error.")).ToLocalChecked();
110+
}
111+
Nan::Set(err, Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code));
112+
Nan::Set(err, Nan::New("errorFunction").ToLocalChecked(), Nan::New("Tree.getAllFilepaths").ToLocalChecked());
113+
Local<v8::Value> argv[1] = {
114+
err
115+
};
116+
callback->Call(1, argv, async_resource);
117+
if (baton->error->message)
118+
{
119+
free((void *)baton->error->message);
120+
}
121+
122+
free((void *)baton->error);
123+
}
124+
else if (baton->error_code < 0)
125+
{
126+
bool callbackFired = false;
127+
if (!callbackErrorHandle.IsEmpty()) {
128+
v8::Local<v8::Value> maybeError = Nan::New(callbackErrorHandle);
129+
if (!maybeError->IsNull() && !maybeError->IsUndefined()) {
130+
v8::Local<v8::Value> argv[1] = {
131+
maybeError
132+
};
133+
callback->Call(1, argv, async_resource);
134+
callbackFired = true;
135+
}
136+
}
137+
138+
if (!callbackFired)
139+
{
140+
Local<v8::Object> err = Nan::To<v8::Object>(Nan::Error("Method getAllFilepaths has thrown an error.")).ToLocalChecked();
141+
Nan::Set(err, Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code));
142+
Nan::Set(err, Nan::New("errorFunction").ToLocalChecked(), Nan::New("Revwalk.getAllFilepaths").ToLocalChecked());
143+
Local<v8::Value> argv[1] = {
144+
err
145+
};
146+
callback->Call(1, argv, async_resource);
147+
}
148+
}
149+
else
150+
{
151+
callback->Call(0, NULL, async_resource);
152+
}
153+
}
154+
155+
delete baton->out;
156+
delete baton;
157+
}

test/tests/tree.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,13 @@ describe("Tree", function() {
112112
);
113113
});
114114
});
115+
116+
it("get all paths from a tree", async function () {
117+
const tree = await this.commit.getTree();
118+
const paths = await tree.getAllFilepaths();
119+
assert.equal(paths.length, 512);
120+
assert.equal(paths[0], ".gitignore");
121+
assert.equal(paths[511], "wscript");
122+
});
123+
115124
});

0 commit comments

Comments
 (0)