Skip to content
This repository has been archived by the owner on Sep 6, 2021. It is now read-only.

Commit

Permalink
Merge pull request #7330 from adobe/zaggino/check-for-update
Browse files Browse the repository at this point in the history
Check for extensions updates
  • Loading branch information
TomMalbran committed Apr 22, 2014
2 parents a2ce391 + 5560bc2 commit 180e4cc
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 73 deletions.
8 changes: 2 additions & 6 deletions src/brackets.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,13 +296,9 @@ define(function (require, exports, module) {

// Check for updates
if (!params.get("skipUpdateCheck") && !brackets.inBrowser) {
// check once a day, plus 2 minutes,
// as the check will skip if the last check was not -24h ago
window.setInterval(UpdateNotification.checkForUpdate, 86520000);

// Check for updates on App Ready
AppInit.appReady(function () {
UpdateNotification.checkForUpdate();
// launches periodic checks for updates cca every 24 hours
UpdateNotification.launchAutomaticUpdate();
});
}
}
Expand Down
138 changes: 105 additions & 33 deletions src/extensibility/ExtensionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
define(function (require, exports, module) {
"use strict";

var FileUtils = require("file/FileUtils"),
var _ = require("thirdparty/lodash"),
FileUtils = require("file/FileUtils"),
Package = require("extensibility/Package"),
Async = require("utils/Async"),
ExtensionLoader = require("utils/ExtensionLoader"),
Expand Down Expand Up @@ -105,13 +106,28 @@ define(function (require, exports, module) {
}

entry.installInfo.owner = entry.registryInfo.owner;
if (entry.installInfo.metadata && entry.installInfo.metadata.version && semver.lt(entry.installInfo.metadata.version, entry.registryInfo.metadata.version)) {

// Assume false
entry.installInfo.updateAvailable = false;
entry.registryInfo.updateAvailable = false;
entry.installInfo.updateCompatible = false;
entry.registryInfo.updateCompatible = false;

var currentVersion = entry.installInfo.metadata ? entry.installInfo.metadata.version : null;
if (currentVersion && semver.lt(currentVersion, entry.registryInfo.metadata.version)) {
// Note: available update may still be incompatible; we check for this when rendering the Update button in ExtensionManagerView._renderItem()
entry.registryInfo.updateAvailable = true;
entry.installInfo.updateAvailable = true;
} else {
entry.installInfo.updateAvailable = false;
entry.registryInfo.updateAvailable = false;
entry.registryInfo.updateAvailable = true;
entry.installInfo.updateAvailable = true;
// Calculate updateCompatible to check if there's an update for current version of Brackets
var lastCompatibleVersionInfo = _.findLast(entry.registryInfo.versions, function (versionInfo) {
return semver.satisfies(brackets.metadata.apiVersion, versionInfo.brackets);
});
if (lastCompatibleVersionInfo && lastCompatibleVersionInfo.version && semver.lt(currentVersion, lastCompatibleVersionInfo.version)) {
entry.installInfo.updateCompatible = true;
entry.registryInfo.updateCompatible = true;
entry.installInfo.lastCompatibleVersion = lastCompatibleVersionInfo.version;
entry.registryInfo.lastCompatibleVersion = lastCompatibleVersionInfo.version;
}
}

$(exports).triggerHandler("registryUpdate", [id]);
Expand Down Expand Up @@ -160,6 +176,7 @@ define(function (require, exports, module) {
extensions[id].registryInfo = data[id];
synchronizeEntry(id);
});
$(exports).triggerHandler("registryDownload");
result.resolve();
})
.fail(function () {
Expand Down Expand Up @@ -506,39 +523,94 @@ define(function (require, exports, module) {
);
}

/**
* Gets an array of extensions that are currently installed and can be updated to a new version
* @return {Array.<{id: string, installVersion: string, registryVersion: string}>}
* where id = extensionId
* installVersion = currently installed version of extension
* registryVersion = latest version compatible with current Brackets
*/
function getAvailableUpdates() {
var result = [];
Object.keys(extensions).forEach(function (extensionId) {
var extensionInfo = extensions[extensionId];
// skip extensions that are not installed or are not in the registry
if (!extensionInfo.installInfo || !extensionInfo.registryInfo) {
return;
}
if (extensionInfo.registryInfo.updateCompatible) {
result.push({
id: extensionId,
installVersion: extensionInfo.installInfo.metadata.version,
registryVersion: extensionInfo.registryInfo.lastCompatibleVersion
});
}
});
return result;
}

/**
* Takes the array returned from getAvailableUpdates() as an input and removes those entries
* that are no longer current - when currently installed version of an extension
* is equal or newer than registryVersion returned by getAvailableUpdates().
* This function is designed to work without the necessity to download extension registry
* @param {Array.<{id: string, installVersion: string, registryVersion: string}>} updates
* previous output of getAvailableUpdates()
* @return {Array.<{id: string, installVersion: string, registryVersion: string}>}
* filtered input as function description
*/
function cleanAvailableUpdates(updates) {
return updates.reduce(function (arr, updateInfo) {
var extDefinition = extensions[updateInfo.id];
if (!extDefinition || !extDefinition.installInfo) {
// extension has been uninstalled in the meantime
return arr;
}

var installedVersion = extDefinition.installInfo.metadata.version;
if (semver.lt(installedVersion, updateInfo.registryVersion)) {
arr.push(updateInfo);
}

return arr;
}, []);
}

// Listen to extension load and loadFailed events
$(ExtensionLoader)
.on("load", _handleExtensionLoad)
.on("loadFailed", _handleExtensionLoad);

// Public exports
exports.downloadRegistry = downloadRegistry;
exports.getCompatibilityInfo = getCompatibilityInfo;
exports.getExtensionURL = getExtensionURL;
exports.remove = remove;
exports.update = update;
exports.extensions = extensions;
exports.cleanupUpdates = cleanupUpdates;
exports.markForRemoval = markForRemoval;
exports.isMarkedForRemoval = isMarkedForRemoval;
exports.unmarkAllForRemoval = unmarkAllForRemoval;
exports.hasExtensionsToRemove = hasExtensionsToRemove;
exports.updateFromDownload = updateFromDownload;
exports.removeUpdate = removeUpdate;
exports.isMarkedForUpdate = isMarkedForUpdate;
exports.hasExtensionsToUpdate = hasExtensionsToUpdate;
exports.removeMarkedExtensions = removeMarkedExtensions;
exports.updateExtensions = updateExtensions;
exports.downloadRegistry = downloadRegistry;
exports.getCompatibilityInfo = getCompatibilityInfo;
exports.getExtensionURL = getExtensionURL;
exports.remove = remove;
exports.update = update;
exports.extensions = extensions;
exports.cleanupUpdates = cleanupUpdates;
exports.markForRemoval = markForRemoval;
exports.isMarkedForRemoval = isMarkedForRemoval;
exports.unmarkAllForRemoval = unmarkAllForRemoval;
exports.hasExtensionsToRemove = hasExtensionsToRemove;
exports.updateFromDownload = updateFromDownload;
exports.removeUpdate = removeUpdate;
exports.isMarkedForUpdate = isMarkedForUpdate;
exports.hasExtensionsToUpdate = hasExtensionsToUpdate;
exports.removeMarkedExtensions = removeMarkedExtensions;
exports.updateExtensions = updateExtensions;
exports.getAvailableUpdates = getAvailableUpdates;
exports.cleanAvailableUpdates = cleanAvailableUpdates;

exports.ENABLED = ENABLED;
exports.START_FAILED = START_FAILED;
exports.ENABLED = ENABLED;
exports.START_FAILED = START_FAILED;

exports.LOCATION_DEFAULT = LOCATION_DEFAULT;
exports.LOCATION_DEV = LOCATION_DEV;
exports.LOCATION_USER = LOCATION_USER;
exports.LOCATION_UNKNOWN = LOCATION_UNKNOWN;
exports.LOCATION_DEFAULT = LOCATION_DEFAULT;
exports.LOCATION_DEV = LOCATION_DEV;
exports.LOCATION_USER = LOCATION_USER;
exports.LOCATION_UNKNOWN = LOCATION_UNKNOWN;

// For unit testing only
exports._reset = _reset;
exports._setExtensions = _setExtensions;
});
exports._reset = _reset;
exports._setExtensions = _setExtensions;
});
4 changes: 2 additions & 2 deletions src/extensibility/ExtensionManagerView.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ define(function (require, exports, module) {

var isInstalledInUserFolder = (entry.installInfo && entry.installInfo.locationType === ExtensionManager.LOCATION_USER);
context.allowRemove = isInstalledInUserFolder;
context.allowUpdate = context.showUpdateButton && context.isCompatible && context.isCompatibleLatest && isInstalledInUserFolder;
context.allowUpdate = context.showUpdateButton && context.isCompatible && context.updateCompatible && isInstalledInUserFolder;
if (!context.allowUpdate) {
context.updateNotAllowedReason = isInstalledInUserFolder ? Strings.CANT_UPDATE : Strings.CANT_UPDATE_DEV;
}
Expand Down Expand Up @@ -310,4 +310,4 @@ define(function (require, exports, module) {
};

exports.ExtensionManagerView = ExtensionManagerView;
});
});
32 changes: 22 additions & 10 deletions src/extensibility/ExtensionManagerViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,13 @@ define(function (require, exports, module) {
*/
function InstalledViewModel() {
ExtensionManagerViewModel.call(this);

// when registry is downloaded, sort extensions again - those with updates will be before others
var self = this;
$(ExtensionManager).on("registryDownload", function () {
self._sortFullSet();
self._setInitialFilter();
});
}

InstalledViewModel.prototype = Object.create(ExtensionManagerViewModel.prototype);
Expand Down Expand Up @@ -405,17 +412,22 @@ define(function (require, exports, module) {
var self = this;

this.sortedFullSet = this.sortedFullSet.sort(function (key1, key2) {
var metadata1 = self.extensions[key1].installInfo.metadata,
metadata2 = self.extensions[key2].installInfo.metadata,
id1 = (metadata1.title || metadata1.name).toLowerCase(),
id2 = (metadata2.title || metadata2.name).toLowerCase();
if (id1 < id2) {
// before sorting by name, put first extensions that have updates
var ua1 = self.extensions[key1].installInfo.updateAvailable,
ua2 = self.extensions[key2].installInfo.updateAvailable;

if (ua1 && !ua2) {
return -1;
} else if (id1 === id2) {
return 0;
} else {
} else if (!ua1 && ua2) {
return 1;
}

var metadata1 = self.extensions[key1].installInfo.metadata,
metadata2 = self.extensions[key2].installInfo.metadata,
id1 = (metadata1.title || metadata1.name).toLocaleLowerCase(),
id2 = (metadata2.title || metadata2.name).toLocaleLowerCase();

return id1.localeCompare(id2);
});
};

Expand All @@ -427,7 +439,7 @@ define(function (require, exports, module) {
var self = this;
this.notifyCount = 0;
this.sortedFullSet.forEach(function (key) {
if (self.extensions[key].installInfo.updateAvailable) {
if (self.extensions[key].installInfo.updateCompatible) {
self.notifyCount++;
}
});
Expand Down Expand Up @@ -483,4 +495,4 @@ define(function (require, exports, module) {

exports.RegistryViewModel = RegistryViewModel;
exports.InstalledViewModel = InstalledViewModel;
});
});
5 changes: 4 additions & 1 deletion src/styles/brackets.less
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,10 @@ a, img {
}

#toolbar-extension-manager {
.sprite-icon(0, 0, 24px, 24px, "images/topcoat-plugin-20.svg");
.sprite-icon(0, 0, 24px, 24px, "images/extension-manager-sprite.svg");
&.updatesAvailable {
.sprite-icon(0, 24px, 24px, 24px, "images/extension-manager-sprite.svg");
}
}

/* Project panel */
Expand Down
9 changes: 9 additions & 0 deletions src/styles/images/extension-manager-sprite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 0 additions & 15 deletions src/styles/images/topcoat-plugin-20.svg

This file was deleted.

Loading

0 comments on commit 180e4cc

Please sign in to comment.