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

Commit 2501136

Browse files
committed
Merge pull request #11184 from adobe/kai/disable-enable-extensions
Disable and enable extensions
2 parents 190d8b7 + 753c84c commit 2501136

11 files changed

Lines changed: 672 additions & 108 deletions

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ Thumbs.db
2020

2121
/src/extensions/disabled
2222

23+
# ignore .disabled file for default extensions
24+
/src/extensions/default/*/.disabled
25+
2326
#OSX .DS_Store files
2427
.DS_Store
2528

@@ -34,3 +37,4 @@ Thumbs.db
3437

3538
# Files that can be automatically downloaded that we don't want to ship with our builds
3639
/src/extensibility/node/node_modules/request/tests/
40+

src/extensibility/ExtensionManager.js

Lines changed: 146 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ define(function (require, exports, module) {
6767
* Extension status constants.
6868
*/
6969
var ENABLED = "enabled",
70+
DISABLED = "disabled",
7071
START_FAILED = "startFailed";
7172

7273
/**
@@ -103,8 +104,9 @@ define(function (require, exports, module) {
103104
/**
104105
* Requested changes to the installed extensions.
105106
*/
106-
var _idsToRemove = [],
107-
_idsToUpdate = [];
107+
var _idsToRemove = {},
108+
_idsToUpdate = {},
109+
_idsToDisable = {};
108110

109111
PreferencesManager.stateManager.definePreference(FOLDER_AUTOINSTALL, "object", undefined);
110112

