Builds ====== - [Overview of the build process](#overview-of-the-build-process) - [The "_compilation_" process](#the-_compilation_-process) - [Extending an entity](#extending-an-entity) - [Overriding entities and build scenarii](#overriding-entities-and-build-scenarii) - [The "_detemplatization_" process](#the-_detemplatization_-process) - [Post-process actions](#post-process-actions) [:back:][Documentation root] # Overview of the build process You build a [buildable] entity by issuing `power_stencil build /`. If you try to build an entity which is not buildable, the process fail with an error message. Let's describe a bit more in detail what this build process is: ![entity-build-flow] Humm :thinking:... What is this _compilation_ step that appears on this schema ??! I thought Ruby was an interpreted language... I guess you understood this is not a "real" _compilation_ process we are discussing about here, like in the sense of compiling some Java or C code. # The "_compilation_" process The mechanism of the compilation is coming from the [universe_compiler] Gem, but the two following features are the ones you really need to understand. :information_source: The compilation process can be applied to any entity, ie it doesn't need to be [buildable] (see in next paragraph how to run the compilation). But an entity needs to be [buildable] to use `power_stencil build` which corresponds actually to _compilation_ + _detemplatization_. ## Extending an entity We could describe this mechanism as inheritance at entity level (not entity type !), said differently this a way for an entity to _inherit_ (or _extend_ in the `PowerStencil` paradigm) the content of another entity. Let's try this with two `base_entities`. First let's define a root entity to inherit from: $ power_stencil create base_entity/root_entity --edit and set the folloging content: ```yaml --- !ruby/object:PowerStencil::SystemEntityDefinitions::ProjectEntity :name: root_entity :property_root: value in root_entity :array_root: - value A - value B :hash_root: item1: value 1 item2: value 2 ``` Now let's create a second entity to extend this one: $ power_stencil create base_entity/inherited_entity --edit And define its content as: ```yaml --- !ruby/object:PowerStencil::SystemEntityDefinitions::ProjectEntity :name: inherited_entity :a_specific_property: This one only exists in inherited entity :extends: !psref type: :base_entity name: root_entity :array_root: - value from inherited_entity :hash_root: item2: value2 but from inherited item3: value3 ``` Once done, if we do a `power_stencil get base_entity/inherited_entity --raw` this exactly what will get. But `PowerStencil` gives a possibility to see how this entity will look like after the compilation process using the `--compiled` option: So if you do $ power_stencil get base_entity/inherited_entity --raw --compiled This is what you get: ```yaml --- !ruby/object:PowerStencil::SystemEntityDefinitions::ProjectEntity :name: inherited_entity :a_specific_property: This one only exists in inherited entity :property_root: value in root_entity :array_root: - value from inherited_entity :hash_root: item1: value 1 item2: value2 but from inherited item3: value3 :extends: !psref type: :base_entity name: root_entity ``` You can notice that this second object looks now like a merged entity. Here are the rules of the merge: - the entity extending another one has always precedence, meaning that if a property is defined in both, only the latter is kept. - hashes are treated a bit differently as a real merge of the two hashes is performed (which is not the case of arrays or simple properties). - the `extends` property is kept even after compilation for reference (meaning that in a template you can still access values of the entity you are extending). :warning: **The entity you extend has to be of the same entity type** or the compilation will fail (actually unless you created the entity yaml file manually, the framework won't even let you save it if the entity inheritance is invalid) ! ## Overriding entities and build scenarii You may have noticed from the output of `power_stencil info` that there is a type of entity named `entity_override`. This is a very specific type of entity linked to the compilation process. The goal of this specific entity is to provide a mechanism to override some of the properties of other entities in the scope of a _build scenario_. This is really a feature turned towards testing possibilities, by it for developers or ops, and as such generally `entity_override` are often created as [local entities] (although they really could be created as standard versioned entities). Let's create our first override: $ power_stencil create entity_override/test_override --edit --user-storage And define its content: ```yaml --- !ruby/object:UniverseCompiler::Entity::Override :overrides: - !psref type: :base_entity name: inherited_entity :name: test_override :property_from_overide: foo :scenario: dev_tests :hash_root: item3: overridden value ``` :information_source: First thing to notice is that an `entity_override` is **able to override properties of multiples entities at once** ! Hence the fact the `overrides` property is an array. :information_source: **There is no constraint on the entity types this override applies to** (as opposed to the extend mechanism) The `scenario` property specifies the build scenario this override will be applied for. :information_source: You can define as many `entity_overrides` as you want for a specific build scenario. Ok, then what happens to `base_entity/inherited_entity` ? As expected, without specifying a build scenario nothing changes $ power_stencil get base_entity/inherited_entity --raw --compiled ```yaml --- !ruby/object:PowerStencil::SystemEntityDefinitions::ProjectEntity :name: inherited_entity :property_root: value in root_entity :array_root: - value from inherited_entity :hash_root: item1: value 1 item2: value2 but from inherited item3: value3 :a_specific_property: This one only exists in inherited entity :extends: !psref type: :base_entity name: root_entity ``` But if you specify the dev_tests scenario: $ power_stencil get base_entity/inherited_entity --raw --compiled --scenario dev_tests ```yaml --- !ruby/object:PowerStencil::SystemEntityDefinitions::ProjectEntity :name: inherited_entity :property_root: value in root_entity :array_root: - value from inherited_entity :hash_root: item1: value 1 item2: value2 but from inherited item3: overridden value :a_specific_property: This one only exists in inherited entity :extends: !psref type: :base_entity name: root_entity :property_from_overide: foo ``` :information_source: You can notice that **the override mechanism occurs after the extend mechanism**, and both can be used on the same entities. :information_source: The `--scenario` command line option obviously exists as well for the `build` sub-command so that you can run a build in the context of a scenario. This override mechanism is really a great way for developers or ops to test something while being sure to avoid introducing errors in the entities repository (by "temporarily patching" an entity to perform a test... and then committing it by mistake... smells like real life, doesn't it ?). # The "_detemplatization_" process Now we have almost everything we need: - We have a nice traceable mechanism to manage [entities] (our shared data), including [special features to keep them dry](#extending-an-entity) and perform [test scenarii](#overriding-entities-and-build-scenarii). - We have a pluggable [templating mechanism][templates], with mechanisms to decide to [which files it may be applied to](#xxx_ignore-files) (or actually which files it should _not_ apply to). When we are using `power_stencil build`, the entities are first compiled then templates associated to the entity specified are used in order to generate the "_detemplatized_" files. Those generated files are located in a subfolder of the `build` directory of the project (which by default is not versioned as per `.git_ignore` located at the root folder of the project). The pattern for the name of the folder where the files are generated is the following: `build/_/_` Why is there 2 times entity type and name ? This is because `power_stencil build` accepts more than one entity as parameter and in this case the first level would be the type and name of all the entities concatenated and then there would be second level folders, one per per entity. # Post-process actions By default `PowerStencil` proposes the `simple_exec` entity type which provides the possibility to run any executable after the build completed. By default it will run a script `main.sh` (automatically generated), but this is completely customizable. When you create a `simple_exec` entity: $ power_stencil create simple_exec/example Actually two entities are created under the hood: ```shell $ power_stencil get example --regexp --- PowerStencil::SystemEntityDefinitions::SimpleExec: :type: :simple_exec :fields: :name: example :post_process: !psref type: :process_descriptor name: simple_exec_example.process --- PowerStencil::SystemEntityDefinitions::ProcessDescriptor: :type: :process_descriptor :fields: :name: simple_exec_example.process :process: "./main.sh" ``` It creates a `process_descriptor` entity (which is referenced from the `simple_exec` entity as the `post_process` field). So you can edit this process descriptor and define there whatever executable you want to be called. This should already cover 95% of everything needed. If you want to do something more custom after the build process completed, this is where you will have to do a [plugin][plugins]. [:back:][Documentation root] [Documentation root]: ../README.md "Back to documentation root" [entities]: entities.md "Entities in PowerStencil" [templates]: templates.md "Templates in PowerStencil" [plugins]: plugins.md "Plugins in PowerStencil" [buildable]: entities.md#buildable-and-buildable_by "How to make an entity buildable ?" [local entities]: entities.md#local-unversioned-entities "Local unversioned entities" [entity-build-flow]: images/power-stencil-entity-build.svg [universe_compiler]: https://gitlab.com/tools4devops/universe_compiler "The underlying engine to manage entities and compilation !"