From 504ba139c192f81058fe5797fc5f487149817368 Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Tue, 26 Jul 2016 14:17:50 -0700 Subject: [PATCH 01/41] Generate script: Don't write .cc or .h files if unchanged The generation script now checks whether the file has changed before writing it to `/src` or `/include`. This is to improve compilation time when testing changes to generated code. It works by creating a `/temp` directory, writing the generated code to `/temp/src` and `/temp/include`, then syncing those folders with `/src` and `/include` by deleting files that no longer exist and copying files that have changed or been added since the last code generation. Finally the `/temp` directory is deleted If `/src` and `/include` don't exist (i.e. it's the first time the generation script has been run), `/temp/src` will be copied to `/src` and `/temp/include` will be copied to `/include`. --- .gitignore | 1 + generate/scripts/generateMissingTests.js | 2 +- generate/scripts/generateNativeCode.js | 71 +++++++++++--------- generate/scripts/utils.js | 84 +++++++++++++++++++++++- package.json | 3 +- 5 files changed, 127 insertions(+), 34 deletions(-) diff --git a/.gitignore b/.gitignore index 5529ab114..82837852e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ /lib/nodegit.js /node_modules/ /src/ +/temp/ /test/coverage/ /test/home/ /test/repos/ diff --git a/generate/scripts/generateMissingTests.js b/generate/scripts/generateMissingTests.js index 4aef70f4d..bfd93aec0 100644 --- a/generate/scripts/generateMissingTests.js +++ b/generate/scripts/generateMissingTests.js @@ -12,7 +12,7 @@ module.exports = function generateMissingTests() { var testFilePath = path.join(testFilesPath, idef.filename + ".js"); var result = {}; - var file = utils.readFile(testFilePath); + var file = utils.readLocalFile(testFilePath); if (file) { var fieldsResult = []; var functionsResult = []; diff --git a/generate/scripts/generateNativeCode.js b/generate/scripts/generateNativeCode.js index 56d52672c..9088fb72e 100644 --- a/generate/scripts/generateNativeCode.js +++ b/generate/scripts/generateNativeCode.js @@ -24,27 +24,27 @@ module.exports = function generateNativeCode() { }; var partials = { - asyncFunction: utils.readFile("templates/partials/async_function.cc"), - callbackHelpers: utils.readFile("templates/partials/callback_helpers.cc"), - convertFromV8: utils.readFile("templates/partials/convert_from_v8.cc"), - convertToV8: utils.readFile("templates/partials/convert_to_v8.cc"), - doc: utils.readFile("templates/partials/doc.cc"), - fields: utils.readFile("templates/partials/fields.cc"), - guardArguments: utils.readFile("templates/partials/guard_arguments.cc"), - syncFunction: utils.readFile("templates/partials/sync_function.cc"), - fieldAccessors: utils.readFile("templates/partials/field_accessors.cc"), - traits: utils.readFile("templates/partials/traits.h") + asyncFunction: utils.readLocalFile("templates/partials/async_function.cc"), + callbackHelpers: utils.readLocalFile("templates/partials/callback_helpers.cc"), + convertFromV8: utils.readLocalFile("templates/partials/convert_from_v8.cc"), + convertToV8: utils.readLocalFile("templates/partials/convert_to_v8.cc"), + doc: utils.readLocalFile("templates/partials/doc.cc"), + fields: utils.readLocalFile("templates/partials/fields.cc"), + guardArguments: utils.readLocalFile("templates/partials/guard_arguments.cc"), + syncFunction: utils.readLocalFile("templates/partials/sync_function.cc"), + fieldAccessors: utils.readLocalFile("templates/partials/field_accessors.cc"), + traits: utils.readLocalFile("templates/partials/traits.h") }; var templates = { - class_content: utils.readFile("templates/templates/class_content.cc"), - struct_content: utils.readFile("templates/templates/struct_content.cc"), - class_header: utils.readFile("templates/templates/class_header.h"), - struct_header: utils.readFile("templates/templates/struct_header.h"), - binding: utils.readFile("templates/templates/binding.gyp"), - nodegitCC: utils.readFile("templates/templates/nodegit.cc"), - nodegitJS: utils.readFile("templates/templates/nodegit.js"), - enums: utils.readFile("templates/templates/enums.js") + class_content: utils.readLocalFile("templates/templates/class_content.cc"), + struct_content: utils.readLocalFile("templates/templates/struct_content.cc"), + class_header: utils.readLocalFile("templates/templates/class_header.h"), + struct_header: utils.readLocalFile("templates/templates/struct_header.h"), + binding: utils.readLocalFile("templates/templates/binding.gyp"), + nodegitCC: utils.readLocalFile("templates/templates/nodegit.cc"), + nodegitJS: utils.readLocalFile("templates/templates/nodegit.js"), + enums: utils.readLocalFile("templates/templates/enums.js") }; var filters = { @@ -99,28 +99,32 @@ module.exports = function generateNativeCode() { return !idef.ignore; }); + const tempDirPath = path.resolve(__dirname, "../../temp"); + const tempSrcDirPath = path.join(tempDirPath, "src"); + const tempIncludeDirPath = path.join(tempDirPath, "include"); - fse.remove(path.resolve(__dirname, "../../src")).then(function() { - return fse.remove(path.resolve(__dirname, "../../include")); - }).then(function() { - return fse.copy(path.resolve(__dirname, "../templates/manual/include"), path.resolve(__dirname, "../../include")); + const finalSrcDirPath = path.join(__dirname, '../../src'); + const finalIncludeDirPath = path.join(__dirname, '../../include'); + + fse.remove(tempDirPath).then(function() { + return fse.copy(path.resolve(__dirname, "../templates/manual/include"), tempIncludeDirPath); }).then(function() { - return fse.copy(path.resolve(__dirname, "../templates/manual/src"), path.resolve(__dirname, "../../src")); + return fse.copy(path.resolve(__dirname, "../templates/manual/src"), tempSrcDirPath); }).then(function() { // Write out single purpose templates. utils.writeFile("../binding.gyp", beautify(templates.binding.render(enabled)), "binding.gyp"); - utils.writeFile("../src/nodegit.cc", templates.nodegitCC.render(enabled), "nodegit.cc"); + utils.writeFile("../temp/src/nodegit.cc", templates.nodegitCC.render(enabled), "nodegit.cc"); utils.writeFile("../lib/nodegit.js", beautify(templates.nodegitJS.render(enabled)), "nodegit.js"); // Write out all the classes. enabled.forEach(function(idef) { if (idef.type && idef.type != "enum") { utils.writeFile( - "../src/" + idef.filename + ".cc", + "../temp/src/" + idef.filename + ".cc", templates[idef.type + "_content"].render(idef), idef.type + "_content.cc" ); utils.writeFile( - "../include/" + idef.filename + ".h", + "../temp/include/" + idef.filename + ".h", templates[idef.type + "_header"].render(idef), idef.type + "_header.h" ); @@ -133,17 +137,24 @@ module.exports = function generateNativeCode() { if (astyle) { return exec( "astyle --options=\".astylerc\" " - + path.resolve(__dirname, "../../src") + "/*.cc " - + path.resolve(__dirname, "../../include") + "/*.h" + + tempSrcDirPath + "/*.cc " + + tempIncludeDirPath + "/*.h" ).then(function() { return exec( "rm " - + path.resolve(__dirname, "../../src") + "/*.cc.orig " - + path.resolve(__dirname, "../../include") + "/*.h.orig " + + tempSrcDirPath + "/*.cc.orig " + + tempIncludeDirPath + "/*.h.orig " ); }); } }, function() {}) + }).then(function() { + return Promise.all([ + utils.syncDirs(tempSrcDirPath, finalSrcDirPath), + utils.syncDirs(tempIncludeDirPath, finalIncludeDirPath), + ]); + }).then(function() { + return fse.remove(tempDirPath); }).catch(console.log); }; diff --git a/generate/scripts/utils.js b/generate/scripts/utils.js index 6868bf653..ef92f1815 100644 --- a/generate/scripts/utils.js +++ b/generate/scripts/utils.js @@ -1,4 +1,5 @@ const fse = require("fs-extra"); +const walk = require("walk"); const fs = require("fs"); const path = require("path"); @@ -10,7 +11,7 @@ var util = { pointerRegex: /\s*\*\s*/, doublePointerRegex: /\s*\*\*\s*/, - readFile: function(file) { + readLocalFile: function(file) { try { return fs.readFileSync(local(file)).toString(); } @@ -19,6 +20,15 @@ var util = { } }, + readFile: function(filePath) { + try { + return fs.readFileSync(filePath).toString(); + } + catch (unhandledException) { + return ""; + } + }, + writeFile: function(file, content, header) { try { var file = local(file); @@ -62,14 +72,84 @@ var util = { }).join(""); }, + getFilePathsRelativeToDir: function(dir) { + const files = []; + const walker = walk.walk(dir, { followLinks: false }); + if (!util.isDirectory(dir)) { + return Promise.resolve([]); + } + + return new Promise(function(resolve, reject) { + walker.on('file', function(root, stat, next) { + files.push(path.relative(dir, path.join(root, stat.name))); + next(); + }); + + walker.on('end', function() { + resolve(files); + }); + + walker.on('errors', function() { + reject(); + }); + }); + }, + + isFile: function(path) { + var isFile; + try { + isFile = fse.statSync(path).isFile(); + } catch(e) { + isFile = false; + } + + return isFile; + }, + + isDirectory: function(path) { + var isDirectory; + try { + isDirectory = fse.statSync(path).isDirectory(); + } catch(e) { + isDirectory = false; + } + + return isDirectory; + }, + isPointer: function(type) { return util.pointerRegex.test(type) || util.doublePointerRegex.test(type); }, isDoublePointer: function(type) { return util.doublePointerRegex.test(type); - } + }, + syncDirs: function(fromDir, toDir) { + return Promise.all([ + util.getFilePathsRelativeToDir(toDir), + util.getFilePathsRelativeToDir(fromDir) + ]).then(function(filePaths) { + const toFilePaths = filePaths[0]; + const fromFilePaths = filePaths[1]; + + // Delete files that aren't in fromDir + toFilePaths.forEach(function(filePath) { + if (!util.isFile(path.join(fromDir, filePath))) { + fse.remove(path.join(toDir, filePath)); + } + }); + + // Copy files that don't exist in toDir or have different contents + fromFilePaths.forEach(function(filePath) { + const toFilePath = path.join(toDir, filePath); + const fromFilePath = path.join(fromDir, filePath); + if (!util.isFile(toFilePath) || util.readFile(toFilePath) !== util.readFile(fromFilePath)) { + fse.copy(fromFilePath, toFilePath); + } + }); + }); + } }; module.exports = util; diff --git a/package.json b/package.json index 99a566a81..c8e06853a 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,8 @@ "js-beautify": "~1.5.10", "jshint": "~2.8.0", "lcov-result-merger": "~1.0.2", - "mocha": "~2.3.4" + "mocha": "~2.3.4", + "walk": "^2.3.9" }, "vendorDependencies": { "libssh2": "1.7.0", From 880d2d1765644cb73be9b455c8c1c52a2ca5c67a Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Sat, 12 Nov 2016 15:50:04 -0700 Subject: [PATCH 02/41] Generate script: write temp generated files to OS specific temp dir --- .gitignore | 1 - generate/scripts/generateJson.js | 3 +-- generate/scripts/generateMissingTests.js | 2 +- generate/scripts/generateNativeCode.js | 10 ++++++---- generate/scripts/utils.js | 7 +++---- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 82837852e..5529ab114 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ /lib/nodegit.js /node_modules/ /src/ -/temp/ /test/coverage/ /test/home/ /test/repos/ diff --git a/generate/scripts/generateJson.js b/generate/scripts/generateJson.js index f1afeb956..09bc901a1 100644 --- a/generate/scripts/generateJson.js +++ b/generate/scripts/generateJson.js @@ -231,8 +231,7 @@ module.exports = function generateJson() { } - utils.writeFile("output/idefs.json", output); - + utils.writeFile(path.join(__dirname, "..", "output", "idefs.json"), output); }; if (require.main === module) { diff --git a/generate/scripts/generateMissingTests.js b/generate/scripts/generateMissingTests.js index bfd93aec0..669f6929c 100644 --- a/generate/scripts/generateMissingTests.js +++ b/generate/scripts/generateMissingTests.js @@ -58,7 +58,7 @@ module.exports = function generateMissingTests() { Promise.all(promises).then( function() { - utils.writeFile("output/missing-tests.json", output); + utils.writeFile(path.join(__dirname, "..", "/output/missing-tests.json"), output); }, function(fail) { console.error(fail); diff --git a/generate/scripts/generateNativeCode.js b/generate/scripts/generateNativeCode.js index 9088fb72e..3cd19c93b 100644 --- a/generate/scripts/generateNativeCode.js +++ b/generate/scripts/generateNativeCode.js @@ -1,6 +1,7 @@ const path = require("path"); const promisify = require("promisify-node"); const fse = promisify(require("fs-extra")); +const os = require('os'); const exec = require('../../utils/execPromise'); const utils = require("./utils"); @@ -99,7 +100,7 @@ module.exports = function generateNativeCode() { return !idef.ignore; }); - const tempDirPath = path.resolve(__dirname, "../../temp"); + const tempDirPath = path.join(os.tmpdir(), 'nodegit_build'); const tempSrcDirPath = path.join(tempDirPath, "src"); const tempIncludeDirPath = path.join(tempDirPath, "include"); @@ -113,18 +114,19 @@ module.exports = function generateNativeCode() { }).then(function() { // Write out single purpose templates. utils.writeFile("../binding.gyp", beautify(templates.binding.render(enabled)), "binding.gyp"); - utils.writeFile("../temp/src/nodegit.cc", templates.nodegitCC.render(enabled), "nodegit.cc"); + utils.writeFile(path.join(tempSrcDirPath, "nodegit.cc"), templates.nodegitCC.render(enabled), "nodegit.cc"); utils.writeFile("../lib/nodegit.js", beautify(templates.nodegitJS.render(enabled)), "nodegit.js"); // Write out all the classes. enabled.forEach(function(idef) { if (idef.type && idef.type != "enum") { utils.writeFile( - "../temp/src/" + idef.filename + ".cc", + path.format({dir: tempSrcDirPath, name: idef.filename, ext: ".cc"}), templates[idef.type + "_content"].render(idef), idef.type + "_content.cc" ); + utils.writeFile( - "../temp/include/" + idef.filename + ".h", + path.format({dir: tempIncludeDirPath, name: idef.filename, ext: ".h"}), templates[idef.type + "_header"].render(idef), idef.type + "_header.h" ); diff --git a/generate/scripts/utils.js b/generate/scripts/utils.js index ef92f1815..df4130bf9 100644 --- a/generate/scripts/utils.js +++ b/generate/scripts/utils.js @@ -29,9 +29,8 @@ var util = { } }, - writeFile: function(file, content, header) { + writeFile: function(filePath, content, header) { try { - var file = local(file); if (typeof content == "object") { content = JSON.stringify(content, null, 2) } @@ -45,8 +44,8 @@ var util = { content; } - fse.ensureFileSync(file); - fse.writeFileSync(file, content); + fse.ensureFileSync(filePath); + fse.writeFileSync(filePath, content); return true; } catch (exception) { From 272c37b800c78dda01889e5495cbe644b3b907f8 Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Sat, 12 Nov 2016 16:32:10 -0700 Subject: [PATCH 03/41] Generate utils: separated writeFile into writeFile and writeLocalFile --- generate/scripts/generateJson.js | 2 +- generate/scripts/generateMissingTests.js | 2 +- generate/scripts/generateNativeCode.js | 6 +++--- generate/scripts/utils.js | 13 ++++++------- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/generate/scripts/generateJson.js b/generate/scripts/generateJson.js index 09bc901a1..323247e13 100644 --- a/generate/scripts/generateJson.js +++ b/generate/scripts/generateJson.js @@ -231,7 +231,7 @@ module.exports = function generateJson() { } - utils.writeFile(path.join(__dirname, "..", "output", "idefs.json"), output); + utils.writeLocalFile("output/idefs.json", output); }; if (require.main === module) { diff --git a/generate/scripts/generateMissingTests.js b/generate/scripts/generateMissingTests.js index 669f6929c..29b6474b3 100644 --- a/generate/scripts/generateMissingTests.js +++ b/generate/scripts/generateMissingTests.js @@ -58,7 +58,7 @@ module.exports = function generateMissingTests() { Promise.all(promises).then( function() { - utils.writeFile(path.join(__dirname, "..", "/output/missing-tests.json"), output); + utils.writeLocalFile("/output/missing-tests.json", output); }, function(fail) { console.error(fail); diff --git a/generate/scripts/generateNativeCode.js b/generate/scripts/generateNativeCode.js index 3cd19c93b..3775a43e9 100644 --- a/generate/scripts/generateNativeCode.js +++ b/generate/scripts/generateNativeCode.js @@ -113,9 +113,9 @@ module.exports = function generateNativeCode() { return fse.copy(path.resolve(__dirname, "../templates/manual/src"), tempSrcDirPath); }).then(function() { // Write out single purpose templates. - utils.writeFile("../binding.gyp", beautify(templates.binding.render(enabled)), "binding.gyp"); + utils.writeLocalFile("../binding.gyp", beautify(templates.binding.render(enabled)), "binding.gyp"); utils.writeFile(path.join(tempSrcDirPath, "nodegit.cc"), templates.nodegitCC.render(enabled), "nodegit.cc"); - utils.writeFile("../lib/nodegit.js", beautify(templates.nodegitJS.render(enabled)), "nodegit.js"); + utils.writeLocalFile("../lib/nodegit.js", beautify(templates.nodegitJS.render(enabled)), "nodegit.js"); // Write out all the classes. enabled.forEach(function(idef) { if (idef.type && idef.type != "enum") { @@ -133,7 +133,7 @@ module.exports = function generateNativeCode() { } }); - utils.writeFile("../lib/enums.js", beautify(templates.enums.render(enabled)), "enums.js"); + utils.writeLocalFile("../lib/enums.js", beautify(templates.enums.render(enabled)), "enums.js"); }).then(function() { return exec("command -v astyle").then(function(astyle) { if (astyle) { diff --git a/generate/scripts/utils.js b/generate/scripts/utils.js index df4130bf9..385274400 100644 --- a/generate/scripts/utils.js +++ b/generate/scripts/utils.js @@ -11,13 +11,8 @@ var util = { pointerRegex: /\s*\*\s*/, doublePointerRegex: /\s*\*\*\s*/, - readLocalFile: function(file) { - try { - return fs.readFileSync(local(file)).toString(); - } - catch (unhandledException) { - return ""; - } + readLocalFile: function(filePath) { + return util.readFile(local(filePath)); }, readFile: function(filePath) { @@ -29,6 +24,10 @@ var util = { } }, + writeLocalFile: function(filePath, content, header) { + return util.writeFile(local(filePath), content, header); + }, + writeFile: function(filePath, content, header) { try { if (typeof content == "object") { From 02060bfbe029875486c2c62853866acb386c7d3f Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Sat, 12 Nov 2016 17:20:08 -0700 Subject: [PATCH 04/41] Remove path.format since it's not available in all node versions --- generate/scripts/generateNativeCode.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generate/scripts/generateNativeCode.js b/generate/scripts/generateNativeCode.js index 3775a43e9..a82bef4e5 100644 --- a/generate/scripts/generateNativeCode.js +++ b/generate/scripts/generateNativeCode.js @@ -120,13 +120,13 @@ module.exports = function generateNativeCode() { enabled.forEach(function(idef) { if (idef.type && idef.type != "enum") { utils.writeFile( - path.format({dir: tempSrcDirPath, name: idef.filename, ext: ".cc"}), + path.join(tempSrcDirPath, idef.filename + ".cc"), templates[idef.type + "_content"].render(idef), idef.type + "_content.cc" ); utils.writeFile( - path.format({dir: tempIncludeDirPath, name: idef.filename, ext: ".h"}), + path.join(tempIncludeDirPath, idef.filename + ".h"), templates[idef.type + "_header"].render(idef), idef.type + "_header.h" ); From 8f911102f347e4e686de30ca4f0f5098fd0bba50 Mon Sep 17 00:00:00 2001 From: Remy Suen Date: Tue, 31 Jan 2017 19:11:52 +0900 Subject: [PATCH 05/41] Expose libgit2 error code to clients when a promise fails When an API function of libgit2 fails within a promise, the promise is rejected with a JavaScript Error object that wraps the recorded error message in giterr_last(). However, the original non-zero return code of the API function is not exposed to the caller of the NodeGit API. This means that NodeGit clients cannot easily identify what the cause of an error is outside of parsing the Error object's message. This is an extremely volatile way of determining the cause as libgit2 may choose to alter the wording of the message at any time. To solve the problem above, the returned JavaScript Error object now esposes the libgit2 error code via its `errno` property. --- .../manual/patches/convenient_patches.cc | 9 +++++++- .../templates/manual/revwalk/fast_walk.cc | 9 +++++++- .../manual/revwalk/file_history_walk.cc | 9 +++++++- generate/templates/partials/async_function.cc | 9 +++++++- test/tests/merge.js | 22 +++++++++++++++++++ 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/generate/templates/manual/patches/convenient_patches.cc b/generate/templates/manual/patches/convenient_patches.cc index 79823e37a..27de54fcf 100644 --- a/generate/templates/manual/patches/convenient_patches.cc +++ b/generate/templates/manual/patches/convenient_patches.cc @@ -95,8 +95,15 @@ void GitPatch::ConvenientFromDiffWorker::HandleOKCallback() { } if (baton->error) { + Local err; + if (baton->error->message) { + err = Nan::Error(baton->error->message)->ToObject(); + } else { + err = Nan::Error("Method convenientFromDiff has thrown an error.")->ToObject(); + } + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); Local argv[1] = { - Nan::Error(baton->error->message) + err }; callback->Call(1, argv); if (baton->error->message) diff --git a/generate/templates/manual/revwalk/fast_walk.cc b/generate/templates/manual/revwalk/fast_walk.cc index 2f263f83f..ec3a10cd7 100644 --- a/generate/templates/manual/revwalk/fast_walk.cc +++ b/generate/templates/manual/revwalk/fast_walk.cc @@ -88,8 +88,15 @@ void GitRevwalk::FastWalkWorker::HandleOKCallback() { if (baton->error) { + Local err; + if (baton->error->message) { + err = Nan::Error(baton->error->message)->ToObject(); + } else { + err = Nan::Error("Method fastWalk has thrown an error.")->ToObject(); + } + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); Local argv[1] = { - Nan::Error(baton->error->message) + err }; callback->Call(1, argv); if (baton->error->message) diff --git a/generate/templates/manual/revwalk/file_history_walk.cc b/generate/templates/manual/revwalk/file_history_walk.cc index 0f511969f..220482679 100644 --- a/generate/templates/manual/revwalk/file_history_walk.cc +++ b/generate/templates/manual/revwalk/file_history_walk.cc @@ -289,8 +289,15 @@ void GitRevwalk::FileHistoryWalkWorker::HandleOKCallback() } if (baton->error) { + Local err; + if (baton->error->message) { + err = Nan::Error(baton->error->message)->ToObject(); + } else { + err = Nan::Error("Method fileHistoryWalk has thrown an error.")->ToObject(); + } + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); Local argv[1] = { - Nan::Error(baton->error->message) + err }; callback->Call(1, argv); if (baton->error->message) diff --git a/generate/templates/partials/async_function.cc b/generate/templates/partials/async_function.cc index 3d3227d4a..e47e5b77b 100644 --- a/generate/templates/partials/async_function.cc +++ b/generate/templates/partials/async_function.cc @@ -155,8 +155,15 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { callback->Call(2, argv); } else { if (baton->error) { + Local err; + if (baton->error->message) { + err = Nan::Error(baton->error->message)->ToObject(); + } else { + err = Nan::Error("Method {{ jsFunctionName }} has thrown an error.")->ToObject(); + } + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); Local argv[1] = { - Nan::Error(baton->error->message) + err }; callback->Call(1, argv); if (baton->error->message) diff --git a/test/tests/merge.js b/test/tests/merge.js index 3a63b0ced..05a719d20 100644 --- a/test/tests/merge.js +++ b/test/tests/merge.js @@ -1298,4 +1298,26 @@ describe("Merge", function() { assert.ok(repository.isDefaultState()); }); }); + + it("can retrieve error code on if common merge base not found", function() { + var repo; + return NodeGit.Repository.open(local("../repos/workdir")) + .then(function(r) { + repo = r; + return repo.getCommit("4bd806114ce26503c103c85dcc985021951bbc18"); + }) + .then(function(commit) { + return commit.getParents(commit.parentcount()); + }) + .then(function(parents) { + return NodeGit.Merge.base(repo, parents[0], parents[1]) + .then(function() { + return Promise.reject(new Error( + "should not be able to retrieve common merge base")); + }, function(err) { + assert.equal("No merge base found", err.message); + assert.equal(NodeGit.Error.CODE.ENOTFOUND, err.errno); + }); + }); + }); }); From cb7be7ec707345fa7e748135fe6c998825eaaa4d Mon Sep 17 00:00:00 2001 From: Remy Suen Date: Wed, 1 Feb 2017 15:42:53 +0900 Subject: [PATCH 06/41] Initialize pointers to prevent warnings during initial assignment In convert_from_v8.cc, the unwrapping of values uses two separate lines of code for variable declaration and variable assignment. When a pointer (or double pointer) is present, the assignment to the newly declared variable creates a compiler warning. To prevent the compilation logs from filling up unnecessarily, pointer variables should initially be assigned a `NULL` value upon its declaration so that the compiler will not emit a warning on the subseqent variable assignment line. --- generate/templates/partials/convert_from_v8.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/generate/templates/partials/convert_from_v8.cc b/generate/templates/partials/convert_from_v8.cc index 425e691f4..f7c4da469 100644 --- a/generate/templates/partials/convert_from_v8.cc +++ b/generate/templates/partials/convert_from_v8.cc @@ -1,6 +1,12 @@ {%if not isPayload %} // start convert_from_v8 block + {%if cType|isPointer %} + {{ cType }} from_{{ name }} = NULL; + {%elsif cType|isDoublePointer %} + {{ cType }} from_{{ name }} = NULL; + {%else%} {{ cType }} from_{{ name }}; + {%endif%} {%if isOptional | or isBoolean %} {%if cppClassName == 'GitStrarray'%} From 1316286d549a83d71942528d6188bc393b3c90bc Mon Sep 17 00:00:00 2001 From: Remy Suen Date: Wed, 1 Feb 2017 19:03:19 +0900 Subject: [PATCH 07/41] Update CONTRIBUTING.md with Slack references Slack has replaced Gitter as the channel of communication between the maintainers of NodeGit. --- CONTRIBUTING.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52a55d148..de461b0a3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,8 @@ Contribution Guidelines We try to be available pretty often to help when problems come up. We like to split incoming questions into two categories: potential bugs/features, and questions. If you want a feature added, or think you've found a bug in the code (or in the examples), search the [issue tracker](https://github.com/nodegit/nodegit/issues) and if you dont -find anything, file a new issue. If you just have questions, instead of using issues, contact us in our [Gitter room](https://gitter.im/nodegit/nodegit). +find anything, file a new issue. If you just have questions, instead of using issues, [sign up](http://slack.libgit2.org/) +to libgit2's Slack instance and then contact us in the [#nodegit channel](https://libgit2.slack.com/messages/nodegit/). ## How to Help ## @@ -21,7 +22,7 @@ These are all good easy ways to start getting involved with the project. You can and see if you can help with any existing issues. Please comment with your intention and any questions before getting started; duplicating work or doing something that would be rejected always sucks. -Additionally, [the documentation](http://www.nodegit.org) needs some love. Get in touch with one of us on Gitter if +Additionally, [the documentation](http://www.nodegit.org) needs some love. Get in touch with one of us on Slack if you'd like to lend a hand with that. -For anything else, Gitter is probably the best way to get in touch as well. Happy coding, merge you soon! +For anything else, Slack is probably the best way to get in touch as well. Happy coding, merge you soon! From 9ee7a9d801bfca0db90be22e8d890f22d23464b8 Mon Sep 17 00:00:00 2001 From: Remy Suen Date: Sat, 4 Feb 2017 17:17:55 +0900 Subject: [PATCH 08/41] Make `RevertOptions` parameter optional in `Revert.revert` libgit2's git_revert function does not require the revert options to be specified so the same should apply to the NodeGit API. --- generate/input/descriptor.json | 5 +++++ test/tests/revert.js | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index bc628cb3d..2135a355d 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -2044,6 +2044,11 @@ "functions": { "git_revert": { "isAsync": true, + "args": { + "given_opts": { + "isOptional": true + } + }, "return": { "isErrorCode": true } diff --git a/test/tests/revert.js b/test/tests/revert.js index b3f151831..a16d8c126 100644 --- a/test/tests/revert.js +++ b/test/tests/revert.js @@ -60,4 +60,11 @@ describe("Revert", function() { assert.ok(_.endsWith(fileName, entries[0].path)); }); }); + + it("RevertOptions is optional", function() { + return Revert.revert(test.repository, test.firstCommit, null) + .catch(function(error) { + throw error; + }); + }); }); From 55d9c8e4b5e776e2adcdd5417988afc824cb5c6a Mon Sep 17 00:00:00 2001 From: Remy Suen Date: Sun, 5 Feb 2017 09:30:53 +0900 Subject: [PATCH 09/41] Synchronize `Reset.fromAnnotated` with `Reset.reset` The reset function is asynchronous and also flags its checkout options as being optional. fromAnnotated should be updated accordingly as the two functions basically do the same thing. --- generate/input/descriptor.json | 11 +++ lib/reset.js | 23 ++++++ test/tests/reset.js | 129 +++++++++++++++++++++++---------- 3 files changed, 125 insertions(+), 38 deletions(-) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index bc628cb3d..243648548 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -2097,6 +2097,17 @@ "return": { "isErrorCode": true } + }, + "git_reset_from_annotated": { + "args": { + "checkout_opts": { + "isOptional": true + } + }, + "isAsync": true, + "return": { + "isErrorCode": true + } } } }, diff --git a/lib/reset.js b/lib/reset.js index 0f304d6be..df770304a 100644 --- a/lib/reset.js +++ b/lib/reset.js @@ -4,6 +4,7 @@ var normalizeOptions = NodeGit.Utils.normalizeOptions; var Reset = NodeGit.Reset; var _default = Reset.default; var _reset = Reset.reset; +var _fromAnnotated = Reset.fromAnnotated; /** * Look up a refs's commit. @@ -50,3 +51,25 @@ Reset.reset = function(repo, target, resetType, opts) { return _reset.call(this, repo, target, resetType, opts); }; + +/** + * Sets the current head to the specified commit oid and optionally + * resets the index and working tree to match. + * + * This behaves like reset but takes an annotated commit, which lets + * you specify which extended sha syntax string was specified by a + * user, allowing for more exact reflog messages. + * + * See the documentation for reset. + * + * @async + * @param {Repository} repo + * @param {AnnotatedCommit} target + * @param {Number} resetType + * @param {CheckoutOptions} opts + */ +Reset.fromAnnotated = function(repo, target, resetType, opts) { + opts = normalizeOptions(opts, NodeGit.CheckoutOptions); + + return _fromAnnotated.call(this, repo, target, resetType, opts); +}; diff --git a/test/tests/reset.js b/test/tests/reset.js index 7cfea3dd3..9bc38fd2b 100644 --- a/test/tests/reset.js +++ b/test/tests/reset.js @@ -8,6 +8,7 @@ describe("Reset", function() { var NodeGit = require("../../"); var Repository = NodeGit.Repository; var Reset = NodeGit.Reset; + var AnnotatedCommit = NodeGit.AnnotatedCommit; var reposPath = local("../repos/workdir"); var currentCommitOid = "32789a79e71fbc9e04d3eff7425e1771eb595150"; @@ -104,25 +105,57 @@ describe("Reset", function() { }); }); - it("can perform a soft reset", function() { - var test = this; - - return Reset.reset(test.repo, test.previousCommit, Reset.TYPE.SOFT) + function resetFrom(repo, commit, resetType, annotated) { + var promise = null; + if (annotated) { + promise = AnnotatedCommit.lookup(repo, commit.id()) + .then(function(annotatedCommit) { + return Reset.fromAnnotated(repo, annotatedCommit, resetType); + }); + } else { + promise = Reset.reset(repo, commit, resetType); + } + return promise .then(function() { - return test.repo.refreshIndex(); + return repo.refreshIndex(); }) .then(function(index) { return index.writeTree(); }) .then(function(oid) { - return test.repo.getTree(oid); + return repo.getTree(oid); }) .then(function(tree) { return tree.getEntry(filePath); }) .then(function(entry) { return entry.getBlob(); - }) + }); + } + + it("can perform a soft reset", function() { + var test = this; + + return resetFrom(test.repo, test.previousCommit, Reset.TYPE.SOFT, false) + .then(function(blob) { + var currentCommitContents = test.currentCommitBlob.toString(); + var previousCommitContents = test.previousCommitBlob.toString(); + var resetContents = blob.toString(); + + // With a soft reset all of the changes should be in the index + // still so the index should still == what we had at the current + // commit and not the one nwe reset to + assert(resetContents == currentCommitContents); + assert(resetContents != previousCommitContents); + + return Reset(test.repo, test.currentCommit, Reset.TYPE.HARD); + }); + }); + + it("can perform an annotated soft reset", function() { + var test = this; + + return resetFrom(test.repo, test.previousCommit, Reset.TYPE.SOFT, true) .then(function(blob) { var currentCommitContents = test.currentCommitBlob.toString(); var previousCommitContents = test.previousCommitBlob.toString(); @@ -130,7 +163,7 @@ describe("Reset", function() { // With a soft reset all of the changes should be in the index // still so the index should still == what we had at the current - // commit and not the one we reset to + // commit and not the one nwe reset to assert(resetContents == currentCommitContents); assert(resetContents != previousCommitContents); @@ -141,22 +174,32 @@ describe("Reset", function() { it("can perform a mixed reset", function() { var test = this; - return Reset.reset(test.repo, test.previousCommit, Reset.TYPE.MIXED) - .then(function() { - return test.repo.refreshIndex(); - }) - .then(function(index) { - return index.writeTree(); - }) - .then(function(oid) { - return test.repo.getTree(oid); - }) - .then(function(tree) { - return tree.getEntry(filePath); - }) - .then(function(entry) { - return entry.getBlob(); + return resetFrom(test.repo, test.previousCommit, Reset.TYPE.MIXED, false) + .then(function(blob) { + var currentCommitContents = test.currentCommitBlob.toString(); + var previousCommitContents = test.previousCommitBlob.toString(); + var resetContents = blob.toString(); + + // With a mixed reset all of the changes should removed from the index + // but still in the working directory. (i.e. unstaged) + assert(resetContents != currentCommitContents); + assert(resetContents == previousCommitContents); + + return fse.readFile(path.join(test.repo.workdir(), filePath)); }) + .then(function(fileContents) { + var currentCommitContents = test.currentCommitBlob.toString(); + + assert(fileContents == currentCommitContents); + + return Reset.reset(test.repo, test.currentCommit, Reset.TYPE.HARD); + }); + }); + + it("can perform an annotated mixed reset", function() { + var test = this; + + return resetFrom(test.repo, test.previousCommit, Reset.TYPE.MIXED, true) .then(function(blob) { var currentCommitContents = test.currentCommitBlob.toString(); var previousCommitContents = test.previousCommitBlob.toString(); @@ -181,22 +224,32 @@ describe("Reset", function() { it("can perform a hard reset", function() { var test = this; - return Reset.reset(test.repo, test.previousCommit, Reset.TYPE.HARD) - .then(function() { - return test.repo.refreshIndex(); - }) - .then(function(index) { - return index.writeTree(); - }) - .then(function(oid) { - return test.repo.getTree(oid); - }) - .then(function(tree) { - return tree.getEntry(filePath); - }) - .then(function(entry) { - return entry.getBlob(); + return resetFrom(test.repo, test.previousCommit, Reset.TYPE.HARD, false) + .then(function(blob) { + var currentCommitContents = test.currentCommitBlob.toString(); + var previousCommitContents = test.previousCommitBlob.toString(); + var resetContents = blob.toString(); + + // With a hard reset all of the changes should removed from the index + // and also removed from the working directory + assert(resetContents != currentCommitContents); + assert(resetContents == previousCommitContents); + + return fse.readFile(path.join(test.repo.workdir(), filePath)); }) + .then(function(fileContents) { + var previousCommitContents = test.previousCommitBlob.toString(); + + assert(fileContents == previousCommitContents); + + return Reset.reset(test.repo, test.currentCommit, Reset.TYPE.HARD); + }); + }); + + it("can perform an annotated hard reset", function() { + var test = this; + + return resetFrom(test.repo, test.previousCommit, Reset.TYPE.HARD, true) .then(function(blob) { var currentCommitContents = test.currentCommitBlob.toString(); var previousCommitContents = test.previousCommitBlob.toString(); From a5fa89c7625c64cfd6c8c0a2cbfe3b87fe0cd645 Mon Sep 17 00:00:00 2001 From: Remy Suen Date: Mon, 6 Feb 2017 19:49:43 +0900 Subject: [PATCH 10/41] Make the `message` argument of `Stash.save` optional libgit2's git_stash_save function does not actually require the message to be set. One will be generated if a message is not given so the parameter should be flagged as being optional in NodeGit as well. --- generate/input/descriptor.json | 5 +++++ test/tests/stash.js | 12 +++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index bc628cb3d..403f0b0b3 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -2175,6 +2175,11 @@ } }, "git_stash_save": { + "args": { + "message": { + "isOptional": true + } + }, "isAsync": true, "return": { "isErrorCode": true diff --git a/test/tests/stash.js b/test/tests/stash.js index 1e0a1d395..637ae00c9 100644 --- a/test/tests/stash.js +++ b/test/tests/stash.js @@ -31,15 +31,13 @@ describe("Stash", function() { }); }); - it("can save and drop a stash", function() { + function saveDropStash(repo, stashMessage) { var fileName = "README.md"; var fileContent = "Cha-cha-cha-chaaaaaangessssss"; - var repo = this.repository; var filePath = path.join(repo.workdir(), fileName); var oldContent; var stashes = []; var stashOid; - var stashMessage = "stash test"; return fse.readFile(filePath) .then(function(content) { @@ -82,6 +80,14 @@ describe("Stash", function() { return Promise.reject(e); }); }); + } + + it("can save and drop a stash", function() { + saveDropStash(this.repository, "stash test"); + }); + + it("can save a stash with no message and drop it", function() { + saveDropStash(this.repository, null); }); it("can save and pop a stash", function() { From 443ed333b02e38b7c85d167dbfa9dc7b122014b4 Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Tue, 7 Feb 2017 14:37:54 -0700 Subject: [PATCH 11/41] Explicitly namespace Local to v8 --- .../manual/include/convenient_hunk.h | 4 +-- .../manual/include/convenient_patch.h | 4 +-- .../manual/include/git_buf_converter.h | 2 +- .../manual/include/str_array_converter.h | 4 +-- generate/templates/manual/include/wrapper.h | 4 +-- generate/templates/partials/async_function.cc | 36 +++++++++---------- .../templates/partials/callback_helpers.cc | 6 ++-- generate/templates/partials/convert_to_v8.cc | 4 +-- .../templates/partials/field_accessors.cc | 16 ++++----- generate/templates/partials/fields.cc | 2 +- generate/templates/partials/sync_function.cc | 6 ++-- generate/templates/templates/class_content.cc | 10 +++--- generate/templates/templates/class_header.h | 4 +-- generate/templates/templates/nodegit.cc | 4 +-- .../templates/templates/struct_content.cc | 10 +++--- generate/templates/templates/struct_header.h | 4 +-- 16 files changed, 60 insertions(+), 60 deletions(-) diff --git a/generate/templates/manual/include/convenient_hunk.h b/generate/templates/manual/include/convenient_hunk.h index 63d77d900..37e9ab111 100644 --- a/generate/templates/manual/include/convenient_hunk.h +++ b/generate/templates/manual/include/convenient_hunk.h @@ -27,9 +27,9 @@ using namespace v8; class ConvenientHunk : public Nan::ObjectWrap { public: static Nan::Persistent constructor_template; - static void InitializeComponent (Local target); + static void InitializeComponent (v8::Local target); - static Local New(void *raw); + static v8::Local New(void *raw); HunkData *GetValue(); char *GetHeader(); diff --git a/generate/templates/manual/include/convenient_patch.h b/generate/templates/manual/include/convenient_patch.h index d6f6c69a1..9d6921ef8 100644 --- a/generate/templates/manual/include/convenient_patch.h +++ b/generate/templates/manual/include/convenient_patch.h @@ -38,9 +38,9 @@ using namespace v8; class ConvenientPatch : public Nan::ObjectWrap { public: static Nan::Persistent constructor_template; - static void InitializeComponent (Local target); + static void InitializeComponent (v8::Local target); - static Local New(void *raw); + static v8::Local New(void *raw); ConvenientLineStats GetLineStats(); git_delta_t GetStatus(); diff --git a/generate/templates/manual/include/git_buf_converter.h b/generate/templates/manual/include/git_buf_converter.h index e2ea08bba..fcbd1eaba 100644 --- a/generate/templates/manual/include/git_buf_converter.h +++ b/generate/templates/manual/include/git_buf_converter.h @@ -10,7 +10,7 @@ using namespace v8; class StrArrayConverter { public: - static git_strarray *Convert (Local val); + static git_strarray *Convert (v8::Local val); }; #endif diff --git a/generate/templates/manual/include/str_array_converter.h b/generate/templates/manual/include/str_array_converter.h index c3509f128..37f1bcc1d 100644 --- a/generate/templates/manual/include/str_array_converter.h +++ b/generate/templates/manual/include/str_array_converter.h @@ -11,11 +11,11 @@ using namespace v8; class StrArrayConverter { public: - static git_strarray *Convert (Local val); + static git_strarray *Convert (v8::Local val); private: static git_strarray *ConvertArray(Array *val); - static git_strarray *ConvertString(Local val); + static git_strarray *ConvertString(v8::Local val); static git_strarray *AllocStrArray(const size_t count); static git_strarray *ConstructStrArray(int argc, char** argv); }; diff --git a/generate/templates/manual/include/wrapper.h b/generate/templates/manual/include/wrapper.h index c040ea64d..9dcbe3186 100644 --- a/generate/templates/manual/include/wrapper.h +++ b/generate/templates/manual/include/wrapper.h @@ -17,10 +17,10 @@ class Wrapper : public Nan::ObjectWrap { public: static Nan::Persistent constructor_template; - static void InitializeComponent (Local target); + static void InitializeComponent (v8::Local target); void *GetValue(); - static Local New(const void *raw); + static v8::Local New(const void *raw); private: Wrapper(void *raw); diff --git a/generate/templates/partials/async_function.cc b/generate/templates/partials/async_function.cc index 3d3227d4a..633ebbfae 100644 --- a/generate/templates/partials/async_function.cc +++ b/generate/templates/partials/async_function.cc @@ -61,7 +61,7 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) { {%endif%} {%endeach%} - Nan::Callback *callback = new Nan::Callback(Local::Cast(info[{{args|jsArgsCount}}])); + Nan::Callback *callback = new Nan::Callback(v8::Local::Cast(info[{{args|jsArgsCount}}])); {{ cppFunctionName }}Worker *worker = new {{ cppFunctionName }}Worker(baton, callback); {%each args|argsInfo as arg %} {%if not arg.isReturn %} @@ -129,14 +129,14 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { if (baton->error_code == GIT_OK) { {%endif%} {%if return.isResultOrError %} - Local result = Nan::New(baton->error_code); + v8::Local result = Nan::New(baton->error_code); {%elsif not .|returnsCount %} - Local result = Nan::Undefined(); + v8::Local result = Nan::Undefined(); {%else%} - Local to; + v8::Local to; {%if .|returnsCount > 1 %} - Local result = Nan::New(); + v8::Local result = Nan::New(); {%endif%} {%each .|returnsInfo 0 1 as _return %} {%partial convertToV8 _return %} @@ -145,17 +145,17 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { {%endif%} {%endeach%} {%if .|returnsCount == 1 %} - Local result = to; + v8::Local result = to; {%endif%} {%endif%} - Local argv[2] = { + v8::Local argv[2] = { Nan::Null(), result }; callback->Call(2, argv); } else { if (baton->error) { - Local argv[1] = { + v8::Local argv[1] = { Nan::Error(baton->error->message) }; callback->Call(1, argv); @@ -163,7 +163,7 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { free((void *)baton->error->message); free((void *)baton->error); } else if (baton->error_code < 0) { - std::queue< Local > workerArguments; + std::queue< v8::Local > workerArguments; {%each args|argsInfo as arg %} {%if not arg.isReturn %} {%if not arg.isSelf %} @@ -175,7 +175,7 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { {%endeach%} bool callbackFired = false; while(!workerArguments.empty()) { - Local node = workerArguments.front(); + v8::Local node = workerArguments.front(); workerArguments.pop(); if ( @@ -191,11 +191,11 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { continue; } - Local nodeObj = node->ToObject(); - Local checkValue = GetPrivate(nodeObj, Nan::New("NodeGitPromiseError").ToLocalChecked()); + v8::Local nodeObj = node->ToObject(); + v8::Local checkValue = GetPrivate(nodeObj, Nan::New("NodeGitPromiseError").ToLocalChecked()); if (!checkValue.IsEmpty() && !checkValue->IsNull() && !checkValue->IsUndefined()) { - Local argv[1] = { + v8::Local argv[1] = { checkValue->ToObject() }; callback->Call(1, argv); @@ -203,10 +203,10 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { break; } - Local properties = nodeObj->GetPropertyNames(); + v8::Local properties = nodeObj->GetPropertyNames(); for (unsigned int propIndex = 0; propIndex < properties->Length(); ++propIndex) { - Local propName = properties->Get(propIndex)->ToString(); - Local nodeToQueue = nodeObj->Get(propName); + v8::Local propName = properties->Get(propIndex)->ToString(); + v8::Local nodeToQueue = nodeObj->Get(propName); if (!nodeToQueue->IsUndefined()) { workerArguments.push(nodeToQueue); } @@ -214,9 +214,9 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::HandleOKCallback() { } if (!callbackFired) { - Local err = Nan::Error("Method {{ jsFunctionName }} has thrown an error.")->ToObject(); + v8::Local err = Nan::Error("Method {{ jsFunctionName }} has thrown an error.")->ToObject(); err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); - Local argv[1] = { + v8::Local argv[1] = { err }; callback->Call(1, argv); diff --git a/generate/templates/partials/callback_helpers.cc b/generate/templates/partials/callback_helpers.cc index acd44f424..c1d0ab74a 100644 --- a/generate/templates/partials/callback_helpers.cc +++ b/generate/templates/partials/callback_helpers.cc @@ -30,7 +30,7 @@ void {{ cppClassName }}::{{ cppFunctionName }}_{{ cbFunction.name }}_async(void {% endif %} {% endeach %} - Local argv[{{ cbFunction.args|jsArgsCount }}] = { + v8::Local argv[{{ cbFunction.args|jsArgsCount }}] = { {% each cbFunction.args|argsInfo as arg %} {% if arg | isPayload %} {%-- payload is always the last arg --%} @@ -54,7 +54,7 @@ void {{ cppClassName }}::{{ cppFunctionName }}_{{ cbFunction.name }}_async(void }; Nan::TryCatch tryCatch; - Local result = callback->Call({{ cbFunction.args|jsArgsCount }}, argv); + v8::Local result = callback->Call({{ cbFunction.args|jsArgsCount }}, argv); if(PromiseCompletion::ForwardIfPromise(result, baton, {{ cppFunctionName }}_{{ cbFunction.name }}_promiseCompleted)) { return; @@ -124,7 +124,7 @@ void {{ cppClassName }}::{{ cppFunctionName }}_{{ cbFunction.name }}_promiseComp {{ cppClassName }}* instance = static_cast<{{ cppClassName }}*>(baton->{% each cbFunction.args|argsInfo as arg %} {% if arg.payload == true %}{{arg.name}}{% elsif arg.lastArg %}{{arg.name}}{% endif %} {% endeach %}); - Local parent = instance->handle(); + v8::Local parent = instance->handle(); SetPrivate(parent, Nan::New("NodeGitPromiseError").ToLocalChecked(), result); baton->result = {{ cbFunction.return.error }}; diff --git a/generate/templates/partials/convert_to_v8.cc b/generate/templates/partials/convert_to_v8.cc index d9b1d8830..bfe268f3e 100644 --- a/generate/templates/partials/convert_to_v8.cc +++ b/generate/templates/partials/convert_to_v8.cc @@ -33,12 +33,12 @@ {%-- // FIXME this is not general purpose enough. --%} {% if size %} - Local tmpArray = Nan::New({{= parsedName =}}->{{ size }}); + v8::Local tmpArray = Nan::New({{= parsedName =}}->{{ size }}); for (unsigned int i = 0; i < {{= parsedName =}}->{{ size }}; i++) { Nan::Set(tmpArray, Nan::New(i), Nan::New({{= parsedName =}}->{{ key }}[i]).ToLocalChecked()); } {% else %} - Local tmpArray = Nan::New({{= parsedName =}}); + v8::Local tmpArray = Nan::New({{= parsedName =}}); {% endif %} to = tmpArray; diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index f9f9065a0..f689b1811 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -39,7 +39,7 @@ } {% elsif field.isLibgitType %} - Local {{ field.name }}(value->ToObject()); + v8::Local {{ field.name }}(value->ToObject()); wrapper->{{ field.name }}.Reset({{ field.name }}); @@ -52,16 +52,16 @@ if (value->IsFunction()) { callback = new Nan::Callback(value.As()); } else if (value->IsObject()) { - Local object = value.As(); - Local callbackKey; + v8::Local object = value.As(); + v8::Local callbackKey; Nan::MaybeLocal maybeObjectCallback = Nan::Get(object, Nan::New("callback").ToLocalChecked()); if (!maybeObjectCallback.IsEmpty()) { - Local objectCallback = maybeObjectCallback.ToLocalChecked(); + v8::Local objectCallback = maybeObjectCallback.ToLocalChecked(); if (objectCallback->IsFunction()) { callback = new Nan::Callback(objectCallback.As()); Nan::MaybeLocal maybeObjectThrottle = Nan::Get(object, Nan::New("throttle").ToLocalChecked()); if(!maybeObjectThrottle.IsEmpty()) { - Local objectThrottle = maybeObjectThrottle.ToLocalChecked(); + v8::Local objectThrottle = maybeObjectThrottle.ToLocalChecked(); if (objectThrottle->IsNumber()) { throttle = (int)objectThrottle.As()->Value(); } @@ -153,7 +153,7 @@ {% endif %} {% endeach %} - Local argv[{{ field.args|jsArgsCount }}] = { + v8::Local argv[{{ field.args|jsArgsCount }}] = { {% each field.args|argsInfo as arg %} {% if arg.name == "payload" %} {%-- payload is always the last arg --%} @@ -176,7 +176,7 @@ }; Nan::TryCatch tryCatch; - Local result = instance->{{ field.name }}.GetCallback()->Call({{ field.args|jsArgsCount }}, argv); + v8::Local result = instance->{{ field.name }}.GetCallback()->Call({{ field.args|jsArgsCount }}, argv); if(PromiseCompletion::ForwardIfPromise(result, baton, {{ cppClassName }}::{{ field.name }}_promiseCompleted)) { return; @@ -245,7 +245,7 @@ {{ 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 %}); - Local parent = instance->handle(); + v8::Local parent = instance->handle(); SetPrivate(parent, Nan::New("NodeGitPromiseError").ToLocalChecked(), result); baton->result = {{ field.return.error }}; diff --git a/generate/templates/partials/fields.cc b/generate/templates/partials/fields.cc index ae3aeae44..9d6e6e39d 100644 --- a/generate/templates/partials/fields.cc +++ b/generate/templates/partials/fields.cc @@ -1,7 +1,7 @@ {% each fields|fieldsInfo as field %} {% if not field.ignore %} NAN_METHOD({{ cppClassName }}::{{ field.cppFunctionName }}) { - Local to; + v8::Local to; {% if field | isFixedLengthString %} char* {{ field.name }} = (char *)Nan::ObjectWrap::Unwrap<{{ cppClassName }}>(info.This())->GetValue()->{{ field.name }}; diff --git a/generate/templates/partials/sync_function.cc b/generate/templates/partials/sync_function.cc index d53a5c2d0..c07c77b51 100644 --- a/generate/templates/partials/sync_function.cc +++ b/generate/templates/partials/sync_function.cc @@ -17,7 +17,7 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) { {%if not arg.isReturn %} {%partial convertFromV8 arg %} {%if arg.saveArg %} - Local {{ arg.name }}(info[{{ arg.jsArg }}]->ToObject()); + v8::Local {{ arg.name }}(info[{{ arg.jsArg }}]->ToObject()); {{ cppClassName }} *thisObj = Nan::ObjectWrap::Unwrap<{{ cppClassName }}>(info.This()); thisObj->{{ cppFunctionName }}_{{ arg.name }}.Reset({{ arg.name }}); @@ -108,9 +108,9 @@ if (Nan::ObjectWrap::Unwrap<{{ cppClassName }}>(info.This())->GetValue() != NULL } {%endif%} - Local to; + v8::Local to; {%if .|returnsCount > 1 %} - Local toReturn = Nan::New(); + v8::Local toReturn = Nan::New(); {%endif%} {%each .|returnsInfo as _return %} {%partial convertToV8 _return %} diff --git a/generate/templates/templates/class_content.cc b/generate/templates/templates/class_content.cc index a6f2a180e..48e67b0eb 100644 --- a/generate/templates/templates/class_content.cc +++ b/generate/templates/templates/class_content.cc @@ -43,10 +43,10 @@ using namespace node; {% endeach %} } - void {{ cppClassName }}::InitializeComponent(Local target) { + void {{ cppClassName }}::InitializeComponent(v8::Local target) { Nan::HandleScope scope; - Local tpl = Nan::New(JSNewFunction); + v8::Local tpl = Nan::New(JSNewFunction); tpl->InstanceTemplate()->SetInternalFieldCount(1); tpl->SetClassName(Nan::New("{{ jsClassName }}").ToLocalChecked()); @@ -69,17 +69,17 @@ using namespace node; InitializeTemplate(tpl); - Local _constructor_template = Nan::GetFunction(tpl).ToLocalChecked(); + v8::Local _constructor_template = Nan::GetFunction(tpl).ToLocalChecked(); constructor_template.Reset(_constructor_template); Nan::Set(target, Nan::New("{{ jsClassName }}").ToLocalChecked(), _constructor_template); } {% else %} - void {{ cppClassName }}::InitializeComponent(Local target) { + void {{ cppClassName }}::InitializeComponent(v8::Local target) { Nan::HandleScope scope; - Local object = Nan::New(); + v8::Local object = Nan::New(); {% each functions as function %} {% if not function.ignore %} diff --git a/generate/templates/templates/class_header.h b/generate/templates/templates/class_header.h index 6f19f517f..ea04c120f 100644 --- a/generate/templates/templates/class_header.h +++ b/generate/templates/templates/class_header.h @@ -52,7 +52,7 @@ class {{ cppClassName }} : public friend class NodeGitWrapper<{{ cppClassName }}Traits>; {%endif %} public: - static void InitializeComponent (Local target); + static void InitializeComponent (v8::Local target); {% each functions as function %} {% if not function.ignore %} @@ -95,7 +95,7 @@ class {{ cppClassName }} : public {% endif %} ) {} - {{ cppClassName }}({{ cType }} *raw, bool selfFreeing, Local owner = Local()) + {{ cppClassName }}({{ cType }} *raw, bool selfFreeing, v8::Local owner = v8::Local()) : NodeGitWrapper<{{ cppClassName }}Traits>(raw, selfFreeing, owner) {} ~{{ cppClassName }}(); diff --git a/generate/templates/templates/nodegit.cc b/generate/templates/templates/nodegit.cc index 23adae3b5..9f392cabc 100644 --- a/generate/templates/templates/nodegit.cc +++ b/generate/templates/templates/nodegit.cc @@ -121,7 +121,7 @@ void OpenSSL_ThreadSetup() { ThreadPool libgit2ThreadPool(10, uv_default_loop()); -extern "C" void init(Local target) { +extern "C" void init(v8::Local target) { // Initialize thread safety in openssl and libssh2 OpenSSL_ThreadSetup(); init_ssh2(); @@ -146,7 +146,7 @@ extern "C" void init(Local target) { NODE_SET_METHOD(target, "getThreadSafetyStatus", LockMasterGetStatus); NODE_SET_METHOD(target, "getThreadSafetyDiagnostics", LockMasterGetDiagnostics); - Local threadSafety = Nan::New(); + v8::Local threadSafety = Nan::New(); threadSafety->Set(Nan::New("DISABLED").ToLocalChecked(), Nan::New((int)LockMaster::Disabled)); threadSafety->Set(Nan::New("ENABLED_FOR_ASYNC_ONLY").ToLocalChecked(), Nan::New((int)LockMaster::EnabledForAsyncOnly)); threadSafety->Set(Nan::New("ENABLED").ToLocalChecked(), Nan::New((int)LockMaster::Enabled)); diff --git a/generate/templates/templates/struct_content.cc b/generate/templates/templates/struct_content.cc index 14b3db242..c6f9e5b91 100644 --- a/generate/templates/templates/struct_content.cc +++ b/generate/templates/templates/struct_content.cc @@ -68,7 +68,7 @@ void {{ cppClassName }}::ConstructFields() { {% if not field.ignore %} {% if not field.isEnum %} {% if field.hasConstructor |or field.isLibgitType %} - Local {{ field.name }}Temp = {{ field.cppClassName }}::New( + v8::Local {{ field.name }}Temp = {{ field.cppClassName }}::New( {%if not field.cType|isPointer %}&{%endif%}this->raw->{{ field.name }}, false )->ToObject(); @@ -82,7 +82,7 @@ void {{ cppClassName }}::ConstructFields() { this->raw->{{ fields|payloadFor field.name }} = (void *)this; {% elsif field.payloadFor %} - Local {{ field.name }} = Nan::Undefined(); + v8::Local {{ field.name }} = Nan::Undefined(); this->{{ field.name }}.Reset({{ field.name }}); {% endif %} {% endif %} @@ -90,10 +90,10 @@ void {{ cppClassName }}::ConstructFields() { {% endeach %} } -void {{ cppClassName }}::InitializeComponent(Local target) { +void {{ cppClassName }}::InitializeComponent(v8::Local target) { Nan::HandleScope scope; - Local tpl = Nan::New(JSNewFunction); + v8::Local tpl = Nan::New(JSNewFunction); tpl->InstanceTemplate()->SetInternalFieldCount(1); tpl->SetClassName(Nan::New("{{ jsClassName }}").ToLocalChecked()); @@ -108,7 +108,7 @@ void {{ cppClassName }}::InitializeComponent(Local target) { InitializeTemplate(tpl); - Local _constructor_template = Nan::GetFunction(tpl).ToLocalChecked(); + v8::Local _constructor_template = Nan::GetFunction(tpl).ToLocalChecked(); constructor_template.Reset(_constructor_template); Nan::Set(target, Nan::New("{{ jsClassName }}").ToLocalChecked(), _constructor_template); } diff --git a/generate/templates/templates/struct_header.h b/generate/templates/templates/struct_header.h index dd8f8570e..94fd3bc0f 100644 --- a/generate/templates/templates/struct_header.h +++ b/generate/templates/templates/struct_header.h @@ -29,8 +29,8 @@ class {{ cppClassName }} : public NodeGitWrapper<{{ cppClassName }}Traits> { // grant full access to base class friend class NodeGitWrapper<{{ cppClassName }}Traits>; public: - {{ cppClassName }}({{ cType }}* raw, bool selfFreeing, v8::Local owner = Local()); - static void InitializeComponent (Local target); + {{ cppClassName }}({{ cType }}* raw, bool selfFreeing, v8::Local owner = v8::Local()); + static void InitializeComponent (v8::Local target); {% each fields as field %} {% if not field.ignore %} From 530555f31da7d0c9033f091c01ddb6bc2f17a3ea Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Tue, 7 Feb 2017 14:38:13 -0700 Subject: [PATCH 12/41] implement unsafe git_remote_ls feature --- generate/input/descriptor.json | 6 +- generate/input/libgit2-supplement.json | 73 ++++++++++ .../templates/manual/include/functions/copy.h | 2 + generate/templates/manual/remote/ls.cc | 127 ++++++++++++++++++ .../templates/manual/src/functions/copy.cc | 10 ++ 5 files changed, 215 insertions(+), 3 deletions(-) create mode 100644 generate/templates/manual/remote/ls.cc diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index a9264214a..2e6327d46 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -1805,6 +1805,9 @@ } }, "remote": { + "dependencies": [ + "../include/remote_head.h" + ], "cType": "git_remote", "selfFreeing": true, "functions": { @@ -1969,9 +1972,6 @@ } } }, - "remote_head": { - "ignore": true - }, "repository": { "dependencies": [ "git2/sys/repository.h" diff --git a/generate/input/libgit2-supplement.json b/generate/input/libgit2-supplement.json index b686795c3..b4e38cc6b 100644 --- a/generate/input/libgit2-supplement.json +++ b/generate/input/libgit2-supplement.json @@ -126,6 +126,40 @@ }, "group": "rebase" }, + "git_remote_reference_list": { + "args": [ + { + "name": "out", + "type": "std::vector *" + }, + { + "name": "callbacks", + "type": "git_remote_callbacks *" + }, + { + "name": "proxy_opts", + "type": "git_proxy_options *" + }, + { + "name": "custom_headers", + "type": "git_strarray *" + }, + { + "name": "remote", + "type": "git_remote *" + } + ], + "type": "function", + "isManual": true, + "cFile": "generate/templates/manual/remote/ls.cc", + "isAsync": true, + "isPrototypeMethod": true, + "group": "remote", + "return": { + "type": "int", + "isErrorCode": true + } + }, "git_reset": { "type": "function", "file": "reset.h", @@ -277,6 +311,12 @@ "git_reflog_entry_message" ] ], + [ + "remote", + [ + "git_remote_reference_list" + ] + ], [ "revwalk", [ @@ -614,6 +654,39 @@ } } ], + [ + "git_remote_head", + { + "types": "struct", + "fields": [ + { + "type": "int", + "name": "local" + }, + { + "type": "git_oid", + "name": "oid" + }, + { + "type": "git_oid", + "name": "loid" + }, + { + "type": "char *", + "name": "name" + }, + { + "type": "char *", + "name": "symref_target" + } + ], + "used": { + "needs": [ + "git_remote_reference_list" + ] + } + } + ], [ "git_time_t", { diff --git a/generate/templates/manual/include/functions/copy.h b/generate/templates/manual/include/functions/copy.h index f7f942475..9983e575a 100644 --- a/generate/templates/manual/include/functions/copy.h +++ b/generate/templates/manual/include/functions/copy.h @@ -14,6 +14,8 @@ const git_index_time *git_index_time_dup(const git_index_time *arg); const git_time *git_time_dup(const git_time *arg); const git_diff_delta *git_diff_delta_dup(const git_diff_delta *arg); const git_diff_file *git_diff_file_dup(const git_diff_file *arg); +git_remote_head *git_remote_head_dup(const git_remote_head *src); + void git_time_dup(git_time **out, const git_time *arg); void git_transfer_progress_dup(git_transfer_progress **out, const git_transfer_progress *arg); diff --git a/generate/templates/manual/remote/ls.cc b/generate/templates/manual/remote/ls.cc new file mode 100644 index 000000000..6f18c08fc --- /dev/null +++ b/generate/templates/manual/remote/ls.cc @@ -0,0 +1,127 @@ +NAN_METHOD(GitRemote::ReferenceList) +{ + if (info.Length() == 0 || !info[0]->IsObject()) { + return Nan::ThrowError("RemoteCallbacks callbacks is required."); + } + if (info.Length() == 1 || !info[1]->IsObject()) { + return Nan::ThrowError("ProxyOptions proxy_opts is required."); + } + + if (info.Length() == 2 || !(Nan::To(info[2]).FromJust())) { + return Nan::ThrowError("Array, String Object, or string custom_headers is required."); + } + if (info.Length() == 3 || !info[3]->IsFunction()) { + return Nan::ThrowError("Callback is required and must be a Function."); + } + + ReferenceListBaton* baton = new ReferenceListBaton; + + baton->error_code = GIT_OK; + baton->error = NULL; + baton->out = new std::vector; + baton->remote = Nan::ObjectWrap::Unwrap(info.This())->GetValue(); + baton->callbacks = Nan::ObjectWrap::Unwrap(info[0]->ToObject())->GetValue(); + baton->proxy_opts = Nan::ObjectWrap::Unwrap(info[1]->ToObject())->GetValue(); + baton->custom_headers = StrArrayConverter::Convert(info[2]); + + Nan::Callback *callback = new Nan::Callback(Local::Cast(info[1])); + ReferenceListWorker *worker = new ReferenceListWorker(baton, callback); + worker->SaveToPersistent("remote", info.This()); + if (!info[1]->IsUndefined() && !info[0]->IsNull()) + worker->SaveToPersistent("callbacks", info[0]->ToObject()); + if (!info[2]->IsUndefined() && !info[1]->IsNull()) + worker->SaveToPersistent("proxy_opts", info[1]->ToObject()); + if (!info[3]->IsUndefined() && !info[2]->IsNull()) + worker->SaveToPersistent("custom_headers", info[2]->ToObject()); + Nan::AsyncQueueWorker(worker); + return; +} + +void GitRemote::ReferenceListWorker::Execute() +{ + giterr_clear(); + baton->error_code = git_remote_connect( + baton->remote, + GIT_DIRECTION_FETCH, + baton->callbacks, + baton->proxy_opts, + baton->custom_headers + ); + + if (baton->error_code != GIT_OK) { + baton->error = git_error_dup(giterr_last()); + delete baton->out; + baton->out = NULL; + return; + } + + const git_remote_head **remote_heads; + size_t num_remote_heads; + baton->error_code = git_remote_ls( + &remote_heads, + &num_remote_heads, + baton->remote + ); + + if (baton->error_code != GIT_OK) { + baton->error = git_error_dup(giterr_last()); + delete baton->out; + baton->out = NULL; + return; + } + + baton->out->reserve(num_remote_heads); + + for (unsigned int head_index = 0; head_index < num_remote_heads; ++head_index) { + git_remote_head *remote_head = git_remote_head_dup(remote_heads[head_index]); + baton->out->push_back(remote_head); + } + + git_remote_disconnect(baton->remote); +} + +void GitRemote::ReferenceListWorker::HandleOKCallback() +{ + if (baton->out != NULL) + { + unsigned int size = baton->out->size(); + Local result = Nan::New(size); + for (unsigned int i = 0; i < size; i++) { + Nan::Set(result, Nan::New(i), GitRemoteHead::New(baton->out->at(i), true)); + } + + delete baton->out; + + Local argv[2] = { + Nan::Null(), + result + }; + callback->Call(2, argv); + } + else if (baton->error) + { + Local argv[1] = { + Nan::Error(baton->error->message) + }; + callback->Call(1, argv); + if (baton->error->message) + { + free((void *)baton->error->message); + } + + free((void *)baton->error); + } + else if (baton->error_code < 0) + { + Local err = Nan::Error("Method next has thrown an error.")->ToObject(); + err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); + Local argv[1] = { + err + }; + callback->Call(1, argv); + } + else + { + callback->Call(0, NULL); + } +} diff --git a/generate/templates/manual/src/functions/copy.cc b/generate/templates/manual/src/functions/copy.cc index f09f2cbaa..747dc24a2 100644 --- a/generate/templates/manual/src/functions/copy.cc +++ b/generate/templates/manual/src/functions/copy.cc @@ -20,3 +20,13 @@ void git_transfer_progress_dup(git_transfer_progress **out, const git_transfer_p *out = (git_transfer_progress *)malloc(sizeof(git_transfer_progress)); memcpy(*out, arg, sizeof(git_transfer_progress)); } + +git_remote_head *git_remote_head_dup(const git_remote_head *src) { + git_remote_head *dest = (git_remote_head *)malloc(sizeof(git_remote_head)); + dest->local = src->local; + git_oid_cpy(&dest->oid, &src->oid); + git_oid_cpy(&dest->loid, &src->loid); + dest->name = strdup(src->name); + dest->symref_target = strdup(src->symref_target); + return dest; +} From 3156c14a19227316f06ce40d6dfaa95963dd17dc Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Tue, 7 Feb 2017 15:22:57 -0700 Subject: [PATCH 13/41] get unsafe git_remote_ls building and running --- generate/templates/manual/remote/ls.cc | 8 +++---- .../templates/manual/src/functions/copy.cc | 4 +++- lib/remote.js | 22 +++++++++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/generate/templates/manual/remote/ls.cc b/generate/templates/manual/remote/ls.cc index 6f18c08fc..07e782055 100644 --- a/generate/templates/manual/remote/ls.cc +++ b/generate/templates/manual/remote/ls.cc @@ -24,7 +24,7 @@ NAN_METHOD(GitRemote::ReferenceList) baton->proxy_opts = Nan::ObjectWrap::Unwrap(info[1]->ToObject())->GetValue(); baton->custom_headers = StrArrayConverter::Convert(info[2]); - Nan::Callback *callback = new Nan::Callback(Local::Cast(info[1])); + Nan::Callback *callback = new Nan::Callback(Local::Cast(info[3])); ReferenceListWorker *worker = new ReferenceListWorker(baton, callback); worker->SaveToPersistent("remote", info.This()); if (!info[1]->IsUndefined() && !info[0]->IsNull()) @@ -63,6 +63,7 @@ void GitRemote::ReferenceListWorker::Execute() baton->remote ); + git_remote_disconnect(baton->remote); if (baton->error_code != GIT_OK) { baton->error = git_error_dup(giterr_last()); delete baton->out; @@ -72,12 +73,10 @@ void GitRemote::ReferenceListWorker::Execute() baton->out->reserve(num_remote_heads); - for (unsigned int head_index = 0; head_index < num_remote_heads; ++head_index) { + for (size_t head_index = 0; head_index < num_remote_heads; ++head_index) { git_remote_head *remote_head = git_remote_head_dup(remote_heads[head_index]); baton->out->push_back(remote_head); } - - git_remote_disconnect(baton->remote); } void GitRemote::ReferenceListWorker::HandleOKCallback() @@ -90,6 +89,7 @@ void GitRemote::ReferenceListWorker::HandleOKCallback() Nan::Set(result, Nan::New(i), GitRemoteHead::New(baton->out->at(i), true)); } + delete baton->out; Local argv[2] = { diff --git a/generate/templates/manual/src/functions/copy.cc b/generate/templates/manual/src/functions/copy.cc index 747dc24a2..9a2e7c3c7 100644 --- a/generate/templates/manual/src/functions/copy.cc +++ b/generate/templates/manual/src/functions/copy.cc @@ -27,6 +27,8 @@ git_remote_head *git_remote_head_dup(const git_remote_head *src) { git_oid_cpy(&dest->oid, &src->oid); git_oid_cpy(&dest->loid, &src->loid); dest->name = strdup(src->name); - dest->symref_target = strdup(src->symref_target); + dest->symref_target = src->symref_target + ? strdup(src->symref_target) + : NULL; return dest; } diff --git a/lib/remote.js b/lib/remote.js index 47fac857e..53ab4fc83 100644 --- a/lib/remote.js +++ b/lib/remote.js @@ -9,6 +9,7 @@ var _connect = Remote.prototype.connect; var _download = Remote.prototype.download; var _fetch = Remote.prototype.fetch; var _push = Remote.prototype.push; +var _referenceList = Remote.prototype.referenceList; var _upload = Remote.prototype.upload; /** @@ -112,6 +113,27 @@ Remote.prototype.push = function(refSpecs, opts) { return _push.call(this, refSpecs, opts); }; +/** + * Lists advertised heads from remote + * + * @async + * @param {RemoteCallbacks} callbacks The callback functions for the connection + * @param {ProxyOptions} proxyOpts Proxy settings + * @param {Array} customHeaders extra HTTP headers to use + * @param {Function} callback + * @return {Number} error code + */ +Remote.prototype.referenceList = function( + callbacks, + proxyOpts, + customHeaders +) { + callbacks = normalizeOptions(callbacks, NodeGit.RemoteCallbacks); + proxyOpts = normalizeOptions(proxyOpts || {}, NodeGit.ProxyOptions); + customHeaders = customHeaders || []; + + return _referenceList.call(this, callbacks, proxyOpts, customHeaders); +}; /** * Connects to a remote * From b46ba8c1499ebebe0127343503e3dfc75482a5af Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Tue, 7 Feb 2017 15:37:54 -0700 Subject: [PATCH 14/41] lock remote during ls execution --- generate/templates/manual/remote/ls.cc | 73 +++++++++++++++----------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/generate/templates/manual/remote/ls.cc b/generate/templates/manual/remote/ls.cc index 07e782055..defff6f20 100644 --- a/generate/templates/manual/remote/ls.cc +++ b/generate/templates/manual/remote/ls.cc @@ -40,42 +40,52 @@ NAN_METHOD(GitRemote::ReferenceList) void GitRemote::ReferenceListWorker::Execute() { giterr_clear(); - baton->error_code = git_remote_connect( - baton->remote, - GIT_DIRECTION_FETCH, - baton->callbacks, - baton->proxy_opts, - baton->custom_headers - ); - if (baton->error_code != GIT_OK) { - baton->error = git_error_dup(giterr_last()); - delete baton->out; - baton->out = NULL; - return; - } + { + LockMaster lockMaster( + /*asyncAction: */true, + baton->remote, + baton->callbacks, + baton->proxy_opts, + baton->custom_headers + ); + baton->error_code = git_remote_connect( + baton->remote, + GIT_DIRECTION_FETCH, + baton->callbacks, + baton->proxy_opts, + baton->custom_headers + ); - const git_remote_head **remote_heads; - size_t num_remote_heads; - baton->error_code = git_remote_ls( - &remote_heads, - &num_remote_heads, - baton->remote - ); + if (baton->error_code != GIT_OK) { + baton->error = git_error_dup(giterr_last()); + delete baton->out; + baton->out = NULL; + return; + } - git_remote_disconnect(baton->remote); - if (baton->error_code != GIT_OK) { - baton->error = git_error_dup(giterr_last()); - delete baton->out; - baton->out = NULL; - return; - } + const git_remote_head **remote_heads; + size_t num_remote_heads; + baton->error_code = git_remote_ls( + &remote_heads, + &num_remote_heads, + baton->remote + ); + + git_remote_disconnect(baton->remote); + if (baton->error_code != GIT_OK) { + baton->error = git_error_dup(giterr_last()); + delete baton->out; + baton->out = NULL; + return; + } - baton->out->reserve(num_remote_heads); + baton->out->reserve(num_remote_heads); - for (size_t head_index = 0; head_index < num_remote_heads; ++head_index) { - git_remote_head *remote_head = git_remote_head_dup(remote_heads[head_index]); - baton->out->push_back(remote_head); + for (size_t head_index = 0; head_index < num_remote_heads; ++head_index) { + git_remote_head *remote_head = git_remote_head_dup(remote_heads[head_index]); + baton->out->push_back(remote_head); + } } } @@ -89,7 +99,6 @@ void GitRemote::ReferenceListWorker::HandleOKCallback() Nan::Set(result, Nan::New(i), GitRemoteHead::New(baton->out->at(i), true)); } - delete baton->out; Local argv[2] = { From a4ead57aaa5208f1ee3a641ef63ab65f3e970526 Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Wed, 8 Feb 2017 08:08:03 -0700 Subject: [PATCH 15/41] Build test for reference list --- lib/remote.js | 6 ++-- test/tests/remote.js | 84 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/lib/remote.js b/lib/remote.js index 53ab4fc83..f89dfd65e 100644 --- a/lib/remote.js +++ b/lib/remote.js @@ -114,21 +114,21 @@ Remote.prototype.push = function(refSpecs, opts) { }; /** - * Lists advertised heads from remote + * Lists advertised references from a remote * * @async * @param {RemoteCallbacks} callbacks The callback functions for the connection * @param {ProxyOptions} proxyOpts Proxy settings * @param {Array} customHeaders extra HTTP headers to use * @param {Function} callback - * @return {Number} error code + * @return {Promise} */ Remote.prototype.referenceList = function( callbacks, proxyOpts, customHeaders ) { - callbacks = normalizeOptions(callbacks, NodeGit.RemoteCallbacks); + callbacks = normalizeOptions(callbacks || {}, NodeGit.RemoteCallbacks); proxyOpts = normalizeOptions(proxyOpts || {}, NodeGit.ProxyOptions); customHeaders = customHeaders || []; diff --git a/test/tests/remote.js b/test/tests/remote.js index dfe3fb318..9f796774e 100644 --- a/test/tests/remote.js +++ b/test/tests/remote.js @@ -2,6 +2,7 @@ var assert = require("assert"); var path = require("path"); var local = path.join.bind(path, __dirname); var _ = require("lodash"); +var fp = require("lodash/fp"); var garbageCollect = require("../utils/garbage_collect.js"); @@ -444,4 +445,87 @@ describe("Remote", function() { Remote.getSelfFreeingInstanceCount()); }); }); + + it("can retrieve the list of references advertised by a remote", function() { + var expectedRemoteHeads = { + HEAD: { + local: 0, + oid: "32789a79e71fbc9e04d3eff7425e1771eb595150", + loid: "0000000000000000000000000000000000000000", + name: "HEAD", + symrefTarget: "refs/heads/master" + }, + "refs/heads/checkout-test": { + local: 0, + oid: "1729c73906bb8467f4095c2f4044083016b4dfde", + loid: "0000000000000000000000000000000000000000", + name: "refs/heads/checkout-test", + symrefTarget: null + }, + "refs/heads/master": { + local: 0, + oid: "32789a79e71fbc9e04d3eff7425e1771eb595150", + loid: "0000000000000000000000000000000000000000", + name: "refs/heads/master", + symrefTarget: null + }, + "refs/heads/rev-walk": { + local: 0, + oid: "32789a79e71fbc9e04d3eff7425e1771eb595150", + loid: "0000000000000000000000000000000000000000", + name: "refs/heads/rev-walk", + symrefTarget: null + }, + "refs/tags/annotated-tag": { + local: 0, + oid: "dc800017566123ff3c746b37284a24a66546667e", + loid: "0000000000000000000000000000000000000000", + name: "refs/tags/annotated-tag", + symrefTarget: null + }, + "refs/tags/annotated-tag^{}": { + local: 0, + oid: "32789a79e71fbc9e04d3eff7425e1771eb595150", + loid: "0000000000000000000000000000000000000000", + name: "refs/tags/annotated-tag^{}", + symrefTarget: null + }, + "refs/tags/light-weight-tag": { + local: 0, + oid: "32789a79e71fbc9e04d3eff7425e1771eb595150", + loid: "0000000000000000000000000000000000000000", + name: "refs/tags/light-weight-tag", + symrefTarget: null + } + }; + + return this.repository.getRemote("origin") + .then(function(remote) { + return remote.referenceList(); + }) + .then(function(remoteHeads) { + var remoteHeadsBySha = fp.flow([ + fp.map(function(remoteHead) { + return { + local: remoteHead.local(), + oid: remoteHead.oid().toString(), + loid: remoteHead.loid().toString(), + name: remoteHead.name(), + symrefTarget: remoteHead.symrefTarget() + }; + }), + fp.keyBy("name") + ])(remoteHeads); + + fp.flow([ + fp.keys, + fp.forEach(function(remoteHeadName) { + assert(fp.isEqual( + expectedRemoteHeads[remoteHeadName], + remoteHeadsBySha[remoteHeadName] + ), "Expectations for head " + remoteHeadName + " were not met."); + }) + ])(expectedRemoteHeads); + }); + }); }); From 7fe20abbf3e2ddd4f00a4e34bc63d0872a6906fc Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Wed, 8 Feb 2017 08:38:15 -0700 Subject: [PATCH 16/41] clean up memory from git_remote_head --- generate/input/descriptor.json | 7 +++++++ generate/templates/manual/include/functions/free.h | 12 ++++++++++++ generate/templates/manual/src/functions/free.cc | 9 +++++++++ generate/templates/templates/binding.gyp | 1 + 4 files changed, 29 insertions(+) create mode 100644 generate/templates/manual/include/functions/free.h create mode 100644 generate/templates/manual/src/functions/free.cc diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index 2e6327d46..da9c37d52 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -1972,6 +1972,13 @@ } } }, + "remote_head": { + "dependencies": [ + "../include/functions/free.h" + ], + "freeFunctionName": "git_remote_head_free", + "selfFreeing": true + }, "repository": { "dependencies": [ "git2/sys/repository.h" diff --git a/generate/templates/manual/include/functions/free.h b/generate/templates/manual/include/functions/free.h new file mode 100644 index 000000000..873417b98 --- /dev/null +++ b/generate/templates/manual/include/functions/free.h @@ -0,0 +1,12 @@ +#include + +#include + +#include "git2.h" + +#ifndef NODEGIT_FREE_FUNCTIONS +#define NODEGIT_FREE_FUNCTIONS + +void git_remote_head_free(git_remote_head *remote_head); + +#endif diff --git a/generate/templates/manual/src/functions/free.cc b/generate/templates/manual/src/functions/free.cc new file mode 100644 index 000000000..a52a7016f --- /dev/null +++ b/generate/templates/manual/src/functions/free.cc @@ -0,0 +1,9 @@ +#include + +#include "git2.h" + +void git_remote_head_free(git_remote_head *remote_head) { + free(remote_head->name); + free(remote_head->symref_target); + free(remote_head); +} diff --git a/generate/templates/templates/binding.gyp b/generate/templates/templates/binding.gyp index ece88cd15..041c1ea27 100644 --- a/generate/templates/templates/binding.gyp +++ b/generate/templates/templates/binding.gyp @@ -18,6 +18,7 @@ "src/promise_completion.cc", "src/wrapper.cc", "src/functions/copy.cc", + "src/functions/free.cc", "src/convenient_patch.cc", "src/convenient_hunk.cc", "src/str_array_converter.cc", From 92833d60518b0538a14c6a1eb604bd8e6af10739 Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Wed, 8 Feb 2017 15:53:27 -0700 Subject: [PATCH 17/41] Update merge branches with processMergeMessageCallback When merging branches, we should provide a callback that allows users to inspect and modify the message that will be used for merging. The generated merge message itself was also incorrect when compared to git core, and so has been updated to match git core. --- lib/repository.js | 40 +++++- test/tests/merge.js | 320 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 350 insertions(+), 10 deletions(-) diff --git a/lib/repository.js b/lib/repository.js index 1a4e6eaa8..995beba94 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -1325,11 +1325,19 @@ Repository.prototype.refreshIndex = function(callback) { * @return {Oid|Index} A commit id for a succesful merge or an index for a * merge with conflicts */ -Repository.prototype.mergeBranches = - function(to, from, signature, mergePreference, mergeOptions) { +Repository.prototype.mergeBranches = function( + to, + from, + signature, + mergePreference, + mergeOptions, + processMergeMessageCallback +) { var repo = this; var fromBranch; var toBranch; + processMergeMessageCallback = processMergeMessageCallback || + function (message) { return message; }; mergePreference = mergePreference || NodeGit.Merge.PREFERENCE.NONE; mergeOptions = normalizeOptions(mergeOptions, NodeGit.MergeOptions); @@ -1414,19 +1422,37 @@ Repository.prototype.mergeBranches = return index.writeTreeTo(repo); }) .then(function(oid) { + var mergeDecorator; + if (fromBranch.isTag()) { + mergeDecorator = "tag"; + } else if (fromBranch.isRemote()) { + mergeDecorator = "remote-tracking branch"; + } else { + mergeDecorator = "branch"; + } + var message = - "Merged " + - fromBranch.shorthand() + - " into " + - toBranch.shorthand(); + "Merge " + + mergeDecorator + + " '" + + fromBranch.shorthand(); + + // https://github.com/git/git/blob/master/builtin/fmt-merge-msg.c#L456-L459 + if (toBranch.shorthand() !== "master") { + message += "' into " + toBranch.shorthand(); + } + return Promise.all([oid, processMergeMessageCallback(message)]); + }) + .then(function([oid, message]) { return repo.createCommit( toBranch.name(), signature, signature, message, oid, - [toCommitOid, fromCommitOid]); + [toCommitOid, fromCommitOid] + ); }) .then(function(commit) { // we've updated the checked out branch, so make sure we update diff --git a/test/tests/merge.js b/test/tests/merge.js index 3a63b0ced..5bf3cb81c 100644 --- a/test/tests/merge.js +++ b/test/tests/merge.js @@ -348,7 +348,7 @@ describe("Merge", function() { }) .then(function(oid) { assert.equal(oid.toString(), - "6806d22d2b6c0095b29dc5ec51829caeb67861f1"); + "65516eb7b20f51d275096cd28f132ff606a09e07"); return repository.getBranchCommit(ourBranchName) .then(function(branchCommit) { @@ -501,7 +501,7 @@ describe("Merge", function() { }) .then(function(commitId) { assert.equal(commitId.toString(), - "5384feb481d9c29081b3a0c1478fcc24a3953efa"); + "96d6f1d0704eb3ef9121a13348d17c1d672c28aa"); }) .then(function() { return repository.getStatus(); @@ -512,6 +512,320 @@ describe("Merge", function() { }); }); + it( + "can merge --no-ff a non-fast-forward using the convenience method " + + "with custom merge message via sync callback", + function() { + var initialFileName = "initialFile.txt"; + var ourFileName = "ourNewFile.txt"; + var theirFileName = "theirNewFile.txt"; + + var initialFileContent = "I'd like to drive somewhere"; + var ourFileContent = "I like Toll Roads. I have an EZ-Pass!"; + var theirFileContent = "I'm skeptical about Toll Roads"; + + var ourSignature = NodeGit.Signature.create + ("Ron Paul", "RonPaul@TollRoadsRBest.info", 123456789, 60); + var theirSignature = NodeGit.Signature.create + ("Greg Abbott", "Gregggg@IllTollYourFace.us", 123456789, 60); + + var repository = this.repository; + var initialCommit; + var ourCommit; + var theirCommit; + var ourBranch; + var theirBranch; + + return fse.writeFile( + path.join(repository.workdir(), initialFileName), + initialFileContent) + // Load up the repository index and make our initial commit to HEAD + .then(function() { + return repository.refreshIndex(); + }) + .then(function(index) { + return index.addByPath(initialFileName) + .then(function() { + return index.write(); + }) + .then(function() { + return index.writeTree(); + }); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "21a553813e2f670815b649eef51eeadb253a5d0c"); + + return repository.createCommit("HEAD", ourSignature, + ourSignature, "initial commit", oid, []); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "af66a9c799a10a23319ee4318c8bb2021521f539"); + + return repository.getCommit(commitOid).then(function(commit) { + initialCommit = commit; + }).then(function() { + return repository.createBranch(ourBranchName, commitOid) + .then(function(branch) { + ourBranch = branch; + return repository.createBranch(theirBranchName, commitOid); + }); + }); + }) + .then(function(branch) { + theirBranch = branch; + }) + .then(function() { + return fse.writeFile(path.join(repository.workdir(), ourFileName), + ourFileContent); + }) + .then(function() { + return repository.refreshIndex(); + }) + .then(function(index) { + return index.addByPath(ourFileName) + .then(function() { + return index.write(); + }) + .then(function() { + return index.writeTree(); + }); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "af60aa06b3537f75b427f6268a130c842c84a137"); + + return repository.createCommit(ourBranch.name(), ourSignature, + ourSignature, "we made a commit", oid, [initialCommit]); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "7ce31c05427659986d50abfb90c8f7db88ef4fa1"); + + return repository.getCommit(commitOid).then(function(commit) { + ourCommit = commit; + }); + }) + .then(function() { + return fse.writeFile(path.join(repository.workdir(), theirFileName), + theirFileContent); + }) + .then(function() { + return repository.refreshIndex(); + }) + .then(function(index) { + return index.addByPath(theirFileName) + .then(function() { + return index.write(); + }) + .then(function() { + return index.writeTree(); + }); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "f007361737a2ca00a0e80fc2daf55064463173b4"); + + return repository.createCommit(theirBranch.name(), theirSignature, + theirSignature, "they made a commit", oid, [initialCommit]); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "b588f0eef1809226f8f7db542940749da15ae1de"); + + return repository.getCommit(commitOid).then(function(commit) { + theirCommit = commit; + }); + }) + .then(function() { + var opts = {checkoutStrategy: NodeGit.Checkout.STRATEGY.FORCE}; + return repository.checkoutBranch(ourBranchName, opts); + }) + .then(function() { + return repository.mergeBranches( + ourBranchName, + theirBranchName, + ourSignature, + NodeGit.Merge.PREFERENCE.NO_FASTFORWARD, + null, + function(message) { + assert(message === "Merge branch 'theirs' into ours"); + return "We manipulated the message, HAH."; + } + ); + }) + .then(function(commitId) { + assert.equal(commitId.toString(), + "5b49a43be0ba95e7767dd9a2880bab4795c6db70"); + }) + .then(function() { + return repository.getStatus(); + }) + .then(function(statuses) { + // make sure we didn't change the index + assert.equal(statuses.length, 0); + }); + } + ); + + it( + "can merge --no-ff a non-fast-forward using the convenience method " + + "with custom merge message via async callback", + function() { + var initialFileName = "initialFile.txt"; + var ourFileName = "ourNewFile.txt"; + var theirFileName = "theirNewFile.txt"; + + var initialFileContent = "I'd like to drive somewhere"; + var ourFileContent = "I like Toll Roads. I have an EZ-Pass!"; + var theirFileContent = "I'm skeptical about Toll Roads"; + + var ourSignature = NodeGit.Signature.create + ("Ron Paul", "RonPaul@TollRoadsRBest.info", 123456789, 60); + var theirSignature = NodeGit.Signature.create + ("Greg Abbott", "Gregggg@IllTollYourFace.us", 123456789, 60); + + var repository = this.repository; + var initialCommit; + var ourCommit; + var theirCommit; + var ourBranch; + var theirBranch; + + return fse.writeFile( + path.join(repository.workdir(), initialFileName), + initialFileContent) + // Load up the repository index and make our initial commit to HEAD + .then(function() { + return repository.refreshIndex(); + }) + .then(function(index) { + return index.addByPath(initialFileName) + .then(function() { + return index.write(); + }) + .then(function() { + return index.writeTree(); + }); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "21a553813e2f670815b649eef51eeadb253a5d0c"); + + return repository.createCommit("HEAD", ourSignature, + ourSignature, "initial commit", oid, []); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "af66a9c799a10a23319ee4318c8bb2021521f539"); + + return repository.getCommit(commitOid).then(function(commit) { + initialCommit = commit; + }).then(function() { + return repository.createBranch(ourBranchName, commitOid) + .then(function(branch) { + ourBranch = branch; + return repository.createBranch(theirBranchName, commitOid); + }); + }); + }) + .then(function(branch) { + theirBranch = branch; + }) + .then(function() { + return fse.writeFile(path.join(repository.workdir(), ourFileName), + ourFileContent); + }) + .then(function() { + return repository.refreshIndex(); + }) + .then(function(index) { + return index.addByPath(ourFileName) + .then(function() { + return index.write(); + }) + .then(function() { + return index.writeTree(); + }); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "af60aa06b3537f75b427f6268a130c842c84a137"); + + return repository.createCommit(ourBranch.name(), ourSignature, + ourSignature, "we made a commit", oid, [initialCommit]); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "7ce31c05427659986d50abfb90c8f7db88ef4fa1"); + + return repository.getCommit(commitOid).then(function(commit) { + ourCommit = commit; + }); + }) + .then(function() { + return fse.writeFile(path.join(repository.workdir(), theirFileName), + theirFileContent); + }) + .then(function() { + return repository.refreshIndex(); + }) + .then(function(index) { + return index.addByPath(theirFileName) + .then(function() { + return index.write(); + }) + .then(function() { + return index.writeTree(); + }); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "f007361737a2ca00a0e80fc2daf55064463173b4"); + + return repository.createCommit(theirBranch.name(), theirSignature, + theirSignature, "they made a commit", oid, [initialCommit]); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "b588f0eef1809226f8f7db542940749da15ae1de"); + + return repository.getCommit(commitOid).then(function(commit) { + theirCommit = commit; + }); + }) + .then(function() { + var opts = {checkoutStrategy: NodeGit.Checkout.STRATEGY.FORCE}; + return repository.checkoutBranch(ourBranchName, opts); + }) + .then(function() { + return repository.mergeBranches( + ourBranchName, + theirBranchName, + ourSignature, + NodeGit.Merge.PREFERENCE.NO_FASTFORWARD, + null, + function(message) { + assert(message === "Merge branch 'theirs' into ours"); + return Promise.resolve("We manipulated the message, HAH."); + } + ); + }) + .then(function(commitId) { + assert.equal(commitId.toString(), + "5b49a43be0ba95e7767dd9a2880bab4795c6db70"); + }) + .then(function() { + return repository.getStatus(); + }) + .then(function(statuses) { + // make sure we didn't change the index + assert.equal(statuses.length, 0); + }); + } + ); + it("can merge --ff-only a fast-forward using the convenience method", function() { var ourFileName = "ourNewFile.txt"; @@ -906,7 +1220,7 @@ describe("Merge", function() { }) .then(function(commitId) { assert.equal(commitId.toString(), - "5384feb481d9c29081b3a0c1478fcc24a3953efa"); + "96d6f1d0704eb3ef9121a13348d17c1d672c28aa"); }); }); From 37f34b56455e2449b8a7d57c87e6ac56b2b52101 Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Thu, 9 Feb 2017 09:06:38 -0700 Subject: [PATCH 18/41] limit reference_list to only wrap git_remote_ls --- generate/input/libgit2-supplement.json | 12 ------- generate/templates/manual/remote/ls.cc | 43 ++------------------------ lib/remote.js | 21 +++---------- test/tests/remote.js | 25 +++++++++++++-- 4 files changed, 30 insertions(+), 71 deletions(-) diff --git a/generate/input/libgit2-supplement.json b/generate/input/libgit2-supplement.json index b4e38cc6b..52bb45651 100644 --- a/generate/input/libgit2-supplement.json +++ b/generate/input/libgit2-supplement.json @@ -132,18 +132,6 @@ "name": "out", "type": "std::vector *" }, - { - "name": "callbacks", - "type": "git_remote_callbacks *" - }, - { - "name": "proxy_opts", - "type": "git_proxy_options *" - }, - { - "name": "custom_headers", - "type": "git_strarray *" - }, { "name": "remote", "type": "git_remote *" diff --git a/generate/templates/manual/remote/ls.cc b/generate/templates/manual/remote/ls.cc index defff6f20..561e0f1f1 100644 --- a/generate/templates/manual/remote/ls.cc +++ b/generate/templates/manual/remote/ls.cc @@ -1,16 +1,6 @@ NAN_METHOD(GitRemote::ReferenceList) { - if (info.Length() == 0 || !info[0]->IsObject()) { - return Nan::ThrowError("RemoteCallbacks callbacks is required."); - } - if (info.Length() == 1 || !info[1]->IsObject()) { - return Nan::ThrowError("ProxyOptions proxy_opts is required."); - } - - if (info.Length() == 2 || !(Nan::To(info[2]).FromJust())) { - return Nan::ThrowError("Array, String Object, or string custom_headers is required."); - } - if (info.Length() == 3 || !info[3]->IsFunction()) { + if (info.Length() == 0 || !info[0]->IsFunction()) { return Nan::ThrowError("Callback is required and must be a Function."); } @@ -20,19 +10,10 @@ NAN_METHOD(GitRemote::ReferenceList) baton->error = NULL; baton->out = new std::vector; baton->remote = Nan::ObjectWrap::Unwrap(info.This())->GetValue(); - baton->callbacks = Nan::ObjectWrap::Unwrap(info[0]->ToObject())->GetValue(); - baton->proxy_opts = Nan::ObjectWrap::Unwrap(info[1]->ToObject())->GetValue(); - baton->custom_headers = StrArrayConverter::Convert(info[2]); - Nan::Callback *callback = new Nan::Callback(Local::Cast(info[3])); + Nan::Callback *callback = new Nan::Callback(Local::Cast(info[0])); ReferenceListWorker *worker = new ReferenceListWorker(baton, callback); worker->SaveToPersistent("remote", info.This()); - if (!info[1]->IsUndefined() && !info[0]->IsNull()) - worker->SaveToPersistent("callbacks", info[0]->ToObject()); - if (!info[2]->IsUndefined() && !info[1]->IsNull()) - worker->SaveToPersistent("proxy_opts", info[1]->ToObject()); - if (!info[3]->IsUndefined() && !info[2]->IsNull()) - worker->SaveToPersistent("custom_headers", info[2]->ToObject()); Nan::AsyncQueueWorker(worker); return; } @@ -44,26 +25,9 @@ void GitRemote::ReferenceListWorker::Execute() { LockMaster lockMaster( /*asyncAction: */true, - baton->remote, - baton->callbacks, - baton->proxy_opts, - baton->custom_headers - ); - baton->error_code = git_remote_connect( - baton->remote, - GIT_DIRECTION_FETCH, - baton->callbacks, - baton->proxy_opts, - baton->custom_headers + baton->remote ); - if (baton->error_code != GIT_OK) { - baton->error = git_error_dup(giterr_last()); - delete baton->out; - baton->out = NULL; - return; - } - const git_remote_head **remote_heads; size_t num_remote_heads; baton->error_code = git_remote_ls( @@ -72,7 +36,6 @@ void GitRemote::ReferenceListWorker::Execute() baton->remote ); - git_remote_disconnect(baton->remote); if (baton->error_code != GIT_OK) { baton->error = git_error_dup(giterr_last()); delete baton->out; diff --git a/lib/remote.js b/lib/remote.js index f89dfd65e..517eae55d 100644 --- a/lib/remote.js +++ b/lib/remote.js @@ -9,7 +9,6 @@ var _connect = Remote.prototype.connect; var _download = Remote.prototype.download; var _fetch = Remote.prototype.fetch; var _push = Remote.prototype.push; -var _referenceList = Remote.prototype.referenceList; var _upload = Remote.prototype.upload; /** @@ -39,7 +38,7 @@ Remote.prototype.connect = function( proxyOpts, customHeaders ) { - callbacks = normalizeOptions(callbacks, NodeGit.RemoteCallbacks); + callbacks = normalizeOptions(callbacks || {}, NodeGit.RemoteCallbacks); proxyOpts = normalizeOptions(proxyOpts || {}, NodeGit.ProxyOptions); customHeaders = customHeaders || []; @@ -117,23 +116,11 @@ Remote.prototype.push = function(refSpecs, opts) { * Lists advertised references from a remote * * @async - * @param {RemoteCallbacks} callbacks The callback functions for the connection - * @param {ProxyOptions} proxyOpts Proxy settings - * @param {Array} customHeaders extra HTTP headers to use - * @param {Function} callback - * @return {Promise} + * @return {Promise>} a list of the remote heads currently + * available on the remote for download */ -Remote.prototype.referenceList = function( - callbacks, - proxyOpts, - customHeaders -) { - callbacks = normalizeOptions(callbacks || {}, NodeGit.RemoteCallbacks); - proxyOpts = normalizeOptions(proxyOpts || {}, NodeGit.ProxyOptions); - customHeaders = customHeaders || []; +Remote.prototype.referenceList = Remote.prototype.referenceList; - return _referenceList.call(this, callbacks, proxyOpts, customHeaders); -}; /** * Connects to a remote * diff --git a/test/tests/remote.js b/test/tests/remote.js index 9f796774e..4dddda2b7 100644 --- a/test/tests/remote.js +++ b/test/tests/remote.js @@ -501,9 +501,15 @@ describe("Remote", function() { return this.repository.getRemote("origin") .then(function(remote) { - return remote.referenceList(); + return Promise.all([ + remote, + remote.connect(NodeGit.Enums.DIRECTION.FETCH) + ]); + }) + .then(function([remote]) { + return Promise.all([remote, remote.referenceList()]); }) - .then(function(remoteHeads) { + .then(function([remote, remoteHeads]) { var remoteHeadsBySha = fp.flow([ fp.map(function(remoteHead) { return { @@ -526,6 +532,21 @@ describe("Remote", function() { ), "Expectations for head " + remoteHeadName + " were not met."); }) ])(expectedRemoteHeads); + + return remote.disconnect(); + }); + }); + + it("will error when retrieving reference list if not connected", function() { + return this.repository.getRemote("origin") + .then(function(remote) { + return remote.referenceList(); + }) + .then(function() { + assert.fail("Unconnected remote should have no reference list."); + }) + .catch(function(notConnectedError) { + assert(notConnectedError.message === "this remote has never connected"); }); }); }); From 96e03dc887c6763c3bacc22364a67e9bbec387c5 Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Fri, 10 Feb 2017 10:40:35 -0700 Subject: [PATCH 19/41] end quote comes after the shorthand --- lib/repository.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/repository.js b/lib/repository.js index 995beba94..0c4ac3c7a 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -1435,11 +1435,12 @@ Repository.prototype.mergeBranches = function( "Merge " + mergeDecorator + " '" + - fromBranch.shorthand(); + fromBranch.shorthand() + + "'"; // https://github.com/git/git/blob/master/builtin/fmt-merge-msg.c#L456-L459 if (toBranch.shorthand() !== "master") { - message += "' into " + toBranch.shorthand(); + message += " into " + toBranch.shorthand(); } return Promise.all([oid, processMergeMessageCallback(message)]); From 2452c40389aee55d314c30c4a311bdb72bb6ce17 Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Fri, 27 Jan 2017 14:12:07 -0700 Subject: [PATCH 20/41] Allow waitForResult to be specified --- generate/templates/manual/include/callback_wrapper.h | 12 +++++++++++- generate/templates/partials/field_accessors.cc | 10 +++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/generate/templates/manual/include/callback_wrapper.h b/generate/templates/manual/include/callback_wrapper.h index b23a7bb36..af53250c1 100644 --- a/generate/templates/manual/include/callback_wrapper.h +++ b/generate/templates/manual/include/callback_wrapper.h @@ -14,6 +14,11 @@ class CallbackWrapper { int throttle; // in milliseconds - if > 0, calls to the JS callback will be throttled uint64_t lastCallTime; + // false will trigger the callback and not wait for the callback to finish + // in this case, the underlying libgit2 function will immediately be given + // the default result + bool waitForResult; + public: CallbackWrapper() { jsCallback = NULL; @@ -33,12 +38,17 @@ class CallbackWrapper { return jsCallback; } - void SetCallback(Nan::Callback* callback, int throttle = 0) { + void SetCallback(Nan::Callback* callback, int throttle = 0, bool waitForResult = true) { if(jsCallback) { delete jsCallback; } jsCallback = callback; this->throttle = throttle; + this->waitForResult = waitForResult; + } + + bool ShouldWaitForResult() { + return waitForResult; } bool WillBeThrottled() { diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index f9f9065a0..c66f24b05 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -48,6 +48,7 @@ {% elsif field.isCallbackFunction %} Nan::Callback *callback = NULL; int throttle = {%if field.return.throttle %}{{ field.return.throttle }}{%else%}0{%endif%}; + bool waitForResult = true; if (value->IsFunction()) { callback = new Nan::Callback(value.As()); @@ -59,6 +60,7 @@ Local objectCallback = maybeObjectCallback.ToLocalChecked(); if (objectCallback->IsFunction()) { callback = new Nan::Callback(objectCallback.As()); + Nan::MaybeLocal maybeObjectThrottle = Nan::Get(object, Nan::New("throttle").ToLocalChecked()); if(!maybeObjectThrottle.IsEmpty()) { Local objectThrottle = maybeObjectThrottle.ToLocalChecked(); @@ -66,6 +68,12 @@ throttle = (int)objectThrottle.As()->Value(); } } + + Nan::MaybeLocal maybeObjectWaitForResult = Nan::Get(object, Nan::New("waitForResult").ToLocalChecked()); + if(!maybeObjectWaitForResult.IsEmpty()) { + Local objectWaitForResult = maybeObjectWaitForResult.ToLocalChecked(); + waitForResult = (bool)objectWaitForResult->BooleanValue(); + } } } } @@ -74,7 +82,7 @@ wrapper->raw->{{ field.name }} = ({{ field.cType }}){{ field.name }}_cppCallback; } - wrapper->{{ field.name }}.SetCallback(callback, throttle); + wrapper->{{ field.name }}.SetCallback(callback, throttle, waitForResult); } {% elsif field.payloadFor %} From 629d45c7d4eebcac80c6e2c7051288ff6b060d43 Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Mon, 30 Jan 2017 17:02:47 -0700 Subject: [PATCH 21/41] Return defaultResult when not waiting for callback result --- .../templates/manual/include/async_baton.h | 31 +++++++++++++------ generate/templates/manual/src/async_baton.cc | 5 +++ .../templates/partials/field_accessors.cc | 21 +++++++++---- generate/templates/templates/binding.gyp | 1 + test/tests/clone.js | 31 +++++++++++++++++++ 5 files changed, 73 insertions(+), 16 deletions(-) create mode 100644 generate/templates/manual/src/async_baton.cc diff --git a/generate/templates/manual/include/async_baton.h b/generate/templates/manual/include/async_baton.h index cfae13b31..5f6874102 100644 --- a/generate/templates/manual/include/async_baton.h +++ b/generate/templates/manual/include/async_baton.h @@ -12,37 +12,48 @@ // or field properties of configuration objects whose values are callbacks) struct AsyncBaton { uv_sem_t semaphore; + + virtual ~AsyncBaton() {} }; +void deleteBaton(AsyncBaton *baton); + template struct AsyncBatonWithResult : public AsyncBaton { ResultT result; ResultT defaultResult; // result returned if the callback doesn't return anything valid + void (*onCompletion)(AsyncBaton *); AsyncBatonWithResult(const ResultT &defaultResult) : defaultResult(defaultResult) { - uv_sem_init(&semaphore, 0); - } - - ~AsyncBatonWithResult() { - uv_sem_destroy(&semaphore); } void Done() { - // signal completion - uv_sem_post(&semaphore); + if (onCompletion) { + onCompletion(this); + } else { + // signal completion + uv_sem_post(&semaphore); + } } - ResultT ExecuteAsync(ThreadPool::Callback asyncCallback) { + ResultT ExecuteAsync(ThreadPool::Callback asyncCallback, void (*onCompletion)(AsyncBaton *) = NULL) { result = 0; + this->onCompletion = onCompletion; + if (!onCompletion) { + uv_sem_init(&semaphore, 0); + } { LockMaster::TemporaryUnlock temporaryUnlock; libgit2ThreadPool.ExecuteReverseCallback(asyncCallback, this); - // wait for completion - uv_sem_wait(&semaphore); + if (!onCompletion) { + // wait for completion + uv_sem_wait(&semaphore); + uv_sem_destroy(&semaphore); + } } return result; diff --git a/generate/templates/manual/src/async_baton.cc b/generate/templates/manual/src/async_baton.cc new file mode 100644 index 000000000..590a19c62 --- /dev/null +++ b/generate/templates/manual/src/async_baton.cc @@ -0,0 +1,5 @@ +#include "../include/async_baton.h" + +void deleteBaton(AsyncBaton *baton) { + delete baton; +} diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index c66f24b05..ab93414ed 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -119,19 +119,28 @@ {{ arg.cType }} {{ arg.name}}{% if not arg.lastArg %},{% endif %} {% endeach %} ) { - {{ field.name|titleCase }}Baton baton({{ field.return.noResults }}); + {{ field.name|titleCase }}Baton *baton = + new {{ field.name|titleCase }}Baton({{ field.return.noResults }}); {% each field.args|argsInfo as arg %} - baton.{{ arg.name }} = {{ arg.name }}; + baton->{{ arg.name }} = {{ arg.name }}; {% endeach %} - {{ cppClassName }}* instance = {{ field.name }}_getInstanceFromBaton(&baton); + {{ cppClassName }}* instance = {{ field.name }}_getInstanceFromBaton(baton); + + {{ field.return.type }} result; if (instance->{{ field.name }}.WillBeThrottled()) { - return baton.defaultResult; + 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 baton.ExecuteAsync({{ field.name }}_async); + return result; } void {{ cppClassName }}::{{ field.name }}_async(void *untypedBaton) { diff --git a/generate/templates/templates/binding.gyp b/generate/templates/templates/binding.gyp index ece88cd15..10b9b456a 100644 --- a/generate/templates/templates/binding.gyp +++ b/generate/templates/templates/binding.gyp @@ -12,6 +12,7 @@ }, "sources": [ + "src/async_baton.cc", "src/lock_master.cc", "src/nodegit.cc", "src/init_ssh2.cc", diff --git a/test/tests/clone.js b/test/tests/clone.js index c7645357d..48205d03d 100644 --- a/test/tests/clone.js +++ b/test/tests/clone.js @@ -166,6 +166,37 @@ describe("Clone", function() { }); }); + it("can clone without waiting for callback results", function() { + var test = this; + var url = "https://github.com/nodegit/test.git"; + var lastReceivedObjects = 0; + var cloneFinished = false; + var opts = { + fetchOpts: { + callbacks: { + transferProgress: { + waitForResult: false, + callback: function(progress) { + var receivedObjects = progress.receivedObjects(); + assert.false( + cloneFinished, + "callback running after clone completion" + ); + assert.gt(receivedObjects, lastReceivedObjects); + lastReceivedObjects = receivedObjects; + } + } + } + } + }; + + return Clone(url, clonePath, opts).then(function(repo) { + assert.ok(repo instanceof Repository); + cloneFinished = true; + test.repository = repo; + }); + }); + it("can clone using nested function", function() { var test = this; var url = "https://github.com/nodegit/test.git"; From 921bf457ac90e935a135350648ac20e54d44db6f Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Mon, 13 Feb 2017 12:12:08 -0700 Subject: [PATCH 22/41] Combine loop callbacks into a single queue --- .../templates/manual/include/thread_pool.h | 31 ++--- generate/templates/manual/src/thread_pool.cc | 112 +++++++----------- 2 files changed, 57 insertions(+), 86 deletions(-) diff --git a/generate/templates/manual/include/thread_pool.h b/generate/templates/manual/include/thread_pool.h index a1eeabbfd..8a346028d 100644 --- a/generate/templates/manual/include/thread_pool.h +++ b/generate/templates/manual/include/thread_pool.h @@ -19,12 +19,13 @@ class ThreadPool { } }; - struct ReverseCall { - Callback reverseCallback; + struct LoopCallback { + Callback callback; void *data; + bool isWork; - ReverseCall(Callback reverseCallback, void *data) - : reverseCallback(reverseCallback), data(data) { + LoopCallback(Callback callback, void *data, bool isWork) + : callback(callback), data(data), isWork(isWork) { } }; @@ -34,22 +35,17 @@ class ThreadPool { uv_sem_t workSemaphore; int workInProgressCount; - // completion callbacks to be performed on the loop - std::queue completionQueue; - uv_mutex_t completionMutex; - uv_async_t completionAsync; - - // async callback made from the threadpool, executed in the loop - std::queue reverseQueue; - uv_mutex_t reverseMutex; - uv_async_t reverseAsync; + // completion and async callbacks to be performed on the loop + std::queue loopQueue; + uv_mutex_t loopMutex; + uv_async_t loopAsync; static void RunEventQueue(void *threadPool); void RunEventQueue(); - static void RunCompletionCallbacks(uv_async_t* handle); - void RunCompletionCallbacks(); - static void RunReverseCallbacks(uv_async_t *handle); - void RunReverseCallbacks(); + static void RunLoopCallbacks(uv_async_t* handle); + void RunLoopCallbacks(); + + void QueueLoopCallback(Callback callback, void *data, bool isWork); public: // Initializes thread pool and spins up the requested number of threads @@ -61,7 +57,6 @@ class ThreadPool { // QueueWork should be called on the loop provided in the constructor. void QueueWork(Callback workCallback, Callback completionCallback, void *data); // Queues a callback on the loop provided in the constructor - // these block the calling thread's execution until the callback completes void ExecuteReverseCallback(Callback reverseCallback, void *data); }; diff --git a/generate/templates/manual/src/thread_pool.cc b/generate/templates/manual/src/thread_pool.cc index d8bedc96e..7eadf0421 100644 --- a/generate/templates/manual/src/thread_pool.cc +++ b/generate/templates/manual/src/thread_pool.cc @@ -4,15 +4,10 @@ ThreadPool::ThreadPool(int numberOfThreads, uv_loop_t *loop) { uv_mutex_init(&workMutex); uv_sem_init(&workSemaphore, 0); - uv_async_init(loop, &completionAsync, RunCompletionCallbacks); - completionAsync.data = this; - uv_unref((uv_handle_t *)&completionAsync); - uv_mutex_init(&completionMutex); - - uv_async_init(loop, &reverseAsync, RunReverseCallbacks); - reverseAsync.data = this; - uv_unref((uv_handle_t *)&reverseAsync); - uv_mutex_init(&reverseMutex); + uv_async_init(loop, &loopAsync, RunLoopCallbacks); + loopAsync.data = this; + uv_unref((uv_handle_t *)&loopAsync); + uv_mutex_init(&loopMutex); workInProgressCount = 0; @@ -26,25 +21,29 @@ void ThreadPool::QueueWork(Callback workCallback, Callback completionCallback, v uv_mutex_lock(&workMutex); // there is work on the thread pool - reference the handle so // node doesn't terminate - uv_ref((uv_handle_t *)&completionAsync); + uv_ref((uv_handle_t *)&loopAsync); workQueue.push(Work(workCallback, completionCallback, data)); workInProgressCount++; uv_mutex_unlock(&workMutex); uv_sem_post(&workSemaphore); } -void ThreadPool::ExecuteReverseCallback(Callback reverseCallback, void *data) { +void ThreadPool::QueueLoopCallback(Callback callback, void *data, bool isWork) { // push the callback into the queue - uv_mutex_lock(&reverseMutex); - ReverseCall reverseCall(reverseCallback, data); - bool queueWasEmpty = reverseQueue.empty(); - reverseQueue.push(reverseCall); - // we only trigger RunReverseCallbacks via the reverseAsync handle if the queue - // was empty. Otherwise, we depend on RunReverseCallbacks to re-trigger itself + uv_mutex_lock(&loopMutex); + LoopCallback loopCallback(callback, data, isWork); + bool queueWasEmpty = loopQueue.empty(); + loopQueue.push(loopCallback); + // we only trigger RunLoopCallbacks via the loopAsync handle if the queue + // was empty. Otherwise, we depend on RunLoopCallbacks to re-trigger itself if (queueWasEmpty) { - uv_async_send(&reverseAsync); + uv_async_send(&loopAsync); } - uv_mutex_unlock(&reverseMutex); + uv_mutex_unlock(&loopMutex); +} + +void ThreadPool::ExecuteReverseCallback(Callback reverseCallback, void *data) { + QueueLoopCallback(reverseCallback, data, false); } void ThreadPool::RunEventQueue(void *threadPool) { @@ -64,63 +63,40 @@ void ThreadPool::RunEventQueue() { // perform the queued work (*work.workCallback)(work.data); - // schedule the callback on the loop - uv_mutex_lock(&completionMutex); - completionQueue.push(work); - uv_mutex_unlock(&completionMutex); - uv_async_send(&completionAsync); + // schedule the completion callback on the loop + QueueLoopCallback(work.completionCallback, work.data, true); } } -void ThreadPool::RunCompletionCallbacks(uv_async_t* handle) { - static_cast(handle->data)->RunCompletionCallbacks(); +void ThreadPool::RunLoopCallbacks(uv_async_t* handle) { + static_cast(handle->data)->RunLoopCallbacks(); } -void ThreadPool::RunCompletionCallbacks() { - // uv_async_send can coalesce calls, so we are not guaranteed one - // RunCompletionCallbacks per uv_async_send call - // so we always process the entire completionQueue - int callbacksCompleted = 0; - uv_mutex_lock(&completionMutex); - while(!completionQueue.empty()) { - Work work = completionQueue.front(); - completionQueue.pop(); - uv_mutex_unlock(&completionMutex); - // perform the queued loop callback - (*work.completionCallback)(work.data); - callbacksCompleted++; - uv_mutex_lock(&completionMutex); +void ThreadPool::RunLoopCallbacks() { + // get the next callback to run + uv_mutex_lock(&loopMutex); + LoopCallback loopCallback = loopQueue.front(); + uv_mutex_unlock(&loopMutex); + + // perform the queued loop callback + (*loopCallback.callback)(loopCallback.data); + + // pop the queue, and if necessary, re-trigger RunLoopCallbacks + uv_mutex_lock(&loopMutex); + loopQueue.pop(); + if (!loopQueue.empty()) { + uv_async_send(&loopAsync); } - uv_mutex_unlock(&completionMutex); + uv_mutex_unlock(&loopMutex); - uv_mutex_lock(&workMutex); // if there is no ongoing work / completion processing, node doesn't need // to be prevented from terminating - workInProgressCount -= callbacksCompleted; - if(!workInProgressCount) { - uv_unref((uv_handle_t *)&completionAsync); - } - uv_mutex_unlock(&workMutex); -} - -void ThreadPool::RunReverseCallbacks(uv_async_t* handle) { - static_cast(handle->data)->RunReverseCallbacks(); -} - -void ThreadPool::RunReverseCallbacks() { - // get the next callback to run - uv_mutex_lock(&reverseMutex); - ReverseCall reverseCall = reverseQueue.front(); - uv_mutex_unlock(&reverseMutex); - - // execute callback - (*reverseCall.reverseCallback)(reverseCall.data); - - // pop the queue, and if necessary, re-trigger RunReverseCallbacks - uv_mutex_lock(&reverseMutex); - reverseQueue.pop(); - if (!reverseQueue.empty()) { - uv_async_send(&reverseAsync); + if (loopCallback.isWork) { + uv_mutex_lock(&workMutex); + workInProgressCount --; + if(!workInProgressCount) { + uv_unref((uv_handle_t *)&loopAsync); + } + uv_mutex_unlock(&workMutex); } - uv_mutex_unlock(&reverseMutex); } From 8421398296364ef71086fc6570cb87498fc536bb Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Tue, 14 Feb 2017 11:04:05 -0700 Subject: [PATCH 23/41] Bump libgit2 to master + proxy fixes --- vendor/libgit2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/libgit2 b/vendor/libgit2 index 0bf052600..3bc15d010 160000 --- a/vendor/libgit2 +++ b/vendor/libgit2 @@ -1 +1 @@ -Subproject commit 0bf05260089002b8101a0be1f79261b3211b10db +Subproject commit 3bc15d0109004e5eeb668644fb2738ba4ee07864 From 7b3da9766811adf0b5222eeda176e35446d2cc51 Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Tue, 14 Feb 2017 12:27:43 -0700 Subject: [PATCH 24/41] Update libgit2-docs --- generate/input/libgit2-docs.json | 847 ++++++++++++++++++------------- 1 file changed, 483 insertions(+), 364 deletions(-) diff --git a/generate/input/libgit2-docs.json b/generate/input/libgit2-docs.json index 34a478605..48099e8b0 100644 --- a/generate/input/libgit2-docs.json +++ b/generate/input/libgit2-docs.json @@ -172,7 +172,7 @@ "git_libgit2_opts" ], "meta": {}, - "lines": 284 + "lines": 312 }, { "file": "config.h", @@ -241,7 +241,7 @@ "git_describe_result_free" ], "meta": {}, - "lines": 158 + "lines": 161 }, { "file": "diff.h", @@ -423,7 +423,7 @@ "git_merge" ], "meta": {}, - "lines": 578 + "lines": 579 }, { "file": "message.h", @@ -556,7 +556,7 @@ "git_oid_shorten_free" ], "meta": {}, - "lines": 265 + "lines": 264 }, { "file": "oidarray.h", @@ -754,7 +754,6 @@ { "file": "remote.h", "functions": [ - "git_remote_rename_problem_cb", "git_remote_create", "git_remote_create_with_fetchspec", "git_remote_create_anonymous", @@ -993,7 +992,7 @@ "git_submodule_location" ], "meta": {}, - "lines": 641 + "lines": 632 }, { "file": "sys/commit.h", @@ -1123,10 +1122,12 @@ "git_repository_set_odb", "git_repository_set_refdb", "git_repository_set_index", - "git_repository_set_bare" + "git_repository_set_bare", + "git_repository_submodule_cache_all", + "git_repository_submodule_cache_clear" ], "meta": {}, - "lines": 136 + "lines": 165 }, { "file": "sys/stream.h", @@ -1250,13 +1251,14 @@ "git_treebuilder_filter_cb", "git_treebuilder_filter", "git_treebuilder_write", + "git_treebuilder_write_with_buffer", "git_treewalk_cb", "git_tree_walk", "git_tree_dup", "git_tree_create_updated" ], "meta": {}, - "lines": 465 + "lines": 478 }, { "file": "types.h", @@ -1974,6 +1976,9 @@ "examples": { "blame.c": [ "ex/HEAD/blame.html#git_blob_free-5" + ], + "general.c": [ + "ex/HEAD/general.html#git_blob_free-2" ] } }, @@ -2050,7 +2055,7 @@ "ex/HEAD/cat-file.html#git_blob_rawcontent-1" ], "general.c": [ - "ex/HEAD/general.html#git_blob_rawcontent-2" + "ex/HEAD/general.html#git_blob_rawcontent-3" ] } }, @@ -2083,8 +2088,8 @@ "ex/HEAD/cat-file.html#git_blob_rawsize-2" ], "general.c": [ - "ex/HEAD/general.html#git_blob_rawsize-3", - "ex/HEAD/general.html#git_blob_rawsize-4" + "ex/HEAD/general.html#git_blob_rawsize-4", + "ex/HEAD/general.html#git_blob_rawsize-5" ] } }, @@ -3165,9 +3170,9 @@ "group": "commit", "examples": { "general.c": [ - "ex/HEAD/general.html#git_commit_lookup-5", "ex/HEAD/general.html#git_commit_lookup-6", - "ex/HEAD/general.html#git_commit_lookup-7" + "ex/HEAD/general.html#git_commit_lookup-7", + "ex/HEAD/general.html#git_commit_lookup-8" ], "log.c": [ "ex/HEAD/log.html#git_commit_lookup-1" @@ -3234,10 +3239,11 @@ "group": "commit", "examples": { "general.c": [ - "ex/HEAD/general.html#git_commit_free-8", "ex/HEAD/general.html#git_commit_free-9", "ex/HEAD/general.html#git_commit_free-10", - "ex/HEAD/general.html#git_commit_free-11" + "ex/HEAD/general.html#git_commit_free-11", + "ex/HEAD/general.html#git_commit_free-12", + "ex/HEAD/general.html#git_commit_free-13" ], "log.c": [ "ex/HEAD/log.html#git_commit_free-2", @@ -3270,7 +3276,7 @@ "group": "commit", "examples": { "general.c": [ - "ex/HEAD/general.html#git_commit_id-12" + "ex/HEAD/general.html#git_commit_id-14" ], "log.c": [ "ex/HEAD/log.html#git_commit_id-6" @@ -3354,9 +3360,9 @@ "ex/HEAD/cat-file.html#git_commit_message-4" ], "general.c": [ - "ex/HEAD/general.html#git_commit_message-13", - "ex/HEAD/general.html#git_commit_message-14", - "ex/HEAD/general.html#git_commit_message-15" + "ex/HEAD/general.html#git_commit_message-15", + "ex/HEAD/general.html#git_commit_message-16", + "ex/HEAD/general.html#git_commit_message-17" ], "log.c": [ "ex/HEAD/log.html#git_commit_message-9", @@ -3456,8 +3462,8 @@ "group": "commit", "examples": { "general.c": [ - "ex/HEAD/general.html#git_commit_time-16", - "ex/HEAD/general.html#git_commit_time-17" + "ex/HEAD/general.html#git_commit_time-18", + "ex/HEAD/general.html#git_commit_time-19" ] } }, @@ -3509,7 +3515,7 @@ "ex/HEAD/cat-file.html#git_commit_committer-5" ], "general.c": [ - "ex/HEAD/general.html#git_commit_committer-18" + "ex/HEAD/general.html#git_commit_committer-20" ], "log.c": [ "ex/HEAD/log.html#git_commit_committer-11" @@ -3542,8 +3548,8 @@ "ex/HEAD/cat-file.html#git_commit_author-6" ], "general.c": [ - "ex/HEAD/general.html#git_commit_author-19", - "ex/HEAD/general.html#git_commit_author-20" + "ex/HEAD/general.html#git_commit_author-21", + "ex/HEAD/general.html#git_commit_author-22" ], "log.c": [ "ex/HEAD/log.html#git_commit_author-12", @@ -3662,7 +3668,7 @@ "ex/HEAD/cat-file.html#git_commit_parentcount-8" ], "general.c": [ - "ex/HEAD/general.html#git_commit_parentcount-21" + "ex/HEAD/general.html#git_commit_parentcount-23" ], "log.c": [ "ex/HEAD/log.html#git_commit_parentcount-19", @@ -3703,7 +3709,7 @@ "group": "commit", "examples": { "general.c": [ - "ex/HEAD/general.html#git_commit_parent-22" + "ex/HEAD/general.html#git_commit_parent-24" ], "log.c": [ "ex/HEAD/log.html#git_commit_parent-21", @@ -3982,7 +3988,7 @@ "group": "commit", "examples": { "general.c": [ - "ex/HEAD/general.html#git_commit_create_v-23" + "ex/HEAD/general.html#git_commit_create_v-25" ], "init.c": [ "ex/HEAD/init.html#git_commit_create_v-1" @@ -4212,8 +4218,8 @@ "git_libgit2_features": { "type": "function", "file": "common.h", - "line": 136, - "lineto": 136, + "line": 154, + "lineto": 154, "args": [], "argline": "", "sig": "", @@ -4228,8 +4234,8 @@ "git_libgit2_opts": { "type": "function", "file": "common.h", - "line": 284, - "lineto": 284, + "line": 312, + "lineto": 312, "args": [ { "name": "option", @@ -4244,7 +4250,7 @@ "comment": " 0 on success, \n<\n0 on failure" }, "description": "

Set or query a library global option

\n", - "comments": "

Available options:

\n\n
* opts(GIT_OPT_GET_MWINDOW_SIZE, size_t *):\n\n    > Get the maximum mmap window size\n\n* opts(GIT_OPT_SET_MWINDOW_SIZE, size_t):\n\n    > Set the maximum mmap window size\n\n* opts(GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, size_t *):\n\n    > Get the maximum memory that will be mapped in total by the library\n\n* opts(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, size_t):\n\n    >Set the maximum amount of memory that can be mapped at any time        by the library\n\n* opts(GIT_OPT_GET_SEARCH_PATH, int level, git_buf *buf)\n\n    > Get the search path for a given level of config data.  "level" must       > be one of `GIT_CONFIG_LEVEL_SYSTEM`, `GIT_CONFIG_LEVEL_GLOBAL`,       > `GIT_CONFIG_LEVEL_XDG`, or `GIT_CONFIG_LEVEL_PROGRAMDATA`.        > The search path is written to the `out` buffer.\n\n* opts(GIT_OPT_SET_SEARCH_PATH, int level, const char *path)\n\n    > Set the search path for a level of config data.  The search path      > applied to shared attributes and ignore files, too.       >       > - `path` lists directories delimited by GIT_PATH_LIST_SEPARATOR.      >   Pass NULL to reset to the default (generally based on environment       >   variables).  Use magic path `$PATH` to include the old value        >   of the path (if you want to prepend or append, for instance).       >       > - `level` must be `GIT_CONFIG_LEVEL_SYSTEM`,      >   `GIT_CONFIG_LEVEL_GLOBAL`, `GIT_CONFIG_LEVEL_XDG`, or       >   `GIT_CONFIG_LEVEL_PROGRAMDATA`.\n\n* opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, git_otype type, size_t size)\n\n    > Set the maximum data size for the given type of object to be      > considered eligible for caching in memory.  Setting to value to       > zero means that that type of object will not be cached.       > Defaults to 0 for GIT_OBJ_BLOB (i.e. won't cache blobs) and 4k        > for GIT_OBJ_COMMIT, GIT_OBJ_TREE, and GIT_OBJ_TAG.\n\n* opts(GIT_OPT_SET_CACHE_MAX_SIZE, ssize_t max_storage_bytes)\n\n    > Set the maximum total data size that will be cached in memory     > across all repositories before libgit2 starts evicting objects        > from the cache.  This is a soft limit, in that the library might      > briefly exceed it, but will start aggressively evicting objects       > from cache when that happens.  The default cache size is 256MB.\n\n* opts(GIT_OPT_ENABLE_CACHING, int enabled)\n\n    > Enable or disable caching completely.     >       > Because caches are repository-specific, disabling the cache       > cannot immediately clear all cached objects, but each cache will      > be cleared on the next attempt to update anything in it.\n\n* opts(GIT_OPT_GET_CACHED_MEMORY, ssize_t *current, ssize_t *allowed)\n\n    > Get the current bytes in cache and the maximum that would be      > allowed in the cache.\n\n* opts(GIT_OPT_GET_TEMPLATE_PATH, git_buf *out)\n\n    > Get the default template path.        > The path is written to the `out` buffer.\n\n* opts(GIT_OPT_SET_TEMPLATE_PATH, const char *path)\n\n    > Set the default template path.        >       > - `path` directory of template.\n\n* opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, const char *file, const char *path)\n\n    > Set the SSL certificate-authority locations.      >       > - `file` is the location of a file containing several     >   certificates concatenated together.     > - `path` is the location of a directory holding several       >   certificates, one per file.     >       > Either parameter may be `NULL`, but not both.\n\n* opts(GIT_OPT_SET_USER_AGENT, const char *user_agent)\n\n    > Set the value of the User-Agent header.  This value will be       > appended to "git/1.0", for compatibility with other git clients.      >       > - `user_agent` is the value that will be delivered as the     >   User-Agent header on HTTP requests.\n\n* opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, int enabled)\n\n    > Enable strict input validation when creating new objects      > to ensure that all inputs to the new objects are valid.  For      > example, when this is enabled, the parent(s) and tree inputs      > will be validated when creating a new commit.  This defaults      > to enabled.\n\n* opts(GIT_OPT_SET_SSL_CIPHERS, const char *ciphers)\n\n    > Set the SSL ciphers use for HTTPS connections.        >       > - `ciphers` is the list of ciphers that are eanbled.\n
\n", + "comments": "

Available options:

\n\n
* opts(GIT_OPT_GET_MWINDOW_SIZE, size_t *):\n\n    > Get the maximum mmap window size\n\n* opts(GIT_OPT_SET_MWINDOW_SIZE, size_t):\n\n    > Set the maximum mmap window size\n\n* opts(GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, size_t *):\n\n    > Get the maximum memory that will be mapped in total by the library\n\n* opts(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, size_t):\n\n    >Set the maximum amount of memory that can be mapped at any time        by the library\n\n* opts(GIT_OPT_GET_SEARCH_PATH, int level, git_buf *buf)\n\n    > Get the search path for a given level of config data.  "level" must       > be one of `GIT_CONFIG_LEVEL_SYSTEM`, `GIT_CONFIG_LEVEL_GLOBAL`,       > `GIT_CONFIG_LEVEL_XDG`, or `GIT_CONFIG_LEVEL_PROGRAMDATA`.        > The search path is written to the `out` buffer.\n\n* opts(GIT_OPT_SET_SEARCH_PATH, int level, const char *path)\n\n    > Set the search path for a level of config data.  The search path      > applied to shared attributes and ignore files, too.       >       > - `path` lists directories delimited by GIT_PATH_LIST_SEPARATOR.      >   Pass NULL to reset to the default (generally based on environment       >   variables).  Use magic path `$PATH` to include the old value        >   of the path (if you want to prepend or append, for instance).       >       > - `level` must be `GIT_CONFIG_LEVEL_SYSTEM`,      >   `GIT_CONFIG_LEVEL_GLOBAL`, `GIT_CONFIG_LEVEL_XDG`, or       >   `GIT_CONFIG_LEVEL_PROGRAMDATA`.\n\n* opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, git_otype type, size_t size)\n\n    > Set the maximum data size for the given type of object to be      > considered eligible for caching in memory.  Setting to value to       > zero means that that type of object will not be cached.       > Defaults to 0 for GIT_OBJ_BLOB (i.e. won't cache blobs) and 4k        > for GIT_OBJ_COMMIT, GIT_OBJ_TREE, and GIT_OBJ_TAG.\n\n* opts(GIT_OPT_SET_CACHE_MAX_SIZE, ssize_t max_storage_bytes)\n\n    > Set the maximum total data size that will be cached in memory     > across all repositories before libgit2 starts evicting objects        > from the cache.  This is a soft limit, in that the library might      > briefly exceed it, but will start aggressively evicting objects       > from cache when that happens.  The default cache size is 256MB.\n\n* opts(GIT_OPT_ENABLE_CACHING, int enabled)\n\n    > Enable or disable caching completely.     >       > Because caches are repository-specific, disabling the cache       > cannot immediately clear all cached objects, but each cache will      > be cleared on the next attempt to update anything in it.\n\n* opts(GIT_OPT_GET_CACHED_MEMORY, ssize_t *current, ssize_t *allowed)\n\n    > Get the current bytes in cache and the maximum that would be      > allowed in the cache.\n\n* opts(GIT_OPT_GET_TEMPLATE_PATH, git_buf *out)\n\n    > Get the default template path.        > The path is written to the `out` buffer.\n\n* opts(GIT_OPT_SET_TEMPLATE_PATH, const char *path)\n\n    > Set the default template path.        >       > - `path` directory of template.\n\n* opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, const char *file, const char *path)\n\n    > Set the SSL certificate-authority locations.      >       > - `file` is the location of a file containing several     >   certificates concatenated together.     > - `path` is the location of a directory holding several       >   certificates, one per file.     >       > Either parameter may be `NULL`, but not both.\n\n* opts(GIT_OPT_SET_USER_AGENT, const char *user_agent)\n\n    > Set the value of the User-Agent header.  This value will be       > appended to "git/1.0", for compatibility with other git clients.      >       > - `user_agent` is the value that will be delivered as the     >   User-Agent header on HTTP requests.\n\n* opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, int enabled)\n\n    > Enable strict input validation when creating new objects      > to ensure that all inputs to the new objects are valid.  For      > example, when this is enabled, the parent(s) and tree inputs      > will be validated when creating a new commit.  This defaults      > to enabled.\n\n* opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, int enabled)\n\n    > Validate the target of a symbolic ref when creating it.  For      > example, `foobar` is not a valid ref, therefore `foobar` is       > not a valid target for a symbolic ref by default, whereas     > `refs/heads/foobar` is.  Disabling this bypasses validation       > so that an arbitrary strings such as `foobar` can be used     > for a symbolic ref target.  This defaults to enabled.\n\n* opts(GIT_OPT_SET_SSL_CIPHERS, const char *ciphers)\n\n    > Set the SSL ciphers use for HTTPS connections.        >       > - `ciphers` is the list of ciphers that are eanbled.\n
\n", "group": "libgit2" }, "git_config_entry_free": { @@ -4466,7 +4472,7 @@ "group": "config", "examples": { "general.c": [ - "ex/HEAD/general.html#git_config_open_ondisk-24" + "ex/HEAD/general.html#git_config_open_ondisk-26" ] } }, @@ -4576,7 +4582,13 @@ }, "description": "

Free the configuration and its associated memory and files

\n", "comments": "", - "group": "config" + "group": "config", + "examples": { + "general.c": [ + "ex/HEAD/general.html#git_config_free-27", + "ex/HEAD/general.html#git_config_free-28" + ] + } }, "git_config_get_entry": { "type": "function", @@ -4643,7 +4655,7 @@ "group": "config", "examples": { "general.c": [ - "ex/HEAD/general.html#git_config_get_int32-25" + "ex/HEAD/general.html#git_config_get_int32-29" ] } }, @@ -4776,7 +4788,7 @@ "group": "config", "examples": { "general.c": [ - "ex/HEAD/general.html#git_config_get_string-26" + "ex/HEAD/general.html#git_config_get_string-30" ] } }, @@ -5588,8 +5600,8 @@ "git_describe_commit": { "type": "function", "file": "describe.h", - "line": 120, - "lineto": 123, + "line": 123, + "lineto": 126, "args": [ { "name": "result", @@ -5625,8 +5637,8 @@ "git_describe_workdir": { "type": "function", "file": "describe.h", - "line": 137, - "lineto": 140, + "line": 140, + "lineto": 143, "args": [ { "name": "out", @@ -5662,8 +5674,8 @@ "git_describe_format": { "type": "function", "file": "describe.h", - "line": 150, - "lineto": 153, + "line": 153, + "lineto": 156, "args": [ { "name": "out", @@ -5699,8 +5711,8 @@ "git_describe_result_free": { "type": "function", "file": "describe.h", - "line": 158, - "lineto": 158, + "line": 161, + "lineto": 161, "args": [ { "name": "result", @@ -6920,7 +6932,7 @@ "group": "giterr", "examples": { "general.c": [ - "ex/HEAD/general.html#giterr_last-27" + "ex/HEAD/general.html#giterr_last-31" ], "network/clone.c": [ "ex/HEAD/network/clone.html#giterr_last-2" @@ -7317,7 +7329,7 @@ "ex/HEAD/diff.html#git_libgit2_init-13" ], "general.c": [ - "ex/HEAD/general.html#git_libgit2_init-28" + "ex/HEAD/general.html#git_libgit2_init-32" ], "init.c": [ "ex/HEAD/init.html#git_libgit2_init-2" @@ -7620,7 +7632,7 @@ "group": "index", "examples": { "general.c": [ - "ex/HEAD/general.html#git_index_free-29" + "ex/HEAD/general.html#git_index_free-33" ], "init.c": [ "ex/HEAD/init.html#git_index_free-4" @@ -7954,7 +7966,7 @@ "group": "index", "examples": { "general.c": [ - "ex/HEAD/general.html#git_index_entrycount-30" + "ex/HEAD/general.html#git_index_entrycount-34" ] } }, @@ -8008,7 +8020,7 @@ "group": "index", "examples": { "general.c": [ - "ex/HEAD/general.html#git_index_get_byindex-31" + "ex/HEAD/general.html#git_index_get_byindex-35" ] } }, @@ -8923,8 +8935,8 @@ "git_merge_init_options": { "type": "function", "file": "merge.h", - "line": 304, - "lineto": 306, + "line": 305, + "lineto": 307, "args": [ { "name": "opts", @@ -8950,8 +8962,8 @@ "git_merge_analysis": { "type": "function", "file": "merge.h", - "line": 375, - "lineto": 380, + "line": 376, + "lineto": 381, "args": [ { "name": "analysis_out", @@ -8992,8 +9004,8 @@ "git_merge_base": { "type": "function", "file": "merge.h", - "line": 391, - "lineto": 395, + "line": 392, + "lineto": 396, "args": [ { "name": "out", @@ -9037,8 +9049,8 @@ "git_merge_bases": { "type": "function", "file": "merge.h", - "line": 406, - "lineto": 410, + "line": 407, + "lineto": 411, "args": [ { "name": "out", @@ -9074,8 +9086,8 @@ "git_merge_base_many": { "type": "function", "file": "merge.h", - "line": 421, - "lineto": 425, + "line": 422, + "lineto": 426, "args": [ { "name": "out", @@ -9111,8 +9123,8 @@ "git_merge_bases_many": { "type": "function", "file": "merge.h", - "line": 436, - "lineto": 440, + "line": 437, + "lineto": 441, "args": [ { "name": "out", @@ -9148,8 +9160,8 @@ "git_merge_base_octopus": { "type": "function", "file": "merge.h", - "line": 451, - "lineto": 455, + "line": 452, + "lineto": 456, "args": [ { "name": "out", @@ -9185,8 +9197,8 @@ "git_merge_file": { "type": "function", "file": "merge.h", - "line": 473, - "lineto": 478, + "line": 474, + "lineto": 479, "args": [ { "name": "out", @@ -9227,8 +9239,8 @@ "git_merge_file_from_index": { "type": "function", "file": "merge.h", - "line": 494, - "lineto": 500, + "line": 495, + "lineto": 501, "args": [ { "name": "out", @@ -9274,8 +9286,8 @@ "git_merge_file_result_free": { "type": "function", "file": "merge.h", - "line": 507, - "lineto": 507, + "line": 508, + "lineto": 508, "args": [ { "name": "result", @@ -9296,8 +9308,8 @@ "git_merge_trees": { "type": "function", "file": "merge.h", - "line": 525, - "lineto": 531, + "line": 526, + "lineto": 532, "args": [ { "name": "out", @@ -9343,8 +9355,8 @@ "git_merge_commits": { "type": "function", "file": "merge.h", - "line": 548, - "lineto": 553, + "line": 549, + "lineto": 554, "args": [ { "name": "out", @@ -9385,8 +9397,8 @@ "git_merge": { "type": "function", "file": "merge.h", - "line": 573, - "lineto": 578, + "line": 574, + "lineto": 579, "args": [ { "name": "repo", @@ -10116,7 +10128,7 @@ "ex/HEAD/cat-file.html#git_object_free-17" ], "general.c": [ - "ex/HEAD/general.html#git_object_free-32" + "ex/HEAD/general.html#git_object_free-36" ], "log.c": [ "ex/HEAD/log.html#git_object_free-38" @@ -10163,8 +10175,8 @@ "ex/HEAD/cat-file.html#git_object_type2string-21" ], "general.c": [ - "ex/HEAD/general.html#git_object_type2string-33", - "ex/HEAD/general.html#git_object_type2string-34" + "ex/HEAD/general.html#git_object_type2string-37", + "ex/HEAD/general.html#git_object_type2string-38" ] } }, @@ -10393,6 +10405,9 @@ "examples": { "cat-file.c": [ "ex/HEAD/cat-file.html#git_odb_free-22" + ], + "general.c": [ + "ex/HEAD/general.html#git_odb_free-39" ] } }, @@ -10432,7 +10447,7 @@ "ex/HEAD/cat-file.html#git_odb_read-23" ], "general.c": [ - "ex/HEAD/general.html#git_odb_read-35" + "ex/HEAD/general.html#git_odb_read-40" ] } }, @@ -10703,7 +10718,7 @@ "group": "odb", "examples": { "general.c": [ - "ex/HEAD/general.html#git_odb_write-36" + "ex/HEAD/general.html#git_odb_write-41" ] } }, @@ -11048,7 +11063,7 @@ "ex/HEAD/cat-file.html#git_odb_object_free-24" ], "general.c": [ - "ex/HEAD/general.html#git_odb_object_free-37" + "ex/HEAD/general.html#git_odb_object_free-42" ] } }, @@ -11097,7 +11112,7 @@ "group": "odb", "examples": { "general.c": [ - "ex/HEAD/general.html#git_odb_object_data-38" + "ex/HEAD/general.html#git_odb_object_data-43" ] } }, @@ -11127,7 +11142,7 @@ "ex/HEAD/cat-file.html#git_odb_object_size-25" ], "general.c": [ - "ex/HEAD/general.html#git_odb_object_size-39" + "ex/HEAD/general.html#git_odb_object_size-44" ] } }, @@ -11154,7 +11169,7 @@ "group": "odb", "examples": { "general.c": [ - "ex/HEAD/general.html#git_odb_object_type-40" + "ex/HEAD/general.html#git_odb_object_type-45" ] } }, @@ -11405,22 +11420,22 @@ "group": "oid", "examples": { "general.c": [ - "ex/HEAD/general.html#git_oid_fromstr-41", - "ex/HEAD/general.html#git_oid_fromstr-42", - "ex/HEAD/general.html#git_oid_fromstr-43", - "ex/HEAD/general.html#git_oid_fromstr-44", - "ex/HEAD/general.html#git_oid_fromstr-45", "ex/HEAD/general.html#git_oid_fromstr-46", "ex/HEAD/general.html#git_oid_fromstr-47", - "ex/HEAD/general.html#git_oid_fromstr-48" + "ex/HEAD/general.html#git_oid_fromstr-48", + "ex/HEAD/general.html#git_oid_fromstr-49", + "ex/HEAD/general.html#git_oid_fromstr-50", + "ex/HEAD/general.html#git_oid_fromstr-51", + "ex/HEAD/general.html#git_oid_fromstr-52", + "ex/HEAD/general.html#git_oid_fromstr-53" ] } }, "git_oid_fromstrp": { "type": "function", "file": "oid.h", - "line": 57, - "lineto": 57, + "line": 56, + "lineto": 56, "args": [ { "name": "out", @@ -11430,7 +11445,7 @@ { "name": "str", "type": "const char *", - "comment": "input hex string; must be at least 4 characters\n long and null-terminated." + "comment": "input hex string; must be null-terminated." } ], "argline": "git_oid *out, const char *str", @@ -11446,8 +11461,8 @@ "git_oid_fromstrn": { "type": "function", "file": "oid.h", - "line": 70, - "lineto": 70, + "line": 69, + "lineto": 69, "args": [ { "name": "out", @@ -11471,15 +11486,15 @@ "type": "int", "comment": " 0 or an error code" }, - "description": "

Parse N characters of a hex formatted object id into a git_oid

\n", - "comments": "

If N is odd, N-1 characters will be parsed instead. The remaining space in the git_oid will be set to zero.

\n", + "description": "

Parse N characters of a hex formatted object id into a git_oid.

\n", + "comments": "

If N is odd, the last byte's high nibble will be read in and the low nibble set to zero.

\n", "group": "oid" }, "git_oid_fromraw": { "type": "function", "file": "oid.h", - "line": 78, - "lineto": 78, + "line": 77, + "lineto": 77, "args": [ { "name": "out", @@ -11505,8 +11520,8 @@ "git_oid_fmt": { "type": "function", "file": "oid.h", - "line": 90, - "lineto": 90, + "line": 89, + "lineto": 89, "args": [ { "name": "out", @@ -11530,12 +11545,12 @@ "group": "oid", "examples": { "general.c": [ - "ex/HEAD/general.html#git_oid_fmt-49", - "ex/HEAD/general.html#git_oid_fmt-50", - "ex/HEAD/general.html#git_oid_fmt-51", - "ex/HEAD/general.html#git_oid_fmt-52", - "ex/HEAD/general.html#git_oid_fmt-53", - "ex/HEAD/general.html#git_oid_fmt-54" + "ex/HEAD/general.html#git_oid_fmt-54", + "ex/HEAD/general.html#git_oid_fmt-55", + "ex/HEAD/general.html#git_oid_fmt-56", + "ex/HEAD/general.html#git_oid_fmt-57", + "ex/HEAD/general.html#git_oid_fmt-58", + "ex/HEAD/general.html#git_oid_fmt-59" ], "network/fetch.c": [ "ex/HEAD/network/fetch.html#git_oid_fmt-1", @@ -11552,8 +11567,8 @@ "git_oid_nfmt": { "type": "function", "file": "oid.h", - "line": 101, - "lineto": 101, + "line": 100, + "lineto": 100, "args": [ { "name": "out", @@ -11584,8 +11599,8 @@ "git_oid_pathfmt": { "type": "function", "file": "oid.h", - "line": 116, - "lineto": 116, + "line": 115, + "lineto": 115, "args": [ { "name": "out", @@ -11611,8 +11626,8 @@ "git_oid_tostr_s": { "type": "function", "file": "oid.h", - "line": 129, - "lineto": 129, + "line": 128, + "lineto": 128, "args": [ { "name": "oid", @@ -11633,8 +11648,8 @@ "git_oid_tostr": { "type": "function", "file": "oid.h", - "line": 148, - "lineto": 148, + "line": 147, + "lineto": 147, "args": [ { "name": "out", @@ -11688,8 +11703,8 @@ "git_oid_cpy": { "type": "function", "file": "oid.h", - "line": 156, - "lineto": 156, + "line": 155, + "lineto": 155, "args": [ { "name": "out", @@ -11722,8 +11737,8 @@ "git_oid_cmp": { "type": "function", "file": "oid.h", - "line": 165, - "lineto": 165, + "line": 164, + "lineto": 164, "args": [ { "name": "a", @@ -11749,8 +11764,8 @@ "git_oid_equal": { "type": "function", "file": "oid.h", - "line": 174, - "lineto": 174, + "line": 173, + "lineto": 173, "args": [ { "name": "a", @@ -11776,8 +11791,8 @@ "git_oid_ncmp": { "type": "function", "file": "oid.h", - "line": 185, - "lineto": 185, + "line": 184, + "lineto": 184, "args": [ { "name": "a", @@ -11808,8 +11823,8 @@ "git_oid_streq": { "type": "function", "file": "oid.h", - "line": 194, - "lineto": 194, + "line": 193, + "lineto": 193, "args": [ { "name": "id", @@ -11835,8 +11850,8 @@ "git_oid_strcmp": { "type": "function", "file": "oid.h", - "line": 204, - "lineto": 204, + "line": 203, + "lineto": 203, "args": [ { "name": "id", @@ -11862,8 +11877,8 @@ "git_oid_iszero": { "type": "function", "file": "oid.h", - "line": 211, - "lineto": 211, + "line": 210, + "lineto": 210, "args": [ { "name": "id", @@ -11892,8 +11907,8 @@ "git_oid_shorten_new": { "type": "function", "file": "oid.h", - "line": 232, - "lineto": 232, + "line": 231, + "lineto": 231, "args": [ { "name": "min_length", @@ -11914,8 +11929,8 @@ "git_oid_shorten_add": { "type": "function", "file": "oid.h", - "line": 258, - "lineto": 258, + "line": 257, + "lineto": 257, "args": [ { "name": "os", @@ -11941,8 +11956,8 @@ "git_oid_shorten_free": { "type": "function", "file": "oid.h", - "line": 265, - "lineto": 265, + "line": 264, + "lineto": 264, "args": [ { "name": "os", @@ -14102,7 +14117,7 @@ "group": "reference", "examples": { "general.c": [ - "ex/HEAD/general.html#git_reference_lookup-55" + "ex/HEAD/general.html#git_reference_lookup-60" ] } }, @@ -14391,7 +14406,7 @@ "group": "reference", "examples": { "general.c": [ - "ex/HEAD/general.html#git_reference_target-56" + "ex/HEAD/general.html#git_reference_target-61" ] } }, @@ -14440,7 +14455,7 @@ "group": "reference", "examples": { "general.c": [ - "ex/HEAD/general.html#git_reference_symbolic_target-57" + "ex/HEAD/general.html#git_reference_symbolic_target-62" ] } }, @@ -14467,7 +14482,7 @@ "group": "reference", "examples": { "general.c": [ - "ex/HEAD/general.html#git_reference_type-58" + "ex/HEAD/general.html#git_reference_type-63" ] } }, @@ -14735,7 +14750,7 @@ "group": "reference", "examples": { "general.c": [ - "ex/HEAD/general.html#git_reference_list-59" + "ex/HEAD/general.html#git_reference_list-64" ] } }, @@ -14852,6 +14867,9 @@ "comments": "", "group": "reference", "examples": { + "general.c": [ + "ex/HEAD/general.html#git_reference_free-65" + ], "status.c": [ "ex/HEAD/status.html#git_reference_free-3" ] @@ -15547,8 +15565,8 @@ "git_remote_create": { "type": "function", "file": "remote.h", - "line": 40, - "lineto": 44, + "line": 38, + "lineto": 42, "args": [ { "name": "out", @@ -15589,8 +15607,8 @@ "git_remote_create_with_fetchspec": { "type": "function", "file": "remote.h", - "line": 57, - "lineto": 62, + "line": 55, + "lineto": 60, "args": [ { "name": "out", @@ -15631,8 +15649,8 @@ "git_remote_create_anonymous": { "type": "function", "file": "remote.h", - "line": 75, - "lineto": 78, + "line": 73, + "lineto": 76, "args": [ { "name": "out", @@ -15671,8 +15689,8 @@ "git_remote_lookup": { "type": "function", "file": "remote.h", - "line": 91, - "lineto": 91, + "line": 89, + "lineto": 89, "args": [ { "name": "out", @@ -15714,8 +15732,8 @@ "git_remote_dup": { "type": "function", "file": "remote.h", - "line": 103, - "lineto": 103, + "line": 101, + "lineto": 101, "args": [ { "name": "dest", @@ -15741,8 +15759,8 @@ "git_remote_owner": { "type": "function", "file": "remote.h", - "line": 111, - "lineto": 111, + "line": 109, + "lineto": 109, "args": [ { "name": "remote", @@ -15763,8 +15781,8 @@ "git_remote_name": { "type": "function", "file": "remote.h", - "line": 119, - "lineto": 119, + "line": 117, + "lineto": 117, "args": [ { "name": "remote", @@ -15785,8 +15803,8 @@ "git_remote_url": { "type": "function", "file": "remote.h", - "line": 130, - "lineto": 130, + "line": 128, + "lineto": 128, "args": [ { "name": "remote", @@ -15812,8 +15830,8 @@ "git_remote_pushurl": { "type": "function", "file": "remote.h", - "line": 141, - "lineto": 141, + "line": 139, + "lineto": 139, "args": [ { "name": "remote", @@ -15839,8 +15857,8 @@ "git_remote_set_url": { "type": "function", "file": "remote.h", - "line": 154, - "lineto": 154, + "line": 152, + "lineto": 152, "args": [ { "name": "repo", @@ -15876,8 +15894,8 @@ "git_remote_set_pushurl": { "type": "function", "file": "remote.h", - "line": 167, - "lineto": 167, + "line": 165, + "lineto": 165, "args": [ { "name": "repo", @@ -15913,8 +15931,8 @@ "git_remote_add_fetch": { "type": "function", "file": "remote.h", - "line": 180, - "lineto": 180, + "line": 178, + "lineto": 178, "args": [ { "name": "repo", @@ -15945,8 +15963,8 @@ "git_remote_get_fetch_refspecs": { "type": "function", "file": "remote.h", - "line": 191, - "lineto": 191, + "line": 189, + "lineto": 189, "args": [ { "name": "array", @@ -15972,8 +15990,8 @@ "git_remote_add_push": { "type": "function", "file": "remote.h", - "line": 204, - "lineto": 204, + "line": 202, + "lineto": 202, "args": [ { "name": "repo", @@ -16004,8 +16022,8 @@ "git_remote_get_push_refspecs": { "type": "function", "file": "remote.h", - "line": 215, - "lineto": 215, + "line": 213, + "lineto": 213, "args": [ { "name": "array", @@ -16031,8 +16049,8 @@ "git_remote_refspec_count": { "type": "function", "file": "remote.h", - "line": 223, - "lineto": 223, + "line": 221, + "lineto": 221, "args": [ { "name": "remote", @@ -16053,8 +16071,8 @@ "git_remote_get_refspec": { "type": "function", "file": "remote.h", - "line": 232, - "lineto": 232, + "line": 230, + "lineto": 230, "args": [ { "name": "remote", @@ -16080,8 +16098,8 @@ "git_remote_connect": { "type": "function", "file": "remote.h", - "line": 249, - "lineto": 249, + "line": 247, + "lineto": 247, "args": [ { "name": "remote", @@ -16127,8 +16145,8 @@ "git_remote_ls": { "type": "function", "file": "remote.h", - "line": 271, - "lineto": 271, + "line": 269, + "lineto": 269, "args": [ { "name": "out", @@ -16164,8 +16182,8 @@ "git_remote_connected": { "type": "function", "file": "remote.h", - "line": 282, - "lineto": 282, + "line": 280, + "lineto": 280, "args": [ { "name": "remote", @@ -16186,8 +16204,8 @@ "git_remote_stop": { "type": "function", "file": "remote.h", - "line": 292, - "lineto": 292, + "line": 290, + "lineto": 290, "args": [ { "name": "remote", @@ -16208,8 +16226,8 @@ "git_remote_disconnect": { "type": "function", "file": "remote.h", - "line": 301, - "lineto": 301, + "line": 299, + "lineto": 299, "args": [ { "name": "remote", @@ -16230,8 +16248,8 @@ "git_remote_free": { "type": "function", "file": "remote.h", - "line": 311, - "lineto": 311, + "line": 309, + "lineto": 309, "args": [ { "name": "remote", @@ -16264,8 +16282,8 @@ "git_remote_list": { "type": "function", "file": "remote.h", - "line": 322, - "lineto": 322, + "line": 320, + "lineto": 320, "args": [ { "name": "out", @@ -16329,7 +16347,7 @@ { "name": "opts", "type": "git_fetch_options *", - "comment": "the `git_push_options` instance to initialize." + "comment": "the `git_fetch_options` instance to initialize." }, { "name": "version", @@ -16835,7 +16853,7 @@ "group": "repository", "examples": { "general.c": [ - "ex/HEAD/general.html#git_repository_open-60" + "ex/HEAD/general.html#git_repository_open-66" ], "network/git2.c": [ "ex/HEAD/network/git2.html#git_repository_open-5" @@ -17040,7 +17058,7 @@ "ex/HEAD/diff.html#git_repository_free-16" ], "general.c": [ - "ex/HEAD/general.html#git_repository_free-61" + "ex/HEAD/general.html#git_repository_free-67" ], "init.c": [ "ex/HEAD/init.html#git_repository_free-6" @@ -17432,7 +17450,12 @@ }, "description": "

Get a snapshot of the repository's configuration

\n", "comments": "

Convenience function to take a snapshot from the repository's configuration. The contents of this snapshot will not change, even if the underlying config files are modified.

\n\n

The configuration file must be freed once it's no longer being used by the user.

\n", - "group": "repository" + "group": "repository", + "examples": { + "general.c": [ + "ex/HEAD/general.html#git_repository_config_snapshot-68" + ] + } }, "git_repository_odb": { "type": "function", @@ -17465,7 +17488,7 @@ "ex/HEAD/cat-file.html#git_repository_odb-33" ], "general.c": [ - "ex/HEAD/general.html#git_repository_odb-62" + "ex/HEAD/general.html#git_repository_odb-69" ] } }, @@ -17524,7 +17547,7 @@ "group": "repository", "examples": { "general.c": [ - "ex/HEAD/general.html#git_repository_index-63" + "ex/HEAD/general.html#git_repository_index-70" ], "init.c": [ "ex/HEAD/init.html#git_repository_index-11" @@ -17992,7 +18015,7 @@ { "name": "checkout_opts", "type": "const git_checkout_options *", - "comment": "Checkout options to be used for a HARD reset.\n The checkout_strategy field will be overridden (based on reset_type).\n This parameter can be used to propagate notify and progress callbacks." + "comment": "Optional checkout options to be used for a HARD reset.\n The checkout_strategy field will be overridden (based on reset_type).\n This parameter can be used to propagate notify and progress callbacks." } ], "argline": "git_repository *repo, git_object *target, git_reset_t reset_type, const git_checkout_options *checkout_opts", @@ -18167,7 +18190,7 @@ { "name": "given_opts", "type": "const git_revert_options *", - "comment": "merge flags" + "comment": "the revert options (or null for defaults)" } ], "argline": "git_repository *repo, git_commit *commit, const git_revert_options *given_opts", @@ -18341,7 +18364,7 @@ "group": "revwalk", "examples": { "general.c": [ - "ex/HEAD/general.html#git_revwalk_new-64" + "ex/HEAD/general.html#git_revwalk_new-71" ], "log.c": [ "ex/HEAD/log.html#git_revwalk_new-49", @@ -18399,7 +18422,7 @@ "group": "revwalk", "examples": { "general.c": [ - "ex/HEAD/general.html#git_revwalk_push-65" + "ex/HEAD/general.html#git_revwalk_push-72" ], "log.c": [ "ex/HEAD/log.html#git_revwalk_push-51" @@ -18623,7 +18646,7 @@ "group": "revwalk", "examples": { "general.c": [ - "ex/HEAD/general.html#git_revwalk_next-66" + "ex/HEAD/general.html#git_revwalk_next-73" ], "log.c": [ "ex/HEAD/log.html#git_revwalk_next-54" @@ -18658,7 +18681,7 @@ "group": "revwalk", "examples": { "general.c": [ - "ex/HEAD/general.html#git_revwalk_sorting-67" + "ex/HEAD/general.html#git_revwalk_sorting-74" ], "log.c": [ "ex/HEAD/log.html#git_revwalk_sorting-55", @@ -18738,7 +18761,7 @@ "group": "revwalk", "examples": { "general.c": [ - "ex/HEAD/general.html#git_revwalk_free-68" + "ex/HEAD/general.html#git_revwalk_free-75" ], "log.c": [ "ex/HEAD/log.html#git_revwalk_free-57" @@ -18842,8 +18865,8 @@ "group": "signature", "examples": { "general.c": [ - "ex/HEAD/general.html#git_signature_new-69", - "ex/HEAD/general.html#git_signature_new-70" + "ex/HEAD/general.html#git_signature_new-76", + "ex/HEAD/general.html#git_signature_new-77" ] } }, @@ -18990,6 +19013,10 @@ "comments": "

Because the signature is not an opaque structure, it is legal to free it manually, but be sure to free the "name" and "email" strings in addition to the structure itself.

\n", "group": "signature", "examples": { + "general.c": [ + "ex/HEAD/general.html#git_signature_free-78", + "ex/HEAD/general.html#git_signature_free-79" + ], "init.c": [ "ex/HEAD/init.html#git_signature_free-13" ], @@ -19471,7 +19498,7 @@ "group": "strarray", "examples": { "general.c": [ - "ex/HEAD/general.html#git_strarray_free-71" + "ex/HEAD/general.html#git_strarray_free-80" ], "remote.c": [ "ex/HEAD/remote.html#git_strarray_free-16", @@ -19512,8 +19539,8 @@ "git_submodule_update_init_options": { "type": "function", "file": "submodule.h", - "line": 179, - "lineto": 180, + "line": 170, + "lineto": 171, "args": [ { "name": "opts", @@ -19539,8 +19566,8 @@ "git_submodule_update": { "type": "function", "file": "submodule.h", - "line": 200, - "lineto": 200, + "line": 191, + "lineto": 191, "args": [ { "name": "submodule", @@ -19571,8 +19598,8 @@ "git_submodule_lookup": { "type": "function", "file": "submodule.h", - "line": 229, - "lineto": 232, + "line": 220, + "lineto": 223, "args": [ { "name": "out", @@ -19603,8 +19630,8 @@ "git_submodule_free": { "type": "function", "file": "submodule.h", - "line": 239, - "lineto": 239, + "line": 230, + "lineto": 230, "args": [ { "name": "submodule", @@ -19625,8 +19652,8 @@ "git_submodule_foreach": { "type": "function", "file": "submodule.h", - "line": 259, - "lineto": 262, + "line": 250, + "lineto": 253, "args": [ { "name": "repo", @@ -19662,8 +19689,8 @@ "git_submodule_add_setup": { "type": "function", "file": "submodule.h", - "line": 289, - "lineto": 294, + "line": 280, + "lineto": 285, "args": [ { "name": "out", @@ -19704,8 +19731,8 @@ "git_submodule_add_finalize": { "type": "function", "file": "submodule.h", - "line": 306, - "lineto": 306, + "line": 297, + "lineto": 297, "args": [ { "name": "submodule", @@ -19726,8 +19753,8 @@ "git_submodule_add_to_index": { "type": "function", "file": "submodule.h", - "line": 318, - "lineto": 320, + "line": 309, + "lineto": 311, "args": [ { "name": "submodule", @@ -19753,8 +19780,8 @@ "git_submodule_owner": { "type": "function", "file": "submodule.h", - "line": 333, - "lineto": 333, + "line": 324, + "lineto": 324, "args": [ { "name": "submodule", @@ -19775,8 +19802,8 @@ "git_submodule_name": { "type": "function", "file": "submodule.h", - "line": 341, - "lineto": 341, + "line": 332, + "lineto": 332, "args": [ { "name": "submodule", @@ -19802,8 +19829,8 @@ "git_submodule_path": { "type": "function", "file": "submodule.h", - "line": 352, - "lineto": 352, + "line": 343, + "lineto": 343, "args": [ { "name": "submodule", @@ -19829,8 +19856,8 @@ "git_submodule_url": { "type": "function", "file": "submodule.h", - "line": 360, - "lineto": 360, + "line": 351, + "lineto": 351, "args": [ { "name": "submodule", @@ -19851,8 +19878,8 @@ "git_submodule_resolve_url": { "type": "function", "file": "submodule.h", - "line": 370, - "lineto": 370, + "line": 361, + "lineto": 361, "args": [ { "name": "out", @@ -19883,8 +19910,8 @@ "git_submodule_branch": { "type": "function", "file": "submodule.h", - "line": 378, - "lineto": 378, + "line": 369, + "lineto": 369, "args": [ { "name": "submodule", @@ -19905,8 +19932,8 @@ "git_submodule_set_branch": { "type": "function", "file": "submodule.h", - "line": 391, - "lineto": 391, + "line": 382, + "lineto": 382, "args": [ { "name": "repo", @@ -19937,8 +19964,8 @@ "git_submodule_set_url": { "type": "function", "file": "submodule.h", - "line": 405, - "lineto": 405, + "line": 396, + "lineto": 396, "args": [ { "name": "repo", @@ -19969,8 +19996,8 @@ "git_submodule_index_id": { "type": "function", "file": "submodule.h", - "line": 413, - "lineto": 413, + "line": 404, + "lineto": 404, "args": [ { "name": "submodule", @@ -19991,8 +20018,8 @@ "git_submodule_head_id": { "type": "function", "file": "submodule.h", - "line": 421, - "lineto": 421, + "line": 412, + "lineto": 412, "args": [ { "name": "submodule", @@ -20013,8 +20040,8 @@ "git_submodule_wd_id": { "type": "function", "file": "submodule.h", - "line": 434, - "lineto": 434, + "line": 425, + "lineto": 425, "args": [ { "name": "submodule", @@ -20035,8 +20062,8 @@ "git_submodule_ignore": { "type": "function", "file": "submodule.h", - "line": 459, - "lineto": 460, + "line": 450, + "lineto": 451, "args": [ { "name": "submodule", @@ -20057,8 +20084,8 @@ "git_submodule_set_ignore": { "type": "function", "file": "submodule.h", - "line": 472, - "lineto": 475, + "line": 463, + "lineto": 466, "args": [ { "name": "repo", @@ -20089,8 +20116,8 @@ "git_submodule_update_strategy": { "type": "function", "file": "submodule.h", - "line": 487, - "lineto": 488, + "line": 478, + "lineto": 479, "args": [ { "name": "submodule", @@ -20111,8 +20138,8 @@ "git_submodule_set_update": { "type": "function", "file": "submodule.h", - "line": 500, - "lineto": 503, + "line": 491, + "lineto": 494, "args": [ { "name": "repo", @@ -20143,8 +20170,8 @@ "git_submodule_fetch_recurse_submodules": { "type": "function", "file": "submodule.h", - "line": 516, - "lineto": 517, + "line": 507, + "lineto": 508, "args": [ { "name": "submodule", @@ -20165,8 +20192,8 @@ "git_submodule_set_fetch_recurse_submodules": { "type": "function", "file": "submodule.h", - "line": 529, - "lineto": 532, + "line": 520, + "lineto": 523, "args": [ { "name": "repo", @@ -20197,8 +20224,8 @@ "git_submodule_init": { "type": "function", "file": "submodule.h", - "line": 547, - "lineto": 547, + "line": 538, + "lineto": 538, "args": [ { "name": "submodule", @@ -20224,8 +20251,8 @@ "git_submodule_repo_init": { "type": "function", "file": "submodule.h", - "line": 562, - "lineto": 565, + "line": 553, + "lineto": 556, "args": [ { "name": "out", @@ -20256,8 +20283,8 @@ "git_submodule_sync": { "type": "function", "file": "submodule.h", - "line": 575, - "lineto": 575, + "line": 566, + "lineto": 566, "args": [ { "name": "submodule", @@ -20278,8 +20305,8 @@ "git_submodule_open": { "type": "function", "file": "submodule.h", - "line": 589, - "lineto": 591, + "line": 580, + "lineto": 582, "args": [ { "name": "repo", @@ -20305,8 +20332,8 @@ "git_submodule_reload": { "type": "function", "file": "submodule.h", - "line": 603, - "lineto": 603, + "line": 594, + "lineto": 594, "args": [ { "name": "submodule", @@ -20332,8 +20359,8 @@ "git_submodule_status": { "type": "function", "file": "submodule.h", - "line": 619, - "lineto": 623, + "line": 610, + "lineto": 614, "args": [ { "name": "status", @@ -20374,8 +20401,8 @@ "git_submodule_location": { "type": "function", "file": "submodule.h", - "line": 639, - "lineto": 641, + "line": 630, + "lineto": 632, "args": [ { "name": "location_status", @@ -21569,6 +21596,50 @@ "comments": "

Clear the working directory and set core.bare to true. You may also want to call git_repository_set_index(repo, NULL) since a bare repo typically does not have an index, but this function will not do that for you.

\n", "group": "repository" }, + "git_repository_submodule_cache_all": { + "type": "function", + "file": "sys/repository.h", + "line": 149, + "lineto": 150, + "args": [ + { + "name": "repo", + "type": "git_repository *", + "comment": "the repository whose submodules will be cached." + } + ], + "argline": "git_repository *repo", + "sig": "git_repository *", + "return": { + "type": "int", + "comment": null + }, + "description": "

Load and cache all submodules.

\n", + "comments": "

Because the .gitmodules file is unstructured, loading submodules is an O(N) operation. Any operation (such as git_rebase_init) that requires accessing all submodules is O(N^2) in the number of submodules, if it has to look each one up individually. This function loads all submodules and caches them so that subsequent calls to git_submodule_lookup are O(1).

\n", + "group": "repository" + }, + "git_repository_submodule_cache_clear": { + "type": "function", + "file": "sys/repository.h", + "line": 164, + "lineto": 165, + "args": [ + { + "name": "repo", + "type": "git_repository *", + "comment": "the repository whose submodule cache will be cleared" + } + ], + "argline": "git_repository *repo", + "sig": "git_repository *", + "return": { + "type": "int", + "comment": null + }, + "description": "

Clear the submodule cache.

\n", + "comments": "

Clear the submodule cache populated by git_repository_submodule_cache_all. If there is no cache, do nothing.

\n\n

The cache incorporates data from the repository's configuration, as well as the state of the working tree, the index, and HEAD. So any time any of these has changed, the cache might become invalid.

\n", + "group": "repository" + }, "git_stream_register_tls": { "type": "function", "file": "sys/stream.h", @@ -21982,7 +22053,7 @@ "group": "tag", "examples": { "general.c": [ - "ex/HEAD/general.html#git_tag_lookup-72" + "ex/HEAD/general.html#git_tag_lookup-81" ] } }, @@ -22043,7 +22114,12 @@ }, "description": "

Close an open tag

\n", "comments": "

You can no longer use the git_tag pointer after this call.

\n\n

IMPORTANT: You MUST call this method when you are through with a tag to release memory. Failure to do so will cause a memory leak.

\n", - "group": "tag" + "group": "tag", + "examples": { + "general.c": [ + "ex/HEAD/general.html#git_tag_free-82" + ] + } }, "git_tag_id": { "type": "function", @@ -22117,7 +22193,7 @@ "group": "tag", "examples": { "general.c": [ - "ex/HEAD/general.html#git_tag_target-73" + "ex/HEAD/general.html#git_tag_target-83" ] } }, @@ -22174,7 +22250,7 @@ "ex/HEAD/cat-file.html#git_tag_target_type-36" ], "general.c": [ - "ex/HEAD/general.html#git_tag_target_type-74" + "ex/HEAD/general.html#git_tag_target_type-84" ] } }, @@ -22204,7 +22280,7 @@ "ex/HEAD/cat-file.html#git_tag_name-37" ], "general.c": [ - "ex/HEAD/general.html#git_tag_name-75" + "ex/HEAD/general.html#git_tag_name-85" ], "tag.c": [ "ex/HEAD/tag.html#git_tag_name-20" @@ -22265,7 +22341,7 @@ "ex/HEAD/cat-file.html#git_tag_message-40" ], "general.c": [ - "ex/HEAD/general.html#git_tag_message-76" + "ex/HEAD/general.html#git_tag_message-86" ], "tag.c": [ "ex/HEAD/tag.html#git_tag_message-21" @@ -23022,8 +23098,8 @@ "group": "tree", "examples": { "general.c": [ - "ex/HEAD/general.html#git_tree_lookup-77", - "ex/HEAD/general.html#git_tree_lookup-78" + "ex/HEAD/general.html#git_tree_lookup-87", + "ex/HEAD/general.html#git_tree_lookup-88" ], "init.c": [ "ex/HEAD/init.html#git_tree_lookup-14" @@ -23093,6 +23169,10 @@ "ex/HEAD/diff.html#git_tree_free-17", "ex/HEAD/diff.html#git_tree_free-18" ], + "general.c": [ + "ex/HEAD/general.html#git_tree_free-89", + "ex/HEAD/general.html#git_tree_free-90" + ], "init.c": [ "ex/HEAD/init.html#git_tree_free-15" ], @@ -23175,7 +23255,7 @@ "ex/HEAD/cat-file.html#git_tree_entrycount-41" ], "general.c": [ - "ex/HEAD/general.html#git_tree_entrycount-79" + "ex/HEAD/general.html#git_tree_entrycount-91" ] } }, @@ -23207,7 +23287,7 @@ "group": "tree", "examples": { "general.c": [ - "ex/HEAD/general.html#git_tree_entry_byname-80" + "ex/HEAD/general.html#git_tree_entry_byname-92" ] } }, @@ -23242,7 +23322,7 @@ "ex/HEAD/cat-file.html#git_tree_entry_byindex-42" ], "general.c": [ - "ex/HEAD/general.html#git_tree_entry_byindex-81" + "ex/HEAD/general.html#git_tree_entry_byindex-93" ] } }, @@ -23380,8 +23460,8 @@ "ex/HEAD/cat-file.html#git_tree_entry_name-43" ], "general.c": [ - "ex/HEAD/general.html#git_tree_entry_name-82", - "ex/HEAD/general.html#git_tree_entry_name-83" + "ex/HEAD/general.html#git_tree_entry_name-94", + "ex/HEAD/general.html#git_tree_entry_name-95" ] } }, @@ -23548,7 +23628,7 @@ "group": "tree", "examples": { "general.c": [ - "ex/HEAD/general.html#git_tree_entry_to_object-84" + "ex/HEAD/general.html#git_tree_entry_to_object-96" ] } }, @@ -23805,11 +23885,43 @@ "comments": "

The tree builder will be written to the given repo, and its identifying SHA1 hash will be stored in the id pointer.

\n", "group": "treebuilder" }, + "git_treebuilder_write_with_buffer": { + "type": "function", + "file": "tree.h", + "line": 389, + "lineto": 390, + "args": [ + { + "name": "oid", + "type": "git_oid *", + "comment": "Pointer to store the OID of the newly written tree" + }, + { + "name": "bld", + "type": "git_treebuilder *", + "comment": "Tree builder to write" + }, + { + "name": "tree", + "type": "git_buf *", + "comment": "Shared buffer for writing the tree. Will be grown as necessary." + } + ], + "argline": "git_oid *oid, git_treebuilder *bld, git_buf *tree", + "sig": "git_oid *::git_treebuilder *::git_buf *", + "return": { + "type": "int", + "comment": " 0 or an error code" + }, + "description": "

Write the contents of the tree builder as a tree object\n using a shared git_buf.

\n", + "comments": "", + "group": "treebuilder" + }, "git_tree_walk": { "type": "function", "file": "tree.h", - "line": 406, - "lineto": 410, + "line": 419, + "lineto": 423, "args": [ { "name": "tree", @@ -23845,8 +23957,8 @@ "git_tree_dup": { "type": "function", "file": "tree.h", - "line": 419, - "lineto": 419, + "line": 432, + "lineto": 432, "args": [ { "name": "out", @@ -23872,8 +23984,8 @@ "git_tree_create_updated": { "type": "function", "file": "tree.h", - "line": 465, - "lineto": 465, + "line": 478, + "lineto": 478, "args": [ { "name": "out", @@ -24449,37 +24561,11 @@ "description": "

Packbuilder progress notification function

\n", "comments": "" }, - "git_remote_rename_problem_cb": { - "type": "callback", - "file": "remote.h", - "line": 29, - "lineto": 29, - "args": [ - { - "name": "problematic_refspec", - "type": "const char *", - "comment": null - }, - { - "name": "payload", - "type": "void *", - "comment": null - } - ], - "argline": "const char *problematic_refspec, void *payload", - "sig": "const char *::void *", - "return": { - "type": "int", - "comment": null - }, - "description": "

git2/remote.h

\n", - "comments": "

@{

\n" - }, "git_push_transfer_progress": { "type": "callback", "file": "remote.h", - "line": 335, - "lineto": 339, + "line": 333, + "lineto": 337, "args": [ { "name": "current", @@ -24539,7 +24625,7 @@ "type": "int", "comment": null }, - "description": "", + "description": "

Callback used to inform of upcoming updates.

\n", "comments": "" }, "git_revwalk_hide_cb": { @@ -25052,8 +25138,8 @@ "git_treewalk_cb": { "type": "callback", "file": "tree.h", - "line": 380, - "lineto": 381, + "line": 393, + "lineto": 394, "args": [ { "name": "root", @@ -25642,7 +25728,8 @@ "git_remote_default_branch", "git_repository_discover", "git_repository_message", - "git_submodule_resolve_url" + "git_submodule_resolve_url", + "git_treebuilder_write_with_buffer" ] } } @@ -27440,17 +27527,17 @@ { "type": "unsigned int", "name": "max_candidates_tags", - "comments": "" + "comments": " default: 10 " }, { "type": "unsigned int", "name": "describe_strategy", - "comments": " default: 10 " + "comments": " default: GIT_DESCRIBE_DEFAULT " }, { "type": "const char *", "name": "pattern", - "comments": " default: GIT_DESCRIBE_DEFAULT " + "comments": "" }, { "type": "int", @@ -27472,6 +27559,29 @@ } } ], + [ + "git_describe_result", + { + "decl": "git_describe_result", + "type": "struct", + "value": "git_describe_result", + "file": "describe.h", + "line": 111, + "lineto": 111, + "tdef": "typedef", + "description": " A struct that stores the result of a describe operation.", + "comments": "", + "used": { + "returns": [], + "needs": [ + "git_describe_commit", + "git_describe_format", + "git_describe_result_free", + "git_describe_workdir" + ] + } + } + ], [ "git_describe_strategy_t", { @@ -29558,7 +29668,7 @@ "type": "enum", "file": "common.h", "line": 111, - "lineto": 116, + "lineto": 134, "block": "GIT_FEATURE_THREADS\nGIT_FEATURE_HTTPS\nGIT_FEATURE_SSH\nGIT_FEATURE_NSEC", "tdef": "typedef", "description": " Combinations of these values describe the features with which libgit2\n was compiled", @@ -29567,25 +29677,25 @@ { "type": "int", "name": "GIT_FEATURE_THREADS", - "comments": "", + "comments": "

If set, libgit2 was built thread-aware and can be safely used from multiple\n threads.

\n", "value": 1 }, { "type": "int", "name": "GIT_FEATURE_HTTPS", - "comments": "", + "comments": "

If set, libgit2 was built with and linked against a TLS implementation.\n Custom TLS streams may still be added by the user to support HTTPS\n regardless of this.

\n", "value": 2 }, { "type": "int", "name": "GIT_FEATURE_SSH", - "comments": "", + "comments": "

If set, libgit2 was built with and linked against libssh2. A custom\n transport may still be added by the user to support libssh2 regardless of\n this.

\n", "value": 4 }, { "type": "int", "name": "GIT_FEATURE_NSEC", - "comments": "", + "comments": "

If set, libgit2 was built with support for sub-second resolution in file\n modification times.

\n", "value": 8 } ], @@ -30564,14 +30674,15 @@ "GIT_OPT_SET_SSL_CERT_LOCATIONS", "GIT_OPT_SET_USER_AGENT", "GIT_OPT_ENABLE_STRICT_OBJECT_CREATION", + "GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION", "GIT_OPT_SET_SSL_CIPHERS", "GIT_OPT_GET_USER_AGENT" ], "type": "enum", "file": "common.h", - "line": 144, - "lineto": 162, - "block": "GIT_OPT_GET_MWINDOW_SIZE\nGIT_OPT_SET_MWINDOW_SIZE\nGIT_OPT_GET_MWINDOW_MAPPED_LIMIT\nGIT_OPT_SET_MWINDOW_MAPPED_LIMIT\nGIT_OPT_GET_SEARCH_PATH\nGIT_OPT_SET_SEARCH_PATH\nGIT_OPT_SET_CACHE_OBJECT_LIMIT\nGIT_OPT_SET_CACHE_MAX_SIZE\nGIT_OPT_ENABLE_CACHING\nGIT_OPT_GET_CACHED_MEMORY\nGIT_OPT_GET_TEMPLATE_PATH\nGIT_OPT_SET_TEMPLATE_PATH\nGIT_OPT_SET_SSL_CERT_LOCATIONS\nGIT_OPT_SET_USER_AGENT\nGIT_OPT_ENABLE_STRICT_OBJECT_CREATION\nGIT_OPT_SET_SSL_CIPHERS\nGIT_OPT_GET_USER_AGENT", + "line": 162, + "lineto": 181, + "block": "GIT_OPT_GET_MWINDOW_SIZE\nGIT_OPT_SET_MWINDOW_SIZE\nGIT_OPT_GET_MWINDOW_MAPPED_LIMIT\nGIT_OPT_SET_MWINDOW_MAPPED_LIMIT\nGIT_OPT_GET_SEARCH_PATH\nGIT_OPT_SET_SEARCH_PATH\nGIT_OPT_SET_CACHE_OBJECT_LIMIT\nGIT_OPT_SET_CACHE_MAX_SIZE\nGIT_OPT_ENABLE_CACHING\nGIT_OPT_GET_CACHED_MEMORY\nGIT_OPT_GET_TEMPLATE_PATH\nGIT_OPT_SET_TEMPLATE_PATH\nGIT_OPT_SET_SSL_CERT_LOCATIONS\nGIT_OPT_SET_USER_AGENT\nGIT_OPT_ENABLE_STRICT_OBJECT_CREATION\nGIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION\nGIT_OPT_SET_SSL_CIPHERS\nGIT_OPT_GET_USER_AGENT", "tdef": "typedef", "description": " Global library options", "comments": "

These are used to select which global option to set or get and are used in git_libgit2_opts().

\n", @@ -30668,15 +30779,21 @@ }, { "type": "int", - "name": "GIT_OPT_SET_SSL_CIPHERS", + "name": "GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION", "comments": "", "value": 15 }, { "type": "int", - "name": "GIT_OPT_GET_USER_AGENT", + "name": "GIT_OPT_SET_SSL_CIPHERS", "comments": "", "value": 16 + }, + { + "type": "int", + "name": "GIT_OPT_GET_USER_AGENT", + "comments": "", + "value": 17 } ], "used": { @@ -30697,8 +30814,8 @@ ], "type": "enum", "file": "merge.h", - "line": 311, - "lineto": 340, + "line": 312, + "lineto": 341, "block": "GIT_MERGE_ANALYSIS_NONE\nGIT_MERGE_ANALYSIS_NORMAL\nGIT_MERGE_ANALYSIS_UP_TO_DATE\nGIT_MERGE_ANALYSIS_FASTFORWARD\nGIT_MERGE_ANALYSIS_UNBORN", "tdef": "typedef", "description": " The results of `git_merge_analysis` indicate the merge opportunities.", @@ -31259,8 +31376,8 @@ ], "type": "enum", "file": "merge.h", - "line": 345, - "lineto": 363, + "line": 346, + "lineto": 364, "block": "GIT_MERGE_PREFERENCE_NONE\nGIT_MERGE_PREFERENCE_NO_FASTFORWARD\nGIT_MERGE_PREFERENCE_FASTFORWARD_ONLY", "tdef": "typedef", "description": " The user's stated preference for merges.", @@ -31937,7 +32054,8 @@ "git_tree_lookup", "git_tree_lookup_prefix", "git_treebuilder_insert", - "git_treebuilder_write" + "git_treebuilder_write", + "git_treebuilder_write_with_buffer" ] } } @@ -31949,8 +32067,8 @@ "type": "struct", "value": "git_oid_shorten", "file": "oid.h", - "line": 216, - "lineto": 216, + "line": 215, + "lineto": 215, "tdef": "typedef", "description": " OID Shortener object", "comments": "", @@ -32428,7 +32546,7 @@ { "type": "int", "name": "GIT_PROXY_NONE", - "comments": "

Do not attempt to connect through a proxy

\n\n

If built against lbicurl, it itself may attempt to connect\n to a proxy if the environment variables specify it.

\n", + "comments": "

Do not attempt to connect through a proxy

\n\n

If built against libcurl, it itself may attempt to connect\n to a proxy if the environment variables specify it.

\n", "value": 0 }, { @@ -32541,8 +32659,8 @@ "type": "struct", "value": "git_push_update", "file": "remote.h", - "line": 343, - "lineto": 360, + "line": 341, + "lineto": 358, "block": "char * src_refname\nchar * dst_refname\ngit_oid src\ngit_oid dst", "tdef": "typedef", "description": " Represents an update which will be performed on the remote during push", @@ -33357,8 +33475,8 @@ ], "type": "enum", "file": "remote.h", - "line": 328, - "lineto": 332, + "line": 326, + "lineto": 330, "block": "GIT_REMOTE_COMPLETION_DOWNLOAD\nGIT_REMOTE_COMPLETION_INDEXING\nGIT_REMOTE_COMPLETION_ERROR\nGIT_REMOTE_COMPLETION_DOWNLOAD\nGIT_REMOTE_COMPLETION_INDEXING\nGIT_REMOTE_COMPLETION_ERROR", "tdef": "typedef", "description": " Argument to the completion callback which tells it which operation\n finished.", @@ -33624,6 +33742,8 @@ "git_repository_set_workdir", "git_repository_state", "git_repository_state_cleanup", + "git_repository_submodule_cache_all", + "git_repository_submodule_cache_clear", "git_repository_workdir", "git_repository_wrap_odb", "git_reset", @@ -35219,15 +35339,14 @@ "unsigned int version", "git_checkout_options checkout_opts", "git_fetch_options fetch_opts", - "unsigned int clone_checkout_strategy", "int allow_fetch" ], "type": "struct", "value": "git_submodule_update_options", "file": "submodule.h", "line": 129, - "lineto": 163, - "block": "unsigned int version\ngit_checkout_options checkout_opts\ngit_fetch_options fetch_opts\nunsigned int clone_checkout_strategy\nint allow_fetch", + "lineto": 154, + "block": "unsigned int version\ngit_checkout_options checkout_opts\ngit_fetch_options fetch_opts\nint allow_fetch", "tdef": "typedef", "description": " Submodule update options structure", "comments": "

Use the GIT_SUBMODULE_UPDATE_OPTIONS_INIT to get the default settings, like this:

\n\n

git_submodule_update_options opts = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;

\n", @@ -35240,18 +35359,13 @@ { "type": "git_checkout_options", "name": "checkout_opts", - "comments": " These options are passed to the checkout step. To disable\n checkout, set the `checkout_strategy` to\n `GIT_CHECKOUT_NONE`. Generally you will want the use\n GIT_CHECKOUT_SAFE to update files in the working\n directory. Use the `clone_checkout_strategy` field\n to set the checkout strategy that will be used in\n the case where update needs to clone the repository." + "comments": " These options are passed to the checkout step. To disable\n checkout, set the `checkout_strategy` to\n `GIT_CHECKOUT_NONE`. Generally you will want the use\n GIT_CHECKOUT_SAFE to update files in the working\n directory. " }, { "type": "git_fetch_options", "name": "fetch_opts", "comments": " Options which control the fetch, including callbacks.\n\n The callbacks to use for reporting fetch progress, and for acquiring\n credentials in the event they are needed." }, - { - "type": "unsigned int", - "name": "clone_checkout_strategy", - "comments": " The checkout strategy to use when the sub repository needs to\n be cloned. Use GIT_CHECKOUT_SAFE to create all files\n in the working directory for the newly cloned repository." - }, { "type": "int", "name": "allow_fetch", @@ -35686,6 +35800,7 @@ "git_treebuilder_new", "git_treebuilder_remove", "git_treebuilder_write", + "git_treebuilder_write_with_buffer", "git_treewalk_cb" ] } @@ -35740,8 +35855,8 @@ "type": "struct", "value": "git_tree_update", "file": "tree.h", - "line": 434, - "lineto": 443, + "line": 447, + "lineto": 456, "block": "git_tree_update_t action\ngit_oid id\ngit_filemode_t filemode\nconst char * path", "tdef": "typedef", "description": " An action to perform during the update of a tree", @@ -35785,8 +35900,8 @@ ], "type": "enum", "file": "tree.h", - "line": 424, - "lineto": 429, + "line": 437, + "lineto": 442, "block": "GIT_TREE_UPDATE_UPSERT\nGIT_TREE_UPDATE_REMOVE", "tdef": "typedef", "description": " The kind of update to perform", @@ -35834,7 +35949,8 @@ "git_treebuilder_insert", "git_treebuilder_new", "git_treebuilder_remove", - "git_treebuilder_write" + "git_treebuilder_write", + "git_treebuilder_write_with_buffer" ] } } @@ -35848,8 +35964,8 @@ ], "type": "enum", "file": "tree.h", - "line": 384, - "lineto": 387, + "line": 397, + "lineto": 400, "block": "GIT_TREEWALK_PRE\nGIT_TREEWALK_POST", "tdef": "typedef", "description": " Tree traversal modes ", @@ -36703,6 +36819,8 @@ "git_repository_set_workdir", "git_repository_state", "git_repository_state_cleanup", + "git_repository_submodule_cache_all", + "git_repository_submodule_cache_clear", "git_repository_workdir", "git_repository_wrap_odb" ] @@ -36936,7 +37054,8 @@ "git_treebuilder_insert", "git_treebuilder_new", "git_treebuilder_remove", - "git_treebuilder_write" + "git_treebuilder_write", + "git_treebuilder_write_with_buffer" ] ] ], @@ -37030,4 +37149,4 @@ "ex/HEAD/tag.html" ] ] -} +} \ No newline at end of file From b2775d25d21705c90446cecfa5eacec521699f56 Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Tue, 14 Feb 2017 14:43:23 -0700 Subject: [PATCH 25/41] Ignore git_treebuilder_write_with_buffer --- generate/input/descriptor.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index a9264214a..1112f0ea0 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -2541,6 +2541,9 @@ } } }, + "git_treebuilder_write_with_buffer": { + "ignore": true + }, "git_treebuilder_new": { "args": { "source": { From cc4f88e67dc8c6d28f8022f0c2d814d8fad23392 Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Tue, 14 Feb 2017 14:47:12 -0700 Subject: [PATCH 26/41] Provide rebase details on finish When using the convenience methods for rebase, we should return all the details about the rebase before finishing. This includes the sha translation map for the rebase operation, and other meta data (old head sha, branch names, new head sha) --- lib/repository.js | 103 ++++++++++++++- test/tests/rebase.js | 308 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 404 insertions(+), 7 deletions(-) diff --git a/lib/repository.js b/lib/repository.js index 1a4e6eaa8..cc1459de7 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -1,5 +1,6 @@ var promisify = require("promisify-node"); var fse = promisify(require("fs-extra")); +var fp = require("lodash/fp"); var NodeGit = require("../"); var Blob = NodeGit.Blob; var Checkout = NodeGit.Checkout; @@ -184,12 +185,35 @@ function getPathHunks(repo, index, filePath, isStaged, additionalDiffOptions) { * invocation of next(). If the callback * returns a promise, the next() will be * called when the promise resolves. + * @param {Function} beforeFinishFn Callback called before the invocation + * of finish(). If the callback returns a + * promise, finish() will be called when the + * promise resolves. This callback will be + * provided a detailed overview of the rebase * @return {Int|Index} An error code for an unsuccesful rebase or an index for * a rebase with conflicts */ -function performRebase(repository, rebase, signature, beforeNextFn) { +function performRebase( + repository, + rebase, + signature, + beforeNextFn, + beforeFinishFn +) { var beforeNextFnResult; + function readRebaseMetadataFile(fileName) { + return fse.readFile( + path.join(repository.path(), "rebase-merge", fileName), + { encoding: "utf8" } + ) + .then(fp.trim); + } + + function calcHeadName(input) { + return input.replace(/refs\/heads\/(.*)/, "$1"); + } + function getPromise() { return rebase.next() .then(function() { @@ -201,11 +225,51 @@ function performRebase(repository, rebase, signature, beforeNextFn) { rebase.commit(null, signature); - return performRebase(repository, rebase, signature, beforeNextFn); + return performRebase( + repository, + rebase, + signature, + beforeNextFn, + beforeFinishFn + ); }); }, function(error) { if (error && error.errno === NodeGit.Error.CODE.ITEROVER) { - return rebase.finish(signature); + const calcRewritten = fp.flow([ + fp.split("\n"), + fp.map(fp.split(" ")) + ]); + + const beforeFinishFnPromise = !beforeFinishFn ? + Promise.resolve() : + Promise.all([ + readRebaseMetadataFile("onto_name"), + readRebaseMetadataFile("onto"), + readRebaseMetadataFile("head-name").then(calcHeadName), + readRebaseMetadataFile("orig-head"), + readRebaseMetadataFile("rewritten").then(calcRewritten) + ]) + .then(function([ + ontoName, + ontoSha, + originalHeadName, + originalHeadSha, + rewritten + ]) { + return beforeFinishFn({ + ontoName, + ontoSha, + originalHeadName, + originalHeadSha, + rebase, + rewritten + }); + }); + + return beforeFinishFnPromise + .then(function() { + return rebase.finish(signature); + }); } else { throw error; } @@ -354,10 +418,19 @@ Repository.prototype.checkoutRef = function(reference, opts) { * promise, the rebase will resume when the * promise resolves. The rebase object is * is passed to the callback. + * @param {Function} beforeFinishFn Callback called before the invocation + * of finish(). If the callback returns a + * promise, finish() will be called when the + * promise resolves. This callback will be + * provided a detailed overview of the rebase * @return {Oid|Index} A commit id for a succesful merge or an index for a * rebase with conflicts */ -Repository.prototype.continueRebase = function(signature, beforeNextFn) { +Repository.prototype.continueRebase = function( + signature, + beforeNextFn, + beforeFinishFn +) { var repo = this; signature = signature || repo.defaultSignature(); @@ -373,7 +446,13 @@ Repository.prototype.continueRebase = function(signature, beforeNextFn) { .then(function(rebase) { rebase.commit(null, signature); - return performRebase(repo, rebase, signature, beforeNextFn); + return performRebase( + repo, + rebase, + signature, + beforeNextFn, + beforeFinishFn + ); }) .then(function(error) { if (error) { @@ -1218,6 +1297,11 @@ Repository.prototype.isReverting = function() { * promise, the rebase will resume when the * promise resolves. The rebase object is * is passed to the callback. + * @param {Function} beforeFinishFn Callback called before the invocation + * of finish(). If the callback returns a + * promise, finish() will be called when the + * promise resolves. This callback will be + * provided a detailed overview of the rebase * @return {Oid|Index} A commit id for a succesful merge or an index for a * rebase with conflicts */ @@ -1227,6 +1311,7 @@ Repository.prototype.rebaseBranches = function( onto, signature, beforeNextFn, + beforeFinishFn, rebaseOptions ) { @@ -1278,7 +1363,13 @@ Repository.prototype.rebaseBranches = function( rebaseOptions ) .then(function(rebase) { - return performRebase(repo, rebase, signature, beforeNextFn); + return performRebase( + repo, + rebase, + signature, + beforeNextFn, + beforeFinishFn + ); }) .then(function(error) { if (error) { diff --git a/test/tests/rebase.js b/test/tests/rebase.js index 70c8e8ee6..56030d197 100644 --- a/test/tests/rebase.js +++ b/test/tests/rebase.js @@ -4,7 +4,7 @@ var local = path.join.bind(path, __dirname); var promisify = require("promisify-node"); var fse = promisify(require("fs-extra")); -describe("Rebase", function() { +describe.only("Rebase", function() { var NodeGit = require("../../"); var RepoUtils = require("../utils/repository_setup"); @@ -915,6 +915,312 @@ describe("Rebase", function() { }); }); + it("beforeFinishFn sync callback receives correct rebase data", function() { + var baseFileName = "baseNewFile.txt"; + var ourFileName = "ourNewFile.txt"; + var theirFileName = "theirNewFile.txt"; + + var baseFileContent = "How do you feel about Toll Roads?"; + var ourFileContent = "I like Toll Roads. I have an EZ-Pass!"; + var theirFileContent = "I'm skeptical about Toll Roads"; + + var ourSignature = NodeGit.Signature.create + ("Ron Paul", "RonPaul@TollRoadsRBest.info", 123456789, 60); + var theirSignature = NodeGit.Signature.create + ("Greg Abbott", "Gregggg@IllTollYourFace.us", 123456789, 60); + + var repository = this.repository; + var ourCommit; + var ourBranch; + var theirBranch; + var ourBranchShaPreRebase; + var ourBranchShaPostRebase = "b937100ee0ea17ef20525306763505a7fe2be29e"; + var theirBranchSha; + + var nextCalls = 0; + + var calledBeforeFinishFn = false; + + return fse.writeFile(path.join(repository.workdir(), baseFileName), + baseFileContent) + // Load up the repository index and make our initial commit to HEAD + .then(function() { + return RepoUtils.addFileToIndex(repository, baseFileName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "b5cdc109d437c4541a13fb7509116b5f03d5039a"); + + return repository.createCommit("HEAD", ourSignature, + ourSignature, "initial commit", oid, []); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "be03abdf0353d05924c53bebeb0e5bb129cda44a"); + + return repository.getCommit(commitOid).then(function(commit) { + ourCommit = commit; + }).then(function() { + return repository.createBranch(ourBranchName, commitOid) + .then(function(branch) { + ourBranch = branch; + return repository.createBranch(theirBranchName, commitOid); + }); + }); + }) + .then(function(branch) { + theirBranch = branch; + return fse.writeFile(path.join(repository.workdir(), theirFileName), + theirFileContent); + }) + .then(function() { + return RepoUtils.addFileToIndex(repository, theirFileName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "be5f0fd38a39a67135ad68921c93cd5c17fefb3d"); + + return repository.createCommit(theirBranch.name(), theirSignature, + theirSignature, "they made a commit", oid, [ourCommit]); + }) + .then(function(commitOid) { + theirBranchSha = commitOid.toString(); + assert.equal(theirBranchSha, + "e9ebd92f2f4778baf6fa8e92f0c68642f931a554"); + + return removeFileFromIndex(repository, theirFileName); + }) + .then(function() { + return fse.remove(path.join(repository.workdir(), theirFileName)); + }) + .then(function() { + return fse.writeFile(path.join(repository.workdir(), ourFileName), + ourFileContent); + }) + .then(function() { + return RepoUtils.addFileToIndex(repository, ourFileName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "77867fc0bfeb3f80ab18a78c8d53aa3a06207047"); + + return repository.createCommit(ourBranch.name(), ourSignature, + ourSignature, "we made a commit", oid, [ourCommit]); + }) + .then(function(commitOid) { + ourBranchShaPreRebase = commitOid.toString(); + assert.equal(ourBranchShaPreRebase, + "e7f37ee070837052937e24ad8ba66f6d83ae7941"); + + return removeFileFromIndex(repository, ourFileName); + }) + .then(function() { + return fse.remove(path.join(repository.workdir(), ourFileName)); + }) + .then(function() { + return repository.checkoutBranch(ourBranchName); + }) + .then(function() { + return repository.rebaseBranches(ourBranchName, theirBranchName, + null, ourSignature, function(rebase) { + assert.ok(rebase instanceof NodeGit.Rebase); + + nextCalls++; + + return Promise.resolve(); + }, function({ + ontoName, + ontoSha, + originalHeadName, + originalHeadSha, + rebase, + rewritten + }) { + calledBeforeFinishFn = true; + + assert.equal(ontoName, theirBranchName); + assert.equal(ontoSha, theirBranchSha); + assert.equal(originalHeadName, ourBranchName); + assert.equal(originalHeadSha, ourBranchShaPreRebase); + assert.deepEqual( + rewritten, + [[ourBranchShaPreRebase, ourBranchShaPostRebase]] + ); + }); + }) + .then(function(commit) { + // verify that the beforeNextFn callback was called + assert.equal(nextCalls, 2); + + // verify that the beforeFinishFn callback was called + assert(calledBeforeFinishFn, "beforeFinishFn was not called"); + + // verify that the "ours" branch has moved to the correct place + assert.equal(commit.id().toString(), ourBranchShaPostRebase); + + return commit.parent(0); + }) + .then(function(commit) { + // verify that we are on top of "their commit" + assert.equal(commit.id().toString(), + "e9ebd92f2f4778baf6fa8e92f0c68642f931a554"); + }); + }); + + it("beforeFinishFn async callback receives correct rebase data", function() { + var baseFileName = "baseNewFile.txt"; + var ourFileName = "ourNewFile.txt"; + var theirFileName = "theirNewFile.txt"; + + var baseFileContent = "How do you feel about Toll Roads?"; + var ourFileContent = "I like Toll Roads. I have an EZ-Pass!"; + var theirFileContent = "I'm skeptical about Toll Roads"; + + var ourSignature = NodeGit.Signature.create + ("Ron Paul", "RonPaul@TollRoadsRBest.info", 123456789, 60); + var theirSignature = NodeGit.Signature.create + ("Greg Abbott", "Gregggg@IllTollYourFace.us", 123456789, 60); + + var repository = this.repository; + var ourCommit; + var ourBranch; + var theirBranch; + var ourBranchShaPreRebase; + var ourBranchShaPostRebase = "b937100ee0ea17ef20525306763505a7fe2be29e"; + var theirBranchSha; + + var nextCalls = 0; + + var calledBeforeFinishFn = false; + + return fse.writeFile(path.join(repository.workdir(), baseFileName), + baseFileContent) + // Load up the repository index and make our initial commit to HEAD + .then(function() { + return RepoUtils.addFileToIndex(repository, baseFileName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "b5cdc109d437c4541a13fb7509116b5f03d5039a"); + + return repository.createCommit("HEAD", ourSignature, + ourSignature, "initial commit", oid, []); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "be03abdf0353d05924c53bebeb0e5bb129cda44a"); + + return repository.getCommit(commitOid).then(function(commit) { + ourCommit = commit; + }).then(function() { + return repository.createBranch(ourBranchName, commitOid) + .then(function(branch) { + ourBranch = branch; + return repository.createBranch(theirBranchName, commitOid); + }); + }); + }) + .then(function(branch) { + theirBranch = branch; + return fse.writeFile(path.join(repository.workdir(), theirFileName), + theirFileContent); + }) + .then(function() { + return RepoUtils.addFileToIndex(repository, theirFileName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "be5f0fd38a39a67135ad68921c93cd5c17fefb3d"); + + return repository.createCommit(theirBranch.name(), theirSignature, + theirSignature, "they made a commit", oid, [ourCommit]); + }) + .then(function(commitOid) { + theirBranchSha = commitOid.toString(); + assert.equal(theirBranchSha, + "e9ebd92f2f4778baf6fa8e92f0c68642f931a554"); + + return removeFileFromIndex(repository, theirFileName); + }) + .then(function() { + return fse.remove(path.join(repository.workdir(), theirFileName)); + }) + .then(function() { + return fse.writeFile(path.join(repository.workdir(), ourFileName), + ourFileContent); + }) + .then(function() { + return RepoUtils.addFileToIndex(repository, ourFileName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "77867fc0bfeb3f80ab18a78c8d53aa3a06207047"); + + return repository.createCommit(ourBranch.name(), ourSignature, + ourSignature, "we made a commit", oid, [ourCommit]); + }) + .then(function(commitOid) { + ourBranchShaPreRebase = commitOid.toString(); + assert.equal(ourBranchShaPreRebase, + "e7f37ee070837052937e24ad8ba66f6d83ae7941"); + + return removeFileFromIndex(repository, ourFileName); + }) + .then(function() { + return fse.remove(path.join(repository.workdir(), ourFileName)); + }) + .then(function() { + return repository.checkoutBranch(ourBranchName); + }) + .then(function() { + return repository.rebaseBranches(ourBranchName, theirBranchName, + null, ourSignature, function(rebase) { + assert.ok(rebase instanceof NodeGit.Rebase); + + nextCalls++; + + return Promise.resolve(); + }, function({ + ontoName, + ontoSha, + originalHeadName, + originalHeadSha, + rebase, + rewritten + }) { + calledBeforeFinishFn = true; + + assert.equal(ontoName, theirBranchName); + assert.equal(ontoSha, theirBranchSha); + assert.equal(originalHeadName, ourBranchName); + assert.equal(originalHeadSha, ourBranchShaPreRebase); + assert.deepEqual( + rewritten, + [[ourBranchShaPreRebase, ourBranchShaPostRebase]] + ); + + return Promise.resolve(); + }); + }) + .then(function(commit) { + // verify that the beforeNextFn callback was called + assert.equal(nextCalls, 2); + + // verify that the beforeFinishFn callback was called + assert(calledBeforeFinishFn, "beforeFinishFn was not called"); + + // verify that the "ours" branch has moved to the correct place + assert.equal(commit.id().toString(), ourBranchShaPostRebase); + + return commit.parent(0); + }) + .then(function(commit) { + // verify that we are on top of "their commit" + assert.equal(commit.id().toString(), + "e9ebd92f2f4778baf6fa8e92f0c68642f931a554"); + }); + }); + it("can rebase with conflicts using the convenience methods", function() { var fileName = "everyonesFile.txt"; From 456594de42f7a7b56a7add332820a917d835f5bd Mon Sep 17 00:00:00 2001 From: John Haley Date: Tue, 14 Feb 2017 14:56:14 -0700 Subject: [PATCH 27/41] Add `worktree` to `libgit2.gyp` --- vendor/libgit2.gyp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vendor/libgit2.gyp b/vendor/libgit2.gyp index 539f6e9ba..3e8009862 100644 --- a/vendor/libgit2.gyp +++ b/vendor/libgit2.gyp @@ -252,6 +252,8 @@ "libgit2/src/varint.h", "libgit2/src/vector.c", "libgit2/src/vector.h", + "libgit2/src/worktree.c", + "libgit2/src/worktree.h", "libgit2/src/xdiff/xdiff.h", "libgit2/src/xdiff/xdiffi.c", "libgit2/src/xdiff/xdiffi.h", From b5e2dc008420c7424b22c7d37bf635fabf526c0c Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Wed, 15 Feb 2017 08:03:31 -0700 Subject: [PATCH 28/41] coverage utility is breaking over destructuring --- test/tests/rebase.js | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/test/tests/rebase.js b/test/tests/rebase.js index 56030d197..177c972ae 100644 --- a/test/tests/rebase.js +++ b/test/tests/rebase.js @@ -1028,22 +1028,18 @@ describe.only("Rebase", function() { nextCalls++; return Promise.resolve(); - }, function({ - ontoName, - ontoSha, - originalHeadName, - originalHeadSha, - rebase, - rewritten - }) { + }, function(rebaseMetadata) { calledBeforeFinishFn = true; - assert.equal(ontoName, theirBranchName); - assert.equal(ontoSha, theirBranchSha); - assert.equal(originalHeadName, ourBranchName); - assert.equal(originalHeadSha, ourBranchShaPreRebase); + assert.equal(rebaseMetadata.ontoName, theirBranchName); + assert.equal(rebaseMetadata.ontoSha, theirBranchSha); + assert.equal(rebaseMetadata.originalHeadName, ourBranchName); + assert.equal( + rebaseMetadata.originalHeadSha, + ourBranchShaPreRebase + ); assert.deepEqual( - rewritten, + rebaseMetadata.rewritten, [[ourBranchShaPreRebase, ourBranchShaPostRebase]] ); }); @@ -1180,22 +1176,18 @@ describe.only("Rebase", function() { nextCalls++; return Promise.resolve(); - }, function({ - ontoName, - ontoSha, - originalHeadName, - originalHeadSha, - rebase, - rewritten - }) { + }, function(rebaseMetadata) { calledBeforeFinishFn = true; - assert.equal(ontoName, theirBranchName); - assert.equal(ontoSha, theirBranchSha); - assert.equal(originalHeadName, ourBranchName); - assert.equal(originalHeadSha, ourBranchShaPreRebase); + assert.equal(rebaseMetadata.ontoName, theirBranchName); + assert.equal(rebaseMetadata.ontoSha, theirBranchSha); + assert.equal(rebaseMetadata.originalHeadName, ourBranchName); + assert.equal( + rebaseMetadata.originalHeadSha, + ourBranchShaPreRebase + ); assert.deepEqual( - rewritten, + rebaseMetadata.rewritten, [[ourBranchShaPreRebase, ourBranchShaPostRebase]] ); From 185cebe99f6fdfbf0c2b544a7fa5e80df48ca1e6 Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Wed, 15 Feb 2017 08:24:06 -0700 Subject: [PATCH 29/41] Address PR concerns --- generate/templates/manual/remote/ls.cc | 2 +- generate/templates/manual/src/functions/copy.cc | 5 ++++- lib/remote.js | 9 ++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/generate/templates/manual/remote/ls.cc b/generate/templates/manual/remote/ls.cc index 561e0f1f1..d426d6f79 100644 --- a/generate/templates/manual/remote/ls.cc +++ b/generate/templates/manual/remote/ls.cc @@ -85,7 +85,7 @@ void GitRemote::ReferenceListWorker::HandleOKCallback() } else if (baton->error_code < 0) { - Local err = Nan::Error("Method next has thrown an error.")->ToObject(); + Local err = Nan::Error("Reference List has thrown an error.")->ToObject(); err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code)); Local argv[1] = { err diff --git a/generate/templates/manual/src/functions/copy.cc b/generate/templates/manual/src/functions/copy.cc index 9a2e7c3c7..90327650b 100644 --- a/generate/templates/manual/src/functions/copy.cc +++ b/generate/templates/manual/src/functions/copy.cc @@ -26,7 +26,10 @@ git_remote_head *git_remote_head_dup(const git_remote_head *src) { dest->local = src->local; git_oid_cpy(&dest->oid, &src->oid); git_oid_cpy(&dest->loid, &src->loid); - dest->name = strdup(src->name); + + dest->name = src->name + ? strdup(src->name) + : NULL; dest->symref_target = src->symref_target ? strdup(src->symref_target) : NULL; diff --git a/lib/remote.js b/lib/remote.js index 517eae55d..b7c897957 100644 --- a/lib/remote.js +++ b/lib/remote.js @@ -113,11 +113,14 @@ Remote.prototype.push = function(refSpecs, opts) { }; /** - * Lists advertised references from a remote + * Lists advertised references from a remote. You must connect to the remote + * before using referenceList. * * @async - * @return {Promise>} a list of the remote heads currently - * available on the remote for download + * @return {Promise>} a list of the remote heads the remote + * had available at the last established + * connection. + * */ Remote.prototype.referenceList = Remote.prototype.referenceList; From 91079d7964e733ad9878b8fb3aa79c17c9ce9195 Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Wed, 15 Feb 2017 08:41:25 -0700 Subject: [PATCH 30/41] remove destructuring --- test/tests/remote.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/tests/remote.js b/test/tests/remote.js index 4dddda2b7..57d77517d 100644 --- a/test/tests/remote.js +++ b/test/tests/remote.js @@ -506,10 +506,13 @@ describe("Remote", function() { remote.connect(NodeGit.Enums.DIRECTION.FETCH) ]); }) - .then(function([remote]) { + .then(function(results) { + var remote = results[0]; return Promise.all([remote, remote.referenceList()]); }) - .then(function([remote, remoteHeads]) { + .then(function(results) { + var remote = results[0]; + var remoteHeads = results[1]; var remoteHeadsBySha = fp.flow([ fp.map(function(remoteHead) { return { From b8a352865e74f281419268fd5d400ed162cc2af1 Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Fri, 24 Feb 2017 13:27:17 -0700 Subject: [PATCH 31/41] Rewind libgit2 to just before worktree --- vendor/libgit2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/libgit2 b/vendor/libgit2 index 3bc15d010..12f0b704d 160000 --- a/vendor/libgit2 +++ b/vendor/libgit2 @@ -1 +1 @@ -Subproject commit 3bc15d0109004e5eeb668644fb2738ba4ee07864 +Subproject commit 12f0b704d2d3269db5bc6d95f098aea3eb645f63 From 25c746ac263d466ad4474af046bb3453ce524c5a Mon Sep 17 00:00:00 2001 From: John Haley Date: Tue, 14 Feb 2017 14:56:14 -0700 Subject: [PATCH 32/41] Revert "Add `worktree` to `libgit2.gyp`" This reverts commit 456594de42f7a7b56a7add332820a917d835f5bd. --- vendor/libgit2.gyp | 2 -- 1 file changed, 2 deletions(-) diff --git a/vendor/libgit2.gyp b/vendor/libgit2.gyp index 3e8009862..539f6e9ba 100644 --- a/vendor/libgit2.gyp +++ b/vendor/libgit2.gyp @@ -252,8 +252,6 @@ "libgit2/src/varint.h", "libgit2/src/vector.c", "libgit2/src/vector.h", - "libgit2/src/worktree.c", - "libgit2/src/worktree.h", "libgit2/src/xdiff/xdiff.h", "libgit2/src/xdiff/xdiffi.c", "libgit2/src/xdiff/xdiffi.h", From b40ee03663c05f314669fbefe056675b9e6ba94a Mon Sep 17 00:00:00 2001 From: Remy Suen Date: Sun, 26 Feb 2017 10:58:12 +0900 Subject: [PATCH 33/41] Fix error message assertion to match libgit2 changes libgit2 has changed all their error messages to start with a lowercased character. Updated the test to reflect this change. --- test/tests/merge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tests/merge.js b/test/tests/merge.js index 05a719d20..85e659166 100644 --- a/test/tests/merge.js +++ b/test/tests/merge.js @@ -1315,7 +1315,7 @@ describe("Merge", function() { return Promise.reject(new Error( "should not be able to retrieve common merge base")); }, function(err) { - assert.equal("No merge base found", err.message); + assert.equal("no merge base found", err.message); assert.equal(NodeGit.Error.CODE.ENOTFOUND, err.errno); }); }); From 3eb9a3073a8368fcc2f9846905a75b407305786e Mon Sep 17 00:00:00 2001 From: Remy Suen Date: Sun, 26 Feb 2017 16:14:09 +0900 Subject: [PATCH 34/41] Added tests for commit body headerField --- test/tests/commit.js | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/tests/commit.js b/test/tests/commit.js index be066093e..097b45ed7 100644 --- a/test/tests/commit.js +++ b/test/tests/commit.js @@ -586,6 +586,24 @@ describe("Commit", function() { }); }); + it("can get header fields", function() { + var commit = this.commit; + return commit.headerField("parent").then(function(field) { + assert.equal(field, + "ecfd36c80a3e9081f200dfda2391acadb56dac27"); + return commit.headerField("author"); + }) + .then(function(field) { + assert.equal(field, + "Michael Robinson 1362012884 +1300"); + return commit.headerField("committer"); + }) + .then(function(field) { + assert.equal(field, + "Michael Robinson 1362012884 +1300"); + }); + }); + describe("Commit's Author", function() { before(function() { this.author = this.commit.author(); @@ -622,6 +640,28 @@ describe("Commit", function() { }); }); + describe("Commit's Body", function() { + + it("null if only summary", function() { + var test = this; + return NodeGit.Commit.lookup(test.repository, + "15315cf41ad76400d9189c85a5827b77b8c392f1") + .then(function(commit) { + assert.equal(commit.body(), null); + }); + }); + + it("non-null when body exists", function() { + var test = this; + return NodeGit.Commit.lookup(test.repository, + "c82fb078a192ea221c9f1093c64321c60d64aa0d") + .then(function(commit) { + assert.equal(commit.body(), + "Added new methods in checkout and repository"); + }); + }); + }); + it("does not leak", function() { var test = this; From 7be2ce128080e7bf9e3499328bc559a499457fdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Cie=C5=9Blak?= Date: Sun, 26 Feb 2017 18:11:38 +0000 Subject: [PATCH 35/41] Real source files are in generate/templates/templates --- generate/scripts/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate/scripts/utils.js b/generate/scripts/utils.js index 385274400..2771c9ced 100644 --- a/generate/scripts/utils.js +++ b/generate/scripts/utils.js @@ -37,7 +37,7 @@ var util = { if (header) { var commentPrefix = ~header.indexOf('.gyp') ? '#' : '//' content = commentPrefix + - " This is a generated file, modify: generate/templates/" + + " This is a generated file, modify: generate/templates/templates/" + header + "\n\n" + content; From 6317e3ea0b5a74a0b211aee8b2460aec5c4838f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Cie=C5=9Blak?= Date: Sun, 26 Feb 2017 19:56:45 +0000 Subject: [PATCH 36/41] Remove nw.js instructions Per https://github.com/nodegit/nodegit.github.com/issues/47 Instructions will get regenerated on the website if not removed manually. --- guides/README.md | 1 - guides/install/nw.js/README.md | 25 ------------------------- 2 files changed, 26 deletions(-) delete mode 100644 guides/install/nw.js/README.md diff --git a/guides/README.md b/guides/README.md index e4a2bdf14..3fda23c7b 100644 --- a/guides/README.md +++ b/guides/README.md @@ -12,7 +12,6 @@ description: Learning NodeGit - [Basics](install/) - [From source](install/from-source) - [Electron](install/electron/) -- [NW.js](install/nw.js/) *** diff --git a/guides/install/nw.js/README.md b/guides/install/nw.js/README.md deleted file mode 100644 index 05b020b42..000000000 --- a/guides/install/nw.js/README.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -layout: full -menu_item: guides -title: NW.js -description: How to install NodeGit with NW.js ---- - -[Return to all guides](../../) - -* * * - -Install for nwjs ----------------- - -Please see the official nw.js docs [here](http://docs.nwjs.io/en/latest/For%20Users/Advanced/Use%20Native%20Node%20Modules/#node-pre-gyp) - -For a slightly simpler version of the third method, use an `.npmrc` file. For example if you have an NW.js app that's targeting version 0.13.0, your `.npmrc` file would look something like: -``` -runtime = node-webkit -target = 0.13.0 -target_arch = x64 -disturl = http://node-webkit.s3.amazonaws.com -``` - -*NOTE: NW.js support is not thoroughly tested. Additionally, there are no pre-built binaries for NW.js, you must compile NodeGit. Visit our [building guides](../from-source) for help* From e3fd3036e5a29bd61278a54a379e1d13bb9ae3b9 Mon Sep 17 00:00:00 2001 From: John Haley Date: Tue, 28 Feb 2017 06:32:41 -0700 Subject: [PATCH 37/41] Remove `sudo: required` from 32-bit linux builds --- .travis.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index e4602d8ac..49baba0cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,13 +22,10 @@ matrix: include: - os: linux env: export NODE_VERSION="4" TARGET_ARCH="ia32" - sudo: required - os: linux env: export NODE_VERSION="6.5" TARGET_ARCH="ia32" - sudo: required - os: linux env: export NODE_VERSION="7.4" TARGET_ARCH="ia32" - sudo: required git: depth: 1 @@ -50,10 +47,6 @@ before_install: - export npm_config_clang=1 - export JOBS=4 - - if [ $TARGET_ARCH == "ia32" ]; then - sudo ln -s /usr/include/asm-generic /usr/include/asm; - fi - - if [ $TRAVIS_OS_NAME != "linux" ]; then git clone https://github.com/creationix/nvm.git ./.nvm; source ./.nvm/nvm.sh; From d7e8b9e899b39d08e5a2b7492560dab0b794089d Mon Sep 17 00:00:00 2001 From: John Haley Date: Tue, 28 Feb 2017 07:03:01 -0700 Subject: [PATCH 38/41] Add tests back in for 32-bit systems --- .travis.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 49baba0cc..ef6f06fc2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -80,14 +80,10 @@ before_script: - git config --global user.email johndoe@example.com script: - - if [ $TARGET_ARCH == "x64" ]; then - if [ -z "$TRAVIS_TAG" ] && [ $TRAVIS_OS_NAME == "linux" ] && [ $NODE_VERSION == "6" ]; then - npm test && npm run cov && npm run coveralls; - else - npm test; - fi + if [ -z "$TRAVIS_TAG" ] && [ $TRAVIS_OS_NAME == "linux" ] && [ $NODE_VERSION == "6" ]; then + npm test && npm run cov && npm run coveralls; else - echo "Not running tests because the binary is not built for 64-bit systems"; + npm test; fi after_success: From c018da163f50acc6add9df3d74905ec150ce8573 Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Tue, 14 Feb 2017 14:00:44 -0700 Subject: [PATCH 39/41] Use wider int to calculate throttle window --- generate/templates/manual/include/callback_wrapper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate/templates/manual/include/callback_wrapper.h b/generate/templates/manual/include/callback_wrapper.h index b23a7bb36..dacdc6c38 100644 --- a/generate/templates/manual/include/callback_wrapper.h +++ b/generate/templates/manual/include/callback_wrapper.h @@ -47,7 +47,7 @@ class CallbackWrapper { } // throttle if needed uint64_t now = uv_hrtime(); - if(lastCallTime > 0 && now < lastCallTime + throttle * 1000000) { + if(lastCallTime > 0 && now < lastCallTime + throttle * (uint64_t)1000000) { // throttled return true; } else { From 4141760652a425786e3b7978c83473af783ccfff Mon Sep 17 00:00:00 2001 From: tyler wanek Date: Tue, 28 Feb 2017 08:22:04 -0700 Subject: [PATCH 40/41] Should test everything, not just rebase --- test/tests/rebase.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tests/rebase.js b/test/tests/rebase.js index 177c972ae..731884f82 100644 --- a/test/tests/rebase.js +++ b/test/tests/rebase.js @@ -4,7 +4,7 @@ var local = path.join.bind(path, __dirname); var promisify = require("promisify-node"); var fse = promisify(require("fs-extra")); -describe.only("Rebase", function() { +describe("Rebase", function() { var NodeGit = require("../../"); var RepoUtils = require("../utils/repository_setup"); From ad991fdd85b9c67786dd94a7652f0afb1e921027 Mon Sep 17 00:00:00 2001 From: John Haley Date: Tue, 28 Feb 2017 11:43:02 -0700 Subject: [PATCH 41/41] Bump to 0.18.0 --- CHANGELOG.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 +- package.json | 2 +- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7be1c515b..2435a2c8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,74 @@ # Change Log +## v0.18.0 [(2017-02-28)](https://github.com/nodegit/nodegit/releases/tag/v0.18.0) + +[Full Changelog](https://github.com/nodegit/nodegit/compare/v0.17.0...v0.18.0) + +### API Changes + + - All callbacks that go to libgit2 now have an optional `waitForResult` flag that can be `true`/`false`. Defaults to false. When true it will not stop libgit2 from continuing on before the JS code is fully executed and resolved (in cases of a Promise). This is useful for progress callbacks (like fetching) where the bubbling up of the progress to JS doesn't really need the C/C++ code to wait for the JS code to fully handle the event before continuing. This can have serious performance implications for many callbacks that can be fired quite frequently. + - `given_opts` in `Revert.revert` are now optional + - `checkout_opts` in `Reset.fromAnnotated` and `Reset.reset` are now optional + - `Reset.fromAnnotated` is now async + - `message` on `Stash.save` is now optional + - `options` on `Stash.apply` and `Stash.pop` is now optional + - Added `processMergeMessageCallback` on `Repository#mergeBranches` to allow for custom merge messages + - Add `beforeFinishFn` to `Repository#rebaseBranches` and `Repository#continueRebase`. This is called before the invocation of `finish()`. If the callback returns a promise, `finish()` will be called when the promise resolves. The `beforeFinishFn` will be called with an object that has on it: + - `ontoName` The name of the branch that we rebased onto + - `ontoSha` The sha that we rebased onto + - `originalHeadName` The name of the branch that we rebased + - `originalHeadSha` The sha of the branch that was rebased + - `rewitten` which is an array of sha pairs that contain which contain what the commit sha was before the rebase and what the commit sha is after the rebase + +### Summary of Changes from bumping libgit2 to 43275f5 + +[PR #1123](https://github.com/nodegit/nodegit/pull/1223) bumped libgit2 which brought in many changes and bug fixes. + +#### Included merged libgit2 PRs: + + - [Use a shared buffer in calls of git_treebuilder_write to avoid heap contention #3892](https://github.com/libgit2/libgit2/pull/3892) + - [WinHTTP: set proper error messages when SSL fails #4050](https://github.com/libgit2/libgit2/pull/4050) + - [Clang analyzer run #4051](https://github.com/libgit2/libgit2/pull/4051) + - [Extend packfile in increments of page_size. #4053](https://github.com/libgit2/libgit2/pull/4053) + - [Fix general example memory leaks #4078](https://github.com/libgit2/libgit2/pull/4078) + - [WIP: some coverity & compiler warning fixes #4086](https://github.com/libgit2/libgit2/pull/4086) + - [Fix a few recent warnings #4087](https://github.com/libgit2/libgit2/pull/4087) + - [Fix uninitialized variable warning #4095](https://github.com/libgit2/libgit2/pull/4095) + - [Update docs for git_oid_fromstrn and p #4096](https://github.com/libgit2/libgit2/pull/4096) + - [Fix digest credentials for proxy in windows #4104](https://github.com/libgit2/libgit2/pull/4104) + - [Vector reverse overflow #4105](https://github.com/libgit2/libgit2/pull/4105) + - [Flag given_opts in git_revert as optional #4108](https://github.com/libgit2/libgit2/pull/4108) + - [Flag checkout_opts in git_reset as optional #4109](https://github.com/libgit2/libgit2/pull/4109) + - [dirname with DOS prefixes #4111](https://github.com/libgit2/libgit2/pull/4111) + - [Add support for lowercase proxy environment variables #4112](https://github.com/libgit2/libgit2/pull/4112) + - [Flag options in git_stash_apply and git_stash_pop as being optional #4117](https://github.com/libgit2/libgit2/pull/4117) + - [rename detection: don't try to detect submodule renames #4119](https://github.com/libgit2/libgit2/pull/4119) + - [tests: fix permissions on testrepo.git index file #4121](https://github.com/libgit2/libgit2/pull/4121) + +#### Included non-merged libgit2 PRs: + + - [negotiate always fails via libcurl #4126](https://github.com/libgit2/libgit2/pull/4126) + - [Fix proxy auto detect not utilizing callbacks #4097](https://github.com/libgit2/libgit2/pull/4097) + +### Summary of Changes to NodeGit outside of libgit2 bump + + - Don't overwrite C++ files for things that haven't changed [PR #1091](https://github.com/nodegit/nodegit/pull/1091) + - Add the option to "fire and forget" callbacks so libgit2 doesn't wait for JS to finish before proceeding [PR #1208](https://github.com/nodegit/nodegit/pull/1208) + - Send back the error code from libgit2 when a call fails [PR #1209](https://github.com/nodegit/nodegit/pull/1209) + - Initialize pointers to null [PR #1210](https://github.com/nodegit/nodegit/pull/1210) + - Replace Gitter with Slack [PR #1212](https://github.com/nodegit/nodegit/pull/1212) + - Make `given_opts` in `Revert.revert` optional [PR #1213](https://github.com/nodegit/nodegit/pull/1213) + - Make `Reset.fromAnnotated` async and `checkout_opts` optional [PR #1214](https://github.com/nodegit/nodegit/pull/1214) + - Make `message` on `Stash.save` optional [PR #1215](https://github.com/nodegit/nodegit/pull/1215) + - Add `Remote.ls` to NodeGit [PR #1218](https://github.com/nodegit/nodegit/pull/1218) + - Add `processMergeMessageCallback` to `Repository#mergeBranches` to allow for custom merge messages [PR #1219](https://github.com/nodegit/nodegit/pull/1219) + - Bump libgit2 to 43275f5 [PR #1223](https://github.com/nodegit/nodegit/pull/1223) from srajko/bump-libgit + - Provide rebase details on finish [PR #1224](https://github.com/nodegit/nodegit/pull/1224) + - Use wider int to calculate throttle window [PR #1232](https://github.com/nodegit/nodegit/pull/1232) + - Update comment to reflect the correct path for generated code output [PR #1236](https://github.com/nodegit/nodegit/pull/1236) + - Remove nwjs example from the docs [PR #1238](https://github.com/nodegit/nodegit/pull/1238) + - Remove `sudo` requirement from linux 32-bit builds [PR #1241](https://github.com/nodegit/nodegit/pull/1241) + ## v0.17.0 [(2017-01-06)](https://github.com/nodegit/nodegit/releases/tag/v0.17.0) [Full Changelog](https://github.com/nodegit/nodegit/compare/v0.16.0...v0.17.0) diff --git a/README.md b/README.md index 84eed5ff8..91907f79b 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ NodeGit -**Stable (libgit2#master): 0.17.0** +**Stable (libgit2#master): 0.18.0** **Stable (libgit2@0.24): 0.14.1** ## Have a problem? Come chat with us! ## diff --git a/package.json b/package.json index 2d67156ec..ff52b8d84 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nodegit", "description": "Node.js libgit2 asynchronous native bindings", - "version": "0.17.0", + "version": "0.18.0", "homepage": "http://nodegit.org", "keywords": [ "libgit2",