diff --git a/src/plugins/ApplyUpdates/ApplyUpdates.js b/src/plugins/ApplyUpdates/ApplyUpdates.js index e95e56de4..60f7ea8cf 100644 --- a/src/plugins/ApplyUpdates/ApplyUpdates.js +++ b/src/plugins/ApplyUpdates/ApplyUpdates.js @@ -4,60 +4,62 @@ define([ 'deepforge/updates/Updates', 'text!./metadata.json', - 'plugin/PluginBase' + 'plugin/ImportLibrary/ImportLibrary/ImportLibrary', ], function ( Updates, pluginMetadata, - PluginBase + PluginBase, ) { 'use strict'; pluginMetadata = JSON.parse(pluginMetadata); - /** - * Initializes a new instance of ApplyUpdates. - * @class - * @augments {PluginBase} - * @classdesc This class represents the plugin ApplyUpdates. - * @constructor - */ - var ApplyUpdates = function () { - // Call base class' constructor. + const ApplyUpdates = function () { PluginBase.call(this); this.pluginMetadata = pluginMetadata; }; - /** - * Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc. - * This is also available at the instance at this.pluginMetadata. - * @type {object} - */ ApplyUpdates.metadata = pluginMetadata; // Prototypical inheritance from PluginBase. ApplyUpdates.prototype = Object.create(PluginBase.prototype); ApplyUpdates.prototype.constructor = ApplyUpdates; - /** - * Main function for the plugin to execute. This will perform the execution. - * Notes: - * - Always log with the provided logger.[error,warning,info,debug]. - * - Do NOT put any user interaction logic UI, etc. inside this method. - * - callback always has to be called even if error happened. - * - * @param {function(string, plugin.PluginResult)} callback - the result callback - */ ApplyUpdates.prototype.main = async function (callback) { // Retrieve the updates to apply const config = this.getCurrentConfig(); - const updateNames = config.updates || []; - - if (!updateNames.length) { + if (!config.updates.length) { this.result.setSuccess(true); return callback(null, this.result); } - // Apply each of the updates + const [libUpdates, migrations] = partition( + config.updates, + update => update.type === Updates.SEED + ); + await this.applyLibraryUpdates(libUpdates); + await this.applyMigrations(migrations); + const updateDisplayNames = config.updates + .map(update => update.type === Updates.SEED ? `${update.name} (library)` : update.name) + .join(', '); + + await this.save(`Applied project updates: ${updateDisplayNames}`); + + this.result.setSuccess(true); + callback(null, this.result); + }; + + ApplyUpdates.prototype.applyLibraryUpdates = async function (updates) { + for (let i = 0; i < updates.length; i++) { + const {name} = updates[i]; + const {branchInfo, rootHash, libraryData} = await this.createGMELibraryFromSeed(name); + await this.core.updateLibrary(this.rootNode, name, rootHash, libraryData); + await this.removeTemporaryBranch(branchInfo); + } + }; + + ApplyUpdates.prototype.applyMigrations = async function (migrations) { + const updateNames = migrations.map(migration => migration.name); const updates = Updates.getUpdates(updateNames); for (let i = 0, len = updates.length; i < len; i++) { @@ -66,12 +68,17 @@ define([ await update.apply(this.core, this.rootNode, this.META); } - // Save the project - await this.save(`Applied project updates: ${updateNames.join(",")}`); - - this.result.setSuccess(true); - callback(null, this.result); }; + function partition(data, fn) { + const partitioned = [[], []]; + data.forEach(datum => { + const partitionIndex = fn(datum) ? 0 : 1; + const partition = partitioned[partitionIndex]; + partition.push(datum); + }); + return partitioned; + } + return ApplyUpdates; }); diff --git a/src/plugins/ImportLibrary/ImportLibrary.js b/src/plugins/ImportLibrary/ImportLibrary.js index 2ddb5f05f..dc0f9ad6e 100644 --- a/src/plugins/ImportLibrary/ImportLibrary.js +++ b/src/plugins/ImportLibrary/ImportLibrary.js @@ -46,38 +46,25 @@ define([ * * @param {function(string, plugin.PluginResult)} callback - the result callback */ - ImportLibrary.prototype.main = function (callback) { + ImportLibrary.prototype.main = async function (callback) { const config = this.getCurrentConfig(); const libraryInfo = config.libraryInfo; - return this.addSeedToBranch(libraryInfo.seed) - .then(branchName => this.createGMELibraryFromBranch(branchName, libraryInfo)) - .then(branchInfo => this.removeTemporaryBranch(branchInfo)) - .then(() => this.updateMetaForLibrary(libraryInfo)) - .then(() => this.addLibraryInitCode(libraryInfo)) - .then(() => this.save(`Imported ${libraryInfo.name} library`)) - .then(() => { - this.result.setSuccess(true); - callback(null, this.result); - }) - .catch(err => { - this.logger.error(`Could not check the libraries: ${err}`); - callback(err, this.result); - }); + const {branchInfo, rootHash, libraryData} = await this.createGMELibraryFromSeed(libraryInfo.seed); + // FIXME: libraryData isn't very good... + await this.core.addLibrary(this.rootNode, libraryInfo.name, rootHash, libraryData); + await this.removeTemporaryBranch(branchInfo); + + await this.updateMetaForLibrary(libraryInfo); + await this.addLibraryInitCode(libraryInfo); + await this.save(`Imported ${libraryInfo.name} library`); + this.result.setSuccess(true); + callback(null, this.result); }; - ImportLibrary.prototype.getUniqueBranchName = function (basename) { - return this.project.getBranches() - .then(branches => { - let name = basename; - let i = 2; - - while (branches[name]) { - name = `${basename}${i}`; - i++; - } - return name; - }); + ImportLibrary.prototype.createGMELibraryFromSeed = async function (name) { + const branchName = await this.addSeedToBranch(name); + return await this.createGMELibraryFromBranch(branchName, name); }; ImportLibrary.prototype.addSeedToBranch = async function (name) { @@ -91,8 +78,19 @@ define([ return branch; }; - ImportLibrary.prototype.createGMELibraryFromBranch = async function (branchName, libraryInfo) { - const name = libraryInfo.name; + ImportLibrary.prototype.getUniqueBranchName = async function (basename) { + const branches = await this.project.getBranches(); + let name = basename; + let i = 2; + + while (branches[name]) { + name = `${basename}${i}`; + i++; + } + return name; + }; + + ImportLibrary.prototype.createGMELibraryFromBranch = async function (branchName) { const libraryData = { projectId: this.projectId, branchName: branchName, @@ -101,15 +99,15 @@ define([ // Get the rootHash and commitHash from the commit on the tmp branch const commits = await this.project.getHistory(branchName, 1); - let commit = commits[0]; - let rootHash = commit.root; + const commit = commits[0]; + const rootHash = commit.root; libraryData.commitHash = commit._id; - await this.core.addLibrary(this.rootNode, name, rootHash, libraryData); - return { + const branchInfo = { name: branchName, hash: commit._id }; + return {branchInfo, rootHash, libraryData}; }; ImportLibrary.prototype.removeTemporaryBranch = function (branch) { diff --git a/src/visualizers/panels/Sidebar/SidebarPanel.js b/src/visualizers/panels/Sidebar/SidebarPanel.js index 2ca4ed924..ed502f774 100644 --- a/src/visualizers/panels/Sidebar/SidebarPanel.js +++ b/src/visualizers/panels/Sidebar/SidebarPanel.js @@ -164,30 +164,20 @@ define([ }); }; - SidebarPanel.prototype.applyUpdates = function (updates) { - // Seed Updates should apply the - const seedUpdates = updates.filter(update => update.type === Updates.SEED); - const promises = seedUpdates.map(update => { - const {name, hash} = update; - return Q.ninvoke(this._client, 'updateLibrary', name, hash); - }); - - // Apply the migrations + SidebarPanel.prototype.applyUpdates = async function (updates) { const pluginId = 'ApplyUpdates'; const migrations = updates .filter(update => update.type === Updates.MIGRATION) .map(update => update.name); - const context = this._client.getCurrentPluginContext(pluginId); - context.pluginConfig = { - updates: migrations - }; - - promises.push( - Q.ninvoke(this._client, 'runServerPlugin', pluginId, context) - ); + if (migrations.length) { + const context = this._client.getCurrentPluginContext(pluginId); + context.pluginConfig = { + updates: updates + }; - return Q.all(promises); + await Q.ninvoke(this._client, 'runServerPlugin', pluginId, context); + } }; return SidebarPanel;