"use strict";
var events_1 = require('events');
var child_process_1 = require('child_process');
var debug = require('debug')('cb:adaptors.npm');
var _ = require('../../lodash.custom');
var path_1 = require("path");
var task_utils_1 = require("../task.utils");
var sh = 'sh';
var shFlag = '-c';
if (process.platform === 'win32') {
    // todo test in windows env to ensure this hasn't broken anything
    // sh = process.env.comspec || 'cmd';
    sh = 'cmd';
    shFlag = '/d /s /c';
}
function runCommand(args, options) {
    var raw = child_process_1.spawn(sh, args, options);
    var cooked = new events_1.EventEmitter();
    raw.on('error', function (er) {
        er.file = [sh, args].join(' ');
        cooked.emit('error', er);
    }).on('close', function (code, signal) {
        if (code === 127) {
            var er = new Error('spawn ENOENT');
            er.code = 'ENOENT';
            er.errno = 'ENOENT';
            er.syscall = 'spawn';
            er.file = [sh, args].join(' ');
            cooked.emit('error', er);
        }
        else {
            cooked.emit('close', code, signal);
        }
    });
    cooked.stdin = raw.stdin;
    cooked.stdout = raw.stdout;
    cooked.stderr = raw.stderr;
    cooked.raw = raw;
    cooked.kill = function (sig) {
        return raw.kill(sig);
    };
    return cooked;
}
exports.runCommand = runCommand;
/**
 * Add the local ./node_modules/.bin directory to the beginning
 * of the users PATH - this will allow it to find local scripts
 * @param {process.env} process
 * @param {Immutable.Map} config
 * @returns {object}
 */
function getEnv(process, config) {
    var localEnv = {};
    var envpath = path_1.join(config.cwd, 'node_modules', '.bin');
    localEnv.PATH = [envpath].concat(process.env.PATH).join(':');
    return localEnv;
}
exports.getEnv = getEnv;
function getArgs(command) {
    return {
        stringInput: command,
        cmd: [shFlag].concat(command),
        errors: []
    };
}
exports.getArgs = getArgs;
function teardown(emitter, task) {
    if ((typeof emitter.raw.exitCode) !== 'number') {
        debug('tearing down a child_process because exitCode is missing');
        emitter.removeAllListeners('close');
        emitter.kill('SIGINT');
        emitter.on('close', function () {
            debug('close method on child encountered');
            // todo - async teardown for sequential
        });
    }
    else {
        debug('child process already completed, not disposing');
    }
}
exports.teardown = teardown;
function getStdio(trigger) {
    // todo - prefixed logging for child processes
    if (trigger.config.suppressOutput) {
        return ['pipe', 'pipe', 'pipe'];
    }
    // process.stdin, process.stdout, process.stderr
    return [process.stdin, process.stdout, 'pipe'];
}
exports.getStdio = getStdio;
function handleExit(emitter, done) {
    var stderr = [];
    emitter.stderr.on('data', function (data) {
        stderr.push(data);
    });
    emitter.on('close', function (code) {
        // todo: Make pretty errors that originate from child processes
        if (code !== 0) {
            var err = new Error("Previous command failed with exit code " + code);
            if (stderr.length) {
                err.stack = stderr.map(String).join('');
            }
            else {
                err.stack = "Previous command failed with exit code " + code;
            }
            err._cbError = true;
            err._cbExitCode = code;
            return done(err);
        }
        done();
    }).on('error', function (err) {
        done(err);
    });
}
exports.handleExit = handleExit;
/**
 * The main export is the function this will be run in the sequence
 * @returns {Function}
 */
function default_1(task, trigger) {
    return function (opts, ctx, done) {
        var commandArgs = getArgs(task.command);
        var npmEnv = getEnv(process, trigger.config);
        var cbEnv = task_utils_1.getCBEnv(trigger);
        var env = _.merge({}, process.env, npmEnv, cbEnv, task.env, trigger.config.env);
        var stdio = getStdio(trigger);
        debug("+ running '%s %s'", sh, commandArgs.cmd.join(' '));
        var emitter = runCommand(commandArgs.cmd, {
            cwd: trigger.config.cwd,
            env: env,
            stdio: stdio // [process.stdin, process.stdout, process.stderr]
        });
        handleExit(emitter, done);
        return function tearDownNpmAdaptor() {
            teardown(emitter, task);
        };
    };
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = default_1;
;
//# sourceMappingURL=@npm.js.map