Wip refactoring

This commit is contained in:
Matthew Arbesfeld
2014-08-07 13:10:50 -07:00
parent 901c5b8ec7
commit 98cf0ae6e9
4 changed files with 154 additions and 119 deletions

View File

@@ -24,6 +24,8 @@ var execFileSync = require('./utils.js').execFileSync;
var cordova = exports;
var supportedPlatforms = ['ios', 'android', 'firefoxos'];
var getLoadedPackages = _.once(function () {
var uniload = require('./uniload.js');
return uniload.load({
@@ -81,35 +83,143 @@ var fetchCordovaPluginFromShaUrl =
return pluginPath;
};
var ensureCordovaPlatforms = function (platforms, cordovaPath) {
var checkIsValidPlugin = function (name) {
var pluginName = name.split('@')[0];
var pluginHash = {
pluginName: name.split('@')[1]
};
// check that every plugin is specifying either an exact constraint or a
// tarball url with sha
utils.ensureOnlyExactVersions(pluginHash);
};
////////////////////////////////////////////////////////////////////////////////
// ensureCordova
////////////////////////////////////////////////////////////////////////////////
// Creates a Cordova project if necessary. Then synchronizes app-level plugins
// and platofrms.
cordova.ensureCordovaProject = function (cordovaPath, appName) {
var localPluginsPath = path.join(cordovaPath, 'local-plugins');
if (! fs.existsSync(cordovaPath)) {
try {
execFileSync('cordova', ['create', path.basename(cordovaPath),
'com.meteor.' + appName,
appName.replace(/\s/g, '')],
{ cwd: path.dirname(cordovaPath) });
// create a folder for storing local plugins
// XXX cache them there
files.mkdir_p(localPluginsPath);
} catch (err) {
process.stderr.write("Error creating Cordova project: " +
err.message + "\n");
}
}
cordova.ensureCordovaPlatforms(cordovaPath);
cordova.ensureCordovaPlugins(cordovaPath);
};
// Ensures that the Cordova platforms are synchronized with the app-level
// platforms.
cordova.ensureCordovaPlatforms = function (cordovaPath) {
var platforms = project.getCordovaPlatforms();
var platformsOutput = execFileSync('cordova', ['platform', 'list'],
{ cwd: cordovaPath }).stdout;
var installedPlatforms = _.map(platformsOutput.split('\n')[0].match(/Installed platforms: (.*)/)[1].split(', '), function (s) { return s.split(' ')[0]; });
_.each(platforms, function (platform) {
if (! _.contains(installedPlatforms, platform))
if (! _.contains(installedPlatforms, platform) &&
_.contains(supportedPlatforms, platform))
execFileSync('cordova', ['platform', 'add', platform], { cwd: cordovaPath });
});
_.each(installedPlatforms, function (platform) {
if (! _.contains(platforms, platform))
if (! _.contains(platforms, platform) &&
_.contains(supportedPlatforms, platform))
execFileSync('cordova', ['platform', 'rm', platform], { cwd: cordovaPath });
});
return true;
};
// Creates a Cordova project if necessary and makes sure added Cordova
// platforms and Cordova plugins are up to date with the project's
// definition.
cordova.ensureCordovaProject = function (options, cordovaPath, bundlePath) {
if (! options.platforms) {
throw new Error("Must pass platforms to a Cordova project.");
// Ensures that the Cordova plugins are synchronized with the app-level
// plugins.
cordova.ensureCordovaPlugins = function (cordovaPath, appPlugins) {
appPlugins = appPlugins || {};
// XXX compare the latest used sha's with the currently required sha's for
// plugins fetched from a github/tarball url.
var pluginsOutput = execFileSync('cordova', ['plugin', 'list'],
{ cwd: cordovaPath }).stdout;
var installedPlugins = {};
// Check if there are any plugins
if (! pluginsOutput.match(/No plugins added/)) {
_.each(pluginsOutput.split('\n'), function (line) {
line = line.trim();
if (line === '')
return;
var plugin = line.split(' ')[0];
var version = line.split(' ')[1];
installedPlugins[plugin] = version;
});
}
var bundler = require(path.join(__dirname, 'bundler.js'));
// XXX the project-level cordova plugins deps override the package-level ones
_.extend(appPlugins, project.getCordovaPlugins());
_.each(appPlugins, function (version, name) {
// no-op if this plugin is already installed
if (_.has(installedPlugins, name)
&& installedPlugins[name] === version
&& _.isEqual(oldSettings[name], newSettings[name]))
return;
if (_.has(installedPlugins, name))
execFileSync('cordova', ['plugin', 'rm', name], { cwd: cordovaPath });
// XXX do something different for plugins fetched from a url.
var pluginInstallCommand = version ? name + '@' + version : name;
if (version && utils.isUrlWithSha(version)) {
pluginInstallCommand =
fetchCordovaPluginFromShaUrl(version, localPluginsPath, name);
}
var additionalArgs = [];
// XXX how do we get settings to work now? Do we require settings to be
// passed every time we add a plugin?
// if (newSettings[name]) {
// if (! _.isObject(newSettings[name]))
// throw new Error("Meteor.settings.cordova." + name + " is expected to be an object");
// _.each(newSettings[name], function (value, variable) {
// additionalArgs.push("--variable");
// additionalArgs.push(variable + "=" + JSON.stringify(value));
// });
// }
var execRes = execFileSync('cordova',
['plugin', 'add', pluginInstallCommand].concat(additionalArgs), { cwd: cordovaPath });
if (! execRes.success)
throw new Error("Failed to install plugin " + name + ": " + execRes.stderr);
});
_.each(installedPlugins, function (version, name) {
if (! _.has(appPlugins, name))
execFileSync('cordova', ['plugin', 'rm', name], { cwd: cordovaPath });
});
};
// Build a Cordova project, creating a Cordova project if necessary.
cordova.buildCordova = function (cordovaPath, options) {
cordova.ensureCordovaProject(cordovaPath, options.appName);
var bundler = require(path.join(__dirname, 'bundler.js'));
var newSettings = options.settings || {};
var webArchName = 'web.cordova';
var bundleResult = bundler.bundle({
@@ -127,28 +237,6 @@ cordova.ensureCordovaProject = function (options, cordovaPath, bundlePath) {
}
var programPath = path.join(bundlePath, 'programs');
var localPluginsPath = path.join(cordovaPath, 'local-plugins');
var newSettings = options.settings || {};
if (! fs.existsSync(cordovaPath)) {
execFileSync('cordova', ['create', path.basename(cordovaPath),
'com.meteor.' + options.appName,
options.appName.replace(/\s/g, '')],
{ cwd: path.dirname(cordovaPath) });
// XXX a hack as platforms management is not implemented yet
var platforms = options.platforms || "firefoxos";
_.each(platforms, function (platform) {
execFileSync('cordova', ['platforms', 'add', platform],
{ cwd: cordovaPath });
});
// create a folder for storing local plugins
// XXX cache them there
files.mkdir_p(localPluginsPath);
}
var oldSettings = {};
try {
fs.readFileSync(path.join(cordovaPath, 'cordova-settings.json'), "utf8");
@@ -183,77 +271,12 @@ cordova.ensureCordovaProject = function (options, cordovaPath, bundlePath) {
var loaderCode = fs.readFileSync(loaderPath);
fs.writeFileSync(path.join(wwwPath, 'meteor_cordova_loader.js'), loaderCode);
ensureCordovaPlatforms(options.platforms, cordovaPath);
// Compare the state of plugins in the Cordova project and the required by the
// Meteor project.
// XXX compare the latest used sha's with the currently required sha's for
// plugins fetched from a github/tarball url.
var pluginsOutput = execFileSync('cordova', ['plugin', 'list'],
{ cwd: cordovaPath }).stdout;
var installedPlugins = {};
// Check if there are any plugins
if (! pluginsOutput.match(/No plugins added/)) {
_.each(pluginsOutput.split('\n'), function (line) {
line = line.trim();
if (line === '')
return;
var plugin = line.split(' ')[0];
var version = line.split(' ')[1];
installedPlugins[plugin] = version;
});
}
var requiredPlugins = bundleResult.starManifest.cordovaDependencies;
// XXX the project-level cordova plugins deps override the package-level ones
_.extend(requiredPlugins, options.plugins || {});
_.each(requiredPlugins, function (version, name) {
// no-op if this plugin is already installed
if (_.has(installedPlugins, name)
&& installedPlugins[name] === version
&& _.isEqual(oldSettings[name], newSettings[name]))
return;
if (_.has(installedPlugins, name))
execFileSync('cordova', ['plugin', 'rm', name], { cwd: cordovaPath });
// XXX do something different for plugins fetched from a url.
var pluginInstallCommand = version ? name + '@' + version : name;
if (version && utils.isUrlWithSha(version)) {
pluginInstallCommand =
fetchCordovaPluginFromShaUrl(version, localPluginsPath, name);
}
var additionalArgs = [];
if (newSettings[name]) {
if (! _.isObject(newSettings[name]))
throw new Error("Meteor.settings.cordova." + name + " is expected to be an object");
_.each(newSettings[name], function (value, variable) {
additionalArgs.push("--variable");
additionalArgs.push(variable + "=" + JSON.stringify(value));
});
}
var execRes = execFileSync('cordova',
['plugin', 'add', pluginInstallCommand].concat(additionalArgs), { cwd: cordovaPath });
if (! execRes.success)
throw new Error("Failed to install plugin " + name + ": " + execRes.stderr);
});
_.each(installedPlugins, function (version, name) {
if (! _.has(requiredPlugins, name))
execFileSync('cordova', ['plugin', 'rm', name], { cwd: cordovaPath });
});
execFileSync('cordova', ['build'], { cwd: cordovaPath });
};
// Start the simulator or physical device for a specific platform.
// platformName is of the form ios/ios-device/android/android-device
cordova.execCordovaOnPlatform = function (platformName, cordovaPath, options) {
cordova.execCordovaOnPlatform = function (cordovaPath, platformName, options) {
// XXX error if an invalid platform
var platform = platformName.split('-')[0];
var isDevice = platformName.split('-')[1] === 'device';
@@ -275,7 +298,6 @@ cordova.execCordovaOnPlatform = function (platformName, cordovaPath, options) {
// packages - list of strings
cordova.filterPackages = function (packages) {
var supportedPlatforms = ['ios', 'android', 'firefoxos'];
// We hard-code the 'cordova' and 'platform' namespaces
var ret = {
rest: [],
@@ -286,9 +308,10 @@ cordova.filterPackages = function (packages) {
_.each(packages, function (p) {
var namespace = p.split(':')[0];
var name = p.split(':')[1];
if (namespace === 'cordova')
if (namespace === 'cordova') {
checkIsValidPlugin(name);
ret.plugins.push(name);
else if (namespace === 'platform') {
} else if (namespace === 'platform') {
if (! _.contains(supportedPlatforms, name))
throw new Error(name + ": no such platform");
ret.platforms.push(name);
@@ -353,8 +376,6 @@ main.registerCommand({
var projectOptions = _.pick(options, 'port', 'host');
projectOptions.appName = appName;
projectOptions.cordovaSettings = cordovaSettings;
projectOptions.plugins = project.getCordovaPlugins();
projectOptions.platforms = project.getCordovaPlatforms();
// XXX in Android simulators you can't access localhost and the correct way is
// to use "10.0.2.2" instead.

View File

@@ -1394,6 +1394,21 @@ main.registerCommand({
});
project.addCordovaPlugins(pluginsDict);
if (cordovaPlugins.length || cordovaPlatforms.length) {
var cordovaPath =
path.join(options.appDir, '.meteor', 'local', 'cordova-build');
var appName = path.basename(options.appDir);
cordova.ensureCordovaProject(cordovaPath, appName);
}
_.each(cordovaPlatforms, function (platform) {
process.stdout.write("added platform " + platform + "\n");
});
_.each(cordovaPlugins, function (plugin) {
process.stdout.write("added cordova plugin " + plugin + "\n");
});
var args = filteredPackages.rest;
if (_.isEmpty(args))

View File

@@ -280,7 +280,7 @@ main.registerCommand({
var cordovaPlatforms = project.getCordovaPlatforms();
_.each(requestedPlatforms, function (platform) {
if (! _.contains(cordovaPlatforms, platform))
throw new Error("XXX Requested platform " + platform + " which is not added to the project. Enter `meteor add platforms:" + platform + "` to add it.");
throw new Error("XXX Requested platform " + platform + " which is not added to the project. Enter `meteor add platform:" + platform + "` to add it.");
});
var cordovaSettings = null;
@@ -290,7 +290,6 @@ main.registerCommand({
}
var cordovaOptions = {
platforms: requestedPlatforms,
host: proxyHost,
port: proxyPort,
appName: path.basename(options.appDir),

View File

@@ -84,7 +84,7 @@ var checkUserPlugins = function(sand, plugins) {
// Add plugins to an app. Change the contents of the plugins and their
// dependencies, make sure that the app still refreshes.
selftest.define("change plugins", function () {
selftest.define("change cordova plugins", function () {
var s = new Sandbox();
var run;
@@ -121,7 +121,7 @@ selftest.define("change plugins", function () {
// Add plugins through the command line, and make sure that the correct set of
// changes is reflected in .meteor/packages, .meteor/versions and list
selftest.define("add plugins", function () {
selftest.define("add cordova plugins", function () {
var s = new Sandbox();
var run;
@@ -131,17 +131,20 @@ selftest.define("add plugins", function () {
s.set("METEOR_TEST_TMP", files.mkdtemp());
s.set("METEOR_OFFLINE_CATALOG", "t");
run = s.run("cordova", "create", "firefoxos");
run.waitSecs(10);
run.expectExit(0);
run = s.run("remove", "standard-app-packages");
run.match("removed");
run = s.run("cordova", "plugin", "add", "org.apache.cordova.camera@0.3.0");
run.match("Added org.apache.cordova.camera");
run = s.run("run", "firefoxos");
run.matchErr("not added to the project");
run.matchErr("meteor add platform:");
run = s.run("cordova", "plugin", "add", "org.apache.cordova.file");
run = s.run("add", "platform:firefoxos");
run.match("added platform");
run = s.run("add", "cordova:org.apache.cordova.camera@0.3.0");
run.match("added cordova plugin org.apache.cordova.camera");
run = s.run("add", "cordova:org.apache.cordova.file");
run.matchErr("Must declare exact version");
checkUserPlugins(s, ["org.apache.cordova.camera"]);
@@ -152,20 +155,17 @@ selftest.define("add plugins", function () {
// XXX message about a plugin?
checkUserPlugins(s, ["org.apache.cordova.camera"]);
run = s.run("cordova", "build", "--settings", "settings.json");
run = s.run("run", "firefoxos");
run.waitSecs(20);
run.expectExit(0);
checkCordovaPlugins(s,
["org.apache.cordova.camera",
"com.phonegap.plugins.facebookconnect",
"org.apache.cordova.file"]);
// Remove a plugin
run = s.run("remove", "contains-cordova-plugin");
run.match("removed");
run = s.run("cordova", "build");
run.waitSecs(10);
run.expectExit(0);
checkCordovaPlugins(s, ["org.apache.cordova.camera"]);
});