// Core Node.js modules. var os = require('os'); var fs = require('fs'); var path = require('path'); var zlib = require('zlib'); var exec = require('child_process').exec; // Third-party modules. var Q = require('q'); var request = require('request'); var tar = require('tar'); var which = require('which'); // This will take in an object and find any matching keys in the environment // to use as overrides. // // ENV variables: // // PKG: Location of `package.json` sans `.json`. // LIBGIT2: Location of libgit2 source. // BUILD: Location of nodegit build directory. function envOverride(obj) { // Look through all keys. return Object.keys(obj).reduce(function(obj, key) { var normalize = key.toUpperCase(); // Check for process environment existence. if (normalize in process.env) { obj[key] = process.env[normalize]; } return obj; }, obj); } // Convert to the correct system path. function systemPath(parts) { return parts.join(path.sep); } // Will be used near the end to configure `node-gyp`. var python; var local = path.join.bind(path, __dirname); // Common reusable paths that can be overwritten by environment variables. var paths = envOverride({ pkg: local('package'), libgit2: local('vendor/libgit2/'), sys: { include: local('include/sys'), src: local('src/sys'), build: local('build/Release/obj.target/src/sys') } }); // Load the package.json. var pkg = require(paths.pkg); // Ensure all dependencies are available. var dependencies = Q.allSettled([ // This will prioritize `python2` over `python`, because we always want to // work with Python 2.* if it's available. Q.nfcall(which, 'python2'), Q.nfcall(which, 'python'), ]) // Determine if all the dependency requirements are met. .then(function(results) { console.info('[nodegit] Determining dependencies.'); // Assign to reusable variables. python = results[0].value || results[1].value; // Missing Python. if (!python) { throw new Error('Python is required to build libgit2.'); } // Now lets check the Python version to ensure it's < 3. return Q.nfcall(exec, python + ' --version').then(function(version) { if (version[1].indexOf('Python 3') === 0) { throw new Error('Incorrect version of Python, gyp requires < 3.'); } }); }) // Successfully found all dependencies. First step is to detect the vendor // directory. .then(function() { console.info('[nodegit] Detecting vendor/libgit2.'); return Q.ninvoke(fs, 'stat', paths.libgit2); }) // If the directory already exists, no need to refetch. .fail(function() { // Otherwise fetch the libgit2 source from GitHub. console.info('[nodegit] Fetching vendor/libgit2.'); var url = 'https://github.com/libgit2/libgit2/tarball/' + pkg.libgit2.sha; var extract = tar.Extract({ path: paths.libgit2, strip: true }); // First extract from Zlib and then extract from Tar. var expand = request.get(url).pipe(zlib.createUnzip()).pipe(extract); return Q.ninvoke(expand, 'on', 'end'); }) // Configure the native module using node-gyp. .then(function() { console.info('[nodegit] Configuring native node module.'); return Q.nfcall(exec, systemPath([ '.', 'node_modules', '.bin', 'node-gyp configure --python ' + python ]), { cwd: '.' }); }) // Build the native module using node-gyp. .then(function() { console.info('[nodegit] Building native node module.'); return Q.nfcall(exec, systemPath([ '.', 'node_modules', '.bin', 'node-gyp build' ]), { cwd: '.', maxBuffer: Number.MAX_VALUE }); }) // Display a success message. .then(function() { console.info('[nodegit] Completed installation successfully.'); }) // Display a warning message about failing to build native node module. .fail(function(message) { console.info('[nodegit] Failed to build nodegit.'); console.info(message.message); console.info(message.stack); });