<commit_before>'use strict';

var file = require('file'),
    fs = require('fs'),
    configHelper = require('../config'),
    config = configHelper.getConfig(),
    _baseDir = configHelper.getBaseDirectory(),
    semver = require('semver'),
    path = require('path'),
    log = require('../logger')('nodecg/lib/bundles/parser'),
    jade = require('jade'),
    util = require('util'),
    npm = require('npm'),
    Q = require('q'),

    pjson = require('../../package.json');

module.exports = function parse(bundleName) {
    var dir = path.resolve(_baseDir, 'bundles/' + bundleName + '/');
    var manifestPath = path.join(dir, 'nodecg.json');

    // Return null if nodecg.json doesn't exist
    if (!fs.existsSync(manifestPath)) {
        return null;
    }

    log.trace("Discovered bundle in folder bundles/%s", bundleName);

    // Read metadata from the nodecg.json manifest file
    var bundle = readManifest(manifestPath);
    bundle.dir = dir;

    // Don't load the bundle if it depends on a different version of NodeCG
    if (!isCompatible(bundle.nodecgDependency)) {
        log.warn("Did not load %s as it requires NodeCG %s. Current version is %s",
            bundle.name, bundle.nodecgDependency, pjson.version);
        return null;
    }

    // If there is a config file for this bundle, parse it
    var cfgPath = path.resolve(_baseDir, 'cfg', bundle.name + '.json');
    bundle.config = readConfig(cfgPath);

    // Read all HTML/CSS/JS files in the package's "dashboard" dir into memory
    // They will then get passed to dashboard.jade at the time of 'GET' and be templated into the final rendered page
    bundle.dashboard = {};
    bundle.dashboard.dir = path.join(bundle.dir, 'dashboard');

    readDashboardResources(bundle);
    readDashboardPanels(bundle);

    // The following operation(s) are async, so we make a collective promise for them
    return Q.all([
        installNpmPackages(bundle)
    ]).then(function() {
        return bundle;
    });
};

function readManifest(path) {
    // Parse the JSON from nodecg.json
    var manifest = JSON.parse(fs.readFileSync(path, 'utf8'));

    // Copy the JSON we use into the beginnings of our bundle object
    return {
        name: manifest.name,
        version: manifest.version,
        description: manifest.description,
        homepage: manifest.homepage,
        authors: manifest.authors,
        license: manifest.license,
        nodecgDependency: manifest.nodecgDependency,
        dependencies: manifest.dependencies,
        extension: manifest.extension,
        bundleDependencies: manifest.bundleDependencies
    };
}

