"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault.js"); Object.defineProperty(exports, "__esModule", { value: true }); exports.exec = exec; var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator.js")); var _fsExtra = require("fs-extra"); var _log = require("./log.js"); var _pkgFetch = require("pkg-fetch"); var _assert = _interopRequireDefault(require("assert")); var _help = _interopRequireDefault(require("./help")); var _common = require("../prelude/common.js"); var _minimist = _interopRequireDefault(require("minimist")); var _packer = _interopRequireDefault(require("./packer.js")); var _path = _interopRequireDefault(require("path")); var _chmod = require("./chmod.js"); var _producer = _interopRequireDefault(require("./producer.js")); var _refiner = _interopRequireDefault(require("./refiner.js")); var _fabricator = require("./fabricator.js"); var _package = require("../package.json"); var _walker = _interopRequireDefault(require("./walker.js")); /* eslint-disable require-atomic-updates */ function isConfiguration(file) { return (0, _common.isPackageJson)(file) || file.endsWith('.config.json'); } // http://www.openwall.com/lists/musl/2012/12/08/4 const { hostArch, hostPlatform, isValidNodeRange, knownArchs, knownPlatforms, toFancyArch, toFancyPlatform } = _pkgFetch.system; const hostNodeRange = 'node' + process.version.match(/^v(\d+)/)[1]; function parseTargets(items) { // [ 'node6-macos-x64', 'node6-linux-x64' ] const targets = []; for (const item of items) { const target = { nodeRange: hostNodeRange, platform: hostPlatform, arch: hostArch }; if (item !== 'host') { for (const token of item.split('-')) { if (!token) continue; if (isValidNodeRange(token)) { target.nodeRange = token; continue; } const p = toFancyPlatform(token); if (knownPlatforms.indexOf(p) >= 0) { target.platform = p; continue; } const a = toFancyArch(token); if (knownArchs.indexOf(a) >= 0) { target.arch = a; continue; } throw (0, _log.wasReported)(`Unknown token '${token}' in '${item}'`); } } targets.push(target); } return targets; } function stringifyTarget(target) { const { nodeRange, platform, arch } = target; return `${nodeRange}-${platform}-${arch}`; } function differentParts(targets) { const nodeRanges = {}; const platforms = {}; const archs = {}; for (const target of targets) { nodeRanges[target.nodeRange] = true; platforms[target.platform] = true; archs[target.arch] = true; } const result = {}; if (Object.keys(nodeRanges).length > 1) { result.nodeRange = true; } if (Object.keys(platforms).length > 1) { result.platform = true; } if (Object.keys(archs).length > 1) { result.arch = true; } return result; } function stringifyTargetForOutput(output, target, different) { const a = [output]; if (different.nodeRange) a.push(target.nodeRange); if (different.platform) a.push(target.platform); if (different.arch) a.push(target.arch); return a.join('-'); } function fabricatorForTarget(target) { const { nodeRange, arch } = target; return { nodeRange, platform: hostPlatform, arch }; } const dryRunResults = {}; function needWithDryRun(_x) { return _needWithDryRun.apply(this, arguments); } function _needWithDryRun() { _needWithDryRun = (0, _asyncToGenerator2.default)(function* (target) { const target2 = Object.assign({ dryRun: true }, target); const result = yield (0, _pkgFetch.need)(target2); (0, _assert.default)(['exists', 'fetched', 'built'].indexOf(result) >= 0); dryRunResults[result] = true; }); return _needWithDryRun.apply(this, arguments); } const targetsCache = {}; function needViaCache(_x2) { return _needViaCache.apply(this, arguments); } function _needViaCache() { _needViaCache = (0, _asyncToGenerator2.default)(function* (target) { const s = stringifyTarget(target); let c = targetsCache[s]; if (c) return c; c = yield (0, _pkgFetch.need)(target); targetsCache[s] = c; return c; }); return _needViaCache.apply(this, arguments); } function exec(_x3) { return _exec.apply(this, arguments); } function _exec() { _exec = (0, _asyncToGenerator2.default)(function* (argv2) { // eslint-disable-line complexity const argv = (0, _minimist.default)(argv2, { boolean: ['b', 'build', 'bytecode', 'd', 'debug', 'h', 'help', 'public', 'v', 'version'], string: ['_', 'c', 'config', 'o', 'options', 'output', 'outdir', 'out-dir', 'out-path', 'public-packages', 't', 'target', 'targets'], default: { bytecode: true } }); if (argv.h || argv.help) { (0, _help.default)(); return; } // version if (argv.v || argv.version) { console.log(_package.version); return; } _log.log.info(`pkg@${_package.version}`); // debug _log.log.debugMode = argv.d || argv.debug; // forceBuild const forceBuild = argv.b || argv.build; // _ if (!argv._.length) { throw (0, _log.wasReported)('Entry file/directory is expected', ['Pass --help to see usage information']); } if (argv._.length > 1) { throw (0, _log.wasReported)('Not more than one entry file/directory is expected'); } // input let input = _path.default.resolve(argv._[0]); if (!(yield (0, _fsExtra.exists)(input))) { throw (0, _log.wasReported)('Input file does not exist', [input]); } if ((yield (0, _fsExtra.stat)(input)).isDirectory()) { input = _path.default.join(input, 'package.json'); if (!(yield (0, _fsExtra.exists)(input))) { throw (0, _log.wasReported)('Input file does not exist', [input]); } } // inputJson let inputJson, inputJsonName; if (isConfiguration(input)) { inputJson = JSON.parse((yield (0, _fsExtra.readFile)(input))); inputJsonName = inputJson.name; if (inputJsonName) { inputJsonName = inputJsonName.split('/').pop(); // @org/foo } } // inputBin let inputBin; if (inputJson) { let bin = inputJson.bin; if (bin) { if (typeof bin === 'object') { if (bin[inputJsonName]) { bin = bin[inputJsonName]; } else { bin = bin[Object.keys(bin)[0]]; // TODO multiple inputs to pkg them all? } } inputBin = _path.default.resolve(_path.default.dirname(input), bin); if (!(yield (0, _fsExtra.exists)(inputBin))) { throw (0, _log.wasReported)('Bin file does not exist (taken from package.json ' + '\'bin\' property)', [inputBin]); } } } if (inputJson && !inputBin) { throw (0, _log.wasReported)('Property \'bin\' does not exist in', [input]); } // inputFin const inputFin = inputBin || input; // config let config = argv.c || argv.config; if (inputJson && config) { throw (0, _log.wasReported)('Specify either \'package.json\' or config. Not both'); } // configJson let configJson; if (config) { config = _path.default.resolve(config); if (!(yield (0, _fsExtra.exists)(config))) { throw (0, _log.wasReported)('Config file does not exist', [config]); } configJson = require(config); // may be either json or js if (!configJson.name && !configJson.files && !configJson.dependencies && !configJson.pkg) { // package.json not detected configJson = { pkg: configJson }; } } // output, outputPath let output = argv.o || argv.output; const outputPath = argv['out-path'] || argv.outdir || argv['out-dir']; let autoOutput = false; if (output && outputPath) { throw (0, _log.wasReported)('Specify either \'output\' or \'out-path\'. Not both'); } if (!output) { let name; if (inputJson) { name = inputJsonName; if (!name) { throw (0, _log.wasReported)('Property \'name\' does not exist in', [argv._[0]]); } } else if (configJson) { name = configJson.name; } if (!name) { name = _path.default.basename(inputFin); } autoOutput = true; const ext = _path.default.extname(name); output = name.slice(0, -ext.length || undefined); output = _path.default.resolve(outputPath || '', output); } else { output = _path.default.resolve(output); } // targets const sTargets = argv.t || argv.target || argv.targets || ''; if (typeof sTargets !== 'string') { throw (0, _log.wasReported)(`Something is wrong near ${JSON.stringify(sTargets)}`); } let targets = parseTargets(sTargets.split(',').filter(t => t)); if (!targets.length) { let jsonTargets; if (inputJson && inputJson.pkg) { jsonTargets = inputJson.pkg.targets; } else if (configJson && configJson.pkg) { jsonTargets = configJson.pkg.targets; } if (jsonTargets) { targets = parseTargets(jsonTargets); } } if (!targets.length) { if (!autoOutput) { targets = parseTargets(['host']); (0, _assert.default)(targets.length === 1); } else { targets = parseTargets(['linux', 'macos', 'win']); } _log.log.info('Targets not specified. Assuming:', `${targets.map(stringifyTarget).join(', ')}`); } // differentParts const different = differentParts(targets); // targets[].output for (const target of targets) { let file; if (targets.length === 1) { file = output; } else { file = stringifyTargetForOutput(output, target, different); } if (target.platform === 'win' && _path.default.extname(file) !== '.exe') file += '.exe'; target.output = file; } // bakes const bakes = (argv.options || '').split(',').filter(bake => bake).map(bake => '--' + bake); // check if input is going // to be overwritten by output for (const target of targets) { if (target.output === inputFin) { if (autoOutput) { target.output += '-' + target.platform; } else { throw (0, _log.wasReported)('Refusing to overwrite input file', [inputFin]); } } } // fetch targets const { bytecode } = argv; for (const target of targets) { target.forceBuild = forceBuild; yield needWithDryRun(target); const f = target.fabricator = fabricatorForTarget(target); f.forceBuild = forceBuild; if (bytecode) { yield needWithDryRun(f); } } if (dryRunResults.fetched && !dryRunResults.built) { _log.log.info('Fetching base Node.js binaries to PKG_CACHE_PATH'); } for (const target of targets) { target.binaryPath = yield needViaCache(target); const f = target.fabricator; if (bytecode) { f.binaryPath = yield needViaCache(f); if (f.platform !== 'win') { yield (0, _chmod.plusx)(f.binaryPath); } } } // marker let marker; if (configJson) { marker = { config: configJson, base: _path.default.dirname(config), configPath: config }; } else { marker = { config: inputJson || {}, // not `inputBin` because only `input` base: _path.default.dirname(input), // is the place for `inputJson` configPath: input }; } marker.toplevel = true; // public const params = {}; if (argv.public) { params.publicToplevel = true; } if (argv['public-packages']) { params.publicPackages = argv['public-packages'].split(','); if (params.publicPackages.indexOf('*') !== -1) { params.publicPackages = ['*']; } } // records let records; let entrypoint = inputFin; const addition = isConfiguration(input) ? input : undefined; const walkResult = yield (0, _walker.default)(marker, entrypoint, addition, params); entrypoint = walkResult.entrypoint; records = walkResult.records; const refineResult = (0, _refiner.default)(records, entrypoint); entrypoint = refineResult.entrypoint; records = refineResult.records; const backpack = (0, _packer.default)({ records, entrypoint, bytecode }); _log.log.debug('Targets:', JSON.stringify(targets, null, 2)); for (const target of targets) { if (yield (0, _fsExtra.exists)(target.output)) { if ((yield (0, _fsExtra.stat)(target.output)).isFile()) { yield (0, _fsExtra.remove)(target.output); } else { throw (0, _log.wasReported)('Refusing to overwrite non-file output', [target.output]); } } else { yield (0, _fsExtra.mkdirp)(_path.default.dirname(target.output)); } const slash = target.platform === 'win' ? '\\' : '/'; yield (0, _producer.default)({ backpack, bakes, slash, target }); if (target.platform !== 'win') { yield (0, _chmod.plusx)(target.output); } } (0, _fabricator.shutdown)(); }); return _exec.apply(this, arguments); }