按顺序运行外部脚本

时间:2017-06-27 11:46:50

标签: javascript node.js gulp

我想从Gulp运行几个SQL脚本:

const gulp = require('gulp');
const dotenv = require('dotenv')
const child_process = require('child_process');

function runSQLScript(script) {
    child_process.execFile('sqlcmd', [
        '-S', process.env.DB_SERVER,
        '-U', process.env.DB_USER,
        '-P', process.env.DB_PASSWORD,
        '-d', process.env.DB_DATABASE,
        '-f', 'i:65001',
        '-i', script
    ], {
        cwd: '../sql/sqlcmd'
    }, function(error, stdout, stderr){
        if (error !== null) {
            console.log("" + stdout);
            console.error("" + error);
        }
        if (stderr.length>0) {
            console.error('' + stderr);
        }
    });
}

gulp.task('sql', ['install-app', 'load-data']);
gulp.task('install-app', function(){
    runSQLScript('install-app.sql');
});
gulp.task('load-data', function(){
    runSQLScript('load-data.sql');
});

然后我跑:

gulp sql

在早期版本中,我使用的是child_process.execFileSync(),我的脚本按预期顺序运行。我切换到child_process.execFile()以便能够报告错误,但现在load-data.sql失败了,因为它不再等待install-app.sql完成。

我可以做什么让任务等到runSQLScript()完成?我选择了错误的方法来打印错误吗?

2 个答案:

答案 0 :(得分:1)

看起来gulp-sequence是最佳选择(如果你的gulp版本是< 4)。

const util = require('util');
const gulp = require('gulp');
const gulpSequence = require('gulp-sequence');
const dotenv = require('dotenv')
const execFile = util.promisify(require('child_process').execFile);

function runSQLScript(script) {
    return execFile('sqlcmd', [
        '-S', process.env.DB_SERVER,
        '-U', process.env.DB_USER,
        '-P', process.env.DB_PASSWORD,
        '-d', process.env.DB_DATABASE,
        '-f', 'i:65001',
        '-i', script
    ], {
        cwd: '../sql/sqlcmd'
    }, function(error, stdout, stderr){
        if (error !== null) {
            console.log("" + stdout);
            console.error("" + error);
        }
        if (stderr.length>0) {
            console.error('' + stderr);
        }
    });
}

gulp.task('sql', gulpSequence('install-app', 'load-data'));
gulp.task('install-app', function(){
    return runSQLScript('install-app.sql');
});
gulp.task('load-data', function(){
    return runSQLScript('load-data.sql');
});

答案 1 :(得分:1)

不幸的是,从.execFileSync()切换到.execFile()似乎是在所有情况下捕获脚本输出的最简单方法。出错时,.execFileSync()不再返回脚本标准输出,并且没有明显的方法来获取它;您可以将其重定向到处理标准输出,但是,如果您需要进一步处理,则存在从那里获取它的问题。虽然冗长和不合逻辑,但异步代码是最不邪恶的。

然后您可以使用gulp-sequence()作为FrankerZ's answer解释。作为util.promisify()(需要Node / 8)的替代方法,您还可以使用q使child_process.execFile()返回承诺。

此外,您似乎需要catch() runSQLScript()返回的承诺。否则,无论前一个脚本的结果如何,第二个脚本都会执行。

const gulp = require('gulp');
const dotenv = require('dotenv')
const child_process = require('child_process');
const Q = require('q');

function runSQLScript(script) {
    var deferred = Q.defer();
    child_process.execFile('sqlcmd', [
        '-S', process.env.DB_SERVER,
        '-U', process.env.DB_USER,
        '-P', process.env.DB_PASSWORD,
        '-d', process.env.DB_DATABASE,
        '-f', 'i:65001',
        '-i', script
    ], {
        cwd: '../sql/sqlcmd'
    }, function(error, stdout, stderr){
        if (error !== null) {
            console.log("" + stdout);
            console.error("" + error);
            deferred.reject();
        } else {
            deferred.resolve();
        }
        if (stderr.length>0) {
            console.error('' + stderr);
        }

    });
    return deferred.promise;
}

gulp.task('sql', gulpSequence('install-app', 'load-data'));
gulp.task('install-app', function(callback){
    runSQLScript('install-app.sql')
        .then(function(){
            callback();
        })
        .catch(function(){
            callback("install-app failed, aborting");
        });
});
gulp.task('load-data', function(callback){
    runSQLScript('load-data.sql')
        .then(function(){
            callback();
        })
        .catch(function(){
            callback("load-data failed, aborting");
        });
});