1
0
Fork 0

Added optional Foxx deps.

This commit is contained in:
Alan Plum 2015-08-11 13:07:33 +02:00
parent 3029891405
commit 1031a3d4e9
6 changed files with 77 additions and 35 deletions

View File

@ -133,6 +133,10 @@ v2.7.0 (XXXX-XX-XX)
* fixed handling of optional parameters in Foxx manifest configurations
* added verbose Foxx manifest dependency format
* added optional Foxx dependencies
* updated chai to 3.0.

View File

@ -73,7 +73,12 @@ A more complete example for a Manifest file:
"dependencies": {
"sessions": "sessions@^1.0.0",
"systemUsers": "users"
"systemUsers": "users",
"mailer": {
"name": "mailer-postmark",
"version": "*",
"required": false
}
}
}
```
@ -159,20 +164,26 @@ The **dependencies** object maps aliases to Foxx apps:
* The **value** is a dependency definition.
The dependency definition can use any of the following formats:
The dependency definition is an object with any of the following properties:
* **name** (optional): the name of the Foxx app this app depends on.
* **version** (Default: `"*"`): a [semver](http://semver.org) version or version range of the Foxx app this app depends on.
* **required** (Default: `true`): whether the dependency is required for this app to be usable or not.
Alternatively the dependency definition can be a string using any of the following formats:
* `*` will allow using any app to be used to meet the dependency.
* `sessions` or `sessions@*` will match any app with the name `sessions`
* `sessions` or `sessions:*` will match any app with the name `sessions`
(such as the *sessions* app in the Foxx application store).
* `sessions@1.0.0` will match the version `1.0.0` of any app with the name `sessions`.
* `sessions:1.0.0` will match the version `1.0.0` of any app with the name `sessions`.
Instead of using a specific version number, you can also use any expression supported by
the [semver](https://github.com/npm/node-semver) module.
Currently the dependency definitions are not enforced in ArangoDB
Currently the dependency definition names and versions are not enforced in ArangoDB
but this may change in a future version.
If an app declares any dependencies,
If an app declares any required dependencies,
you need to fulfill its dependencies before it becomes active.
In the meantime a fallback application will be mounted that responds to all
requests with a HTTP 500 status code indicating a server-side error.

View File

@ -80,7 +80,7 @@
hasUnconfiguredDependencies: function () {
return _.any(this.get('deps'), function (dep) {
return dep.current === undefined;
return dep.current === undefined && dep.definition.required !== false;
});
},

View File

@ -350,24 +350,27 @@
var tableContent = _.map(this.model.get('deps'), function(obj, name) {
var currentValue = obj.current === undefined ? '' : String(obj.current);
var defaultValue = '';
var description = obj.definition;
var checks = [
{
rule: Joi.string().optional().allow(''),
msg: 'Has to be a string.'
},
{
var description = obj.definition.name;
if (obj.definition.version !== '*') {
description += '@' + obj.definition.version;
}
var checks = [{
rule: Joi.string().optional().allow(''),
msg: 'Has to be a string.'
}];
if (obj.definition.required) {
checks.push({
rule: Joi.string().required(),
msg: 'This value is required.'
}
];
});
}
return window.modalView.createTextEntry(
'app_deps_' + name,
obj.title,
currentValue,
description,
defaultValue,
true,
obj.definition.required,
checks
);
});

View File

@ -289,17 +289,19 @@ ArangoApp.prototype.updateDeps = function (deps) {
if (!expected[name]) {
invalid.push("Unexpected dependency " + name);
}
this._options.dependencies[name] = mount;
this._options.dependencies[name] = mount || undefined;
}, this);
_.each(this._options.dependencies, function (mount, name) {
Object.defineProperty(this._dependencies, name, {
configurable: true,
enumerable: true,
get: function () {
return require("org/arangodb/foxx").requireApp(mount);
}
});
if (mount) {
Object.defineProperty(this._dependencies, name, {
configurable: true,
enumerable: true,
get: function () {
return require("org/arangodb/foxx").requireApp(mount);
}
});
}
}, this);
return invalid;
@ -406,7 +408,7 @@ ArangoApp.prototype.needsConfiguration = function() {
return _.any(config, function (cfg) {
return cfg.current === undefined && cfg.required !== false;
}) || _.any(deps, function (dep) {
return dep.current === undefined;
return dep.current === undefined && dep.definition.required !== false;
});
};

View File

@ -116,7 +116,15 @@ const manifestSchema = {
dependencies: (
joi.object().optional()
.pattern(RE_EMPTY, joi.forbidden())
.pattern(RE_NOT_EMPTY, joi.string().required())
.pattern(RE_NOT_EMPTY, joi.alternatives().try(
joi.string().required(),
joi.object().required()
.keys({
name: joi.string().default('*'),
version: joi.string().default('*'),
required: joi.boolean().default(true)
})
))
),
description: joi.string().allow('').default(''),
engines: (
@ -368,19 +376,33 @@ function checkManifest(filename, manifest) {
}
});
if (typeof manifest.controllers === 'string') {
manifest.controllers = {'/': manifest.controllers};
}
if (typeof manifest.tests === 'string') {
manifest.tests = [manifest.tests];
}
if (validationErrors.length) {
throw new ArangoError({
errorNum: errors.ERROR_INVALID_APPLICATION_MANIFEST.code,
errorMessage: validationErrors.join('\n')
});
} else {
if (manifest.dependencies) {
Object.keys(manifest.dependencies).forEach(function (key) {
const dependency = manifest.dependencies[key];
if (typeof dependency === 'string') {
const tokens = dependency.split(':');
manifest.dependencies[key] = {
name: tokens[0] || '*',
version: tokens[1] || '*',
required: true
};
}
});
}
if (typeof manifest.controllers === 'string') {
manifest.controllers = {'/': manifest.controllers};
}
if (typeof manifest.tests === 'string') {
manifest.tests = [manifest.tests];
}
}
}