zoukankan      html  css  js  c++  java
  • 一、 common-bin源码

    'use strict';
    
    const debug = require('debug')('common-bin');
    const cp = require('child_process');
    const is = require('is-type-of');
    const unparse = require('dargs');
    
    // 存储子进程
    const childs = new Set();
    //hooke标识,用来标识是否已经存在子进行了
    let hadHook = false;
    
    //启动任意一下子进和的时候,就放置一个钩子,
    //并且只有第一次存放子进程的时候会放置钩子,
    //钩子只会执行一次(once的特性)
    function gracefull(proc) {
      // 保存子进程引用
      childs.add(proc);
    
      // 设置一次钩子
      /* istanbul ignore else */
      if (!hadHook) {
        hadHook = true;
        let signal;
        [ 'SIGINT', 'SIGQUIT', 'SIGTERM' ].forEach(event => {
          process.once(event, () => {
            signal = event;
            process.exit(0);
          });
        });
        //主进程退出,自动销毁子进程
        process.once('exit', () => {
          // had test at my-helper.test.js, but coffee can't collect coverage info.
          for (const child of childs) {
            debug('kill child %s with %s', child.pid, signal);
            child.kill(signal);
          }
        });
      }
    }
    
    /**
     *  封装fork起动子进程, 返回promise并且优雅的退出
     * @method helper#forkNode
     * @param {String} modulePath - bin path
     * @param {Array} [args] - arguments
     * @param {Object} [options] - options
     * @return {Promise} err or undefined
     * @see https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options
     */
    exports.forkNode = (modulePath, args = [], options = {}) => {
      options.stdio = options.stdio || 'inherit';
      debug('Run fork `%s %s %s`', process.execPath, modulePath, args.join(' '));
      const proc = cp.fork(modulePath, args, options);
      gracefull(proc);
    
      return new Promise((resolve, reject) => {
        proc.once('exit', code => {
          childs.delete(proc);
          if (code !== 0) {
            const err = new Error(modulePath + ' ' + args + ' exit with code ' + code);
            err.code = code;
            reject(err);
          } else {
            resolve();
          }
        });
      });
    };
    
    /**
     *  封装fork起动子进程, 返回promise并且优雅的退出
     * @method helper#forkNode
     * @param {String} cmd - command
     * @param {Array} [args] - arguments
     * @param {Object} [options] - options
     * @return {Promise} err or undefined
     * @see https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
     */
    exports.spawn = (cmd, args = [], options = {}) => {
      options.stdio = options.stdio || 'inherit';
      debug('Run spawn `%s %s`', cmd, args.join(' '));
    
      return new Promise((resolve, reject) => {
        const proc = cp.spawn(cmd, args, options);
        gracefull(proc);
        proc.once('error', err => {
          /* istanbul ignore next */
          reject(err);
        });
        proc.once('exit', code => {
          childs.delete(proc);
    
          if (code !== 0) {
            return reject(new Error(`spawn ${cmd} ${args.join(' ')} fail, exit code: ${code}`));
          }
          resolve();
        });
      });
    };
    
    /**
     * 执行npm install
     * @method helper#npmInstall
     * @param {String} npmCli - npm cli, such as `npm` / `cnpm` / `npminstall`
     * @param {String} name - node module name
     * @param {String} cwd - target directory
     * @return {Promise} err or undefined
     */
    exports.npmInstall = (npmCli, name, cwd) => {
      const options = {
        stdio: 'inherit',
        env: process.env,
        cwd,
      };
    
      const args = [ 'i', name ];
      console.log('[common-bin] `%s %s` to %s ...', npmCli, args.join(' '), options.cwd);
    
      return exports.spawn(npmCli, args, options);
    };
    
    /**
     * 调用方法
     * @method helper#callFn
     * @param {Function} fn - support generator / async / normal function return promise
     * @param {Array} [args] - fn args
     * @param {Object} [thisArg] - this
     * @return {Object} result
     */
    exports.callFn = function* (fn, args = [], thisArg) {
      if (!is.function(fn)) return;
      if (is.generatorFunction(fn)) {
        return yield fn.apply(thisArg, args);
      }
      const r = fn.apply(thisArg, args);
      if (is.promise(r)) {
        return yield r;
      }
      return r;
    };
    
    /**
     * unparse argv and change it to array style
     * @method helper#unparseArgv
     * @param {Object} argv - yargs style
     * @param {Object} [options] - options, see more at https://github.com/sindresorhus/dargs
     * @param {Array} [options.includes] - keys or regex of keys to include
     * @param {Array} [options.excludes] - keys or regex of keys to exclude
     * @return {Array} [ '--debug=7000', '--debug-brk' ]
     */
    exports.unparseArgv = (argv, options = {}) => {
      // revert argv object to array
      // yargs will paser `debug-brk` to `debug-brk` and `debugBrk`, so we need to filter
      return [ ...new Set(unparse(argv, options)) ];
    };
    
    /**
     * extract execArgv from argv
     * @method helper#extractExecArgv
     * @param {Object} argv - yargs style
     * @return {Object} { debugPort, debugOptions: {}, execArgvObj: {} }
     */
    exports.extractExecArgv = argv => {
      const debugOptions = {};
      const execArgvObj = {};
      let debugPort;
    
      for (const key of Object.keys(argv)) {
        const value = argv[key];
        // skip undefined set uppon (camel etc.)
        if (value === undefined) continue;
        // debug / debug-brk / debug-port / inspect / inspect-brk / inspect-port
        if ([ 'debug', 'debug-brk', 'debug-port', 'inspect', 'inspect-brk', 'inspect-port' ].includes(key)) {
          if (typeof value === 'number') debugPort = value;
          debugOptions[key] = argv[key];
          execArgvObj[key] = argv[key];
        } else if (match(key, [ 'es_staging', 'expose_debug_as', /^harmony.*/ ])) {
          execArgvObj[key] = argv[key];
        } else if (key.startsWith('node-options--')) {
          // support node options, like: commond --node-options--trace-warnings => execArgv.push('--trace-warnings')
          execArgvObj[key.replace('node-options--', '')] = argv[key];
        }
      }
      return { debugPort, debugOptions, execArgvObj };
    };
    
    function match(key, arr) {
      return arr.some(x => x instanceof RegExp ? x.test(key) : x === key); // eslint-disable-line no-confusing-arrow
    }
  • 相关阅读:
    Mybatis-Plus02 CRUD
    Idea一直卡在loading archetype list问题解决(或者报Unable to import maven project: See logs for details)
    Mybatis-Plus01 快速开始
    用PS给视频磨皮美颜
    Linux基本内容
    【maven】IDEA工程右边的maven配置中Plugins有重复的命令
    段誉身具凌波微波,动无常则,若危若安,一次能走一级台阶或者两级台阶,他要爬一段30级的山路,问有多少种走法?分析如何计算,然后编程解答。 进阶问题:当他轻功熟练度提升,一次最多可以走三级,那就结果有什么变化?后来走火入魔了,不能走一级,只能走二或三级,又有什么变化?
    小陆每天要写一份工作日报,日报标题含有日期。几年后,他翻开以前的日报,想知道两份日报的日期是否同为星期几,请编程帮助他判断。
    高性能HTML5/JS开发框架DevExtreme 新版——v20.2.7发布
    跨平台UI开发框架DevExpress XAF 拥有超强性能,你Get了吗?
  • 原文地址:https://www.cnblogs.com/hellolol/p/11474498.html
Copyright © 2011-2022 走看看