Source: extensions.js

/*
 * periodic
 * http://github.com/typesettin/periodic
 *
 * Copyright (c) 2014 Yaw Joseph Etse. All rights reserved.
 */

'use strict';

var fs = require('fs-extra'),
	async = require('async'),
	semver = require('semver'),
	path = require('path'),
	npm = require('npm'),
	Utilities = require('periodicjs.core.utilities'),
	CoreUtilities,
	extensionFilePath,
	extensionSkipModifyConf,
	extensionDirName;
/**
 * A module that represents a extension manager.
 * @{@link https://github.com/typesettin/periodic}
 * @author Yaw Joseph Etse
 * @constructor
 * @copyright Copyright (c) 2014 Typesettin. All rights reserved.
 * @license MIT
 * @requires module:fs
 * @requires module:util-extent
 * @throws {Error} If missing configuration files
 * @todo to do later
 */
var Extensions = function (appsettings) {
	var extensionsConfig = {},
		extensionsFiles = [];
	CoreUtilities = new Utilities({
		settings: appsettings
	});
	/** 
	 * gets the configuration information
	 * @return { string } file path for config file
	 */
	this.settings = function () {
		return extensionsConfig;
	};

	this.files = function () {
		return extensionsFiles;
	};

	this.savePluginConfig = function (name, value) {
		this[name] = value;
	}.bind(this);

	this.loadExtensions = function (obj) {
		extensionsFiles.forEach(function (file) {
			require(file)(obj);
		});
	};

	/** 
	 * load extension config file: content/extensions/extensions.json
	 * @throws {Error} If missing config file
	 */
	this.init = function (appsettings) {
		extensionSkipModifyConf = typeof process.env.npm_config_skip_install_periodic_ext === 'string' || typeof process.env.npm_config_skip_ext_conf === 'string';
		/** 
		 * @description if passing dirname of extension, load the config file relative to that dirname
		 */
		if (typeof appsettings !== 'undefined' && typeof appsettings.dirname !== 'undefined') {
			extensionDirName = appsettings.dirname;
			extensionFilePath = path.resolve(extensionDirName, '../../content/extensions/extensions.json');
		}
		/**
		 * @description define extension file path to use
		 */
		else if (typeof appsettings !== 'undefined' && typeof appsettings.extensionFilePath !== 'undefined') {
			extensionFilePath = appsettings.extensionFilePath;
		}
		/**
		 * @description this is the default extension config file path
		 */
		else {
			extensionFilePath = path.join(path.resolve(process.cwd(), './content/extensions/'), 'extensions.json');
		}
		/**
		 * @description use the existing config file without modifying it
		 */
		if (extensionSkipModifyConf !== true || appsettings.skipconffile !== true) {
			extensionsConfig = fs.readJSONSync(extensionFilePath);
		}
		/**
		 * @description set array of compatible extensions if the semver is compatible, only set this array if loading extension core to add extension routes to express
		 */
		if (typeof appsettings !== 'undefined' && typeof appsettings.version !== 'undefined') {
			extensionsConfig.extensions.forEach(function (val) {
				try {
					if (semver.lte(val.periodicCompatibility, appsettings.version) && val.enabled) {
						extensionsFiles.push(this.getExtensionFilePath(val.name));
					}
				}
				catch (e) {
					console.error(e);
					throw new Error('Invalid Extension Configuration');
				}
			}.bind(this));
		}
	}.bind(this);

	this.init(appsettings);
};

Extensions.prototype.getExtensionConfFilePath = function () {
	return extensionFilePath;
};

Extensions.prototype.getExtensions = function (options, callback) {
	fs.readJson(extensionFilePath, function (err, extJson) {
		if (err) {
			callback(err, null);
		}
		else {
			callback(null, extJson.extensions);
		}
	});
};

Extensions.prototype.getExtensionFilePath = function (extensionName) {
	return path.join(path.resolve(process.cwd(), './node_modules/', extensionName), 'index.js');
};

Extensions.prototype.getExtensionPeriodicConfFilePath = function (extensionName) {
	return path.join(path.resolve(process.cwd(), './node_modules/', extensionName), 'periodicjs.ext.json');
};

Extensions.prototype.getExtensionFilePath = function (extensionName) {
	return path.join(path.resolve(process.cwd(), './node_modules/', extensionName), 'index.js');
};

