Subcomponent Configuration Language =================================== Subcomponent uses its own configuration language to describe the different components and the interactions they have with each other. This language, a bit unusual is loosely based on the Edje_ syntax. Brief Overview --------------- It is a descriptive configuration language that allows to store uniquely identified, typed key-value pairs. It exposes two main concepts: - *properties* - and *blocks*. Before going in the details of properties and blocks, here is a simple code example: .. code:: javascript subcomponents { my-component { name: "A pretty name"; path: "clone-me-here"; fetch { git { url: "git://example.com/repo.git", "https://example2.com/repo.git"; branch: "master"; clone-recursive: false; } } } } By writing the above code, you actually described a component named ``my-component``, that you described with ``A pretty name``. It will be retrieved at ``clone-me-here/``, using the *fetch method* **git**. You provided two URLs that can be used to retrieve the component. If for some reason the first URL fails (firewall issue, mirror down, ...), the other URL will be used to fetch the component. It will be retrieved on branch ``master``, and every time you update the component, it will re-sync itself with upstream changes. It will also not clone its submodules, as you explicitely disabled them. All of this is possible by setting *properties* among some *blocks*. A *property* is expressed within a block as its name, followed by a column. ``url`` and ``branch`` for instance are two properties. It shall be followed by the value to be affected to the property, and be terminated by a semicolumn. A property holds a **typed value**. Passing an invalid type to a propery causes the subcomponent compiler to throw an error. For instance, if you had written ``clone-recursive: "false";``, subcomponent would have refused you to pass a string to a property that expects a boolean value. Types of properties are written in the parser and cannot be bypassed. The supported types are: - *boolean*: expects ``true`` or ``false``; - *string*: expects an expression encompassed between two double quotes; - *composite list*: a finite set of values of the same type. The ``url`` property in the previous example is a list of strings. Two elements are separated by a comma. Lists of lists are not possible, due to the syntax of the list itself. As stated earlier, a *property* can only be contained in a *block*. A *block* holds its name and a finite set of properties. Blocks cannot be contained by properties. In the previous example, ``subcomponents``, ``my-component``, ``fetch`` and ``git`` are four blocks. The properties and blocks they contain are enclosed between one opening and one closing braces. The text written just before opening the curly brace defines the name of the block. Two properties that are on the same block hierarchy level cannot share the same name. Syntactic notes --------------- Blocks and properties are *identifiers* at a lexical level. An identifier: - can start with: a letter (lowercase or uppercase) or an underscore; - contain letters, digits, underscores or hyphens. Subcomponent support C99 comments: multi-lines and single-line: - `//` tells to ignore everything until a newline; - `/*` and `*/` ignore all text in between. Whitespaces are syntactically equivalent as comments. Describing a component ---------------------- Components are *blocks* contained in the **subcomponents** block. There is virtually no limitation on the number of described component. Note that two components cannot have the same name. A component can the following properties in its top-level block: - ``name``, a *string* that describes the component in a short sentence, - ``path``, a *string* that defines The path where the component will be made available. If it is not absolute, it will be interpreted as relative to the working directory of the subcomponent process that retrieved the component. A component then **must** define a ``fetch`` block. The ``fetch`` block shall contain one or more blocks that describe each a different *fetch method*. A *fetch method* is the subcomponent term to describe the means to make a component available to the user. If several *fetch methods* are described, the first one to be tried will be the first described. If it fails, the next one is tried, on so on, sequentially. ``git`` is currently the only fetch method that subcomponent implements. Every single fetch method implement one propery in common: ``url``, which is a list of strings. Each string element shall contain a URL that can be used by the fetch method to retrieve the component. It is mandatory to affect this property with a value. It can be a list of one element (equivalent to a single string). How the URL will be actually used is up to the underlying fetch method. If a fetch method fails to retrieve the component using an URL item, it will try the following one. This mechanism allows subcomponent to offer a resilient way to retrieve components. Imagine that you want to fetch a component host on some server, but at this precise instant, you are out of luck, the server is down... if you provided a fallback URL, set a known mirror, you can still get your component! The Git fetch method ~~~~~~~~~~~~~~~~~~~~ Exactly one of the following properties must be defined. They are mutually exclusive: - ``branch``: a *string* that indicates which git branch shall be fetched, - ``commit``: a *string* that indicates which git commit shall be checkouted, - ``tag``: a *string* that indicated which git tag shall be retrieved. Then, the following properties can be set to obtain better performances: - ``clone-recusrive``: a *boolean* that is *true* by default. If your component contains git submodules, they will be automatically fetched if this property is *true*. Otherwise they will be ignored. - ``shallow``: a *boolean* that is *false* by default. If enabled, the component will be shallow-cloned. This option is reserved to fetching *branches*. - ``shallow-submodules``: a *boolean* that is *false* by default. If tenabled, the component can shallow-clone its git submodules. - ``remote``: a *string* that defaults to *subcomponent*. It is the name of the git remote that subcomponent expects to have an exclusive access on. Be aware that using shallowing can be hazardeous if not well-understood. If you update your component from a first shallow clone to another revision, subcomponent will be obliged to unshallow the repository, leading to higher fetching times. Shallowing is great when you know exactly what you are doing though. Some implementation details --------------------------- It is worth noting that subcomponent code is implicitely encompassed inside a *unique anonymous block*: a block without a name. Only one does exist, and it contains everything else: blocks and properties. To uniquely identify a property among others, using just their name is not sufficient. Once the subcomponent compiler has processed every single file that was provided to him, it has generated a key-value database that is a bit hash table. Imagine the following block at the top-level of subcomponent: .. code:: javascript a_block { another_block { a_boolean_property: true; } } As stated before, this block is actually contained by the unique anonymous block. The property ``a_boolean_property`` is actually named ``/a_block/another_block/a_boolean_property`` in the database. .. _Edje: https://www.enlightenment.org/themes/start