blob: 6f70c4ca5cec111bd321e9f11123dee1859092f6 [file]
var path = require('path'),
fs = require('fs'),
et = require('elementtree'),
n = require('ncallbacks'),
config_changes = require('./util/config-changes'),
action_stack = require('./util/action-stack'),
platform_modules = require('./platforms');
module.exports = function installPlugin(platform, project_dir, id, plugins_dir, subdir, cli_variables, www_dir, callback) {
if (!platform_modules[platform]) {
var err = new Error(platform + " not supported.");
if (callback) callback(err);
else throw err;
return;
}
var current_stack = new action_stack();
possiblyFetch(current_stack, platform, project_dir, id, plugins_dir, subdir, cli_variables, www_dir, undefined /* git_ref */, true, callback);
};
function possiblyFetch(actions, platform, project_dir, id, plugins_dir, subdir, cli_variables, www_dir, git_ref, is_top_level, callback) {
var plugin_dir = path.join(plugins_dir, id);
// Check that the plugin has already been fetched.
if (!fs.existsSync(plugin_dir)) {
// if plugin doesnt exist, use fetch to get it.
// TODO: Actual value for git_ref.
require('../plugman').fetch(id, plugins_dir, false, '.', git_ref, function(err, plugin_dir) {
if (err) {
callback(err);
} else {
// update ref to plugin_dir after successful fetch, via fetch callback
runInstall(actions, platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, is_top_level, callback);
}
});
} else {
runInstall(actions, platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, is_top_level, callback);
}
}
function runInstall(actions, platform, project_dir, plugin_dir, plugins_dir, cli_variables, www_dir, is_top_level, callback) {
var xml_path = path.join(plugin_dir, 'plugin.xml')
, xml_text = fs.readFileSync(xml_path, 'utf-8')
, plugin_et = new et.ElementTree(et.XML(xml_text))
, filtered_variables = {};
var name = plugin_et.findall('name').text;
var plugin_id = plugin_et._root.attrib['id'];
// check if platform has plugin installed already.
var platform_config = config_changes.get_platform_json(plugins_dir, platform);
var plugin_basename = path.basename(plugin_dir);
var is_installed = false;
Object.keys(platform_config.installed_plugins).forEach(function(installed_plugin_id) {
if (installed_plugin_id == plugin_id) {
is_installed = true;
}
});
Object.keys(platform_config.dependent_plugins).forEach(function(installed_plugin_id) {
if (installed_plugin_id == plugin_id) {
is_installed = true;
}
});
if (is_installed) {
console.log('Plugin "' + plugin_id + '" already installed, \'sall good.');
if (callback) callback();
return;
}
// checking preferences, if certain variables are not provided, we should throw.
prefs = plugin_et.findall('./preference') || [];
prefs = prefs.concat(plugin_et.findall('./platform[@name="'+platform+'"]/preference'));
var missing_vars = [];
prefs.forEach(function (pref) {
var key = pref.attrib["name"].toUpperCase();
if (cli_variables[key] == undefined)
missing_vars.push(key)
else
filtered_variables[key] = cli_variables[key]
});
if (missing_vars.length > 0) {
var err = new Error('Variable(s) missing: ' + missing_vars.join(", "));
if (callback) callback(err);
else throw err;
return;
}
// Check for dependencies, (co)recurse to install each one
var dependencies = plugin_et.findall('dependency');
if (dependencies && dependencies.length) {
var end = n(dependencies.length, function() {
handleInstall(actions, plugin_id, plugin_et, platform, project_dir, plugins_dir, plugin_basename, plugin_dir, filtered_variables, www_dir, is_top_level, callback);
});
dependencies.forEach(function(dep) {
var dep_plugin_id = dep.attrib.id;
var dep_subdir = dep.attrib.subdir;
var dep_url = dep.attrib.url;
var dep_git_ref = dep.attrib.commit;
if (dep_subdir) {
dep_subdir = path.join.apply(null, dep_subdir.split('/'));
}
var dep_plugin_dir = path.join(plugins_dir, dep_plugin_id);
if (fs.existsSync(dep_plugin_dir)) {
console.log('Dependent plugin ' + dep_plugin_id + ' already fetched, using that version.');
runInstall(actions, platform, project_dir, dep_plugin_dir, plugins_dir, filtered_variables, www_dir, false, end);
} else {
console.log('Dependent plugin ' + dep_plugin_id + ' not fetched, retrieving then installing.');
possiblyFetch(actions, platform, project_dir, dep_url, plugins_dir, dep_subdir, filtered_variables, www_dir, dep_git_ref, false, function(err) {
if (err) {
if (callback) callback(err);
else throw err;
} else end();
});
}
});
} else {
handleInstall(actions, plugin_id, plugin_et, platform, project_dir, plugins_dir, plugin_basename, plugin_dir, filtered_variables, www_dir, is_top_level, callback);
}
}
function handleInstall(actions, plugin_id, plugin_et, platform, project_dir, plugins_dir, plugin_basename, plugin_dir, filtered_variables, www_dir, is_top_level, callback) {
console.log('Installing plugin ' + plugin_id + '...');
var handler = platform_modules[platform];
www_dir = www_dir || handler.www_dir(project_dir);
var platformTag = plugin_et.find('./platform[@name="'+platform+'"]');
var assets = plugin_et.findall('asset');
if (platformTag) {
var sourceFiles = platformTag.findall('./source-file'),
headerFiles = platformTag.findall('./header-file'),
resourceFiles = platformTag.findall('./resource-file'),
libFiles = platformTag.findall('./lib-file'),
frameworks = platformTag.findall('./framework');
assets = assets.concat(platformTag.findall('./asset'));
// queue up native stuff
sourceFiles && sourceFiles.forEach(function(source) {
actions.push(actions.createAction(handler["source-file"].install, [source, plugin_dir, project_dir, plugin_id], handler["source-file"].uninstall, [source, project_dir, plugin_id]));
});
headerFiles && headerFiles.forEach(function(header) {
actions.push(actions.createAction(handler["header-file"].install, [header, plugin_dir, project_dir, plugin_id], handler["header-file"].uninstall, [header, project_dir, plugin_id]));
});
resourceFiles && resourceFiles.forEach(function(resource) {
actions.push(actions.createAction(handler["resource-file"].install, [resource, plugin_dir, project_dir], handler["resource-file"].uninstall, [resource, project_dir]));
});
frameworks && frameworks.forEach(function(framework) {
actions.push(actions.createAction(handler["framework"].install, [framework, plugin_dir, project_dir], handler["framework"].uninstall, [framework, project_dir]));
});
libFiles && libFiles.forEach(function(lib) {
actions.push(actions.createAction(handler["lib-file"].install, [lib, plugin_dir, project_dir], handler["lib-file"].uninstall, [lib, project_dir]));
});
}
// queue up asset installation
var common = require('./platforms/common');
assets && assets.forEach(function(asset) {
actions.push(actions.createAction(common.asset.install, [asset, plugin_dir, www_dir], common.asset.uninstall, [asset, www_dir, plugin_id]));
});
// run through the action stack
actions.process(platform, project_dir, function(err) {
if (err) {
if (callback) callback(err);
else throw err;
} else {
// WIN!
// Log out plugin INFO element contents in case additional install steps are necessary
var info = (platformTag ? platformTag.findall('./info') : '');
if(info.length) {
console.log(info[0].text);
}
// queue up the plugin so prepare knows what to do.
config_changes.add_installed_plugin_to_prepare_queue(plugins_dir, plugin_basename, platform, filtered_variables, is_top_level);
// call prepare after a successful install
require('./../plugman').prepare(project_dir, platform, plugins_dir);
console.log(plugin_id + ' installed.');
if (callback) callback();
}
});
}