diff --git a/js/server/modules/org/arangodb/actions.js b/js/server/modules/org/arangodb/actions.js index 4a9ff0ccea..7d6b905c8c 100644 --- a/js/server/modules/org/arangodb/actions.js +++ b/js/server/modules/org/arangodb/actions.js @@ -2144,10 +2144,18 @@ function stringifyRequestAddress (req) { return out; } +function setFoxxRouting(mount, routes) { + +} + // ----------------------------------------------------------------------------- // --SECTION-- MODULE EXPORTS // ----------------------------------------------------------------------------- +// Insert the routing information for one foxx application + +exports.setFoxxRouting = setFoxxRouting; + // load all actions from the actions directory exports.startup = startup; diff --git a/js/server/modules/org/arangodb/foxx/arangoApp.js b/js/server/modules/org/arangodb/foxx/arangoApp.js index 8e0d4768a3..67d79ec969 100644 --- a/js/server/modules/org/arangodb/foxx/arangoApp.js +++ b/js/server/modules/org/arangodb/foxx/arangoApp.js @@ -55,7 +55,6 @@ this.comments = []; this.name = app._name; this.version = app._version; - this.appId = app._id; this.mount = app._mount; this.collectionPrefix = app._collectionPrefix; this.options = app._options; @@ -108,7 +107,6 @@ //////////////////////////////////////////////////////////////////////////////// var ArangoApp = function (config) { - this._id = config.id; // ??? this._manifest = config.manifest; this._name = config.manifest.name; this._version = config.manifest.version; @@ -121,6 +119,10 @@ var ArangoApp = function (config) { this._exports = {}; this._collectionPrefix = this._mount.substr(1).replace(/-/g, "_").replace(/\//g, "_") + "_"; this._context = new AppContext(this); + + if (this._manifest.hasOwnProperty("defaultDocument")) { + this._manifest.defaultDocument = "index.html"; + } }; // ----------------------------------------------------------------------------- @@ -145,7 +147,6 @@ var ArangoApp = function (config) { ArangoApp.prototype.toJSON = function () { var json = { - id: this._id, manifest: this._manifest, name: this._name, version: this._version, diff --git a/js/server/modules/org/arangodb/foxx/controller.js b/js/server/modules/org/arangodb/foxx/controller.js index 123cbb7ff3..2d6645a114 100644 --- a/js/server/modules/org/arangodb/foxx/controller.js +++ b/js/server/modules/org/arangodb/foxx/controller.js @@ -101,7 +101,6 @@ Controller = function (context, options) { options: { name: context.name, version: context.version, - appId: context.appId, mount: context.mount, isDevelopment: context.isDevelopment, isProduction: context.isProduction, diff --git a/js/server/modules/org/arangodb/foxx/manager.js b/js/server/modules/org/arangodb/foxx/manager.js index 154832cdf8..8c787a770d 100644 --- a/js/server/modules/org/arangodb/foxx/manager.js +++ b/js/server/modules/org/arangodb/foxx/manager.js @@ -32,13 +32,13 @@ (function() { "use strict"; -// ----------------------------------------------------------------------------- -// --CHAPTER-- used code -// ----------------------------------------------------------------------------- + // ----------------------------------------------------------------------------- + // --CHAPTER-- used code + // ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- -// --SECTION-- imports -// ----------------------------------------------------------------------------- + // ----------------------------------------------------------------------------- + // --SECTION-- imports + // ----------------------------------------------------------------------------- var fs = require("fs"); var utils = require("org/arangodb/foxx/manager-utils"); @@ -55,223 +55,223 @@ var throwDownloadError = arangodb.throwDownloadError; var throwFileNotFound = arangodb.throwFileNotFound; -// ----------------------------------------------------------------------------- -// --SECTION-- private variables -// ----------------------------------------------------------------------------- + // ----------------------------------------------------------------------------- + // --SECTION-- private variables + // ----------------------------------------------------------------------------- -var appCache = {}; + var appCache = {}; -// ----------------------------------------------------------------------------- -// --SECTION-- private functions -// ----------------------------------------------------------------------------- + // ----------------------------------------------------------------------------- + // --SECTION-- private functions + // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @brief lookup app in cache -/// Returns either the app or undefined if it is not cached. -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /// @brief lookup app in cache + /// Returns either the app or undefined if it is not cached. + //////////////////////////////////////////////////////////////////////////////// -var lookupApp = function(mount) { - if (!appCache.hasOwnProperty(mount)) { - throw "App not found"; - } - return appCache[mount]; -}; - - -//////////////////////////////////////////////////////////////////////////////// -/// @brief check a manifest for completeness -/// -/// this implements issue #590: Manifest Lint -//////////////////////////////////////////////////////////////////////////////// - -var checkManifest = function(filename, mf) { - // add some default attributes - if (! mf.hasOwnProperty("author")) { - // add a default (empty) author - mf.author = ""; - } - - if (! mf.hasOwnProperty("description")) { - // add a default (empty) description - mf.description = ""; - } - - // Validate all attributes specified in the manifest - // the following attributes are allowed with these types... - var expected = { - "assets": [ false, "object" ], - "author": [ false, "string" ], - "configuration": [ false, "object" ], - "contributors": [ false, "array" ], - "controllers": [ false, "object" ], - "defaultDocument": [ false, "string" ], - "description": [ true, "string" ], - "engines": [ false, "object" ], - "files": [ false, "object" ], - "isSystem": [ false, "boolean" ], - "keywords": [ false, "array" ], - "lib": [ false, "string" ], - "license": [ false, "string" ], - "name": [ true, "string" ], - "repository": [ false, "object" ], - "setup": [ false, "string" ], - "teardown": [ false, "string" ], - "thumbnail": [ false, "string" ], - "version": [ true, "string" ], - "rootElement": [ false, "boolean" ], - "exports": [ false, "object" ] + var lookupApp = function(mount) { + if (!appCache.hasOwnProperty(mount)) { + throw "App not found"; + } + return appCache[mount]; }; - var att, failed = false; - var expectedType, actualType; - for (att in expected) { - if (expected.hasOwnProperty(att)) { + //////////////////////////////////////////////////////////////////////////////// + /// @brief check a manifest for completeness + /// + /// this implements issue #590: Manifest Lint + //////////////////////////////////////////////////////////////////////////////// + + var checkManifest = function(filename, mf) { + // add some default attributes + if (! mf.hasOwnProperty("author")) { + // add a default (empty) author + mf.author = ""; + } + + if (! mf.hasOwnProperty("description")) { + // add a default (empty) description + mf.description = ""; + } + + // Validate all attributes specified in the manifest + // the following attributes are allowed with these types... + var expected = { + "assets": [ false, "object" ], + "author": [ false, "string" ], + "configuration": [ false, "object" ], + "contributors": [ false, "array" ], + "controllers": [ false, "object" ], + "defaultDocument": [ false, "string" ], + "description": [ true, "string" ], + "engines": [ false, "object" ], + "files": [ false, "object" ], + "isSystem": [ false, "boolean" ], + "keywords": [ false, "array" ], + "lib": [ false, "string" ], + "license": [ false, "string" ], + "name": [ true, "string" ], + "repository": [ false, "object" ], + "setup": [ false, "string" ], + "teardown": [ false, "string" ], + "thumbnail": [ false, "string" ], + "version": [ true, "string" ], + "rootElement": [ false, "boolean" ], + "exports": [ false, "object" ] + }; + + var att, failed = false; + var expectedType, actualType; + + for (att in expected) { + if (expected.hasOwnProperty(att)) { + if (mf.hasOwnProperty(att)) { + // attribute is present in manifest, now check data type + expectedType = expected[att][1]; + actualType = Array.isArray(mf[att]) ? "array" : typeof(mf[att]); + + if (actualType !== expectedType) { + console.error("Manifest '%s' uses an invalid data type (%s) for %s attribute '%s'", + filename, + actualType, + expectedType, + att); + failed = true; + } + } + else { + // attribute not present in manifest + if (expected[att][0]) { + // required attribute + console.error("Manifest '%s' does not provide required attribute '%s'", + filename, + att); + + failed = true; + } + } + } + } + + if (failed) { + throw new ArangoError({ + errorNum: errors.ERROR_MANIFEST_FILE_ATTRIBUTE_MISSING.code, + errorMessage: errors.ERROR_MANIFEST_FILE_ATTRIBUTE_MISSING.message + }); + } + + // additionally check if there are superfluous attributes in the manifest + for (att in mf) { if (mf.hasOwnProperty(att)) { - // attribute is present in manifest, now check data type - expectedType = expected[att][1]; - actualType = Array.isArray(mf[att]) ? "array" : typeof(mf[att]); - - if (actualType !== expectedType) { - console.error("Manifest '%s' uses an invalid data type (%s) for %s attribute '%s'", - filename, - actualType, - expectedType, - att); - failed = true; - } - } - else { - // attribute not present in manifest - if (expected[att][0]) { - // required attribute - console.error("Manifest '%s' does not provide required attribute '%s'", - filename, - att); - - failed = true; + if (! expected.hasOwnProperty(att)) { + console.warn("Manifest '%s' contains an unknown attribute '%s'", + filename, + att); } } } - } + }; - if (failed) { - throw new ArangoError({ - errorNum: errors.ERROR_MANIFEST_FILE_ATTRIBUTE_MISSING.code, - errorMessage: errors.ERROR_MANIFEST_FILE_ATTRIBUTE_MISSING.message - }); - } - // additionally check if there are superfluous attributes in the manifest - for (att in mf) { - if (mf.hasOwnProperty(att)) { - if (! expected.hasOwnProperty(att)) { - console.warn("Manifest '%s' contains an unknown attribute '%s'", - filename, - att); - } + + //////////////////////////////////////////////////////////////////////////////// + /// @brief validates a manifest file and returns it. + /// All errors are handled including file not found. Returns undefined if manifest is invalid + //////////////////////////////////////////////////////////////////////////////// + + var validateManifestFile = function(file) { + var mf; + if (!fs.exists(file)) { + return; } - } -}; + try { + mf = JSON.parse(fs.read(file)); + } catch (err) { + console.errorLines( + "Cannot parse app manifest '%s': %s", file, String(err)); + return; + } + try { + checkManifest(file, mf); + } catch (err) { + console.errorLines( + "Manifest file '%s' invalid: %s", file, String(err)); + return; + } + return mf; + }; + //////////////////////////////////////////////////////////////////////////////// + /// @brief Checks if the mountpoint is reserved for system apps + //////////////////////////////////////////////////////////////////////////////// + var isSystemMount = function(mount) { + return (/^\/_/).test(mount); + }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief validates a manifest file and returns it. -/// All errors are handled including file not found. Returns undefined if manifest is invalid -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /// @brief returns the root path for application. Knows about system apps + //////////////////////////////////////////////////////////////////////////////// -var validateManifestFile = function(file) { - var mf; - if (!fs.exists(file)) { - return; - } - try { - mf = JSON.parse(fs.read(file)); - } catch (err) { - console.errorLines( - "Cannot parse app manifest '%s': %s", file, String(err)); - return; - } - try { - checkManifest(file, mf); - } catch (err) { - console.errorLines( - "Manifest file '%s' invalid: %s", file, String(err)); - return; - } - return mf; -}; + var computeRootAppPath = function(mount) { + if (isSystemMount(mount)) { + return module.systemAppPath(); + } + return module.appPath(); + }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief Checks if the mountpoint is reserved for system apps -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /// @brief transforms a mount point to a sub-path relative to root + //////////////////////////////////////////////////////////////////////////////// -var isSystemMount = function(mount) { - return (/^\/_/).test(mount); -}; + var transformMountToPath = function(mount) { + var list = mount.split("/"); + list.push("APP"); + return fs.join.apply(this, list); + }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns the root path for application. Knows about system apps -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /// @brief returns the application path for mount point + //////////////////////////////////////////////////////////////////////////////// -var computeRootAppPath = function(mount) { - if (isSystemMount(mount)) { - return module.systemAppPath(); - } - return module.appPath(); -}; + var computeAppPath = function(mount) { + var root = computeRootAppPath(mount); + var mountPath = transformMountToPath(mount); + return fs.join(root, mountPath); + }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief transforms a mount point to a sub-path relative to root -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /// @brief executes an app script + //////////////////////////////////////////////////////////////////////////////// -var transformMountToPath = function(mount) { - var list = mount.split("/"); - list.push("APP"); - return fs.join.apply(this, list); -}; + var executeAppScript = function(app, name) { + var desc = app._manifest; + if (desc.hasOwnProperty(name)) { + app.loadAppScript(desc[name]); + } + }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns the application path for mount point -//////////////////////////////////////////////////////////////////////////////// - -var computeAppPath = function(mount) { - var root = computeRootAppPath(mount); - var mountPath = transformMountToPath(mount); - return fs.join(root, mountPath); -}; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief executes an app script -//////////////////////////////////////////////////////////////////////////////// - -var executeAppScript = function(app, name) { - var desc = app._manifest; - if (desc.hasOwnProperty(name)) { - app.loadAppScript(desc[name]); - } -}; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief sets up an app -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /// @brief sets up an app + //////////////////////////////////////////////////////////////////////////////// var setupApp = function (app) { return executeAppScript(app, "setup"); }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief tears down an app -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /// @brief tears down an app + //////////////////////////////////////////////////////////////////////////////// var teardownApp = function (app) { return executeAppScript(app, "teardown"); }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns the app path and manifest -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /// @brief returns the app path and manifest + //////////////////////////////////////////////////////////////////////////////// var appConfig = function (mount, options) { @@ -299,386 +299,403 @@ var executeAppScript = function(app, name) { }; }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief Creates an app with options and returns it -/// All errors are handled including app not found. Returns undefined if app is invalid. -/// If the app is valid it will be added into the local app cache. -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /// @brief Creates an app with options and returns it + /// All errors are handled including app not found. Returns undefined if app is invalid. + /// If the app is valid it will be added into the local app cache. + //////////////////////////////////////////////////////////////////////////////// -var createApp = function(mount, options) { - var config = appConfig(mount); - config.options = options || {}; - var app = new ArangoApp(config); - if (app === null) { - console.errorLines( - "Cannot find application '%s'", mount); - return; - } - appCache[mount] = app; - return app; -}; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Extracts an app from zip and moves it to temporary path -/// -/// return path to app -//////////////////////////////////////////////////////////////////////////////// - -var extractAppToPath = function (archive, targetPath, noDelete) { - var tempFile = fs.getTempFile("zip", false); - fs.makeDirectory(tempFile); - fs.unzipFile(archive, tempFile, false, true); - - // ............................................................................. - // throw away source file - // ............................................................................. - if (!noDelete) { - try { - fs.remove(archive); + var createApp = function(mount, options) { + var config = appConfig(mount); + config.options = options || {}; + var app = new ArangoApp(config); + if (app === null) { + console.errorLines( + "Cannot find application '%s'", mount); + return; } - catch (err1) { - arangodb.printf("Cannot remove temporary file '%s'\n", archive); - } - } + appCache[mount] = app; + return app; + }; - // ............................................................................. - // locate the manifest file - // ............................................................................. + //////////////////////////////////////////////////////////////////////////////// + /// @brief Extracts an app from zip and moves it to temporary path + /// + /// return path to app + //////////////////////////////////////////////////////////////////////////////// - var tree = fs.listTree(tempFile).sort(function(a,b) { - return a.length - b.length; - }); - var found; - var mf = "manifest.json"; - var re = /[\/\\\\]manifest\.json$/; // Windows! - var tf; - var i; + var extractAppToPath = function (archive, targetPath, noDelete) { + var tempFile = fs.getTempFile("zip", false); + fs.makeDirectory(tempFile); + fs.unzipFile(archive, tempFile, false, true); - for (i = 0; i < tree.length && found === undefined; ++i) { - tf = tree[i]; - - if (re.test(tf) || tf === mf) { - found = tf; - } - } - - if (found === undefined) { - throwFileNotFound("Cannot find manifest file in zip file '" + tempFile + "'"); - } - - var mp; - - if (found === mf) { - mp = "."; - } - else { - mp = found.substr(0, found.length - mf.length - 1); - } - - fs.move(fs.join(tempFile, mp), targetPath); - - // ............................................................................. - // throw away temporary app folder - // ............................................................................. - try { - fs.removeDirectoryRecursive(tempFile); - } - catch (err1) { - arangodb.printf("Cannot remove temporary folder '%s'\n", tempFile); - } - -}; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief builds a github repository URL -//////////////////////////////////////////////////////////////////////////////// - -var buildGithubUrl = function (appInfo) { - var splitted = appInfo.split(":"); - var repository = splitted[1]; - var version = splitted[2]; - if (version === undefined) { - version = "master"; - } - return 'https://github.com/' + repository + '/archive/' + version + '.zip'; -}; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Downloads an app from remote zip file and copies it to mount path -//////////////////////////////////////////////////////////////////////////////// - -var installAppFromRemote = function(url, targetPath) { - var tempFile = fs.getTempFile("downloads", false); - - try { - var result = download(url, "", { - method: "get", - followRedirects: true, - timeout: 30 - }, tempFile); - - if (result.code < 200 || result.code > 299) { - throwDownloadError("Could not download from '" + url + "'"); - } - } - catch (err) { - throwDownloadError("Could not download from '" + url + "': " + String(err)); - } - extractAppToPath(tempFile, targetPath); -}; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Copies an app from local, either zip file or folder, to mount path -//////////////////////////////////////////////////////////////////////////////// - -var installAppFromLocal = function(path, targetPath) { - if (fs.isDirectory(path)) { - var tempFile = fs.getTempFile("downloads", false); - - var tree = fs.listTree(path); - var files = []; - var i; - var filename; - - for (i = 0; i < tree.length; ++i) { - filename = fs.join(path, tree[i]); - - if (fs.isFile(filename)) { - files.push(tree[i]); + // ............................................................................. + // throw away source file + // ............................................................................. + if (!noDelete) { + try { + fs.remove(archive); + } + catch (err1) { + arangodb.printf("Cannot remove temporary file '%s'\n", archive); } } - if (files.length === 0) { - throwFileNotFound("Directory '" + String(path) + "' is empty"); + // ............................................................................. + // locate the manifest file + // ............................................................................. + + var tree = fs.listTree(tempFile).sort(function(a,b) { + return a.length - b.length; + }); + var found; + var mf = "manifest.json"; + var re = /[\/\\\\]manifest\.json$/; // Windows! + var tf; + var i; + + for (i = 0; i < tree.length && found === undefined; ++i) { + tf = tree[i]; + + if (re.test(tf) || tf === mf) { + found = tf; + } + } + + if (found === undefined) { + throwFileNotFound("Cannot find manifest file in zip file '" + tempFile + "'"); + } + + var mp; + + if (found === mf) { + mp = "."; + } + else { + mp = found.substr(0, found.length - mf.length - 1); + } + + fs.move(fs.join(tempFile, mp), targetPath); + + // ............................................................................. + // throw away temporary app folder + // ............................................................................. + try { + fs.removeDirectoryRecursive(tempFile); + } + catch (err1) { + arangodb.printf("Cannot remove temporary folder '%s'\n", tempFile); + } + + }; + + //////////////////////////////////////////////////////////////////////////////// + /// @brief builds a github repository URL + //////////////////////////////////////////////////////////////////////////////// + + var buildGithubUrl = function (appInfo) { + var splitted = appInfo.split(":"); + var repository = splitted[1]; + var version = splitted[2]; + if (version === undefined) { + version = "master"; + } + return 'https://github.com/' + repository + '/archive/' + version + '.zip'; + }; + + //////////////////////////////////////////////////////////////////////////////// + /// @brief Downloads an app from remote zip file and copies it to mount path + //////////////////////////////////////////////////////////////////////////////// + + var installAppFromRemote = function(url, targetPath) { + var tempFile = fs.getTempFile("downloads", false); + + try { + var result = download(url, "", { + method: "get", + followRedirects: true, + timeout: 30 + }, tempFile); + + if (result.code < 200 || result.code > 299) { + throwDownloadError("Could not download from '" + url + "'"); + } + } + catch (err) { + throwDownloadError("Could not download from '" + url + "': " + String(err)); } - fs.zipFile(tempFile, path, files); extractAppToPath(tempFile, targetPath); - } else { - extractAppToPath(path, targetPath, true); - } -}; + }; -// ----------------------------------------------------------------------------- -// --SECTION-- public functions -// ----------------------------------------------------------------------------- + //////////////////////////////////////////////////////////////////////////////// + /// @brief Copies an app from local, either zip file or folder, to mount path + //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// @brief sets up a Foxx application -/// -/// Input: -/// * mount: the mount path starting with a "/" -/// -/// Output: -/// - -//////////////////////////////////////////////////////////////////////////////// + var installAppFromLocal = function(path, targetPath) { + if (fs.isDirectory(path)) { + var tempFile = fs.getTempFile("downloads", false); -var setup = function (mount) { - checkParameter( - "setup()", - [ [ "Mount path", "string" ] ], - [ mount ] ); + var tree = fs.listTree(path); + var files = []; + var i; + var filename; - var app = lookupApp(mount); + for (i = 0; i < tree.length; ++i) { + filename = fs.join(path, tree[i]); - try { - setupApp(app); - } catch (err) { - console.errorLines( - "Setup not possible for mount '%s': %s", mount, String(err.stack || err)); - throw err; - } -}; + if (fs.isFile(filename)) { + files.push(tree[i]); + } + } -//////////////////////////////////////////////////////////////////////////////// -/// @brief tears down a Foxx application -/// -/// Input: -/// * mount: the mount path starting with a "/" -/// -/// Output: -/// - -//////////////////////////////////////////////////////////////////////////////// + if (files.length === 0) { + throwFileNotFound("Directory '" + String(path) + "' is empty"); + } + fs.zipFile(tempFile, path, files); + extractAppToPath(tempFile, targetPath); + } else { + extractAppToPath(path, targetPath, true); + } + }; -var teardown = function (mount) { - checkParameter( - "teardown()", - [ [ "Mount path", "string" ] ], - [ mount ] ); + // ----------------------------------------------------------------------------- + // --SECTION-- public functions + // ----------------------------------------------------------------------------- - var app = lookupApp(mount); - try { - teardownApp(app); - } catch (err) { - console.errorLines( - "Teardown not possible for mount '%s': %s", mount, String(err.stack || err)); - throw err; - } -}; + //////////////////////////////////////////////////////////////////////////////// + /// @brief sets up a Foxx application + /// + /// Input: + /// * mount: the mount path starting with a "/" + /// + /// Output: + /// - + //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// @brief Scans the sources of the given mountpoint and publishes the routes -/// -/// TODO: Long Documentation! -//////////////////////////////////////////////////////////////////////////////// -var scanFoxx = function(mount, options) { - delete appCache[mount]; - var app = createApp(mount, options); - utils.tmp_getStorage().save(app.toJSON()); - var routes = routeApp(app); - require("console").log("Routes", Object.keys(routes)); - // TODO Routing? -}; + var setup = function (mount) { + checkParameter( + "setup()", + [ [ "Mount path", "string" ] ], + [ mount ] ); + + var app = lookupApp(mount); + + try { + setupApp(app); + } catch (err) { + console.errorLines( + "Setup not possible for mount '%s': %s", mount, String(err.stack || err)); + throw err; + } + }; + + //////////////////////////////////////////////////////////////////////////////// + /// @brief tears down a Foxx application + /// + /// Input: + /// * mount: the mount path starting with a "/" + /// + /// Output: + /// - + //////////////////////////////////////////////////////////////////////////////// + + var teardown = function (mount) { + checkParameter( + "teardown()", + [ [ "Mount path", "string" ] ], + [ mount ] ); + + var app = lookupApp(mount); + try { + teardownApp(app); + } catch (err) { + console.errorLines( + "Teardown not possible for mount '%s': %s", mount, String(err.stack || err)); + throw err; + } + }; + + //////////////////////////////////////////////////////////////////////////////// + /// @brief Scans the sources of the given mountpoint and publishes the routes + /// + /// TODO: Long Documentation! + //////////////////////////////////////////////////////////////////////////////// + var scanFoxx = function(mount, options) { + delete appCache[mount]; + var app = createApp(mount, options); + utils.tmp_getStorage().save(app.toJSON()); + var routes = routeApp(app); + require("console").log("Routes", Object.keys(routes)); + // TODO Routing weiter? + }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief Internal install function. Check install. -/// Does not check parameters and throws errors. -//////////////////////////////////////////////////////////////////////////////// -var _install = function(appInfo, mount, options, runSetup) { - var targetPath = computeAppPath(mount, true); - if (fs.exists(targetPath)) { - throw "An app is already installed at this location."; - } - fs.makeDirectoryRecursive(targetPath); - // Remove the empty APP folder. - // Ohterwise move will fail. - fs.removeDirectory(targetPath); + //////////////////////////////////////////////////////////////////////////////// + /// @brief Internal install function. Check install. + /// Does not check parameters and throws errors. + //////////////////////////////////////////////////////////////////////////////// + var _install = function(appInfo, mount, options, runSetup) { + var targetPath = computeAppPath(mount, true); + if (fs.exists(targetPath)) { + throw "An app is already installed at this location."; + } + fs.makeDirectoryRecursive(targetPath); + // Remove the empty APP folder. + // Ohterwise move will fail. + fs.removeDirectory(targetPath); - if (appInfo === "EMPTY") { - // Make Empty app - throw "Not implemented yet"; - } else if (/^GIT:/.test(appInfo)) { - installAppFromRemote(buildGithubUrl(appInfo), targetPath); - } else if (/^https?:/.test(appInfo)) { - installAppFromRemote(appInfo, targetPath); - } else if (/^((\/)|(\.\/)|(\.\.\/))/.test(appInfo)) { - installAppFromLocal(appInfo, targetPath); - } else { - // try appstore - throw "Not implemented yet"; - } - scanFoxx(mount, options); - if (runSetup) { - setup(mount); - } -}; + if (appInfo === "EMPTY") { + // Make Empty app + throw "Not implemented yet"; + } else if (/^GIT:/.test(appInfo)) { + installAppFromRemote(buildGithubUrl(appInfo), targetPath); + } else if (/^https?:/.test(appInfo)) { + installAppFromRemote(appInfo, targetPath); + } else if (/^((\/)|(\.\/)|(\.\.\/))/.test(appInfo)) { + installAppFromLocal(appInfo, targetPath); + } else { + // try appstore + throw "Not implemented yet"; + } + scanFoxx(mount, options); + if (runSetup) { + setup(mount); + } + }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief Installs a new foxx application on the given mount point. -/// -/// TODO: Long Documentation! -//////////////////////////////////////////////////////////////////////////////// -var install = function(appInfo, mount, options) { - checkParameter( - "mount(, , [])", - [ [ "Install information", "string" ], - [ "Mount path", "string" ] ], - [ appInfo, mount ] ); - _install(appInfo, mount, options, true); -}; + //////////////////////////////////////////////////////////////////////////////// + /// @brief Installs a new foxx application on the given mount point. + /// + /// TODO: Long Documentation! + //////////////////////////////////////////////////////////////////////////////// + var install = function(appInfo, mount, options) { + checkParameter( + "mount(, , [])", + [ [ "Install information", "string" ], + [ "Mount path", "string" ] ], + [ appInfo, mount ] ); + _install(appInfo, mount, options, true); + }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief Internal install function. Check install. -/// Does not check parameters and throws errors. -//////////////////////////////////////////////////////////////////////////////// -var _uninstall = function(mount) { - var targetPath = computeAppPath(mount, true); - if (!fs.exists(targetPath)) { - throw "No foxx app found at this location."; - } - teardown(mount); - // TODO Delete routing? - utils.tmp_getStorage().removeByExample({mount: mount}); - delete appCache[mount]; - // Remove the APP folder. - fs.removeDirectoryRecursive(targetPath, true); -}; + //////////////////////////////////////////////////////////////////////////////// + /// @brief Internal install function. Check install. + /// Does not check parameters and throws errors. + //////////////////////////////////////////////////////////////////////////////// + var _uninstall = function(mount) { + var targetPath = computeAppPath(mount, true); + if (!fs.exists(targetPath)) { + throw "No foxx app found at this location."; + } + teardown(mount); + // TODO Delete routing? + utils.tmp_getStorage().removeByExample({mount: mount}); + delete appCache[mount]; + // Remove the APP folder. + fs.removeDirectoryRecursive(targetPath, true); + }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief Uninstalls the foxx application on the given mount point. -/// -/// TODO: Long Documentation! -//////////////////////////////////////////////////////////////////////////////// -var uninstall = function(mount) { - checkParameter( - "mount()", - [ [ "Mount path", "string" ] ], - [ mount ] ); - _uninstall(mount); -}; + //////////////////////////////////////////////////////////////////////////////// + /// @brief Uninstalls the foxx application on the given mount point. + /// + /// TODO: Long Documentation! + //////////////////////////////////////////////////////////////////////////////// + var uninstall = function(mount) { + checkParameter( + "mount()", + [ [ "Mount path", "string" ] ], + [ mount ] ); + _uninstall(mount); + }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief Replaces a foxx application on the given mount point by an other one. -/// -/// TODO: Long Documentation! -//////////////////////////////////////////////////////////////////////////////// -var replace = function(appInfo, mount, options) { - checkParameter( - "mount(, , [])", - [ [ "Install information", "string" ], - [ "Mount path", "string" ] ], - [ appInfo, mount ] ); - _uninstall(mount, true); - _install(appInfo, mount, options, true); -}; + //////////////////////////////////////////////////////////////////////////////// + /// @brief Replaces a foxx application on the given mount point by an other one. + /// + /// TODO: Long Documentation! + //////////////////////////////////////////////////////////////////////////////// + var replace = function(appInfo, mount, options) { + checkParameter( + "mount(, , [])", + [ [ "Install information", "string" ], + [ "Mount path", "string" ] ], + [ appInfo, mount ] ); + _uninstall(mount, true); + _install(appInfo, mount, options, true); + }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief Upgrade a foxx application on the given mount point by a new one. -/// -/// TODO: Long Documentation! -//////////////////////////////////////////////////////////////////////////////// -var upgrade = function(appInfo, mount, options) { - checkParameter( - "mount(, , [])", - [ [ "Install information", "string" ], - [ "Mount path", "string" ] ], - [ appInfo, mount ] ); - _uninstall(mount, false); - _install(appInfo, mount, options, false); -}; + //////////////////////////////////////////////////////////////////////////////// + /// @brief Upgrade a foxx application on the given mount point by a new one. + /// + /// TODO: Long Documentation! + //////////////////////////////////////////////////////////////////////////////// + var upgrade = function(appInfo, mount, options) { + checkParameter( + "mount(, , [])", + [ [ "Install information", "string" ], + [ "Mount path", "string" ] ], + [ appInfo, mount ] ); + _uninstall(mount, false); + _install(appInfo, mount, options, false); + }; -// ----------------------------------------------------------------------------- -// --SECTION-- exports -// ----------------------------------------------------------------------------- + //////////////////////////////////////////////////////////////////////////////// + /// @brief initializes the Foxx apps + //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// @brief Exports -//////////////////////////////////////////////////////////////////////////////// + var initializeFoxx = function() { + appCache = {}; + var cursor = utils.tmp_getStorage().all(); + var config, app; -exports.scanFoxx = scanFoxx; -exports.install = install; -exports.setup = setup; -exports.teardown = teardown; -exports.uninstall = uninstall; -exports.replace = replace; -exports.upgrade = upgrade; + while (cursor.hasNext()) { + config = cursor.next(); + app = new ArangoApp(config); + appCache[app._mount] = app; + var routes = routeApp(app); + require("console").log("Routes", Object.keys(routes)); + // TODO Routing weiter? + } + }; -//////////////////////////////////////////////////////////////////////////////// -/// @brief Exports from foxx utils module. -//////////////////////////////////////////////////////////////////////////////// + // ----------------------------------------------------------------------------- + // --SECTION-- exports + // ----------------------------------------------------------------------------- -exports.mountedApp = utils.mountedApp; -exports.list = utils.list; -exports.listJson = utils.listJson; -exports.listDevelopment = utils.listDevelopment; -exports.listDevelopmentJson = utils.listDevelopmentJson; + //////////////////////////////////////////////////////////////////////////////// + /// @brief Exports + //////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// @brief Exports from foxx store module. -//////////////////////////////////////////////////////////////////////////////// + exports.scanFoxx = scanFoxx; + exports.install = install; + exports.setup = setup; + exports.teardown = teardown; + exports.uninstall = uninstall; + exports.replace = replace; + exports.upgrade = upgrade; -exports.available = store.available; -exports.availableJson = store.availableJson; -exports.getFishbowlStorage = store.getFishbowlStorage; -exports.search = store.search; -exports.searchJson = store.searchJson; -exports.update = store.update; -exports.info = store.info; + //////////////////////////////////////////////////////////////////////////////// + /// @brief Exports from foxx utils module. + //////////////////////////////////////////////////////////////////////////////// -// TODO implement!! -exports.initializeFoxx = function () {}; + exports.mountedApp = utils.mountedApp; + exports.list = utils.list; + exports.listJson = utils.listJson; + exports.listDevelopment = utils.listDevelopment; + exports.listDevelopmentJson = utils.listDevelopmentJson; + //////////////////////////////////////////////////////////////////////////////// + /// @brief Exports from foxx store module. + //////////////////////////////////////////////////////////////////////////////// + + exports.available = store.available; + exports.availableJson = store.availableJson; + exports.getFishbowlStorage = store.getFishbowlStorage; + exports.search = store.search; + exports.searchJson = store.searchJson; + exports.update = store.update; + exports.info = store.info; + + exports.initializeFoxx = initializeFoxx; }()); // ----------------------------------------------------------------------------- diff --git a/js/server/modules/org/arangodb/foxx/routing.js b/js/server/modules/org/arangodb/foxx/routing.js index f4a5a722a1..f3a17c205d 100644 --- a/js/server/modules/org/arangodb/foxx/routing.js +++ b/js/server/modules/org/arangodb/foxx/routing.js @@ -39,6 +39,7 @@ var fs = require("fs"); var frontendDevelopmentMode = require("internal").frontendDevelopmentMode; var console = require("console"); + var setFoxxRouting = require("org/arangodb/actions").setFoxxRouting; // ----------------------------------------------------------------------------- // --SECTION-- private functions @@ -297,7 +298,7 @@ var i; var mount = app._mount; - var defaultDocument = app._manifest.defaultDocument; // TODO by default "index.html" + var defaultDocument = app._manifest.defaultDocument; // setup the routes var routes = { @@ -364,11 +365,9 @@ if (controllers.hasOwnProperty(i)) { file = controllers[i]; - // TODO ???? // set up a context for the application start function tmpContext = { prefix: arangodb.normalizeURL("/" + i), // app mount - routingInfo: {}, foxxes: [] }; @@ -423,6 +422,7 @@ // install all files and assets installAssets(app, routes); + setFoxxRouting(app._mount, routes); // and return all routes return routes; }