<commit_before>var getopt = require('node-getopt')
    , q = require('q')
    , _ = require('lodash')
    , util = require('util')
    , fs = require('fs')
    , novautils = require('../component-utils')
    , novaform = require('novaform')
    , novastl = require('novastl')
    , AWS = require('aws-sdk')
    , uuid = require('node-uuid')
    , moment = require('moment')
    , Stack = require('../stack')
    , s3utils = require('../s3utils')
    , config = require('../configuration')
    , Project = require('../project')
    , Ref = require('../ref')
    , assert = require('assert');

var cmdopts = module.exports.opts = getopt.create([
    ['w', 'wait', 'Wait for completion'],
    ['n', 'noop', 'Do not actually deploy'],
    ['', 'template-output=ARG', 'Dump the generated CloudFormation template to a file'],
    ['h', 'help', 'Display help']
]);

cmdopts.setHelp('[[OPTIONS]]\n');

function Command(args, helpCallback) {
    if (!(this instanceof Command)) {
        return new Command(name, properties);
    }

    this.displayHelpAndExit = helpCallback;

    var opts = this.opts = cmdopts.parse(args);
    this.commandOptions = this.opts.options;

    if (opts.options.help) {
        helpCallback();
        return;
    }

    if (_(opts.argv).isEmpty()) {
        helpCallback('Missing project/component reference');
        return;
    } else if (opts.argv.length !== 1) {
        helpCallback('Too many project/component references specified');
        return;
    }

    var ref = opts.argv[0];
    ref = this.ref = Ref.parse(ref);
    if (!this.ref) {
        helpCallback('Invalid project ref');
        return;
    }
    if (!this.ref.component) {
        helpCallback('Component was not specified')
        return;
    }

    this.project = Project.load(this.ref.project, config.paramsObject, function(e) {
        helpCallback(util.format('Failed to load project "%s": %s', ref.project, e.message));
    });
    if (!this.project) {
        helpCallback(util.format('Could not find project "%s"', this.ref.project));
        return;
    }

    this.component = this.project.findComponent(this.ref.component);
    if (!this.component) {
        helpCallback(util.format('Component "%s" does not exist', this.ref.component));
        return;
    }
}

Command.prototype._waitForStack = function(options, shouldStopCallback) {
    var cfn = options.cfn;
    var stackName = options.stackName;
    var maxWaitSeconds = options.maxWaitSeconds || 15 * 60;
    var waitSeconds = options.waitSeconds || 1;

    var start = moment();
    var maxEnd = moment(start);
    maxEnd.add(maxWaitSeconds, 'seconds');

    var getStackStatus = q.nbind(Stack.getStackStatus, Stack);

    var f = function() {
        return getStackStatus(cfn, stackName).then(function(status) {
            var callbackResult = shouldStopCallback(status);
            if (callbackResult) {
                return callbackResult;
            }
            if (moment().isAfter(maxEnd)) {
                throw new Error('Timeout');
            }
            return q.delay(waitSeconds * 1000).then(f);
        });
    };

    return f();
};

