wip refactoring

... towards an idempotent `ensureCordovaProject` sub-routine
This commit is contained in:
Slava Kim
2014-07-14 15:23:22 -07:00
parent b5b55bb792
commit f28d0cdf32
2 changed files with 179 additions and 71 deletions

View File

@@ -1459,7 +1459,11 @@ main.registerCommand({
// cordova
///////////////////////////////////////////////////////////////////////////////
var generateCordovaBoilerplate = function (clientDir, clientJson, boilerplateTemplateSource) {
var generateCordovaBoilerplate = function (clientDir) {
var clientJsonPath = path.join(clientDir, 'program.json');
var clientJson = JSON.parse(fs.readFileSync(clientJsonPath, 'utf8'));
var boilerplatePath = path.join(__dirname, 'client', 'cordova-boilerplate.html');
var boilerplateTemplateSource = fs.readFileSync(boilerplatePath, 'utf8');
var boilerplateData = {
css: [],
js: [],
@@ -1509,6 +1513,82 @@ var generateCordovaBoilerplate = function (clientDir, clientJson, boilerplateTem
HTML.toHTML(boilerplateHtmlJs, boilerplateInstance);
};
// Creates a Cordova project if necessary and makes sure added Cordova
// platforms and Cordova plugins are up to date with the project's
// definition.
var ensureCordovaProject = function (appName, projectPath, bundlePath) {
// XXX temp hack as the easiest way to ensure right now is to destroy and
// recreate
files.rm_recursive(projectPath);
var bundler = require(path.join(__dirname, 'bundler.js'));
var loader = project.getPackageLoader();
var clientArchName = 'client.cordova';
var bundleResult = bundler.bundle({
outputPath: bundlePath,
buildOptions: {
minify: false, // XXX ! options.debug,
arch: archinfo.host(),
clientArchs: [clientArchName]
}
});
if (bundleResult.errors) {
throw new Error("Errors prevented bundling:\n" +
bundleResult.errors.formatMessages());
}
var programPath = path.join(bundlePath, 'programs');
// XXX check if Cordova folder exists, don't run `cordova create`
execFileSync('cordova', ['create', path.basename(projectPath),
'com.meteor.' + appName,
appName.replace(/\s/g, '')],
{ cwd: path.dirname(projectPath) });
var wwwPath = path.join(projectPath, "www");
var cordovaProgramPath = path.join(programPath, clientArchName);
var cordovaProgramAppPath = path.join(cordovaProgramPath, 'app');
// XXX hack, copy files from app folder one level up
files.cp_r(cordovaProgramAppPath, cordovaProgramPath);
files.rm_recursive(cordovaProgramAppPath);
// rewrite the www folder
files.rm_recursive(wwwPath);
files.cp_r(cordovaProgramPath, wwwPath);
// clean up the temporary bundle directory
files.rm_recursive(bundlePath);
// generate index.html
var indexHtml = generateCordovaBoilerplate(wwwPath);
fs.writeFileSync(path.join(wwwPath, 'index.html'), indexHtml, 'utf8');
// XXX get the output of `cordova plugins` and compare to the project
// dependencies; add/remove plugins if different.
// XXX compare the latest used sha's with the currently required sha's for
// plugins fetched from a github/tarball url.
// XXX get platforms from project file
// _.each(platforms, function (platform) {
// execFileSync('cordova', ['platform', 'add', platform], { cwd: projectPath });
// });
_.each(bundleResult.starManifest.cordovaDependencies,
function (version, name) {
// XXX do something different for plugins fetched from a url.
execFileSync('cordova', ['plugin', 'add', name + '@' + version],
{ cwd: projectPath });
});
execFileSync('cordova', ['build'], { cwd: projectPath });
};
main.registerCommand({
name: 'cordova',
minArgs: 1,
@@ -1519,75 +1599,22 @@ main.registerCommand({
},
}, function (options) {
var localDir = path.join(options.appDir, '.meteor', 'local');
var cordovaPath = path.join(localDir, 'client.cordova');
var cordovaPath = path.join(localDir, 'cordova-build');
var bundleDir = path.join(localDir, 'bundle-tar');
var appName = path.basename(options.appDir);
if (options.args[0] === 'create') {
files.rm_recursive(cordovaPath);
var buildDir = path.join(localDir, 'build_tar');
var outputPath = path.join(buildDir, 'bundle');
var cordovaCommand = options.args[0];
var cordovaArgs = options.args.slice(1);
var bundler = require(path.join(__dirname, 'bundler.js'));
var loader = project.getPackageLoader();
stats.recordPackages(options.appDir);
var clientArchs = ['client.cordova'];
var bundleResult = bundler.bundle({
outputPath: outputPath,
buildOptions: {
minify: false, // XXX ! options.debug,
arch: archinfo.host(),
clientArchs: clientArchs
}
});
if (bundleResult.errors) {
process.stdout.write("Errors prevented bundling:\n");
process.stdout.write(bundleResult.errors.formatMessages());
return 1;
}
var programPath = path.join(outputPath, 'programs');
var appName = path.basename(options.appDir);
execFileSync('cordova', ['create', 'client.cordova',
'com.meteor.' + appName,
appName.replace(/\s/g, '')], { cwd: localDir });
var wwwPath = path.join(cordovaPath, "www");
var fromPath = path.join(programPath, 'client.cordova');
var appPath = path.join(fromPath, 'app');
files.cp_r(appPath, fromPath);
files.rm_recursive(appPath);
files.rm_recursive(wwwPath);
files.cp_r(fromPath, wwwPath);
var clientJsonPath = path.join(wwwPath, 'program.json');
var clientJson = JSON.parse(fs.readFileSync(clientJsonPath, 'utf8'));
var boilerplatePath = path.join(__dirname, 'client', 'cordova-boilerplate.html');
var boilerplateTemplateSource = fs.readFileSync(boilerplatePath, 'utf8');
var indexHtml = generateCordovaBoilerplate(wwwPath, clientJson, boilerplateTemplateSource);
fs.writeFileSync(path.join(wwwPath, 'index.html'), indexHtml, 'utf8');
_.each(options.args.slice(1), function (arch) {
execFileSync('cordova', ['platform', 'add', arch], { cwd: cordovaPath });
});
_.each(bundleResult.starManifest.cordovaDependencies,
function (version, name) {
execFileSync('cordova', ['plugin', 'add', name + '@' + version],
{ cwd: cordovaPath });
});
execFileSync('cordova', ['build'], { cwd: cordovaPath });
files.rm_recursive(fromPath);
files.rm_recursive(buildDir);
} else {
// XXX error if not a Cordova project
execFileSync('cordova', options.args, { cwd: cordovaPath });
try {
ensureCordovaProject(appName, cordovaPath, bundleDir);
} catch (e) {
process.stderr.write('Errors preventing the Cordova project from build:\n');
process.stderr.write(e.stack);
return 1;
}
// XXX error if not a Cordova project
execFileSync('cordova', options.args, { cwd: cordovaPath });
});

View File

@@ -22,9 +22,9 @@ var trimLine = function (line) {
return line;
};
// Given a set of lines, each of the form "foo@bar", return an array of form
// [{packageName: foo, versionConstraint: bar}]. If there is bar,
// versionConstraint is null.
// Given a set of lines, each of the form "foo@bar", return an object of form
// {foo: "bar", bar: null}. If there is "bar", value of the corresponding key is
// null.
var processPerConstraintLines = function(lines) {
var ret = {};
@@ -66,6 +66,15 @@ var Project = function () {
// and recorded in the .meteor/versions file.
self.dependencies = null;
// Plugins & versions of all Cordova plugins dependencies.
// A mapping from the Cordova plugin identifier to a semver string or a
// tarball url with sha.
// XXX Ignores the transitive dependencies.
self.cordovaPlugins = null;
// Platfroms & versions used by the Cordova project.
self.cordovaPlatforms = null
// The package loader for this project, with the project's dependencies as its
// version file. (See package-loader.js for more information about package
// loaders). Derived from self.dependencies.
@@ -128,6 +137,12 @@ _.extend(Project.prototype, {
// Also, make sure we have an app identifier for this app.
self.ensureAppIdentifier();
self.cordovaPlugins = processPerConstraintLines(
files.getLinesOrEmpty(self._getCordovaPluginsFile()));
self.cordovaPlatforms = processPerConstraintLines(
files.getLinesOrEmpty(self._getCordovaPlatformsFile()));
// Lastly, invalidate everything that we have computed -- obviously the
// dependencies that we counted with the previous rootPath are wrong and we
// need to recompute them.
@@ -442,6 +457,30 @@ _.extend(Project.prototype, {
return path.join(self.rootDir, '.meteor', 'versions');
},
getCordovaPlugins: function () {
var self = this;
return self.cordovaPlugins;
},
getCordovaPlatforms: function () {
var self = this;
return self.cordovaPlatforms;
},
// Returns the file path to the .meteor/cordova-plugins file, containing the
// Cordova plugins dependencies for this specific project.
_getCordovaPluginsFile: function () {
var self = this;
return path.join(self.rootDir, '.meteor', 'cordova-plugins');
},
// Returns the file path to the .meteor/cordova-platforms file, containing the
// targetted Cordova platforms for this specific project.
_getCordovaPlatformsFile: function () {
var self = this;
return path.join(self.rootDir, '.meteor', 'cordova-platforms');
},
// Give the package loader attached to this project to the caller.
//
// Returns a packageLoader that has been pre-loaded with this project's
@@ -800,7 +839,49 @@ _.extend(Project.prototype, {
appendText += upgrader + '\n';
fs.appendFileSync(self._finishedUpgradersFile(), appendText);
},
// Adds the passed plugins to the cordovaPlugins list. If the plugin was
// already in the list, just updates it in-place.
// newPlugins is an object with a mapping from the Cordova plugin identifier
// to an semver string or a tarball url with a sha.
addCordovaPlugins: function (newPlugins) {
var self = this;
self.cordovaPlugins = _.extend(self.cordovaPlugins, newPlugins);
var plugins = self._getCordovaPluginsFile();
var lines = files.getLinesOrEmpty(plugins);
_.each(self.cordovaPlugins, function (versionString, plugin) {
if (versionString)
lines.push(plugin + '@' + versionString);
else
lines.push(plugin);
});
lines.push('\n');
fs.writeFileSync(plugins, lines.join('\n'), 'utf8');
},
// Removes the plugins from the cordova-plugins file if they existed.
// pluginsToRemove - array of Cordova plugin identifiers
removeCordovaPlugins: function (pluginsToRemove) {
var self = this;
self.cordovaPlugins =
_.omit.apply(null, [self.cordovaPlugins].concat(pluginsToRemove));
var plugins = self._getCordovaPluginsFile();
var lines = files.getLinesOrEmpty(plugins);
_.each(self.cordovaPlugins, function (versionString, plugin) {
if (versionString)
lines.push(plugin + '@' + versionString);
else
lines.push(plugin);
});
lines.push('\n');
fs.writeFileSync(plugins, lines.join('\n'), 'utf8');
}
// XXX addCordovaPlatforms, removeCordovaPlatforms
});
// The project is currently a singleton, but there is no universal reason for