function installNpmPackages(bundle) {
    var deferred = Q.defer();
    if (!bundle.dependencies) {
        deferred.resolve();
        return;
    }
    npm.load({ prefix: bundle.dir, loglevel: 'warn' }, function (er) {
        if (er) {
            deferred.reject(new Error(
                util.format("[%s] Failed to load npm to install dependencies:", bundle.name, er.message)
            ));
            return;
        }

        // astoundingly stupid hack to make NPM not spam the console with
        // details about EVERY SINGLE installed package
        console._stdout = { write : function () {} };

        // Get list of currently installed dependencies
        // We only want to install if missing or version isn't satisfied
        npm.commands.ls([], true, function(er, data) {

            log.trace('npm ls, bundle: %s, data:', bundle.name, data);

            // npm.commands.install takes an array of string arguments
            // we must take the bundle's list of deps and turn them into arg strings
            var args = [];
            for (var dependency in bundle.dependencies) {
                if (!bundle.dependencies.hasOwnProperty(dependency)) continue;

                log.trace('dependency %s, exists?:', dependency, typeof data.dependencies[dependency] !== "undefined");

                if (!data.dependencies[dependency] ||
                    !!semver.satisfies(data.dependencies[dependency].version, bundle.dependencies[dependency])) {
                    log.trace('adding %s to install list', dependency);
                    args.push(dependency + '@' + bundle.dependencies[dependency]);
                }
            }

            if (args.length > 0) {
                npm.commands.install(args, function (er, data) {
                    if (er) {
                        deferred.reject(new Error(
                            util.format("[%s] Failed to install npm dependencies:", bundle.name, er.message)
                        ));
                    } else {
                        deferred.resolve();
                        console._stdout = process.stdout;
                    }
                });
            } else {
                deferred.resolve();
                console._stdout = process.stdout;
            }
        });
    });
    return deferred.promise;<commit_msg>Actually ignore existing dependencies for real this time<commit_after>'use strict';

var file = require('file'),
    fs = require('fs'),
    configHelper = require('../config'),
    config = configHelper.getConfig(),
    _baseDir = configHelper.getBaseDirectory(),
    semver = require('semver'),
    path = require('path'),
    log = require('../logger')('nodecg/lib/bundles/parser'),
    jade = require('jade'),
    util = require('util'),
    npm = require('npm'),
    Q = require('q'),

    pjson = require('../../package.json');

module.exports = function parse(bundleName) {
    var dir = path.resolve(_baseDir, 'bundles/' + bundleName + '/');
    var manifestPath = path.join(dir, 'nodecg.json');

    // Return null if nodecg.json doesn't exist
    if (!fs.existsSync(manifestPath)) {
        return null;
    }

    log.trace("Discovered bundle in folder bundles/%s", bundleName);

    // Read metadata from the nodecg.json manifest file
    var bundle = readManifest(manifestPath);
    bundle.dir = dir;

    // Don't load the bundle if it depends on a different version of NodeCG
    if (!isCompatible(bundle.nodecgDependency)) {
        log.warn("Did not load %s as it requires NodeCG %s. Current version is %s",
            bundle.name, bundle.nodecgDependency, pjson.version);
        return null;
    }

    // If there is a config file for this bundle, parse it
    var cfgPath = path.resolve(_baseDir, 'cfg', bundle.name + '.json');
    bundle.config = readConfig(cfgPath);

    // Read all HTML/CSS/JS files in the package's "dashboard" dir into memory
    // They will then get passed to dashboard.jade at the time of 'GET' and be templated into the final rendered page
    bundle.dashboard = {};
    bundle.dashboard.dir = path.join(bundle.dir, 'dashboard');

    readDashboardResources(bundle);
    readDashboardPanels(bundle);

    // The following operation(s) are async, so we make a collective promise for them
    return Q.all([
        installNpmPackages(bundle)
    ]).then(function() {
        return bundle;
    });
};

function readManifest(path) {
    // Parse the JSON from nodecg.json
    var manifest = JSON.parse(fs.readFileSync(path, 'utf8'));

    // Copy the JSON we use into the beginnings of our bundle object
    return {
        name: manifest.name,
        version: manifest.version,
        description: manifest.description,
        homepage: manifest.homepage,
        authors: manifest.authors,
        license: manifest.license,
        nodecgDependency: manifest.nodecgDependency,
        dependencies: manifest.dependencies,
        extension: manifest.extension,
        bundleDependencies: manifest.bundleDependencies
    };
}

function installNpmPackages(bundle) {
    var deferred = Q.defer();
    if (!bundle.dependencies) {
        deferred.resolve();
        return;
    }
    npm.load({ prefix: bundle.dir, loglevel: 'warn' }, function (er) {
        if (er) {
            deferred.reject(new Error(
                util.format("[%s] Failed to load npm to install dependencies:", bundle.name, er.message)
            ));
            return;
        }

        // astoundingly stupid hack to make NPM not spam the console with
        // details about EVERY SINGLE installed package
        console._stdout = { write : function () {} };

        // Get list of currently installed dependencies
        // We only want to install if missing or version isn't satisfied
        npm.commands.ls([], true, function(er, data) {

            log.trace('npm ls, bundle: %s, data:', bundle.name, data);

            // npm.commands.install takes an array of string arguments
            // we must take the bundle's list of deps and turn them into arg strings
            var args = [];
            for (var dependency in bundle.dependencies) {
                if (!bundle.dependencies.hasOwnProperty(dependency)) continue;

                log.trace('dependency %s, exists?:', dependency, typeof data.dependencies[dependency] !== "undefined");

                if (!data.dependencies[dependency] ||
                    !semver.satisfies(data.dependencies[dependency].version, bundle.dependencies[dependency])) {
                    log.trace('adding %s to install list', dependency);
                    args.push(dependency + '@' + bundle.dependencies[dependency]);
                }
            }

            if (args.length > 0) {
                npm.commands.install(args, function (er, data) {
                    if (er) {
                        deferred.reject(new Error(
                            util.format("[%s] Failed to install npm dependencies:", bundle.name, er.message)
                        ));
                    } else {
                        deferred.resolve();
                        console._stdout = process.stdout;
                    }
                });
            } else {
                deferred.resolve();
                console._stdout = process.stdout;
            }
        });
    });
    return deferred.promise;
{'fraction_non_alphanumeric': 0.11555421928242132, 'fraction_numerical': 0.0004008819402685909, 'mean_word_length': 2.1559139784946235, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '1962818', 'n_tokens_mistral': 2673, 'n_tokens_neox': 2526, 'n_words': 764}