From cc5ae9d1bc48f67e61bd852fc80b34e842fb4695 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Fri, 26 Jul 2013 23:57:00 +0200 Subject: [PATCH] added purge() --- .../admin/js/modules/org/arangodb/arangosh.js | 6 + js/actions/api-foxx.js | 19 +++ .../modules/org/arangodb/foxx-manager.js | 30 ++++- js/client/tests/shell-fm.js | 120 +++++++++++++++++- .../modules/org/arangodb/foxx-manager.js | 53 +++++++- lib/V8/v8-utils.cpp | 41 +++--- 6 files changed, 242 insertions(+), 27 deletions(-) diff --git a/html/admin/js/modules/org/arangodb/arangosh.js b/html/admin/js/modules/org/arangodb/arangosh.js index 1553108121..a086494ef4 100644 --- a/html/admin/js/modules/org/arangodb/arangosh.js +++ b/html/admin/js/modules/org/arangodb/arangosh.js @@ -109,6 +109,12 @@ exports.checkRequestResult = function (requestResult) { throw new ArangoError(requestResult); } + + var copy = requestResult._shallowCopy; + + delete copy.error; + + return copy; }; //////////////////////////////////////////////////////////////////////////////// diff --git a/js/actions/api-foxx.js b/js/actions/api-foxx.js index b3128e45b0..f812eda42c 100644 --- a/js/actions/api-foxx.js +++ b/js/actions/api-foxx.js @@ -241,6 +241,25 @@ actions.defineHttp({ }) }); +//////////////////////////////////////////////////////////////////////////////// +/// @brief purgesp a FOXX application +//////////////////////////////////////////////////////////////////////////////// + +actions.defineHttp({ + url : "_admin/foxx/purge", + context : "admin", + prefix : false, + + callback: easyPostCallback({ + body: true, + callback: function (body) { + var name = body.name; + + return foxxManager.purge(name); + } + }) +}); + // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- diff --git a/js/client/modules/org/arangodb/foxx-manager.js b/js/client/modules/org/arangodb/foxx-manager.js index abd682ce92..cc283287e8 100644 --- a/js/client/modules/org/arangodb/foxx-manager.js +++ b/js/client/modules/org/arangodb/foxx-manager.js @@ -587,14 +587,14 @@ exports.run = function (args) { exports.teardown(args[1]); } else if (type === 'unmount') { - res = exports.unmount(args[1]); + exports.unmount(args[1]); } else if (type === 'install') { if (3 < args.length) { - exports.install(args[1], args[2], JSON.parse(args[3])); + res = exports.install(args[1], args[2], JSON.parse(args[3])); } else { - exports.install(args[1], args[2]); + res = exports.install(args[1], args[2]); } printf("Application %s installed successfully at mount point %s\n", @@ -608,6 +608,13 @@ exports.run = function (args) { res.appId, res.mount); } + else if (type === 'purge') { + res = exports.purge(args[1]); + + printf("Application %s and %d mounts purged successfully\n", + res.name, + res.purged.length); + } else if (type === 'list') { if (1 < args.length && args[1] === "prefix") { exports.list(true); @@ -887,6 +894,22 @@ exports.uninstall = function (mount) { return exports.unmount(mount); }; +//////////////////////////////////////////////////////////////////////////////// +/// @brief purges a FOXX application +//////////////////////////////////////////////////////////////////////////////// + +exports.purge = function (key) { + 'use strict'; + + var req = { + name: key + }; + + var res = arango.POST("/_admin/foxx/purge", JSON.stringify(req)); + + return arangosh.checkRequestResult(res); +}; + //////////////////////////////////////////////////////////////////////////////// /// @brief returns all installed FOXX applications //////////////////////////////////////////////////////////////////////////////// @@ -1225,6 +1248,7 @@ exports.help = function () { "teardown" : "teardown execute the teardown script (app must be still be mounted)", "unmount" : "unmounts a mounted foxx application", "uninstall" : "unmounts a mounted foxx application and calls its teardown method", + "purge" : "physically removes a foxx application and all mounts", "list" : "lists all installed foxx applications", "fetched" : "lists all fetched foxx applications that were fetched into the local repository", "available" : "lists all foxx applications available in the local repository", diff --git a/js/client/tests/shell-fm.js b/js/client/tests/shell-fm.js index 9300a38884..563bac3f21 100644 --- a/js/client/tests/shell-fm.js +++ b/js/client/tests/shell-fm.js @@ -41,6 +41,41 @@ function FoxxManagerSuite () { return { +//////////////////////////////////////////////////////////////////////////////// +/// @brief test update +//////////////////////////////////////////////////////////////////////////////// + + testUpdate : function () { + fm.update(); + + var result = fm.availableJson(); + var i, n; + + n = result.length; + assertTrue(n > 0); + + // validate the results structure + for (i = 0; i < n; ++i) { + var entry = result[i]; + + assertTrue(entry.hasOwnProperty("description")); + assertTrue(entry.hasOwnProperty("name")); + assertTrue(entry.hasOwnProperty("author")); + assertTrue(entry.hasOwnProperty("latestVersion")); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test available +//////////////////////////////////////////////////////////////////////////////// +/* + testFetch : function () { + fm.update(); + fm.purge("itzpapalotl"); + + fm.fetch("github", "jsteemann/itzpapalotl"); + }, +*/ //////////////////////////////////////////////////////////////////////////////// /// @brief test search //////////////////////////////////////////////////////////////////////////////// @@ -99,7 +134,9 @@ function FoxxManagerSuite () { /// @brief test install //////////////////////////////////////////////////////////////////////////////// - testInstall : function () { + testInstallSingle : function () { + fm.update(); + try { fm.uninstall("/itz"); } @@ -107,15 +144,84 @@ function FoxxManagerSuite () { } fm.install("itzpapalotl", "/itz"); - - var endpoint = arango.getEndpoint(); - endpoint = endpoint.replace(/^tcp:/g, 'http:').replace(/^ssl:/g, 'https:'); - - var url = endpoint + '/itz'; + + var url = '/itz/random'; + var fetched = arango.GET(url); - require("internal").print(arango.GET(url)); + assertTrue(fetched.hasOwnProperty("name")); fm.uninstall("/itz"); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test install +//////////////////////////////////////////////////////////////////////////////// + + testInstallMulti : function () { + fm.update(); + + try { + fm.uninstall("/itz1"); + fm.uninstall("/itz2"); + } + catch (err) { + } + + fm.install("itzpapalotl", "/itz1"); + fm.install("itzpapalotl", "/itz2"); + + var url, fetched; + + url = '/itz1/random'; + fetched = arango.GET(url); + assertTrue(fetched.hasOwnProperty("name")); + + url = '/itz2/random'; + fetched = arango.GET(url); + + assertTrue(fetched.hasOwnProperty("name")); + + fm.uninstall("/itz1"); + fm.uninstall("/itz2"); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test uninstall +//////////////////////////////////////////////////////////////////////////////// + + testUninstallInstalled : function () { + fm.update(); + + try { + fm.uninstall("/itz"); + } + catch (err) { + } + + fm.install("itzpapalotl", "/itz"); + fm.uninstall("/itz"); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test uninstall +//////////////////////////////////////////////////////////////////////////////// + + testUninstallUninstalled : function () { + fm.update(); + + try { + fm.uninstall("/itz"); + } + catch (err) { + } + + try { + // already uninstalled + fm.uninstall("/itz"); + fail(); + } + catch (err) { + } } }; diff --git a/js/server/modules/org/arangodb/foxx-manager.js b/js/server/modules/org/arangodb/foxx-manager.js index 5f1889af78..47ca64b46b 100644 --- a/js/server/modules/org/arangodb/foxx-manager.js +++ b/js/server/modules/org/arangodb/foxx-manager.js @@ -690,7 +690,7 @@ exports.mount = function (appId, mount, options) { executeGlobalContextFunction("require(\"org/arangodb/actions\").reloadRouting()"); } - return { appId: app._id, mountId: doc._key }; + return { appId: app._id, mountId: doc._key, mount: mount }; }; //////////////////////////////////////////////////////////////////////////////// @@ -754,7 +754,7 @@ exports.teardown = function (mount) { /// @brief unmounts a FOXX application /// /// Input: -/// * key: mount key o mount point +/// * key: mount key or mount point /// /// Output: /// * appId: the application identifier @@ -783,6 +783,55 @@ exports.unmount = function (mount) { return { appId: doc.app, mount: doc.mount, collectionPrefix: doc.collectionPrefix }; }; +//////////////////////////////////////////////////////////////////////////////// +/// @brief purges a FOXX application +/// +/// Input: +/// * name: application name +/// +/// Output: +/// * appId: the application identifier +/// * mount: the mount path starting with "/" +/// * collectionPrefix: the collection prefix +//////////////////////////////////////////////////////////////////////////////// + +exports.purge = function (name) { + 'use strict'; + + var doc = getStorage().firstExample({ type: "app", name: name }); + + if (doc === null) { + throw new Error("Cannot find application '" + name + "'"); + } + + if (doc.isSystem) { + throw new Error("Cannot purge system application"); + } + + var purged = [ ]; + + var cursor = getStorage().byExample({ type: "mount", name: name }); + + while (cursor.hasNext()) { + var mount = cursor.next(); + + exports.teardown(mount.mount); + exports.unmount(mount.mount); + + purged.push(mount.mount); + } + + // remove the app + getStorage().remove(doc); + + executeGlobalContextFunction("require(\"org/arangodb/actions\").reloadRouting()"); + + var path = fs.join(module.appPath(), doc.path); + fs.removeDirectoryRecursive(path, true); + + return { appId: doc.app, name: name, purged: purged }; +}; + //////////////////////////////////////////////////////////////////////////////// /// @brief sets up a development app /// diff --git a/lib/V8/v8-utils.cpp b/lib/V8/v8-utils.cpp index 5911f8fff4..a5e7645f12 100644 --- a/lib/V8/v8-utils.cpp +++ b/lib/V8/v8-utils.cpp @@ -1830,7 +1830,7 @@ static v8::Handle JS_RemoveRecursiveDirectory (v8::Arguments const& a v8::HandleScope scope; // extract the arguments - if (argv.Length() != 1) { + if (argv.Length() < 1) { TRI_V8_EXCEPTION_USAGE(scope, "removeDirectoryRecursive()"); } @@ -1844,24 +1844,35 @@ static v8::Handle JS_RemoveRecursiveDirectory (v8::Arguments const& a TRI_V8_EXCEPTION_PARAMETER(scope, " must be a valid directory name"); } - char* tempPath = TRI_GetUserTempPath(); + bool force = false; + + if (argv.Length() > 1) { + force = TRI_ObjectToBoolean(argv[1]); + } + + if (! force) { + // check if we're inside the temp directory. force will override this check + char* tempPath = TRI_GetUserTempPath(); - if (tempPath == NULL || strlen(tempPath) < 6) { - // some security measure so we don't accidently delete all our files + if (tempPath == 0 || strlen(tempPath) < 6) { + // some security measure so we don't accidently delete all our files + if (tempPath != 0) { + TRI_FreeString(TRI_CORE_MEM_ZONE, tempPath); + } + + TRI_V8_EXCEPTION_PARAMETER(scope, "temporary directory name is too short. will not remove directory"); + } + + const string path(*name); + if (! TRI_EqualString2(path.c_str(), tempPath, strlen(tempPath))) { + TRI_FreeString(TRI_CORE_MEM_ZONE, tempPath); + + TRI_V8_EXCEPTION_PARAMETER(scope, "directory to be removed is outside of temporary path"); + } + TRI_FreeString(TRI_CORE_MEM_ZONE, tempPath); - - TRI_V8_EXCEPTION_PARAMETER(scope, "temporary directory name is too short. will not remove directory"); } - const string path(*name); - if (! TRI_EqualString2(path.c_str(), tempPath, strlen(tempPath))) { - TRI_FreeString(TRI_CORE_MEM_ZONE, tempPath); - - TRI_V8_EXCEPTION_PARAMETER(scope, "directory to be removed is outside of temporary path"); - } - - TRI_FreeString(TRI_CORE_MEM_ZONE, tempPath); - int res = TRI_RemoveDirectory(*name); if (res != TRI_ERROR_NO_ERROR) {