Extensions.prototype.getExtensionPackageJsonFilePath = function (extensionName) {
	return path.join(path.resolve(process.cwd(), './node_modules/', extensionName), 'package.json');
};

Extensions.prototype.getExtensionPeriodicConfFilePath = function (extensionName) {
	return path.join(path.resolve(process.cwd(), './node_modules/', extensionName), 'periodicjs.ext.json');
};

Extensions.prototype.installPublicDirectory = function (options, callback) {
	var extdir = options.extdir,
		extpublicdir = options.extpublicdir;
	// console.log("extname",extname);
	// fs.readdir(extdir, function (err, files) {
	fs.readdir(extdir, function (err) {
		// console.log("files",files);
		if (err) {
			callback(null, 'No public files to copy');
		}
		else {
			//make destination dir
			fs.mkdirs(extpublicdir, function (err) {
				if (err) {
					callback(err, null);
				}
				else {
					fs.copy(extdir, extpublicdir, function (err) {
						if (err) {
							callback(err, null);
						}
						else {
							callback(null, 'Copied public files');
						}
					});
				}
			});
		}
	});
};

/**
 * get both installed files, and the default files in ext conf directory, if missin files, add them to missing conf files array
 * @param {object} options ext_default_config_file_path - ext conf files,ext_installed_config_file_path - destination for ext conf files
 * @param  {Function} callback async.parallel callback
 * @return {Array}            array of missing conf files
 */
Extensions.prototype.getExtensionConfigFiles = function (options, callback) {
	var ext_default_config_file_path = options.ext_default_config_file_path,
		ext_installed_config_file_path = options.ext_installed_config_file_path,
		missing_conf_files = [],
		installed_conf_files = [];

	async.parallel({
			defaultExtConfFiles: function (cb) {
				fs.readdir(ext_default_config_file_path, function (err, files) {
					cb(null, files);
				});
			},
			installedExtConfFiles: function (cb) {
				fs.readdir(ext_installed_config_file_path, function (err, files) {
					cb(null, files);
				});
			}
		},
		function (err, result) {
			try {
				if (result.defaultExtConfFiles && result.defaultExtConfFiles.length > 0) {
					missing_conf_files = result.defaultExtConfFiles;
					if (result.installedExtConfFiles && result.installedExtConfFiles.length > 0) {
						for (var c in missing_conf_files) {
							for (var d in result.installedExtConfFiles) {
								if (missing_conf_files[c] === result.installedExtConfFiles[d]) {
									installed_conf_files.push(missing_conf_files.splice(c, 1)[0]);
								}
							}
						}
					}
				}
				callback(null, {
					ext_default_config_file_path: ext_default_config_file_path,
					ext_installed_config_file_path: ext_installed_config_file_path,
					missingExtConfFiles: missing_conf_files
				});
			}
			catch (e) {
				callback(e, null);
			}
		});
};

/**
 * copy missing files if any are missing
 * @param {object} options ext_default_config_file_path - ext conf files,ext_installed_config_file_path - destination for ext conf files,missingExtConfFiles array of missing files
 * @param  {Function} callback            async callback
 */
Extensions.prototype.copyMissingConfigFiles = function (options, callback) {
	var ext_default_config_file_path = options.ext_default_config_file_path,
		ext_installed_config_file_path = options.ext_installed_config_file_path,
		missingExtConfFiles = options.missingExtConfFiles;
	if (missingExtConfFiles && missingExtConfFiles.length > 0) {
		async.each(missingExtConfFiles, function (file, cb) {
			fs.copy(path.resolve(ext_default_config_file_path, file), path.resolve(ext_installed_config_file_path, file), cb);
		}, function (err) {
			callback(err);
		});
	}
	else {
		callback(null);
	}
};

/**
 * copy extension config files if they don't exist
 * @param  {object}   options  configdir - default config files, extconfigdir - install directory of config files
 * @param  {Function} callback async callback
 * @return {Function}            async callback
 */
Extensions.prototype.installConfigDirectory = function (options, callback) {
	var defaultconfigdir = options.configdir,
		installextconfigdir = options.extconfigdir;

	if (defaultconfigdir && installextconfigdir) {

		fs.mkdirs(installextconfigdir, function (err) {
			if (err) {
				callback(err, null);
			}
			else {
				async.waterfall([
						function (cb) {
							cb(null, {
								ext_default_config_file_path: defaultconfigdir,
								ext_installed_config_file_path: installextconfigdir
							});
						},
						this.getExtensionConfigFiles,
						this.copyMissingConfigFiles
					],
					function (err) {
						if (err) {
							callback(err, null);
						}
						else {
							callback(null, 'Copied config files');
						}
					}.bind(this));
			}
		}.bind(this));
	}
	else {
		callback(null, 'No config files to copy');
	}
};

