123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- '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 osFilterObj = importLazy('os-filter-obj');
-
- 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());
- }
-
- return Promise.resolve();
- });
- }
-
- /**
- * 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 = osFilterObj(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(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);
- }
-
- 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(arr) {
- return arr.reduce((acc, elem) => {
- if (Array.isArray(elem)) {
- acc.push(...elem);
- } else {
- acc.push(elem);
- }
-
- return acc;
- }, []);
- }
|