Compare commits
9 Commits
Author | SHA1 | Date |
---|---|---|
John McLear | 7d96ea1e32 | |
John McLear | bc72cbe88a | |
John McLear | 80e0e2d932 | |
John McLear | 3e78be371d | |
Hossein M | b18a0e48da | |
John McLear | 698a76a1c8 | |
John McLear | 450608374a | |
John McLear | 43490df113 | |
John McLear | f6661d41be |
|
@ -13,7 +13,7 @@ Etherpad is a real-time collaborative editor [scalable to thousands of simultane
|
|||
# Installation
|
||||
|
||||
## Requirements
|
||||
- `nodejs` >= **10.13.0**.
|
||||
- `nodejs` >= **10.17.0**.
|
||||
|
||||
## GNU/Linux and other UNIX-like systems
|
||||
|
||||
|
@ -25,7 +25,7 @@ git clone --branch master https://github.com/ether/etherpad-lite.git && cd ether
|
|||
```
|
||||
|
||||
### Manual install
|
||||
You'll need git and [node.js](https://nodejs.org) installed (minimum required Node version: **10.13.0**).
|
||||
You'll need git and [node.js](https://nodejs.org) installed (minimum required Node version: **10.17.0**).
|
||||
|
||||
**As any user (we recommend creating a separate user called etherpad):**
|
||||
|
||||
|
|
|
@ -263,7 +263,7 @@ fs.readdir(pluginPath, (err, rootFiles) => {
|
|||
console.warn('No engines or node engine in package.json');
|
||||
if (autoFix) {
|
||||
const engines = {
|
||||
node: '>=10.13.0',
|
||||
node: '^10.17.0 || >=11.14.0',
|
||||
};
|
||||
parsedPackageJSON.engines = engines;
|
||||
writePackageJson(parsedPackageJSON);
|
||||
|
|
|
@ -225,7 +225,7 @@ publish your plugin.
|
|||
"author": "USERNAME (REAL NAME) <MAIL@EXAMPLE.COM>",
|
||||
"contributors": [],
|
||||
"dependencies": {"MODULE": "0.3.20"},
|
||||
"engines": { "node": ">= 10.13.0"}
|
||||
"engines": { "node": "^10.17.0 || >=11.14.0"}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -100,6 +100,6 @@
|
|||
"lint": "eslint ."
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
"node": "^10.17.0 || >=11.14.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,8 +32,8 @@ log4js.replaceConsole();
|
|||
* any modules that require newer versions of NodeJS
|
||||
*/
|
||||
const NodeVersion = require('./utils/NodeVersion');
|
||||
NodeVersion.enforceMinNodeVersion('10.13.0');
|
||||
NodeVersion.checkDeprecationStatus('10.13.0', '1.8.3');
|
||||
NodeVersion.enforceMinNodeVersion('10.17.0');
|
||||
NodeVersion.checkDeprecationStatus('10.17.0', '1.8.3');
|
||||
|
||||
const UpdateCheck = require('./utils/UpdateCheck');
|
||||
const db = require('./db/DB');
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -140,7 +140,7 @@
|
|||
"root": true
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0",
|
||||
"node": "^10.17.0 || >=11.14.0",
|
||||
"npm": ">=5.5.1"
|
||||
},
|
||||
"repository": {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global exports, require */
|
||||
'use strict';
|
||||
|
||||
const _ = require('underscore');
|
||||
const pluginDefs = require('./plugin_defs');
|
||||
|
@ -15,30 +15,28 @@ exports.deprecationNotices = {};
|
|||
|
||||
const deprecationWarned = {};
|
||||
|
||||
function checkDeprecation(hook) {
|
||||
const checkDeprecation = (hook) => {
|
||||
const notice = exports.deprecationNotices[hook.hook_name];
|
||||
if (notice == null) return;
|
||||
if (deprecationWarned[hook.hook_fn_name]) return;
|
||||
console.warn(`${hook.hook_name} hook used by the ${hook.part.plugin} plugin ` +
|
||||
`(${hook.hook_fn_name}) is deprecated: ${notice}`);
|
||||
deprecationWarned[hook.hook_fn_name] = true;
|
||||
}
|
||||
};
|
||||
|
||||
exports.bubbleExceptions = true;
|
||||
|
||||
const hookCallWrapper = function (hook, hook_name, args, cb) {
|
||||
if (cb === undefined) cb = function (x) { return x; };
|
||||
const hookCallWrapper = (hook, hook_name, args, cb) => {
|
||||
if (cb === undefined) cb = (x) => x;
|
||||
|
||||
checkDeprecation(hook);
|
||||
|
||||
// Normalize output to list for both sync and async cases
|
||||
const normalize = function (x) {
|
||||
const normalize = (x) => {
|
||||
if (x === undefined) return [];
|
||||
return x;
|
||||
};
|
||||
const normalizedhook = function () {
|
||||
return normalize(hook.hook_fn(hook_name, args, (x) => cb(normalize(x))));
|
||||
};
|
||||
const normalizedhook = () => normalize(hook.hook_fn(hook_name, args, (x) => cb(normalize(x))));
|
||||
|
||||
if (exports.bubbleExceptions) {
|
||||
return normalizedhook();
|
||||
|
@ -51,7 +49,7 @@ const hookCallWrapper = function (hook, hook_name, args, cb) {
|
|||
}
|
||||
};
|
||||
|
||||
exports.syncMapFirst = function (lst, fn) {
|
||||
exports.syncMapFirst = (lst, fn) => {
|
||||
let i;
|
||||
let result;
|
||||
for (i = 0; i < lst.length; i++) {
|
||||
|
@ -61,11 +59,11 @@ exports.syncMapFirst = function (lst, fn) {
|
|||
return [];
|
||||
};
|
||||
|
||||
exports.mapFirst = function (lst, fn, cb, predicate) {
|
||||
exports.mapFirst = (lst, fn, cb, predicate) => {
|
||||
if (predicate == null) predicate = (x) => (x != null && x.length > 0);
|
||||
let i = 0;
|
||||
|
||||
var next = function () {
|
||||
const next = () => {
|
||||
if (i >= lst.length) return cb(null, []);
|
||||
fn(lst[i++], (err, result) => {
|
||||
if (err) return cb(err);
|
||||
|
@ -104,7 +102,7 @@ exports.mapFirst = function (lst, fn, cb, predicate) {
|
|||
//
|
||||
// See the tests in tests/backend/specs/hooks.js for examples of supported and prohibited behaviors.
|
||||
//
|
||||
function callHookFnSync(hook, context) {
|
||||
const callHookFnSync = (hook, context) => {
|
||||
checkDeprecation(hook);
|
||||
|
||||
// This var is used to keep track of whether the hook function already settled.
|
||||
|
@ -190,7 +188,7 @@ function callHookFnSync(hook, context) {
|
|||
|
||||
settle(null, val, 'returned value');
|
||||
return outcome.val;
|
||||
}
|
||||
};
|
||||
|
||||
// Invokes all registered hook functions synchronously.
|
||||
//
|
||||
|
@ -203,7 +201,7 @@ function callHookFnSync(hook, context) {
|
|||
// 1. Collect all values returned by the hook functions into an array.
|
||||
// 2. Convert each `undefined` entry into `[]`.
|
||||
// 3. Flatten one level.
|
||||
exports.callAll = function (hookName, context) {
|
||||
exports.callAll = (hookName, context) => {
|
||||
if (context == null) context = {};
|
||||
const hooks = pluginDefs.hooks[hookName] || [];
|
||||
return _.flatten(hooks.map((hook) => {
|
||||
|
@ -248,7 +246,7 @@ exports.callAll = function (hookName, context) {
|
|||
//
|
||||
// See the tests in tests/backend/specs/hooks.js for examples of supported and prohibited behaviors.
|
||||
//
|
||||
async function callHookFnAsync(hook, context) {
|
||||
const callHookFnAsync = async (hook, context) => {
|
||||
checkDeprecation(hook);
|
||||
return await new Promise((resolve, reject) => {
|
||||
// This var is used to keep track of whether the hook function already settled.
|
||||
|
@ -326,7 +324,7 @@ async function callHookFnAsync(hook, context) {
|
|||
(val) => settle(null, val, 'returned value'),
|
||||
(err) => settle(err, null, 'Promise rejection'));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Invokes all registered hook functions asynchronously.
|
||||
//
|
||||
|
@ -350,20 +348,22 @@ exports.aCallAll = async (hookName, context, cb) => {
|
|||
const hooks = pluginDefs.hooks[hookName] || [];
|
||||
let resultsPromise = Promise.all(hooks.map((hook) => callHookFnAsync(hook, context)
|
||||
// `undefined` (but not `null`!) is treated the same as [].
|
||||
.then((result) => (result === undefined) ? [] : result))).then((results) => _.flatten(results, 1));
|
||||
.then((result) => (result === undefined) ? [] : result)))
|
||||
.then((results) => _.flatten(results, 1));
|
||||
if (cb != null) resultsPromise = resultsPromise.then((val) => cb(null, val), cb);
|
||||
return await resultsPromise;
|
||||
};
|
||||
|
||||
exports.callFirst = function (hook_name, args) {
|
||||
exports.callFirst = (hook_name, args) => {
|
||||
if (!args) args = {};
|
||||
if (pluginDefs.hooks[hook_name] === undefined) return [];
|
||||
return exports.syncMapFirst(pluginDefs.hooks[hook_name], (hook) => hookCallWrapper(hook, hook_name, args));
|
||||
return exports.syncMapFirst(pluginDefs.hooks[hook_name],
|
||||
(hook) => hookCallWrapper(hook, hook_name, args));
|
||||
};
|
||||
|
||||
function aCallFirst(hook_name, args, cb, predicate) {
|
||||
const aCallFirst = (hook_name, args, cb, predicate) => {
|
||||
if (!args) args = {};
|
||||
if (!cb) cb = function () {};
|
||||
if (!cb) cb = () => {};
|
||||
if (pluginDefs.hooks[hook_name] === undefined) return cb(null, []);
|
||||
exports.mapFirst(
|
||||
pluginDefs.hooks[hook_name],
|
||||
|
@ -373,10 +373,10 @@ function aCallFirst(hook_name, args, cb, predicate) {
|
|||
cb,
|
||||
predicate
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/* return a Promise if cb is not supplied */
|
||||
exports.aCallFirst = function (hook_name, args, cb, predicate) {
|
||||
exports.aCallFirst = (hook_name, args, cb, predicate) => {
|
||||
if (cb === undefined) {
|
||||
return new Promise((resolve, reject) => {
|
||||
aCallFirst(hook_name, args, (err, res) => err ? reject(err) : resolve(res), predicate);
|
||||
|
@ -386,10 +386,10 @@ exports.aCallFirst = function (hook_name, args, cb, predicate) {
|
|||
}
|
||||
};
|
||||
|
||||
exports.callAllStr = function (hook_name, args, sep, pre, post) {
|
||||
if (sep == undefined) sep = '';
|
||||
if (pre == undefined) pre = '';
|
||||
if (post == undefined) post = '';
|
||||
exports.callAllStr = (hook_name, args, sep, pre, post) => {
|
||||
if (sep === undefined) sep = '';
|
||||
if (pre === undefined) pre = '';
|
||||
if (post === undefined) post = '';
|
||||
const newCallhooks = [];
|
||||
const callhooks = exports.callAll(hook_name, args);
|
||||
for (let i = 0, ii = callhooks.length; i < ii; i++) {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
const log4js = require('log4js');
|
||||
const plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins');
|
||||
const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
|
||||
const plugins = require('./plugins');
|
||||
const hooks = require('./hooks');
|
||||
const npm = require('npm');
|
||||
const request = require('request');
|
||||
const util = require('util');
|
||||
|
@ -13,22 +15,22 @@ const loadNpm = async () => {
|
|||
npm.on('log', log4js.getLogger('npm').log);
|
||||
};
|
||||
|
||||
const onAllTasksFinished = () => {
|
||||
hooks.aCallAll('restartServer', {}, () => {});
|
||||
};
|
||||
|
||||
let tasks = 0;
|
||||
|
||||
function wrapTaskCb(cb) {
|
||||
tasks++;
|
||||
|
||||
return function () {
|
||||
cb && cb.apply(this, arguments);
|
||||
return function (...args) {
|
||||
cb && cb.apply(this, args);
|
||||
tasks--;
|
||||
if (tasks == 0) onAllTasksFinished();
|
||||
if (tasks === 0) onAllTasksFinished();
|
||||
};
|
||||
}
|
||||
|
||||
function onAllTasksFinished() {
|
||||
hooks.aCallAll('restartServer', {}, () => {});
|
||||
}
|
||||
|
||||
exports.uninstall = async (pluginName, cb = null) => {
|
||||
cb = wrapTaskCb(cb);
|
||||
try {
|
||||
|
@ -60,7 +62,7 @@ exports.install = async (pluginName, cb = null) => {
|
|||
exports.availablePlugins = null;
|
||||
let cacheTimestamp = 0;
|
||||
|
||||
exports.getAvailablePlugins = function (maxCacheAge) {
|
||||
exports.getAvailablePlugins = (maxCacheAge) => {
|
||||
const nowTimestamp = Math.round(Date.now() / 1000);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -87,31 +89,33 @@ exports.getAvailablePlugins = function (maxCacheAge) {
|
|||
};
|
||||
|
||||
|
||||
exports.search = function (searchTerm, maxCacheAge) {
|
||||
return exports.getAvailablePlugins(maxCacheAge).then((results) => {
|
||||
const res = {};
|
||||
exports.search = (searchTerm, maxCacheAge) => exports.getAvailablePlugins(maxCacheAge).then(
|
||||
(results) => {
|
||||
const res = {};
|
||||
|
||||
if (searchTerm) {
|
||||
searchTerm = searchTerm.toLowerCase();
|
||||
}
|
||||
|
||||
for (const pluginName in results) {
|
||||
// for every available plugin
|
||||
if (pluginName.indexOf(plugins.prefix) != 0) continue; // TODO: Also search in keywords here!
|
||||
|
||||
if (searchTerm && !~results[pluginName].name.toLowerCase().indexOf(searchTerm) &&
|
||||
(typeof results[pluginName].description !== 'undefined' && !~results[pluginName].description.toLowerCase().indexOf(searchTerm))
|
||||
) {
|
||||
if (typeof results[pluginName].description === 'undefined') {
|
||||
console.debug('plugin without Description: %s', results[pluginName].name);
|
||||
}
|
||||
|
||||
continue;
|
||||
if (searchTerm) {
|
||||
searchTerm = searchTerm.toLowerCase();
|
||||
}
|
||||
|
||||
res[pluginName] = results[pluginName];
|
||||
}
|
||||
for (const pluginName in results) {
|
||||
// for every available plugin
|
||||
// TODO: Also search in keywords here!
|
||||
if (pluginName.indexOf(plugins.prefix) !== 0) continue;
|
||||
|
||||
return res;
|
||||
});
|
||||
};
|
||||
if (searchTerm && !~results[pluginName].name.toLowerCase().indexOf(searchTerm) &&
|
||||
(typeof results[pluginName].description !== 'undefined' &&
|
||||
!~results[pluginName].description.toLowerCase().indexOf(searchTerm))
|
||||
) {
|
||||
if (typeof results[pluginName].description === 'undefined') {
|
||||
console.debug('plugin without Description: %s', results[pluginName].name);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
res[pluginName] = results[pluginName];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
// This module contains processed plugin definitions. The data structures in this file are set by
|
||||
// plugins.js (server) or client_plugins.js (client).
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const fs = require('fs').promises;
|
||||
const hooks = require('./hooks');
|
||||
const npm = require('npm/lib/npm.js');
|
||||
const readInstalled = require('./read-installed.js');
|
||||
const path = require('path');
|
||||
const tsort = require('./tsort');
|
||||
|
@ -13,11 +14,9 @@ const defs = require('./plugin_defs');
|
|||
|
||||
exports.prefix = 'ep_';
|
||||
|
||||
exports.formatPlugins = function () {
|
||||
return _.keys(defs.plugins).join(', ');
|
||||
};
|
||||
exports.formatPlugins = () => Object.keys(defs.plugins).join(', ');
|
||||
|
||||
exports.formatPluginsWithVersion = function () {
|
||||
exports.formatPluginsWithVersion = () => {
|
||||
const plugins = [];
|
||||
_.forEach(defs.plugins, (plugin) => {
|
||||
if (plugin.package.name !== 'ep_etherpad-lite') {
|
||||
|
@ -28,17 +27,17 @@ exports.formatPluginsWithVersion = function () {
|
|||
return plugins.join(', ');
|
||||
};
|
||||
|
||||
exports.formatParts = function () {
|
||||
return _.map(defs.parts, (part) => part.full_name).join('\n');
|
||||
};
|
||||
exports.formatParts = () => _.map(defs.parts, (part) => part.full_name).join('\n');
|
||||
|
||||
exports.formatHooks = function (hook_set_name) {
|
||||
exports.formatHooks = (hook_set_name) => {
|
||||
const res = [];
|
||||
const hooks = pluginUtils.extractHooks(defs.parts, hook_set_name || 'hooks');
|
||||
|
||||
_.chain(hooks).keys().forEach((hook_name) => {
|
||||
_.forEach(hooks[hook_name], (hook) => {
|
||||
res.push(`<dt>${hook.hook_name}</dt><dd>${hook.hook_fn_name} from ${hook.part.full_name}</dd>`);
|
||||
res.push(`<dt>${hook.hook_name}</dt>
|
||||
<dd>${hook.hook_fn_name} from ${hook.part.full_name}</dd>
|
||||
`);
|
||||
});
|
||||
});
|
||||
return `<dl>${res.join('\n')}</dl>`;
|
||||
|
@ -57,7 +56,7 @@ const callInit = async () => {
|
|||
}));
|
||||
};
|
||||
|
||||
exports.pathNormalization = function (part, hook_fn_name, hook_name) {
|
||||
exports.pathNormalization = (part, hook_fn_name, hook_name) => {
|
||||
const tmp = hook_fn_name.split(':'); // hook_fn_name might be something like 'C:\\foo.js:myFunc'.
|
||||
// If there is a single colon assume it's 'filename:funcname' not 'C:\\filename'.
|
||||
const functionName = (tmp.length > 1 ? tmp.pop() : null) || hook_name;
|
||||
|
@ -67,7 +66,7 @@ exports.pathNormalization = function (part, hook_fn_name, hook_name) {
|
|||
return `${fileName}:${functionName}`;
|
||||
};
|
||||
|
||||
exports.update = async function () {
|
||||
exports.update = async () => {
|
||||
const packages = await exports.getPackages();
|
||||
const parts = {}; // Key is full name. sortParts converts this into a topologically sorted array.
|
||||
const plugins = {};
|
||||
|
@ -83,13 +82,14 @@ exports.update = async function () {
|
|||
await callInit();
|
||||
};
|
||||
|
||||
exports.getPackages = async function () {
|
||||
// Load list of installed NPM packages, flatten it to a list, and filter out only packages with names that
|
||||
exports.getPackages = async () => {
|
||||
// Load list of installed NPM packages, flatten it to a list
|
||||
// and filter out only packages with names that
|
||||
const dir = settings.root;
|
||||
const data = await util.promisify(readInstalled)(dir);
|
||||
|
||||
const packages = {};
|
||||
function flatten(deps) {
|
||||
const flatten = (deps) => {
|
||||
_.chain(deps).keys().each((name) => {
|
||||
if (name.indexOf(exports.prefix) === 0) {
|
||||
packages[name] = _.clone(deps[name]);
|
||||
|
@ -102,7 +102,7 @@ exports.getPackages = async function () {
|
|||
// I don't think we need recursion
|
||||
// if (deps[name].dependencies !== undefined) flatten(deps[name].dependencies);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const tmp = {};
|
||||
tmp[data.name] = data;
|
||||
|
@ -110,7 +110,7 @@ exports.getPackages = async function () {
|
|||
return packages;
|
||||
};
|
||||
|
||||
async function loadPlugin(packages, plugin_name, plugins, parts) {
|
||||
const loadPlugin = async (packages, plugin_name, plugins, parts) => {
|
||||
const plugin_path = path.resolve(packages[plugin_name].path, 'ep.json');
|
||||
try {
|
||||
const data = await fs.readFile(plugin_path);
|
||||
|
@ -129,9 +129,9 @@ async function loadPlugin(packages, plugin_name, plugins, parts) {
|
|||
} catch (er) {
|
||||
console.error(`Unable to load plugin definition file ${plugin_path}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function partsToParentChildList(parts) {
|
||||
const partsToParentChildList = (parts) => {
|
||||
const res = [];
|
||||
_.chain(parts).keys().forEach((name) => {
|
||||
_.each(parts[name].post || [], (child_name) => {
|
||||
|
@ -145,15 +145,13 @@ function partsToParentChildList(parts) {
|
|||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
// Used only in Node, so no need for _
|
||||
function sortParts(parts) {
|
||||
return tsort(
|
||||
partsToParentChildList(parts)
|
||||
).filter(
|
||||
(name) => parts[name] !== undefined
|
||||
).map(
|
||||
(name) => parts[name]
|
||||
);
|
||||
}
|
||||
const sortParts = (parts) => tsort(
|
||||
partsToParentChildList(parts)
|
||||
).filter(
|
||||
(name) => parts[name] !== undefined
|
||||
).map(
|
||||
(name) => parts[name]
|
||||
);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
'use strict';
|
||||
// A copy of npm/lib/utils/read-installed.js
|
||||
// that is hacked to not cache everything :)
|
||||
|
||||
|
@ -89,14 +90,13 @@ as far as the left-most node_modules folder.
|
|||
*/
|
||||
|
||||
|
||||
const npm = require('npm/lib/npm.js');
|
||||
const fs = require('graceful-fs');
|
||||
const path = require('path');
|
||||
const asyncMap = require('slide').asyncMap;
|
||||
const semver = require('semver');
|
||||
const log = require('log4js').getLogger('pluginfw');
|
||||
|
||||
function readJson(file, callback) {
|
||||
const readJson = (file, callback) => {
|
||||
fs.readFile(file, (er, buf) => {
|
||||
if (er) {
|
||||
callback(er);
|
||||
|
@ -108,31 +108,27 @@ function readJson(file, callback) {
|
|||
callback(er);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = readInstalled;
|
||||
|
||||
function readInstalled(folder, cb) {
|
||||
const readInstalled = (folder, cb) => {
|
||||
/* This is where we clear the cache, these three lines are all the
|
||||
* new code there is */
|
||||
rpSeen = {};
|
||||
riSeen = [];
|
||||
const fuSeen = [];
|
||||
|
||||
const d = npm.config.get('depth');
|
||||
readInstalled_(folder, null, null, null, 0, d, (er, obj) => {
|
||||
const depth = 1;
|
||||
readInstalled_(folder, null, null, null, 0, depth, (er, obj) => {
|
||||
if (er) return cb(er);
|
||||
// now obj has all the installed things, where they're installed
|
||||
// figure out the inheritance links, now that the object is built.
|
||||
resolveInheritance(obj);
|
||||
cb(null, obj);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var rpSeen = {};
|
||||
function readInstalled_(folder, parent, name, reqver, depth, maxDepth, cb) {
|
||||
// console.error(folder, name)
|
||||
module.exports = readInstalled;
|
||||
|
||||
let rpSeen = {};
|
||||
const readInstalled_ = (folder, parent, name, reqver, depth, maxDepth, cb) => {
|
||||
let installed,
|
||||
obj,
|
||||
real,
|
||||
|
@ -170,7 +166,7 @@ function readInstalled_(folder, parent, name, reqver, depth, maxDepth, cb) {
|
|||
|
||||
let errState = null;
|
||||
let called = false;
|
||||
function next(er) {
|
||||
const next = (er) => {
|
||||
if (errState) return;
|
||||
if (er) {
|
||||
errState = er;
|
||||
|
@ -230,12 +226,12 @@ function readInstalled_(folder, parent, name, reqver, depth, maxDepth, cb) {
|
|||
}
|
||||
return cb(null, obj);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// starting from a root object, call findUnmet on each layer of children
|
||||
var riSeen = [];
|
||||
function resolveInheritance(obj) {
|
||||
let riSeen = [];
|
||||
const resolveInheritance = (obj) => {
|
||||
if (typeof obj !== 'object') return;
|
||||
if (riSeen.indexOf(obj) !== -1) return;
|
||||
riSeen.push(obj);
|
||||
|
@ -248,12 +244,13 @@ function resolveInheritance(obj) {
|
|||
Object.keys(obj.dependencies).forEach((dep) => {
|
||||
resolveInheritance(obj.dependencies[dep]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// find unmet deps by walking up the tree object.
|
||||
// No I/O
|
||||
const fuSeen = [];
|
||||
function findUnmet(obj) {
|
||||
const findUnmet = (obj) => {
|
||||
if (typeof obj === 'string') return;
|
||||
if (fuSeen.indexOf(obj) !== -1) return;
|
||||
fuSeen.push(obj);
|
||||
// console.error("find unmet", obj.name, obj.parent && obj.parent.name)
|
||||
|
@ -281,59 +278,66 @@ function findUnmet(obj) {
|
|||
}' but will load\n${
|
||||
found.path},\nwhich is version ${found.version}`
|
||||
, 'unmet dependency');
|
||||
found = {};
|
||||
found.invalid = true;
|
||||
}
|
||||
deps[d] = found;
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
function copy(obj) {
|
||||
const copy = (obj) => {
|
||||
if (!obj || typeof obj !== 'object') return obj;
|
||||
if (Array.isArray(obj)) return obj.map(copy);
|
||||
|
||||
const o = {};
|
||||
for (const i in obj) o[i] = copy(obj[i]);
|
||||
for (const i in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, i)) {
|
||||
o[i] = copy(obj[i]);
|
||||
}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
if (module === require.main) {
|
||||
const util = require('util');
|
||||
console.error('testing');
|
||||
|
||||
let called = 0;
|
||||
|
||||
readInstalled(process.cwd(), (er, map) => {
|
||||
console.error(called++);
|
||||
if (er) return console.error(er.stack || er.message);
|
||||
cleanup(map);
|
||||
console.error(util.inspect(map, true, 10, true));
|
||||
});
|
||||
|
||||
const seen = [];
|
||||
function cleanup(map) {
|
||||
const cleanup = (map) => {
|
||||
if (seen.indexOf(map) !== -1) return;
|
||||
seen.push(map);
|
||||
for (var i in map) {
|
||||
switch (i) {
|
||||
case '_id':
|
||||
case 'path':
|
||||
case 'extraneous': case 'invalid':
|
||||
case 'dependencies': case 'name':
|
||||
continue;
|
||||
default: delete map[i];
|
||||
for (const i in map) {
|
||||
if (Object.prototype.hasOwnProperty.call(map, i)) {
|
||||
switch (i) {
|
||||
case '_id':
|
||||
case 'path':
|
||||
case 'extraneous': case 'invalid':
|
||||
case 'dependencies': case 'name':
|
||||
continue;
|
||||
default: delete map[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
const dep = map.dependencies;
|
||||
// delete map.dependencies
|
||||
if (dep) {
|
||||
// map.dependencies = dep
|
||||
for (var i in dep) {
|
||||
if (typeof dep[i] === 'object') {
|
||||
cleanup(dep[i]);
|
||||
for (const j in dep) {
|
||||
if (typeof dep[j] === 'object') {
|
||||
cleanup(dep[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
'use strict';
|
||||
const _ = require('underscore');
|
||||
const defs = require('./plugin_defs');
|
||||
|
||||
|
@ -8,13 +9,13 @@ const disabledHookReasons = {
|
|||
},
|
||||
};
|
||||
|
||||
function loadFn(path, hookName) {
|
||||
const loadFn = (path, hookName) => {
|
||||
let functionName;
|
||||
const parts = path.split(':');
|
||||
|
||||
// on windows: C:\foo\bar:xyz
|
||||
if (parts[0].length == 1) {
|
||||
if (parts.length == 3) {
|
||||
if (parts[0].length === 1) {
|
||||
if (parts.length === 3) {
|
||||
functionName = parts.pop();
|
||||
}
|
||||
path = parts.join(':');
|
||||
|
@ -30,9 +31,9 @@ function loadFn(path, hookName) {
|
|||
fn = fn[name];
|
||||
});
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
|
||||
function extractHooks(parts, hook_set_name, normalizer) {
|
||||
const extractHooks = (parts, hook_set_name, normalizer) => {
|
||||
const hooks = {};
|
||||
_.each(parts, (part) => {
|
||||
_.chain(part[hook_set_name] || {})
|
||||
|
@ -50,20 +51,23 @@ function extractHooks(parts, hook_set_name, normalizer) {
|
|||
|
||||
const disabledReason = (disabledHookReasons[hook_set_name] || {})[hook_name];
|
||||
if (disabledReason) {
|
||||
console.error(`Hook ${hook_set_name}/${hook_name} is disabled. Reason: ${disabledReason}`);
|
||||
console.error(`Hook ${hook_set_name}/${hook_name} is disabled.
|
||||
Reason: ${disabledReason}`);
|
||||
console.error(`The hook function ${hook_fn_name} from plugin ${part.plugin} ` +
|
||||
'will never be called, which may cause the plugin to fail');
|
||||
console.error(`Please update the ${part.plugin} plugin to not use the ${hook_name} hook`);
|
||||
console.error(`Please update the ${part.plugin} plugin to not
|
||||
use the ${hook_name} hook`);
|
||||
return;
|
||||
}
|
||||
|
||||
let hook_fn;
|
||||
try {
|
||||
var hook_fn = loadFn(hook_fn_name, hook_name);
|
||||
hook_fn = loadFn(hook_fn_name, hook_name);
|
||||
if (!hook_fn) {
|
||||
throw 'Not a function';
|
||||
throw new Error('Not a function');
|
||||
}
|
||||
} catch (exc) {
|
||||
console.error(`Failed to load '${hook_fn_name}' for '${part.full_name}/${hook_set_name}/${hook_name}': ${exc.toString()}`);
|
||||
console.error(`Failed to load '${hook_fn_name}' for
|
||||
'${part.full_name}/${hook_set_name}/${hook_name}': ${exc.toString()}`);
|
||||
}
|
||||
if (hook_fn) {
|
||||
if (hooks[hook_name] == null) hooks[hook_name] = [];
|
||||
|
@ -72,7 +76,7 @@ function extractHooks(parts, hook_set_name, normalizer) {
|
|||
});
|
||||
});
|
||||
return hooks;
|
||||
}
|
||||
};
|
||||
|
||||
exports.extractHooks = extractHooks;
|
||||
|
||||
|
@ -88,10 +92,10 @@ exports.extractHooks = extractHooks;
|
|||
* No plugins: []
|
||||
* Some plugins: [ 'ep_adminpads', 'ep_add_buttons', 'ep_activepads' ]
|
||||
*/
|
||||
exports.clientPluginNames = function () {
|
||||
exports.clientPluginNames = () => {
|
||||
const client_plugin_names = _.uniq(
|
||||
defs.parts
|
||||
.filter((part) => part.hasOwnProperty('client_hooks'))
|
||||
.filter((part) => Object.prototype.hasOwnProperty.call(part, 'client_hooks'))
|
||||
.map((part) => `plugin-${part.plugin}`)
|
||||
);
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ const tsort = (edges) => {
|
|||
Object.keys(nodes).forEach(visit);
|
||||
|
||||
return sorted;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* TEST
|
||||
|
|
Loading…
Reference in New Issue