/**
 * set the extension JSON to be appended to extensions.json
 * @param {object}   options  logfile,extpackfile - package.json for ext, extconffile - periodicjs.ext.json, enabled - set the enabled status
 * @param {Function} callback async callback
 * @returns {Function} async callback
 */
Extensions.prototype.setExtConf = function (options, callback) {
	var logfile = options.logfile,
		// extname = options.extname,
		extpackfile = options.extpackfile,
		extconffile = options.extconffile,
		enabledstatus = (options.enabled) ? options.enabled : false,
		extpackfileJSON = {};

	this.getExtensions({}, function (err, currentExtensionsConf) {
		async.parallel({
			packfile: function (callback) {
				fs.readJson(extpackfile, callback);
				// Extensions.readJSONFileAsync(extpackfile, callback);
			},
			conffile: function (callback) {
				fs.readJson(extconffile, callback);
				// Extensions.readJSONFileAsync(extconffile, callback);
			}
		}, function (err, results) {
			if (err) {
				callback(err, null);
			}
			else {
				extpackfileJSON = {
					'name': results.packfile.name,
					'version': results.packfile.version,
					'periodicCompatibility': results.conffile.periodicCompatibility,
					'installed': true,
					'enabled': enabledstatus,
					'date': new Date(),
					'periodicConfig': results.conffile
				};

				callback(null, {
					currentExtensions: currentExtensionsConf,
					extToAdd: extpackfileJSON,
					logfile: logfile,
					cli: options.cli
				});
			}
		});
	});
};

/**
 * updates extensions.json with extToAdd
 * @param  {object}   options  currentExtensions - current ext conf, extToAdd - extension to add
 * @param  {Function} callback async callback
 * @return {Function}            async callback
 */
Extensions.prototype.updateExtConfFile = function (options, callback) {
	var currentExtConfSettings = {},
		currentExtensions = options.currentExtensions,
		extToAdd = options.extToAdd;
	currentExtConfSettings.extensions = [];

	if (!extToAdd.name) {
		callback('extension conf doesn\'t have a valid name', null);
	}
	else if (!semver.valid(extToAdd.version)) {
		callback('extension conf doesn\'t have a valid semver', null);
	}
	else if (!semver.valid(extToAdd.periodicConfig.periodicCompatibility)) {
		callback('extension conf doesn\'t have a valid periodic semver', null);
	}
	else {
		var alreadyInConf = false,
			extIndex;
		for (var x in currentExtensions) {
			if (currentExtensions[x].name === extToAdd.name) {
				alreadyInConf = true;
				extIndex = x;
			}
		}
		if (alreadyInConf) {
			currentExtensions[extIndex] = extToAdd;
		}
		else {
			currentExtensions.push(extToAdd);
		}
		currentExtConfSettings.extensions = currentExtensions;

		fs.outputJson(this.getExtensionConfFilePath(), currentExtConfSettings, function (err) {
			if (err) {
				callback(err, null);
			}
			else {
				callback(null, {
					message: extToAdd.name + ' installed, extensions.conf updated \r\n  ====##END##====',
					updatedExtensions: currentExtConfSettings.extensions
				});
			}
		});
	}
};

/**
 * Returns the position in array of extensions and data of extension in the extension configuration json file
 * @param  {object} options contains, extname name to look up, array of extensions from the extension file
 * @return {object}         selectedExt - ext json data,err - error in finding ext in conf,numX - index of ext in conf
 */
Extensions.prototype.getCurrentExt = function (options) {
	var extname = options.extname,
		currentExtensions = options.currentextconf.extensions,
		z = false,
		err,
		selectedExt;

	for (var x in currentExtensions) {
		if (currentExtensions[x].name === extname) {
			z = x;
		}
	}

	if (z !== false) {
		selectedExt = currentExtensions[z];
	}
	else {
		err = new Error('selected ext(' + extname + ') is not in the current configuration');
	}

	return {
		selectedExt: selectedExt,
		err: err,
		numX: z
	};
};

