diff --git a/src/node/utils/AbsolutePaths.js b/src/node/utils/AbsolutePaths.js index 2736599b6..3a7e60f0d 100644 --- a/src/node/utils/AbsolutePaths.js +++ b/src/node/utils/AbsolutePaths.js @@ -19,10 +19,17 @@ */ var log4js = require('log4js'); +var path = require('path'); var _ = require('underscore'); var absPathLogger = log4js.getLogger('AbsolutePaths'); +/* + * findEtherpadRoot() computes its value only on first invocation. + * Subsequent invocations are served from this variable. + */ +var etherpadRoot = null; + /** * If stringArray's last elements are exactly equal to lastDesiredElements, * returns a copy in which those last elements are popped, or false otherwise. @@ -49,3 +56,61 @@ var popIfEndsWith = function(stringArray, lastDesiredElements) { absPathLogger.debug(`${stringArray.join(path.sep)} does not end with "${lastDesiredElements.join(path.sep)}"`); return false; }; + +/** + * Heuristically computes the directory in which Etherpad is installed. + * + * All the relative paths have to be interpreted against this absolute base + * path. Since the Unix and Windows install have a different layout on disk, + * they are treated as two special cases. + * + * The path is computed only on first invocation. Subsequent invocations return + * a cached value. + * + * The cached value is stored in AbsolutePaths.etherpadRoot via a side effect. + * + * @return {string} The identified absolute base path. If such path cannot be + * identified, prints a log and exits the application. + */ +exports.findEtherpadRoot = function() { + if (etherpadRoot !== null) { + return etherpadRoot; + } + + const findRoot = require('find-root'); + const foundRoot = findRoot(__dirname); + + var directoriesToStrip; + if (process.platform === 'win32') { + /* + * Given the structure of our Windows package, foundRoot's value + * will be the following on win32: + * + * \node_modules\ep_etherpad-lite + */ + directoriesToStrip = ['node_modules', 'ep_etherpad-lite']; + } else { + /* + * On Unix platforms, foundRoot's value will be: + * + * \src + */ + directoriesToStrip = ['src']; + } + + const maybeEtherpadRoot = popIfEndsWith(foundRoot.split(path.sep), directoriesToStrip); + if (maybeEtherpadRoot === false) { + absPathLogger.error(`Could not identity Etherpad base path in this ${process.platform} installation in "${foundRoot}"`); + process.exit(1); + } + + // SIDE EFFECT on this module-level variable + etherpadRoot = maybeEtherpadRoot.join(path.sep); + + if (path.isAbsolute(etherpadRoot)) { + return etherpadRoot; + } + + absPathLogger.error(`To run, Etherpad has to identify an absolute base path. This is not: "${etherpadRoot}"`); + process.exit(1); +}; diff --git a/src/package.json b/src/package.json index b6df2acb3..bbb069201 100644 --- a/src/package.json +++ b/src/package.json @@ -38,6 +38,7 @@ "etherpad-yajsml": "0.0.2", "express": "4.16.3", "express-session": "1.15.6", + "find-root": "1.1.0", "formidable": "1.2.1", "graceful-fs": "4.1.3", "jsonminify": "0.4.1",