@@ -186,8 +188,9 @@ define(function (require, exports, module) {
186188
*/
187189
function _reset() {
188190
exports.extensions = extensions = {};
189-
_idsToRemove = [];
190-
_idsToUpdate = [];
191+
_idsToRemove = {};
192+
_idsToUpdate = {};
193+
_idsToDisable = {};
191194
}
192195

193196
/**
@@ -240,8 +243,9 @@ define(function (require, exports, module) {
240243
* @param {string} path The local path of the loaded extension's folder.
241244
*/
242245
function _handleExtensionLoad(e, path) {
243-
function setData(id, metadata) {
246+
function setData(metadata) {
244247
var locationType,
248+
id = metadata.name,
245249
userExtensionPath = ExtensionLoader.getUserExtensionPath();
246250
if (path.indexOf(userExtensionPath) === 0) {
247251
locationType = LOCATION_USER;
@@ -265,27 +269,33 @@ define(function (require, exports, module) {
265269
metadata: metadata,
266270
path: path,
267271
locationType: locationType,
268-
status: (e.type === "loadFailed" ? START_FAILED : ENABLED)
272+
status: (e.type === "loadFailed" ? START_FAILED : (e.type === "disabled" ? DISABLED : ENABLED))
269273
};
270274

271275
synchronizeEntry(id);
272276
loadTheme(id);
273277
exports.trigger("statusChange", id);
274278
}
279+
280+
function deduceMetadata() {
281+
var match = path.match(/\/([^\/]+)$/),
282+
name = (match && match[1]) || path,
283+
metadata = { name: name, title: name };
284+
return metadata;
285+
}
275286

276-
ExtensionUtils.loadPackageJson(path)
287+
ExtensionUtils.loadMetadata(path)
277288
.done(function (metadata) {
278-
setData(metadata.name, metadata);
289+
setData(metadata);
279290
})
280-
.fail(function () {
291+
.fail(function (disabled) {
281292
// If there's no package.json, this is a legacy extension. It was successfully loaded,
282293
// but we don't have an official ID or metadata for it, so we just create an id and
283294
// "title" for it (which is the last segment of its pathname)
284295
// and record that it's enabled.
285-
var match = path.match(/\/([^\/]+)$/),
286-
name = (match && match[1]) || path,
287-
metadata = { name: name, title: name };
288-
setData(name, metadata);
296+
var metadata = deduceMetadata();
297+
metadata.disabled = disabled;
298+
setData(metadata);
289299
});
290300
}
291301

@@ -398,6 +408,58 @@ define(function (require, exports, module) {
398408
}
399409
return result.promise();
400410
}
411+
412+
/**
413+
* @private
414+
*
415+
* Disables or enables the installed extensions.
416+
*
417+
* @param {string} id The id of the extension to disable or enable.
418+
* @param {boolean} enable A boolean indicating whether to enable or disable.
419+
* @return {$.Promise} A promise that's resolved when the extension action is
420+
* completed or rejected with an error that prevents the action from completion.
421+
*/
422+
function _enableOrDisable(id, enable) {
423+
var result = new $.Deferred(),
424+
extension = extensions[id];
425+
if (extension && extension.installInfo) {
426+
Package[(enable ? "enable" : "disable")](extension.installInfo.path)
427+
.done(function () {
428+
extension.installInfo.status = enable ? ENABLED : DISABLED;
429+
extension.installInfo.metadata.disabled = !enable;
430+
result.resolve();
431+
exports.trigger("statusChange", id);
432+
})
433+
.fail(function (err) {
434+
result.reject(err);
435+
});
436+
} else {
437+
result.reject(StringUtils.format(Strings.EXTENSION_NOT_INSTALLED, id));
438+
}
439+
return result.promise();
440+
}
441+
442+
/**
443+
* Disables the installed extension with the given id.
444+
*
445+
* @param {string} id The id of the extension to disable.
446+
* @return {$.Promise} A promise that's resolved when the extenion is disabled or
447+
* rejected with an error that prevented the disabling.
448+
*/
449+
function disable(id) {
450+
return _enableOrDisable(id, false);
451+
}
452+
453+
/**
454+
* Enables the installed extension with the given id.
455+
*
456+
* @param {string} id The id of the extension to enable.
457+
* @return {$.Promise} A promise that's resolved when the extenion is enabled or
458+
* rejected with an error that prevented the enabling.
459+
*/
460+
function enable(id) {
461+
return _enableOrDisable(id, true);
462+
}
401463

402464
/**
403465
* Updates an installed extension with the given package file.
@@ -452,7 +514,7 @@ define(function (require, exports, module) {
452514
}
453515
exports.trigger("statusChange", id);
454516
}
455-
517+
456518
/**
457519
* Returns true if an extension is marked for removal.
458520
* @param {string} id The id of the extension to check.
@@ -461,7 +523,7 @@ define(function (require, exports, module) {
461523
function isMarkedForRemoval(id) {
462524
return !!(_idsToRemove[id]);
463525
}
464-
526+
465527
/**
466528
* Returns true if there are any extensions marked for removal.
467529
* @return {boolean} true if there are extensions to remove
@@ -470,6 +532,46 @@ define(function (require, exports, module) {
470532
return Object.keys(_idsToRemove).length > 0;
471533
}
472534

535+
/**
536+
* Marks an extension for disabling later, or unmarks an extension previously marked.
537+
*
538+
* @param {string} id The id of the extension
539+
* @param {boolean} mark Whether to mark or unmark the extension.
540+
*/
541+
function markForDisabling(id, mark) {
542+
if (mark) {
543+
_idsToDisable[id] = true;
544+
} else {
545+
delete _idsToDisable[id];
546+
}
547+
exports.trigger("statusChange", id);
548+
}
549+
550+
/**
551+
* Returns true if an extension is mark for disabling.
552+
*
553+
* @param {string} id The id of the extension to check.
554+
* @return {boolean} true if it's been mark for disabling, false otherwise.
555+
*/
556+
function isMarkedForDisabling(id) {
557+
return !!(_idsToDisable[id]);
558+
}
559+
560+
/**
561+
* Returns true if there are any extensions marked for disabling.
562+
* @return {boolean} true if there are extensions to disable
563+
*/
564+
function hasExtensionsToDisable() {
565+
return Object.keys(_idsToDisable).length > 0;
566+
}
567+
568+
/**
569+
* Unmarks all the extensions that have been marked for disabling.
570+
*/
571+
function unmarkAllForDisabling() {
572+
_idsToDisable = {};
573+
}
574+
473575
/**
474576
* If a downloaded package appears to be an update, mark the extension for update.
475577
* If an extension was previously marked for removal, marking for update will
@@ -542,6 +644,25 @@ define(function (require, exports, module) {
542644
}
543645
);
544646
}
647+
648+
/**
649+
* Disables extensions marked for disabling.
650+
*
651+
* If the return promise is rejected, the argument will contain an array of objects. Each
652+
* element is an object identifying the extension failed with "item" property set to the
653+
* extension id which has failed to be disabled and "error" property set to the error.
654+
*
655+
* @return {$.Promise} A promise that's resolved when all extensions marked for disabling are
656+
* disabled or rejected if one or more extensions can't be disabled.
657+
*/
658+
function disableMarkedExtensions() {
659+
return Async.doInParallel_aggregateErrors(
660+
Object.keys(_idsToDisable),
661+
function (id) {
662+
return disable(id);
663+
}
664+
);
665+
}
545666

546667
/**
547668
* Updates extensions previously marked for update.
@@ -764,7 +885,8 @@ define(function (require, exports, module) {
764885
// Listen to extension load and loadFailed events
765886
ExtensionLoader
766887
.on("load", _handleExtensionLoad)
767-
.on("loadFailed", _handleExtensionLoad);
888+
.on("loadFailed", _handleExtensionLoad)
889+
.on("disabled", _handleExtensionLoad);
768890

769891

770892
EventDispatcher.makeEventDispatcher(exports);
@@ -775,24 +897,32 @@ define(function (require, exports, module) {
775897
exports.getExtensionURL = getExtensionURL;
776898
exports.remove = remove;
777899
exports.update = update;
900+
exports.disable = disable;
901+
exports.enable = enable;
778902
exports.extensions = extensions;
779903
exports.cleanupUpdates = cleanupUpdates;
780904
exports.markForRemoval = markForRemoval;
781905
exports.isMarkedForRemoval = isMarkedForRemoval;
782906
exports.unmarkAllForRemoval = unmarkAllForRemoval;
783907
exports.hasExtensionsToRemove = hasExtensionsToRemove;
908+
exports.markForDisabling = markForDisabling;
909+
exports.isMarkedForDisabling = isMarkedForDisabling;
910+
exports.unmarkAllForDisabling = unmarkAllForDisabling;
911+
exports.hasExtensionsToDisable = hasExtensionsToDisable;
784912
exports.updateFromDownload = updateFromDownload;
785913
exports.removeUpdate = removeUpdate;
786914
exports.isMarkedForUpdate = isMarkedForUpdate;
787915
exports.hasExtensionsToUpdate = hasExtensionsToUpdate;
788916
exports.removeMarkedExtensions = removeMarkedExtensions;
917+
exports.disableMarkedExtensions = disableMarkedExtensions;
789918
exports.updateExtensions = updateExtensions;
790919
exports.getAvailableUpdates = getAvailableUpdates;
791920
exports.cleanAvailableUpdates = cleanAvailableUpdates;
792921

793922
exports.hasDownloadedRegistry = false;
794923

795924
exports.ENABLED = ENABLED;
925+
exports.DISABLED = DISABLED;
796926
exports.START_FAILED = START_FAILED;
797927

798928
exports.LOCATION_DEFAULT = LOCATION_DEFAULT;

0 commit comments

Comments
 (0)