/**
 * remove an extensions public files
 * @param  {object}   options  contains path to ext files in public directory
 * @param  {Function} callback async callback
 * @return {Function}            async callback(err,status)
 */
Extensions.prototype.removePublicFiles = function (options, callback) {
	var publicDir = options.publicdir;
	if (publicDir) {
		fs.remove(publicDir, function (err) {
			if (err) {
				callback(err, null);
			}
			else {
				callback(null, 'removed public directory');
			}
		});
	}
	else {
		callback(null, 'no public directory to remove');
	}
};

/**
 * remove an extensions config files
 * @param  {object}   options contains path to ext files in content/config directory
 * @param  {Function} callback async callback
 * @return {Function}            async callback(err,status)
 */
Extensions.prototype.removeConfigFiles = function (options, callback) {
	var configDir = options.configdir;
	if (configDir) {
		fs.remove(configDir, function (err) {
			if (err) {
				callback(err, null);
			}
			else {
				callback(null, 'removed config directory');
			}
		});
	}
	else {
		callback(null, 'no conf directory to remove');
	}
};

/**
 * remove extension from extensions.json
 * @param  {object}   options  extname,currentExtensionsConfJson
 * @param  {Function} callback async callback
 * @return {Function}            async callback(err,status)
 */
Extensions.prototype.removeExtFromConf = function (options, callback) {
	var extname = options.extname,
		currentExtensionsConf = options.currentExtensionsConfJson,
		selectedExtObj = this.getCurrentExt({
			extname: extname,
			currentextconf: currentExtensionsConf
		}),
		numX = selectedExtObj.numX;

	if (selectedExtObj.err) {
		callback(null, {
			message: extname + ' error in extensions.json: ' + selectedExtObj.err + ', application restarting \r\n  ====##REMOVED-END##===='
		});
	}
	else if (numX) {
		currentExtensionsConf.extensions.splice(numX, 1);
		fs.outputJson(
			this.getExtensionConfFilePath(),
			currentExtensionsConf,
			function (err) {
				if (err) {
					callback(err, null);
				}
				else {
					callback(null, {
						message: extname + ' removed, extensions.conf updated, application restarting \r\n  ====##REMOVED-END##===='
					});
				}
			}
		);
	}
	else {
		callback(null, {
			message: extname + ' was not found in extensions.conf updated, application restarting \r\n  ====##REMOVED-END##===='
		});
	}
};

Extensions.prototype.enableExtension = function (options, callback) {
	var selectedExtObj = {
			selectedExt: options.extension,
			numX: options.extensionx
		},
		selectedExt = selectedExtObj.selectedExt,
		numX = selectedExtObj.numX,
		selectedExtDeps = selectedExt.periodicConfig.periodicDependencies,
		numSelectedExtDeps = selectedExtDeps.length,
		confirmedDeps = [],
		appSettings = options.appSettings;

	selectedExt.enabled = true;
	appSettings.extconf.extensions = options.extensions;

	try {
		if (!semver.lte(
				selectedExt.periodicCompatibility, appSettings.version)) {
			callback(new Error('This extension requires periodic version: ' + selectedExt.periodicCompatibility + ' not: ' + appSettings.version), null);
		}
		else {
			for (var x in selectedExtDeps) {
				var checkDep = selectedExtDeps[x];
				for (var y in appSettings.extconf.extensions) {
					var checkExt = appSettings.extconf.extensions[y];
					if (checkDep.extname === checkExt.name && checkExt.enabled) {
						confirmedDeps.push(checkExt.name);
					}
				}
			}
			if (numSelectedExtDeps === confirmedDeps.length) {
				appSettings.extconf.extensions[numX].enabled = true;

				fs.outputJson(
					this.getExtensionConfFilePath(),
					appSettings.extconf,
					function (err) {
						if (err) {
							callback(err, null);
						}
						else {
							callback(null, 'extension enabled');
						}
					}
				);
			}
			else {
				callback(new Error('Missing ' + (numSelectedExtDeps - confirmedDeps.length) + ' enabled extensions.'), null);
			}
		}
	}
	catch (e) {
		callback(e, null);
	}
};

