UNPKG

gypkg

Version:

GYP based package manager

165 lines (128 loc) 4.42 kB
'use strict'; const path = require('path'); const fs = require('fs'); const os = require('os'); const url = require('url'); const util = require('util'); const spawnSync = require('child_process').spawnSync; const spawn = require('child_process').spawn; const async = require('async'); const rimraf = require('rimraf'); const GYP_MAIN = path.join(__dirname, '..', 'tools', 'gyp', 'gyp_main.py'); const COMMON_GYPI = path.join(__dirname, '..', 'common.gypi'); const GIT = process.env.GIT_SSH_COMMAND || process.env.GIT_SSH || process.env.GIT_EXEC_PATH || 'git'; function GYPKG() { // Nothing to initialize } module.exports = GYPKG; GYPKG.prototype.generate = function generate(gyp, extra) { const GYP_FILE = path.resolve(gyp); const ROOT_DIR = path.dirname(GYP_FILE); const OUT_DIR = path.join(ROOT_DIR, 'out'); const OPTIONS_GYPI = path.resolve(ROOT_DIR, 'options.gypi'); let args = [ GYP_MAIN, GYP_FILE, `-I${COMMON_GYPI}`, `--depth=${path.resolve('.')}` ]; if (fs.existsSync(OPTIONS_GYPI)) args.push(`-I${OPTIONS_GYPI}`); // Default to make if (process.platform !== 'win32') { if (!extra.some(arg => arg === '-f')) args.push('-f', 'make'); if (!extra.some(arg => arg === 'ninja')) { args.push(`-Goutput_dir=${OUT_DIR}`); args.push(`--generator-output=${OUT_DIR}`); } } if (!extra.some(arg => /^-Dhost_arch=/.test(arg))) args.push(`-Dhost_arch=${os.arch()}`); if (!extra.some(arg => /^-Dtarget_arch=/.test(arg))) args.push(`-Dtarget_arch=${os.arch()}`); // Compatibility with existing GYP files if (!extra.some(arg => /^-Dlibrary=/.test(arg))) args.push(`-Dlibrary=static_library`); args = args.concat(extra); const env = {}; util._extend(env, process.env); env.GYPKG_DEPS = path.resolve(ROOT_DIR, 'gypkg_deps'); console.log(`Running GYP with arguments:\n ${args.slice(1).join(' ')}`); const res = spawnSync('python', args, { env: env, stdio: [ 'inherit', null, 'pipe' ] }); if (res.status !== 0) throw new Error(res.stderr.toString()); }; GYPKG.prototype.deps = function deps(list, callback) { async.map(list, (dep, callback) => { const match = dep.match(/^(.*):([^:]+):([^:]+)$/); if (!match) return callback(new Error('Dependency format is: "url:file.gyp:target"')); this.installDep(match[1], match[2], match[3], callback); }, callback) }; GYPKG.prototype.installDep = function installDep(uri, gyp, target, callback) { let branch = uri.match(/#([^#]+)$/); if (branch !== null) { branch = branch[1]; uri = uri.replace(/#[^#]+$/, ''); } uri = uri.replace(/^git@([^:]*):(.*)(?:.git)?$/, 'git+ssh://$1/$2'); const parsed = url.parse(uri); // Local file if (!parsed.protocol) { if (branch) return callback(new Error('Can\'t use a branch of a local dependency')); return callback(null, path.join(parsed.path, gyp) + ':' + target); } let id = parsed.path.slice(1); if (branch) id += '@' + branch; else id += '@latest'; if (parsed.host !== 'github.com') id = path.join(parsed.host, id); const INSTALL_DIR = path.join(process.env.GYPKG_DEPS, id); function done(err) { if (err) return callback(err); callback(null, path.join(INSTALL_DIR, gyp) + ':' + target); } // TODO(indutny): support semver (very large task) fs.exists(INSTALL_DIR, (exists) => { if (exists) return this.updateDep(INSTALL_DIR, uri, branch, done); else return this.cloneDep(INSTALL_DIR, uri, branch, done); }); }; GYPKG.prototype.git = function git(args, options, callback) { const git = spawn(GIT, args, util._extend({ stdio: [ 'inherit', null, 'pipe' ] }, options)); let chunks = ''; git.stderr.on('data', chunk => chunks += chunk); git.on('exit', (code) => { if (code !== 0) return callback(new Error(`git ${args.join(' ')} failed\n${chunks}`)); return callback(null); }); }; GYPKG.prototype.updateDep = function updateDep(target, uri, branch, callback) { const options = { cwd: target }; const args = [ 'pull', uri ]; if (branch) args.push(branch); this.git(args, options, callback); }; GYPKG.prototype.cloneDep = function cloneDep(target, uri, branch, callback) { const args = [ 'clone', '--depth', 1 ]; if (branch) args.push('--branch', branch); args.push(uri, target); this.git(args, {}, callback); };