From 6b74adfae9239ad21fbdcbe07605bd8f811c5ef2 Mon Sep 17 00:00:00 2001 From: Lucy Cifferello Date: Thu, 15 Oct 2020 15:57:29 -0600 Subject: [PATCH] more type examples around config/manifest --- source/contributing/services/config.rst | 226 ++++++++++++++++------ source/contributing/services/manifest.rst | 54 ++++-- 2 files changed, 203 insertions(+), 77 deletions(-) diff --git a/source/contributing/services/config.rst b/source/contributing/services/config.rst index 8def522..f081097 100644 --- a/source/contributing/services/config.rst +++ b/source/contributing/services/config.rst @@ -4,6 +4,7 @@ Service Configurations ********************** +These files define the configuration spec, a structure that defines the set of values the config can hold, and the configuration rules, the rule-set that define dependencies between config variables in order to coexist. Config Spec =========== @@ -14,102 +15,166 @@ TODO include screenshots - Prior to service installation when the user needs to be made aware of any necessary dependency configurations - The user installs a service and the service is in the "Needs Config" state -- Whenever a use edits a service configuration (ie. TODO) +- Whenever a use edits a service config (ie. TODO) - When config pointers get updated (TODO define) -@aiden are all keys kebab case? (some snake, some camel in code) +All keys in Config Spec are in camelCase. Due to a backwards compatibility issue, ``app-id`` is an exception and will always be kebab case, as will the ``String`` value of ``app-id``. -TODO commas or no commas +If null by default is true, nullable must be true. +If null by default is false, nullable could be either. + +Lists of any type do not contain the nullable/default for each item in list. The list *itself* can be nullable/have default. + +Descriptions are encouraged but not required. + +``Tag`` is the key that will be rendered on the UI element. + +The ``Config`` type is written in the same syntax as the config rules: + +Range is loosely based off mathematical range syntax, with infinity replaced with ``*``: + + ``[ || ]`` = inclusive + + ``( || )`` = noninclusive + + ``*`` = infinity on either end + +eg: + +.. code:: + + [0,*) - all numbers to infinity including 0 Types ----- -.. code::typescript +.. code:: typescript interface ConfigSpec { serviceId: ValueSpecAny } - pub enum ValueSpecAny { - Boolean(WithDescription>), - Enum(WithDescription>), - List(ValueSpecList), - Number(WithDescription>>), - Object(WithDescription>), - String(WithDescription>>), - Union(WithDescription>), - Pointer(WithDescription), + interface ListSpec { + spec: T + range: NumRange TODO define Range + default: String } interface ValueSpec { Boolean: { type: String (ie. "boolean") name: String - description: String TODO char length + description?: String + changeWarning?: String default: Boolean - }, + } Enum: { type: String (ie. "enum") name: String - description: String TODO char length + description?: String + changeWarning?: String default: Enum - values: new Set(String), - }, - List: [ValueSpec.Enum | ValueSpec.Object | ValueSpec.Number | ValueSpec.String], + values: new Set(String) + } Number: { type: String (ie. "number") name: String - description: String TODO char length + description?: String + changeWarning?: String default: Boolean nullable: Boolean - range?: Number TODO f64?, - integral: Boolean, - units?: String, - }, + range?: Range + integral: Boolean + units?: String + } Object: { type: String (ie. "object") name: String - description: String TODO char length + description?: String + changeWarning?: String nullable: Boolean - null-by-default: Boolean, - spec: ConfigSpec, - }, + null-by-default: Boolean + spec: ConfigSpec + } String: { type: String (ie. "string") name: String - description: String TODO char length + description?: String + changeWarning?: String nullable: Boolean + default: String | Entropy pattern?: { - pattern: Regex, - pattern-description: String, - }, - }, + pattern: Regex + pattern-description: String + } + } Union: { type: String (ie. "union") name: String - description: String TODO char length + description?: String + changeWarning?: String default: Boolean variants: { - key: ConfigSpec, - }, - tag: String, - }, + key: ConfigSpec + } + tag: { + id: String, + name: String, + description?: String, + variantNames: { + key: String + }, + } + } Pointer: { type: String (ie. "pointer") name: String - description: String TODO char length - subtype: app - app-id: String - target: AppPointerSpecVariants, - index: String - }, + description?: String + changeWarning?: String + subtype: PointerType + app-id: String (*always* kebab case) + target: AppPointerSpecVariants | SystemPointerSpecVariants + index?: String (dependent on target being AppPointerSpecVariants) + } + List: { + name: String + type: String (ie. "list") + subtype: String + description?: String + changeWarning?: String + range: Range (ie. "[0,*)") + default: ListSpec || [] + spec: { + type: String // can only be Enum | Number | Object | String + } + } + Map: { + name: String + type: String (ie. "map") + description?: String + changeWarning?: String + default: {} + range: Range + tag: { + name: String + description: String + } + spec: ConfigSpec + } } + type Range = String + type PointerType = App | System + interface AppPointerSpecVariants { LanAddress | TorAddress | Config } + interface SystemPointerSpecVariants {} + interface Config { + index: String + } + Examples: .. code:: yaml - --- password: type: string nullable: false @@ -213,30 +278,71 @@ Config Rules These rules define application level rules. A rule is a boolean expression that we demand to be true. If it is failing, it is not true. -Rules are composed of _ concepts: +They follow the `Backus–Naur `_ metasyntax for writing rules. -* Variables -* Terms +Rules are composed of two main concepts: -Variables can be: booleans, numbers, strings - - different syntax depending on what you want it to be - - ? casts to boolean value. if not a boolean, whether or not its null - - # treat as a number. If not a number, will parse as NaN. String numbers are not currently supported. - - ‘ cast into a string. Applies to any value except for an object or a list. +* Variables - accessor into a configuration +* Terms - either a variable or type literal (ie. a boolean term is a boolean variable, a boolean expression, or a comparison operation between numbers or strings.) -Term: token that yields a value +Variables can be: -A boolean term is a boolean variable, a boolean expression, or a comparison operation between numbers or strings. +- booleans, numbers, strings +- different syntax depending on what you want it to be +- ``?`` casts to boolean value. if not a boolean, whether or not its null +- ``#`` treat as a number. If not a number, will parse as NaN. String numbers are not currently supported. +- ``'`` cast into a string. Applies to any value except for an object or a list. +- ``!`` equals not If application does not satisfy a rule, give a set of suggestions, in the form of operation to preform: -- Set -- Push -- Delete + + - Set + + - Push + + - Delete + +.. code::typescript + + enum SuggestionVariant = Set | Delete | Push + + interface Set { + var: String, + to: SetVariant, + } + interface Delete { + src: String, + } + interface Push { + to: String, + value: Value, + } + + enum SetVariant = To | ToValue | ToEntropy + + type To = String + type ToValue = Value + interface ToEntropy { + charset: String (eg. 'a-z,A-Z,0-9') + len: Number + } + +SetVariant Examples: + +.. code:: yaml + + to: 'users' + + to-entropy: { + charset: 'a-z,A-Z,0-9' + len: 22 + } + + to: true .. code:: yaml - --- - rule: 'rpc.enable? OR !(''advanced.pruning.mode = "manual")' - description: "RPC must be enabled for manual pruning." + description: "RPC must be enabled for manual pruning." diff --git a/source/contributing/services/manifest.rst b/source/contributing/services/manifest.rst index c66b3be..9e777a5 100644 --- a/source/contributing/services/manifest.rst +++ b/source/contributing/services/manifest.rst @@ -4,7 +4,7 @@ Service Manifest **************** -This file describes the service and it's requirements. Important to note is the dependencies key, which contains rules for optional or required other services that are depended on to successfully run the service at hand. +This file describes the service and it's requirements. Important to note is the dependencies key, which contains rules for optional or required other services that are depended on for the developed service to successfully run. Formatting: - Serialization language:``.yaml`` @@ -12,14 +12,15 @@ Formatting: Below are the types and sub-type definitions, with necessary elaborations: -Manifest +Example ``manifest.yaml`` with field notes: + .. code:: yaml # manifest version compatibility ie. v0 (this is currently the only option) compat: v0 # service id, used for uniqueness and BE identification ie. bitcoind id: String - # semantic version for the release + # version number of the release conforming to the semantic versioning scheme version: String # display name of service title: String @@ -31,9 +32,9 @@ Manifest release_notes: String # denoting the existence of instructions.md has_instructions: Boolean - # required version of EmbassyOS to run service + # required semver version range of EmbassyOS to run service eg. ">=1.0.0" os_version_required: VersionReq - # recommended version of EmbassyOS to run service + # recommended semver version range of EmbassyOS to run service eg."^1.0.0" os_version_recommended: VersionReq # a list of objects of ports to run the service on localhost and tor ports: @@ -56,20 +57,39 @@ Manifest # A map of dependent services, see below for more details dependencies: Dependencies -Version -.. code:: yaml - - @aiden define type if more than string - -VersionReq -.. code:: yaml - - @aiden define type if more than string - - Dependencies ------------ +The key of each field in the dependencies object is the lowercase, kebab-case app ID of the service that is depended on. Each dependency contains a set of rules that need to be fulfilled as true if the dependency is to be properly installed. The interface should provide suggestions for the behavior if the denoted rule cannot be met with previous configurations. + +Let's take this snippet for example: + +.. code:: yaml + + ... + dependencies: + btc-rpc-proxy: + version: "^0.1.0" + optional: Can configure an external bitcoin node. + description: Required for fetching validated blocks. + config: + - rule: '''users.*.name = "c-lightning"' + description: 'Must have an RPC user named "c-lightning"' + suggestions: + - PUSH: + to: 'users' + value: + name: c-lightning + ... + +.. role:: raw-html(raw) + :format: html +:raw-html:`
` + +The service ``btc-rpc-proxy`` is a dependency of the service ``c-lightning``. ``c-lightning`` requires it to be installed at a version >=0.1.0 <0.2.0. There exists a rule that states the config option ``user.name`` must be equal to "c-lightning". If this value does not exist for ``user.name`` when accessed, ``PUSH`` the value "c-lighting" to the field. + +Types for ``manifest.yaml`` fields: + .. code:: typescript interface Dependencies [{ @@ -117,7 +137,7 @@ Dependencies ---- -Examples: +Examples of actual ``manifest.yaml`` files for existing services: .. code:: yaml