Extensions.prototype.disableExtension = function (options, callback) {
	var selectedExtObj = {
			selectedExt: options.extension,
			numX: options.extensionx
		},
		// selectedExt = selectedExtObj.selectedExt,
		numX = selectedExtObj.numX,
		appSettings = options.appSettings;

	appSettings.extconf.extensions[numX].enabled = false;

	try {
		fs.outputJson(
			this.getExtensionConfFilePath(),
			appSettings.extconf,
			function (err) {
				if (err) {
					callback(err, null);
				}
				else {
					callback(null, 'extension disabled');
				}
			}
		);
	}
	catch (e) {
		callback(e, null);
	}
};

Extensions.prototype.getconfigdir = function (options) {
	return path.resolve(process.cwd(), 'content/config/extensions/', options.extname);
};

Extensions.prototype.extFunctions = function () {
	return {
		getlogfile: function (options) {
			var installfileprefix = (options.installprefix) ? options.installprefix : 'install-ext.',
				extfilename = (options.extfilename) ? options.extfilename : CoreUtilities.makeNiceName(options.reponame);

			return path.join(options.logdir, installfileprefix + options.userid + '.' + extfilename + '.' + options.timestamp + '.log');
		},
		getrepourl: function (options) {
			return (options.repoversion === 'latest' || !options.repoversion) ?
				'https://github.com/' + options.reponame + '/archive/master.tar.gz' :
				'https://github.com/' + options.reponame + '/tarball/' + options.repoversion;
		},
		getlogdir: function () {
			return path.resolve(process.cwd(), 'content/extensions/log/');
		},
		getextdir: function () {
			return path.join(process.cwd(), './node_modules');
		},
		getconfigdir: function (options) {
			return path.resolve(process.cwd(), 'config/extensions/', options.extname);
		}
	};
};

Extensions.prototype.uninstall_viaNPM = function (options, callback) {
	var extname = options.extname;

	npm.load({
			'strict-ssl': false,
			'production': true
				// prefix: extdir
		},
		function (err) {
			if (err) {
				callback(err, null);
			}
			else {
				npm.commands.uninstall([extname], function (err, data) {
					if (err) {
						callback(err, null);
					}
					else {
						callback(null, data);
					}
				});
				npm.on('log', function (message) {
					console.log(message);
				});
			}
		});
};

/**
 * move ext to before specified extension in extension.json extension array
 * @param  {object}   options  extname,movebefore - this is the name of the extension you want to move it before
 * @param  {Function} callback async callback
 * @return {Function}            async callback
 */
Extensions.prototype.moveExtensionBefore = function (options, callback) {
	var extname = options.extname,
		movebefore = options.movebefore,
		indexofext = false,
		extobj = false,
		indexofmovebefore = false,
		currentExtensionsConfFileJson,
		newExtensionConfToSave = {};

	this.getExtensions({}, function (err, currentExtensionsConf) {
		if (err) {
			callback(err, null);
		}
		else {
			currentExtensionsConfFileJson = currentExtensionsConf;
			for (var i in currentExtensionsConf) {
				if (currentExtensionsConf[i].name === extname && indexofext === false) {
					indexofext = i;
				}
				if (currentExtensionsConf[i].name === movebefore && indexofmovebefore === false) {
					indexofmovebefore = i;
				}
			}
			if (indexofext < indexofmovebefore) {
				callback(null, {
					message: 'MOVE BEFORE WARN: Extension (' + currentExtensionsConf[indexofext].name + ') is already before (' + currentExtensionsConf[indexofmovebefore].name + ')'
				});
			}
			else if (indexofmovebefore === false || indexofext === false) {
				callback(null, {
					message: 'MOVE BEFORE ERROR: trying to move extensions that are not in configuration'
				});
			}
			else {
				// console.log('indexofmovebefore',indexofmovebefore,'indexofext',indexofext);
				extobj = currentExtensionsConf.splice(indexofext, 1)[0];
				if (extobj.name === extname) {
					currentExtensionsConf.splice(indexofmovebefore, 0, extobj);
					newExtensionConfToSave.extensions = currentExtensionsConf;
					fs.outputJson(this.getExtensionConfFilePath(), newExtensionConfToSave, function (err) {
						if (err) {
							callback(err, null);
						}
						else {
							callback(null, {
								message: 'successfully moved extenion',
								updatedExtensions: newExtensionConfToSave.extensions
							});
						}
					});
				}
				else {
					// console.log('currentExtensionsConf',currentExtensionsConf);
					callback(null, {
						message: 'MOVE BEFORE ERROR: INVALID EXT CONFIG, MAY HAVE DUPLICATE EXTENSIONS'
					});
				}
			}
		}
	}.bind(this));
};

