function runInstall()

in src/plugman/install.js [249:364]


function runInstall (actions, platform, project_dir, plugin_dir, plugins_dir, options) {
    project_dir = cordovaUtil.convertToRealPathSafe(project_dir);
    plugin_dir = cordovaUtil.convertToRealPathSafe(plugin_dir);
    plugins_dir = cordovaUtil.convertToRealPathSafe(plugins_dir);
    options = options || {};
    options.graph = options.graph || new DepGraph();
    options.pluginInfoProvider = options.pluginInfoProvider || new PluginInfoProvider();

    const pluginInfoProvider = options.pluginInfoProvider;
    const pluginInfo = pluginInfoProvider.get(plugin_dir);
    let filtered_variables = {};
    const platformJson = PlatformJson.load(plugins_dir, platform);

    if (platformJson.isPluginInstalled(pluginInfo.id)) {
        if (options.is_top_level) {
            let msg = 'Plugin "' + pluginInfo.id + '" already installed on ' + platform + '.';
            if (platformJson.isPluginDependent(pluginInfo.id)) {
                msg += ' Making it top-level.';
                platformJson.makeTopLevel(pluginInfo.id).save();
            }
            events.emit('log', msg);
        } else {
            events.emit('log', 'Dependent plugin "' + pluginInfo.id + '" already installed on ' + platform + '.');
        }

        // CB-11022 return true always in this case since if the plugin is installed
        // we don't need to call prepare in any way
        return Promise.resolve(true);
    }
    events.emit('log', 'Installing "' + pluginInfo.id + '" for ' + platform);

    const theEngines = getEngines(pluginInfo, platform, project_dir, plugin_dir);

    const install = {
        actions,
        platform,
        project_dir,
        plugins_dir,
        top_plugin_id: pluginInfo.id,
        top_plugin_dir: plugin_dir
    };

    return Promise.resolve().then(function () {
        if (options.platformVersion) {
            return Promise.resolve(options.platformVersion);
        }
        return Promise.resolve(cordovaUtil.getPlatformVersion(project_dir));
    }).then(function (platformVersion) {
        options.platformVersion = platformVersion;
        return callEngineScripts(theEngines, path.resolve(plugins_dir, '..'));
    }).then(function (engines) {
        return checkEngines(engines);
    }).then(function () {
        filtered_variables = variableMerge.mergeVariables(plugin_dir, platform, options);
        install.filtered_variables = filtered_variables;

        // Check for dependencies
        const dependencies = pluginInfo.getDependencies(platform);
        if (dependencies.length) {
            return installDependencies(install, dependencies, options);
        }
        return Promise.resolve(true);
    }
    ).then(
        function () {
            const install_plugin_dir = path.join(plugins_dir, pluginInfo.id);

            // may need to copy to destination...
            if (!fs.existsSync(install_plugin_dir)) {
                copyPlugin(plugin_dir, plugins_dir, options.link, pluginInfoProvider);
            }

            const projectRoot = cordovaUtil.isCordova();

            if (projectRoot) {
                // using unified hooksRunner
                const hookOptions = {
                    cordova: { platforms: [platform] },
                    plugin: {
                        id: pluginInfo.id,
                        pluginInfo,
                        platform: install.platform,
                        dir: install.top_plugin_dir
                    },
                    nohooks: options.nohooks
                };

                // CB-10708 This is the case when we're trying to install plugin using plugman to specific
                // platform inside of the existing CLI project. In this case we need to put plugin's files
                // into platform_www but plugman CLI doesn't allow us to do that, so we set it here
                options.usePlatformWww = true;

                const hooksRunner = new HooksRunner(projectRoot);

                return hooksRunner.fire('before_plugin_install', hookOptions).then(function () {
                    return handleInstall(actions, pluginInfo, platform, project_dir, plugins_dir, install_plugin_dir, filtered_variables, options);
                }).then(function (installResult) {
                    return hooksRunner.fire('after_plugin_install', hookOptions)
                        // CB-11022 Propagate install result to caller to be able to avoid unnecessary prepare
                        .then(_ => installResult);
                });
            } else {
                return handleInstall(actions, pluginInfo, platform, project_dir, plugins_dir, install_plugin_dir, filtered_variables, options);
            }
        }
    ).catch(
        function (error) {
            if (error.skip) {
                events.emit('warn', 'Skipping \'' + pluginInfo.id + '\' for ' + platform);
            } else {
                events.emit('warn', 'Failed to install \'' + pluginInfo.id + '\': ' + error.stack);
                throw error;
            }
        }
    );
}