diff --git a/.npmignore b/.npmignore index bf9f1e379..046bdf56a 100644 --- a/.npmignore +++ b/.npmignore @@ -1,11 +1,14 @@ +/.travis/ /build/ /examples/ +/generate/ +/guides/ +/lib/ /test/ /vendor/Release/ -/generate/output -/generate/**/*.json -!/generate/input/*.json +!/include +!/src .astylerc .editorconfig @@ -15,8 +18,10 @@ .travis.yml appveyor.yml -*.vcxproj +!binding.gyp + *.filters -*.sln *.log *.md +*.sln +*.vcxproj diff --git a/.travis.yml b/.travis.yml index 3bc67c522..8324af2fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -78,7 +78,7 @@ before_install: fi install: - - BUILD_ONLY=true npm install + - npm install # This is a random private key used purely for testing. before_script: diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a68b5b8d..a6a0e149b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## v0.14.0 [(2016-06-09)](https://github.com/nodegit/nodegit/releases/tag/v0.14.0) + +[Full Changelog](https://github.com/nodegit/nodegit/compare/v0.13.2...v0.14.0) + +- Improve lifecycle scripts and install process [PR #1055](https://github.com/nodegit/nodegit/pull/1055) +- Fix example code [PR #1058](https://github.com/nodegit/nodegit/pull/1058) + ## v0.13.2 [(2016-06-09)](https://github.com/nodegit/nodegit/releases/tag/v0.13.2) [Full Changelog](https://github.com/nodegit/nodegit/compare/v0.13.1...v0.13.2) diff --git a/README.md b/README.md index c46b32758..8eccf2883 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ NodeGit -**Stable: 0.13.2** +**Stable: 0.14.0** ## Have a problem? Come chat with us! ## diff --git a/appveyor.yml b/appveyor.yml index 7081da9f3..3934f045e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,7 +23,6 @@ init: # what combinations to test environment: JOBS: 4 - BUILD_ONLY: true GIT_SSH: c:\projects\nodegit\vendor\plink.exe GYP_MSVS_VERSION: 2013 matrix: diff --git a/examples/clone.js b/examples/clone.js index b6171e864..a23060464 100644 --- a/examples/clone.js +++ b/examples/clone.js @@ -31,7 +31,7 @@ fse.remove(path).then(function() { return entry.getBlob(); }) .done(function(blob) { - console.log(entry.filename(), entry.sha(), blob.rawsize() + "b"); + console.log(entry.name(), entry.sha(), blob.rawsize() + "b"); console.log("========================================================\n\n"); var firstTenLines = blob.toString().split("\n").slice(0, 10).join("\n"); console.log(firstTenLines); diff --git a/examples/general.js b/examples/general.js index 7062f134f..ce432cb50 100644 --- a/examples/general.js +++ b/examples/general.js @@ -220,7 +220,7 @@ nodegit.Repository.open(path.resolve(__dirname, "../.git")) if (entry.isDirectory()) { promises.push(entry.getTree().then(dfs)); } else if (entry.isFile()) { - console.log("Tree Entry:", entry.filename()); + console.log("Tree Entry:", entry.name()); } }); diff --git a/examples/read-file.js b/examples/read-file.js index 4203a5cf4..991a5ae39 100644 --- a/examples/read-file.js +++ b/examples/read-file.js @@ -16,7 +16,7 @@ nodegit.Repository.open(path.resolve(__dirname, "../.git")) return _entry.getBlob(); }) .then(function(blob) { - console.log(_entry.filename(), _entry.sha(), blob.rawsize() + "b"); + console.log(_entry.name(), _entry.sha(), blob.rawsize() + "b"); console.log("========================================================\n\n"); var firstTenLines = blob.toString().split("\n").slice(0, 10).join("\n"); console.log(firstTenLines); diff --git a/generate/index.js b/generate/index.js index 739ef15c7..6bdaa42ef 100644 --- a/generate/index.js +++ b/generate/index.js @@ -4,6 +4,8 @@ var generateMissingTests = require("./scripts/generateMissingTests"); var submoduleStatus = require("../lifecycleScripts/submodules/getStatus"); module.exports = function generate() { + console.log("[nodegit] Generating native code"); + return submoduleStatus() .then(function(statuses) { var dirtySubmodules = statuses @@ -14,9 +16,9 @@ module.exports = function generate() { }); if (dirtySubmodules.length) { - console.log("WARNING - Some submodules are out-of-sync"); + console.warn("[nodegit] WARNING - Some submodules are out-of-sync"); dirtySubmodules.forEach(function(submodule) { - console.log("\t" + submodule.name); + console.warn("[nodegit]\t" + submodule.name); }); } }) @@ -26,8 +28,8 @@ module.exports = function generate() { generateMissingTests(); }) .catch(function(e) { - console.log("ERROR - Could not generate native code"); - console.log(e); + console.error("[nodegit] ERROR - Could not generate native code"); + console.error(e); }); } diff --git a/generate/scripts/generateJson.js b/generate/scripts/generateJson.js index 369218b2e..f1afeb956 100644 --- a/generate/scripts/generateJson.js +++ b/generate/scripts/generateJson.js @@ -222,7 +222,7 @@ module.exports = function generateJson() { _.merge(enumerable, _.omit(override, ["values"])); output.push(enumerable); - }).value(); + }); output = _.sortBy(output, "typeName"); diff --git a/generate/scripts/generateMissingTests.js b/generate/scripts/generateMissingTests.js index 1094de8a1..4aef70f4d 100644 --- a/generate/scripts/generateMissingTests.js +++ b/generate/scripts/generateMissingTests.js @@ -1,6 +1,4 @@ const path = require("path"); -const promisify = require("promisify-node"); -const fse = promisify(require("fs-extra")); const utils = require("./utils"); const testFilesPath = "../test/tests"; diff --git a/generate/scripts/helpers.js b/generate/scripts/helpers.js index b1c265201..bb4953e8e 100644 --- a/generate/scripts/helpers.js +++ b/generate/scripts/helpers.js @@ -345,7 +345,7 @@ var Helpers = { if (fnDef.jsFunctionName == utils.camelCase(collidingName)) { fnDef.jsFunctionName = utils.camelCase(newName); } - }).value(); + }); if ("git_" + typeDef.typeName == fnDef.cFunctionName) { fnDef.useAsOnRootProto = true; diff --git a/generate/scripts/utils.js b/generate/scripts/utils.js index b09d9a15f..6868bf653 100644 --- a/generate/scripts/utils.js +++ b/generate/scripts/utils.js @@ -1,4 +1,3 @@ -const promisify = require("promisify-node"); const fse = require("fs-extra"); const fs = require("fs"); diff --git a/lifecycleScripts/configureLibssh2.js b/lifecycleScripts/configureLibssh2.js index efc3920c1..23acd1ff0 100644 --- a/lifecycleScripts/configureLibssh2.js +++ b/lifecycleScripts/configureLibssh2.js @@ -42,6 +42,6 @@ if (require.main === module) { console.log("nothing to do"); } else { - module.exports(); + module.exports().done(); } } diff --git a/lifecycleScripts/install.js b/lifecycleScripts/install.js index cde01665f..16b047120 100644 --- a/lifecycleScripts/install.js +++ b/lifecycleScripts/install.js @@ -1,187 +1,62 @@ -var path = require("path"); -var fs = require("fs"); -var cp = require("child_process"); -var prepareForBuild = require("./prepareForBuild"); -var exec = require("../utils/execPromise"); +var buildFlags = require("../utils/buildFlags"); +var spawn = require("child_process").spawn; module.exports = function install() { - var fromRegistry; + console.log("[nodegit] Running install script"); - try { - fs.statSync(path.join(__dirname, "..", "include")); - fs.statSync(path.join(__dirname, "..", "src")); - fs.statSync(path.join(__dirname, "..", "dist")); - fromRegistry = true; - } - catch(e) { - fromRegistry = false; - } + var nodePreGyp = "node-pre-gyp"; - if (!fromRegistry) { - console.info("[nodegit] Local install, no fetching allowed."); - return prepareAndBuild(); - } - if (process.env.BUILD_DEBUG) { - console.info("[nodegit] Doing a debug build, no fetching allowed."); - return prepareAndBuild(); - } - if (process.env.BUILD_ONLY) { - console.info("[nodegit] BUILD_ONLY is set to true, no fetching allowed."); - return prepareAndBuild(); + if (process.platform === "win32") { + nodePreGyp += ".cmd"; } - return installPrebuilt(); + var args = ["install"]; - function installPrebuilt() { - console.info("[nodegit] Fetching binary from S3."); - var npg = pathForTool("node-pre-gyp"); - return exec("\""+ npg + "\" install --fallback-to-build=false") - .then( - function() { - console.info("[nodegit] Completed installation successfully."); - }, - function(err) { - console.info("[nodegit] Failed to install prebuilt binary:"); - console.error(err); - console.info("[nodegit] Building manually. (You'll be here a while.)"); - return prepareAndBuild(); - } + if (buildFlags.mustBuild) { + console.info( + "[nodegit] Pre-built download disabled, building from source." ); - } + args.push("--build-from-source"); - function pathForTool(name) { - var toolPath = path.resolve(".", "node_modules", ".bin", name); - if (process.platform == "win32") { - toolPath += ".cmd"; + if (buildFlags.debugBuild) { + console.info("[nodegit] Building debug version."); + args.push("--debug"); } - return toolPath; } - - function prepareAndBuild() { - console.info("[nodegit] Regenerating and configuring code"); - return prepareForBuild() - .then(function() { - return build(); - }) - .then(function() { - return transpileJavascript(); - }); + else { + args.push("--fallback-to-build"); } - function transpileJavascript() { - var cmd = pathForTool("babel"); - var args = [ - "--presets", - "es2015", - "-d", - "./dist", - "./lib" - ]; - var opts = { - cwd: ".", - maxBuffer: Number.MAX_VALUE, - env: process.env, - stdio: "inherit" - }; - var home = process.platform == "win32" ? - process.env.USERPROFILE : process.env.HOME; + return new Promise(function(resolve, reject) { + var spawnedNodePreGyp = spawn(nodePreGyp, args); - opts.env.HOME = path.join(home, ".nodegit-gyp"); - - return new Promise(function(resolve, reject) { - var child = cp.spawn(cmd, args, opts); - child.on("close", function(code) { - if (code) { - reject(code); - process.exitCode = 13; - } - else { - resolve(); - } - }); + spawnedNodePreGyp.stdout.on("data", function(data) { + console.info(data.toString().trim()); }); - } - - function build() { - console.info("[nodegit] Everything is ready to go, attempting compilation"); - var electronVersion = process.env.ELECTRON_VERSION; - var nwjsVersion = process.env.NWJS_VERSION; - var opts = { - cwd: ".", - maxBuffer: Number.MAX_VALUE, - env: process.env, - stdio: "inherit" - }; - - var builder = "node-gyp"; - var debug = (process.env.BUILD_DEBUG ? "--debug" : ""); - var target = ""; - var arch = (process.env.TARGET_ARCH ? - "--arch=" + process.env.TARGET_ARCH : ""); - var distUrl = ""; - var runtime = ""; - - process.argv.forEach(function(arg) { - if (~arg.indexOf("electronVersion")) { - electronVersion = arg.split("=")[1].trim(); - } - else if (~arg.indexOf("nsjwVersion")) { - nwjsVersion = arg.split("=")[1].trim(); - } - }); + spawnedNodePreGyp.stderr.on("data", function(data) { + console.error(data.toString().trim()); + }); - if (electronVersion) { - target = "--target=" + electronVersion; - distUrl = "--dist-url=https://atom.io/download/atom-shell"; - runtime = "--runtime=electron"; + spawnedNodePreGyp.on("close", function(code) { + if (!code) { + resolve(); + } else { + reject(code); } - else if (nwjsVersion) { - builder = "nw-gyp"; - target = "--target=" + nwjsVersion; - runtime = "--runtime=node-webkit"; - } - - var home = process.platform == "win32" ? - process.env.USERPROFILE : process.env.HOME; - - opts.env.HOME = path.join(home, ".nodegit-gyp"); - - var cmd = pathForTool(builder); - var args = [ - "rebuild", - debug, - target, - arch, - distUrl, - runtime - ] - .filter(function(arg) { - return arg; - }); - - return new Promise(function(resolve, reject) { - var child = cp.spawn(cmd, args, opts); - child.on("close", function(code) { - console.log(code); - if (code) { - reject(code); - process.exitCode = 13; - } - else { - resolve(); - } - }); - }); - } + }); + }) + .then(function() { + console.info("[nodegit] Completed installation successfully."); + }); }; // Called on the command line if (require.main === module) { - module - .exports() - .catch(function(err) { - console.error(err); - return -1; + module.exports() + .catch(function(e) { + console.error("[nodegit] ERROR - Could not finish install"); + console.error("[nodegit] ERROR - finished with error code: " + e); + process.exit(e); }); } diff --git a/lifecycleScripts/postinstall.js b/lifecycleScripts/postinstall.js new file mode 100755 index 000000000..5e543da53 --- /dev/null +++ b/lifecycleScripts/postinstall.js @@ -0,0 +1,80 @@ +var fse = require("fs-extra"); +var path = require("path"); + +var exec = require("../utils/execPromise"); +var buildFlags = require("../utils/buildFlags"); + +var rootPath = path.join(__dirname, ".."); + +function printStandardLibError() { + console.log( + "[nodegit] ERROR - the latest libstdc++ is missing on your system!" + ); + console.log(""); + console.log("On Ubuntu you can install it using:"); + console.log(""); + console.log("$ sudo add-apt-repository ppa:ubuntu-toolchain-r/test"); + console.log("$ sudo apt-get update"); + console.log("$ sudo apt-get install libstdc++-4.9-dev"); +} + +module.exports = function install() { + if (buildFlags.isGitRepo) { + // If we're building NodeGit from a git repo we aren't going to do any + // cleaning up + return Promise.resolve(); + } + + return exec("node dist/nodegit.js") + .catch(function(e) { + if (~e.toString().indexOf("Module version mismatch")) { + console.warn( + "[nodegit] WARN - NodeGit was built for a different version of node." + ); + console.warn( + "If you are building NodeGit for electron/nwjs you can " + + "ignore this warning." + ); + } + else { + throw e; + } + }) + .then(function() { + // Is we're using NodeGit from a package manager then let's clean up after + // ourselves when we install successfully. + if (!buildFlags.mustBuild) { + // We can't remove the source files yet because apparently the + // "standard workflow" for native node moduels in Electron/nwjs is to + // build them for node and then nah eff that noise let's rebuild them + // again for the actual platform! Hurray!!! When that madness is dead + // we can clean up the source which is a serious amount of data. + // fse.removeSync(path.join(rootPath, "vendor")); + // fse.removeSync(path.join(rootPath, "src")); + // fse.removeSync(path.join(rootPath, "include")); + + fse.removeSync(path.join(rootPath, "build/Release/*.a")); + fse.removeSync(path.join(rootPath, "build/Release/obj.target")); + } + }); +}; + +// Called on the command line +if (require.main === module) { + module.exports() + .catch(function(e) { + console.error("[nodegit] ERROR - Could not finish postinstall"); + + if ( + process.pladtform === "linux" && + ~e.toString().indexOf("libstdc++") + ) { + printStandardLibError(); + } + else { + console.log(e); + } + + process.exit(1); + }); +} diff --git a/lifecycleScripts/preinstall.js b/lifecycleScripts/preinstall.js new file mode 100644 index 000000000..4d712aa83 --- /dev/null +++ b/lifecycleScripts/preinstall.js @@ -0,0 +1,43 @@ +var path = require("path"); +var local = path.join.bind(path, __dirname); + +var exec = require(local("../utils/execPromise")); +var configure = require(local("configureLibssh2")); +var buildFlags = require(local("../utils/buildFlags")); + +module.exports = function prepareForBuild() { + console.log("[nodegit] Running pre-install script"); + + return exec("npm -v") + .then(function(npmVersion) { + if (npmVersion.split(".")[0] < 3) { + console.log("[nodegit] npm@2 installed, pre-loading required packages"); + return exec("npm install --ignore-scripts"); + } + + return Promise.resolve(); + }) + .then(function() { + return configure(); + }) + .then(function() { + if (buildFlags.isGitRepo) { + var submodules = require(local("submodules")); + var generate = require(local("../generate")); + return submodules() + .then(function() { + return generate(); + }); + } + }); +}; + +// Called on the command line +if (require.main === module) { + module.exports() + .catch(function(e) { + console.error("[nodegit] ERROR - Could not finish preinstall"); + console.error(e); + process.exit(1); + }); +} diff --git a/lifecycleScripts/prepareForBuild.js b/lifecycleScripts/prepareForBuild.js deleted file mode 100644 index 27557d273..000000000 --- a/lifecycleScripts/prepareForBuild.js +++ /dev/null @@ -1,37 +0,0 @@ -var cp = require("child_process"); -var path = require("path"); - -var local = path.join.bind(path, __dirname); - -var submodules = require(local("submodules")); -var configure = require(local("configureLibssh2")); -var generate = require(local("../generate")); - -module.exports = function prepareForBuild() { - return new Promise(function(resolve, reject) { - cp.exec("npm install --ignore-scripts", function(err, stdout, stderr) { - if (err) { - console.error(stderr); - reject(err, stderr); - } - else { - resolve(); - console.info(stdout); - } - }); - }) - .then(function() { - return submodules(); - }) - .then(function() { - return Promise.all([ - configure(), - generate() - ]); - }); -}; - -// Called on the command line -if (require.main === module) { - module.exports(); -} diff --git a/lifecycleScripts/submodules/index.js b/lifecycleScripts/submodules/index.js index 596d255e4..17a2e5565 100644 --- a/lifecycleScripts/submodules/index.js +++ b/lifecycleScripts/submodules/index.js @@ -11,12 +11,13 @@ var exec = require(path.join(rootDir, "./utils/execPromise")); module.exports = function submodules() { return gitExecutableLocation() .catch(function() { - console.log("ERROR - Compilation of NodeGit requires git CLI to be " + - "installed and on the path"); + console.error("[nodegit] ERROR - Compilation of NodeGit requires git " + + "CLI to be installed and on the path"); throw new Error("git CLI is not installed or not on the path"); }) .then(function() { + console.log("[nodegit] Checking submodule status"); return submoduleStatus(); }) .then(function(statuses) { @@ -33,11 +34,11 @@ module.exports = function submodules() { }); if (dirtySubmodules.length) { - console.log( - "ERROR - The following submodules have uncommited changes:" + console.error( + "[nodegit] ERROR - Some submodules have uncommited changes:" ); dirtySubmodules.forEach(printSubmodule); - console.log( + console.error( "\nThey must either be committed or discarded before we build" ); @@ -53,11 +54,11 @@ module.exports = function submodules() { }); if (outOfSyncSubmodules.length) { - console.log( - "WARNING - The following submodules are pointing to an new commit:" + console.warn( + "[nodegit] WARNING - Some submodules are pointing to an new commit:" ); outOfSyncSubmodules.forEach(printSubmodule); - console.log("\nThey will not be updated."); + console.warn("\nThey will not be updated."); } return Promise.all(statuses @@ -65,6 +66,8 @@ module.exports = function submodules() { return !status.onNewCommit; }) .map(function(submoduleToUpdate) { + console.log("[nodegit] Initializing submodules"); + return exec( "git submodule update --init --recursive " + submoduleToUpdate.name ); diff --git a/package.json b/package.json index e5d431d25..9b236e6bb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nodegit", "description": "Node.js libgit2 asynchronous native bindings", - "version": "0.13.2", + "version": "0.14.0", "homepage": "http://nodegit.org", "keywords": [ "libgit2", @@ -33,15 +33,16 @@ "engines": { "node": ">= 0.12" }, - "bundledDependencies": [ - "node-pre-gyp" - ], "dependencies": { "fs-extra": "~0.26.2", + "lodash": "^4.13.1", + "nan": "^2.2.0", + "node-gyp": "^3.3.1", "node-pre-gyp": "~0.6.15", "promisify-node": "~0.3.0" }, "devDependencies": { + "aws-sdk": "^2.3.19", "babel-cli": "^6.7.7", "babel-preset-es2015": "^6.6.0", "clean-for-publish": "~1.0.2", @@ -51,11 +52,7 @@ "js-beautify": "~1.5.10", "jshint": "~2.8.0", "lcov-result-merger": "~1.0.2", - "lodash": "~3.10.1", - "mocha": "~2.3.4", - "nan": "^2.2.0", - "node-gyp": "~3.0.3", - "nw-gyp": "~0.12.4" + "mocha": "~2.3.4" }, "vendorDependencies": { "libgit2": { @@ -84,8 +81,9 @@ "mergecov": "lcov-result-merger 'test/**/*.info' 'test/coverage/merged.lcov' && ./lcov-1.10/bin/genhtml test/coverage/merged.lcov --output-directory test/coverage/report", "mocha": "mocha test/runner test/tests --timeout 15000", "mochaDebug": "mocha --debug-brk test/runner test/tests --timeout 15000", - "postinstall": "node postinstall.js", - "prepublish": "node lifecycleScripts/prepareForBuild.js && npm run babel", + "postinstall": "node lifecycleScripts/postinstall", + "preinstall": "node lifecycleScripts/preinstall", + "prepublish": "npm run babel", "rebuild": "node generate && npm run babel && node-gyp configure build", "rebuildDebug": "node generate && npm run babel && node-gyp configure --debug build", "recompile": "node-gyp configure build", diff --git a/postinstall.js b/postinstall.js deleted file mode 100755 index 88047959f..000000000 --- a/postinstall.js +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env node - -var fs = require("fs"); -var child_process = require("child_process"); - -if (process.platform !== "linux") { - return; -} - -child_process.exec("node dist/nodegit.js", function(error, stdout, stderr) { - if (stderr && ~stderr.indexOf("libstdc++")) { - console.log("[ERROR] Seems like the latest libstdc++ is missing on your system!"); - console.log(""); - console.log("On Ubuntu you can install it using:"); - console.log(""); - console.log("$ sudo add-apt-repository ppa:ubuntu-toolchain-r/test"); - console.log("$ sudo apt-get update"); - console.log("$ sudo apt-get install libstdc++-4.9-dev"); - } -}); diff --git a/utils/buildFlags.js b/utils/buildFlags.js new file mode 100644 index 000000000..7b41cae83 --- /dev/null +++ b/utils/buildFlags.js @@ -0,0 +1,17 @@ +var fs = require("fs"); +var path = require("path"); + +var isGitRepo; + +try { + fs.statSync(path.join(__dirname, "..", ".git")); + isGitRepo = true; +} catch (e) { + isGitRepo = false; +} + +module.exports = { + debugBuild: process.env.BUILD_DEBUG, + isGitRepo: isGitRepo, + mustBuild: isGitRepo || process.env.BUILD_DEBUG || process.env.BUILD_ONLY, +}; diff --git a/utils/execPromise.js b/utils/execPromise.js index d369ab612..c186a12bc 100644 --- a/utils/execPromise.js +++ b/utils/execPromise.js @@ -1,6 +1,17 @@ -var promisify = require("promisify-node"); var cp = require('child_process'); -module.exports = promisify(function(command, opts, callback) { - return cp.exec(command, opts, callback); -}); +// We have to manually promisify this because at this is required in lifecycle +// methods and we are not guaranteed that any 3rd party packages are installed +// at this point +module.exports = function(command, opts) { + return new Promise(function(resolve, reject) { + return cp.exec(command, opts, function(err, result) { + if (err) { + reject(err); + } + else { + resolve(result); + } + }); + }); +};