UNPKG

bin-wrapper-china

Version:

Binary mirror download link replacement for mainland China

224 lines (193 loc) 3.9 kB
'use strict'; const fs = require('fs'); const path = require('path'); const url = require('url'); const pify = require('pify'); const importLazy = require('import-lazy')(require); const binCheck = importLazy('bin-check'); const binVersionCheck = importLazy('bin-version-check'); const download = importLazy('download'); const osFilterObject = importLazy('os-filter-obj'); const urlReplacer = require('./url-replacer'); const statAsync = pify(fs.stat); const chmodAsync = pify(fs.chmod); /** * Initialize a new `BinWrapper` * * @param {Object} options * @api public */ module.exports = class BinWrapper { constructor(options = {}) { this.options = options; if (this.options.strip <= 0) { this.options.strip = 0; } else if (!this.options.strip) { this.options.strip = 1; } } /** * Get or set files to download * * @param {String} src * @param {String} os * @param {String} arch * @api public */ src(src, os, arch) { if (arguments.length === 0) { return this._src; } this._src = this._src || []; this._src.push({ url: src, os, arch }); return this; } /** * Get or set the destination * * @param {String} dest * @api public */ dest(dest) { if (arguments.length === 0) { return this._dest; } this._dest = dest; return this; } /** * Get or set the binary * * @param {String} bin * @api public */ use(bin) { if (arguments.length === 0) { return this._use; } this._use = bin; return this; } /** * Get or set a semver range to test the binary against * * @param {String} range * @api public */ version(range) { if (arguments.length === 0) { return this._version; } this._version = range; return this; } /** * Get path to the binary * * @api public */ path() { return path.join(this.dest(), this.use()); } /** * Run * * @param {Array} cmd * @api public */ run(cmd = ['--version']) { return this.findExisting().then(() => { if (this.options.skipCheck) { return; } return this.runCheck(cmd); }); } /** * Run binary check * * @param {Array} cmd * @api private */ runCheck(cmd) { return binCheck(this.path(), cmd).then(works => { if (!works) { throw new Error( `The \`${this.path()}\` binary doesn’t seem to work correctly` ); } if (this.version()) { return binVersionCheck(this.path(), this.version()); } }); } /** * Find existing files * * @api private */ findExisting() { return statAsync(this.path()).catch(error => { if (error && error.code === 'ENOENT') { return this.download(); } return Promise.reject(error); }); } /** * Download files * * @api private */ download() { const files = osFilterObject(this.src() || []); const urls = []; if (files.length === 0) { return Promise.reject( new Error( 'No binary found matching your system. It’s probably not supported.' ) ); } files.forEach(file => urls.push(file.url)); return Promise.all( urls.map(urlReplacer).map(url => download(url, this.dest(), { extract: true, strip: this.options.strip }) ) ).then(result => { const resultingFiles = flatten( result.map((item, index) => { if (Array.isArray(item)) { return item.map(file => file.path); } // eslint-disable-next-line node/no-deprecated-api const parsedUrl = url.parse(files[index].url); const parsedPath = path.parse(parsedUrl.pathname); return parsedPath.base; }) ); return Promise.all( resultingFiles.map(fileName => { return chmodAsync(path.join(this.dest(), fileName), 0o755); }) ); }); } }; function flatten(array) { return array.reduce((acc, element) => { if (Array.isArray(element)) { acc.push(...element); } else { acc.push(element); } return acc; }, []); }