Command.prototype.execute = function() {
    var that = this;

    return q().then(function() {
        // init deployment

        var stackName = that.ref.makeStackName();

        var deploymentDate = moment.utc();
        var deploymentId = uuid.v4();

        config.currentDeployment.id = deploymentId;
        config.currentDeployment.date = deploymentDate;
        config.currentDeployment.ref = that.ref;
        config.currentDeployment.region = that.component.region;

        return {
            projectName: that.ref.project,
            componentName: that.ref.component,
            deploymentDate: deploymentDate,
            deploymentId: deploymentId,
            stackName: stackName,
        };
    }).then(function(deploymentConfig) {
        var region = that.component.region;
        var cfn = that.cfn = new AWS.CloudFormation({ region : region });
        return _.extend(deploymentConfig, {
            cfn: cfn,
        });
    }).then(function(deploymentConfig) {
        // TODO: validate project's components, make sure dependencies exist
        var deplist = [];

        function walkDeps(result, componentName, walked) {
            if (!walked) {
                walked = [];
            }
            if (walked.indexOf(componentName) !== -1) {
                throw new Error('recursive dependency');
            }

            walked.push(componentName);

            var component = that.project.findComponent(componentName);
            if (!component) {
                throw new Error(util.format('Could not find dependent component "%s"', componentName));
            }
            var deps = _.map(component.dependencies, function(depname) {
                var w = walked ? walked.slice() : [];
                return walkDeps([depname], depname, w);
            });

            deps.sort(function(a, b) { return a.length - b.length; });

            deps.forEach(function(deps) {
                deps.reverse();
                deps.forEach(function(d) {
                    var idx = result.indexOf(d);
                    if (idx !== -1) {
                        result.splice(idx, 1);
                    }
                    result.unshift(d);
                });
            });

            return result;
        }

        var deplist = walkDeps([], that.component.name);

        return _.extend(deploymentConfig, {
            dependentComponents: deplist,
        });
    }).then(function(deploymentConfig) {
        if (config.commonOptions.verbose) {
            console.log('Fetching outputs of dependent stacks...');
        }

        var cfn = deploymentConfig.cfn;
        var componentNames = deploymentConfig.dependentComponents;

        var stackInfoPromises = componentNames.map(function(depname) {
            return Ref(that.ref.project, depname).makeStackName();
        }).map(function(stackName) {
            var getStackInfo = q.nbind(Stack.getStackInfo, Stack);
            return getStackInfo(cfn, stackName);
        });

        return q.all(stackInfoPromises).then(function(stackInfos) {
            var invalidStacks = _.filter(stackInfos, function(stackInfo) {<commit_msg>Handle dependencies that are not in the same region as the current component<commit_after>var getopt = require('node-getopt')
    , q = require('q')
    , _ = require('lodash')
    , util = require('util')
    , fs = require('fs')
    , novautils = require('../component-utils')
    , novaform = require('novaform')
    , novastl = require('novastl')
    , AWS = require('aws-sdk')
    , uuid = require('node-uuid')
    , moment = require('moment')
    , Stack = require('../stack')
    , s3utils = require('../s3utils')
    , config = require('../configuration')
    , Project = require('../project')
    , Ref = require('../ref')
    , assert = require('assert');

var cmdopts = module.exports.opts = getopt.create([
    ['w', 'wait', 'Wait for completion'],
    ['n', 'noop', 'Do not actually deploy'],
    ['', 'template-output=ARG', 'Dump the generated CloudFormation template to a file'],
    ['h', 'help', 'Display help']
]);

cmdopts.setHelp('[[OPTIONS]]\n');

function Command(args, helpCallback) {
    if (!(this instanceof Command)) {
        return new Command(name, properties);
    }

    this.displayHelpAndExit = helpCallback;

    var opts = this.opts = cmdopts.parse(args);
    this.commandOptions = this.opts.options;

    if (opts.options.help) {
        helpCallback();
        return;
    }

    if (_(opts.argv).isEmpty()) {
        helpCallback('Missing project/component reference');
        return;
    } else if (opts.argv.length !== 1) {
        helpCallback('Too many project/component references specified');
        return;
    }

    var ref = opts.argv[0];
    ref = this.ref = Ref.parse(ref);
    if (!this.ref) {
        helpCallback('Invalid project ref');
        return;
    }
    if (!this.ref.component) {
        helpCallback('Component was not specified')
        return;
    }

    this.project = Project.load(this.ref.project, config.paramsObject, function(e) {
        helpCallback(util.format('Failed to load project "%s": %s', ref.project, e.message));
    });
    if (!this.project) {
        helpCallback(util.format('Could not find project "%s"', this.ref.project));
        return;
    }

    this.component = this.project.findComponent(this.ref.component);
    if (!this.component) {
        helpCallback(util.format('Component "%s" does not exist', this.ref.component));
        return;
    }
}

Command.prototype._waitForStack = function(options, shouldStopCallback) {
    var cfn = options.cfn;
    var stackName = options.stackName;
    var maxWaitSeconds = options.maxWaitSeconds || 15 * 60;
    var waitSeconds = options.waitSeconds || 1;

    var start = moment();
    var maxEnd = moment(start);
    maxEnd.add(maxWaitSeconds, 'seconds');

    var getStackStatus = q.nbind(Stack.getStackStatus, Stack);

    var f = function() {
        return getStackStatus(cfn, stackName).then(function(status) {
            var callbackResult = shouldStopCallback(status);
            if (callbackResult) {
                return callbackResult;
            }
            if (moment().isAfter(maxEnd)) {
                throw new Error('Timeout');
            }
            return q.delay(waitSeconds * 1000).then(f);
        });
    };

    return f();
};

Command.prototype.execute = function() {
    var that = this;

    return q().then(function() {
        // init deployment

        var stackName = that.ref.makeStackName();

        var deploymentDate = moment.utc();
        var deploymentId = uuid.v4();

        config.currentDeployment.id = deploymentId;
        config.currentDeployment.date = deploymentDate;
        config.currentDeployment.ref = that.ref;
        config.currentDeployment.region = that.component.region;

        return {
            projectName: that.ref.project,
            componentName: that.ref.component,
            deploymentDate: deploymentDate,
            deploymentId: deploymentId,
            stackName: stackName,
        };
    }).then(function(deploymentConfig) {
        var region = that.component.region;
        var cfn = that.cfn = new AWS.CloudFormation({ region : region });
        return _.extend(deploymentConfig, {
            cfn: cfn,
        });
    }).then(function(deploymentConfig) {
        // TODO: validate project's components, make sure dependencies exist
        var deplist = [];

        function walkDeps(result, componentName, walked) {
            if (!walked) {
                walked = [];
            }
            if (walked.indexOf(componentName) !== -1) {
                throw new Error('recursive dependency');
            }

            walked.push(componentName);

            var component = that.project.findComponent(componentName);
            if (!component) {
                throw new Error(util.format('Could not find dependent component "%s"', componentName));
            }
            var deps = _.map(component.dependencies, function(depname) {
                var w = walked ? walked.slice() : [];
                return walkDeps([depname], depname, w);
            });

            deps.sort(function(a, b) { return a.length - b.length; });

            deps.forEach(function(deps) {
                deps.reverse();
                deps.forEach(function(d) {
                    var idx = result.indexOf(d);
                    if (idx !== -1) {
                        result.splice(idx, 1);
                    }
                    result.unshift(d);
                });
            });

            return result;
        }

        var deplist = walkDeps([], that.component.name);

        return _.extend(deploymentConfig, {
            dependentComponents: deplist,
        });
    }).then(function(deploymentConfig) {
        if (config.commonOptions.verbose) {
            console.log('Fetching outputs of dependent stacks...');
        }

        var componentNames = deploymentConfig.dependentComponents;

        var stackInfoPromises = componentNames.map(function(depname) {
            var component = that.project.findComponent(depname);
            if (!component) {
                throw new Error(util.format('Dependent component "%s" does not exist', depname));
            }
            var region = component.region;

            var stackName = Ref(that.ref.project, depname).makeStackName();

            var cfn = new AWS.CloudFormation({ region : region });
            var getStackInfo = q.nbind(Stack.getStackInfo, Stack);
            return getStackInfo(cfn, stackName);
        });

        return q.all(stackInfoPromises).then(function(stackInfos) {
            var invalidStacks = _.filter(stackInfos, function(stackInfo) {
{'fraction_non_alphanumeric': 0.13192182410423453, 'fraction_numerical': 0.002636885373041725, 'mean_word_length': 2.1683046683046685, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3800159', 'n_tokens_mistral': 3592, 'n_tokens_neox': 3478, 'n_words': 774}