/**
 * installs extension files to public directory, content directory and inserts into extenions.json
 * @param  {object}   options  dirname
 * @param  {Function} callback async callback
 * @return {Function}            callback(err,results)
 */
Extensions.prototype.install = function (options, callback) {
	var dirname = options.dirname || extensionDirName,
		skipconffile = typeof process.env.npm_config_skip_install_periodic_ext === 'string' || typeof process.env.npm_config_skip_ext_conf === 'string',
		enableOnInstall = typeof process.env.npm_config_enable_ext === 'string',
		packagejsonFileJSON = fs.readJSONSync(path.resolve(dirname, './package.json')),
		extname = options.extname || packagejsonFileJSON.name,
		extdir = path.resolve(dirname, './public'),
		configdir = path.resolve(dirname, './config'),
		extpublicdir = path.resolve(dirname, '../../public/extensions/', extname),
		extconfigdir = path.resolve(dirname, '../../content/config/extensions/', extname),
		extpackfile = path.resolve(dirname, './package.json'),
		extconffile = path.resolve(dirname, './periodicjs.ext.json'),
		movebefore = options.movebefore,
		enabled = options.enabled || enableOnInstall;

	async.series({
		installExtPublicDirectory: function (asynccallback) {
			this.installPublicDirectory({
				extname: extname,
				extdir: extdir,
				extpublicdir: extpublicdir
			}, asynccallback);
		}.bind(this),
		installExtConfigDirectory: function (asynccallback) {
			this.installConfigDirectory({
				extname: extname,
				configdir: configdir,
				extconfigdir: extconfigdir
			}, asynccallback);
		}.bind(this),
		installExtSetPeriodicConf: function (asynccallback) {
			if (skipconffile) {
				asynccallback(null, 'skipping extension conf file');
			}
			else {
				this.setExtConf({
					extname: extname,
					extpackfile: extpackfile,
					extconffile: extconffile,
					enabled: enabled,
				}, asynccallback);
			}
		}.bind(this)
	}, function (err, results) {
		if (err) {
			callback(err, null);
		}
		else if (skipconffile) {
			callback(null, 'skipping extension conf file and installed extension');
		}
		else {
			// console.log(results.installExtPublicDirectory);
			this.updateExtConfFile(results.installExtSetPeriodicConf,
				function (err, status) {
					if (err) {
						callback(err, null);
					}
					else {
						if (movebefore) {
							this.moveExtensionBefore({
									extname: extname,
									movebefore: movebefore
								},
								function (err, movestatus) {
									if (err) {
										callback(err, null);
									}
									else {
										callback(null, movestatus.message + ' - ' + status.message);
									}
								});
						}
						else {
							callback(null, status.message);
						}
					}
				}.bind(this));
		}
	}.bind(this));
};

/**
 * removes extension files from public directory, content directory and from extenions.json
 * @param  {object}   options  dirname,removepublicdir,removeconfigdir
 * @param  {Function} callback async callback
 * @return {Function}            callback(err,results)
 */
Extensions.prototype.uninstall = function (options, callback) {
	// console.log('process.env',process.env);
	var dirname = options.dirname || extensionDirName,
		packagejsonFileJSON = fs.readJSONSync(path.resolve(dirname, './package.json')),
		extname = options.extname || packagejsonFileJSON.name,
		extpublicdir = (options.removepublicdir) ? path.resolve(__dirname, '../../public/extensions/', extname) : null,
		extconfigdir = (options.removeconfigdir) ? path.resolve(__dirname, '../../content/config/extensions/', extname) : null,
		extensionFileJson = fs.readJSONSync(extensionFilePath);

	async.series({
		removeExtPublicDirectory: function (callback) {
			this.removePublicFiles({
				publicdir: extpublicdir
			}, callback);
		}.bind(this),
		removeExtConfigDirectory: function (callback) {
			this.removeConfigFiles({
				configdir: extconfigdir
			}, callback);
		}.bind(this),
		removeExtFromPeriodicConf: function (callback) {
			this.removeExtFromConf({
				extname: extname,
				currentExtensionsConfJson: extensionFileJson
			}, callback);
		}.bind(this)
	}, function (err, results) {
		if (err) {
			callback(err, null);
		}
		else {
			callback(null, results);
		}
	}.bind(this));
};

module.exports = Extensions;