Blob Blame History Raw
Understanding Modules
=====================
Alain Reguera Delgado <al@centos.org.cu>
v0.1, Oct 2013

Overview
--------

From version 0.5, the *centos-art.sh* script introduces the idea of
modules to its base design. Modules are a collection of functions
written in Bash that can call one another to create individual
execution environments. They may be nested to achieve high levels of
maintainability and extensibility. This make possible for modules
writers to divide complicated tasks into smaller tasks that can be
easier to debug, maintain and share with other modules efficiently
(e.g., instead of loading modules all at once, they are only loaded at
demand and unset once they conclude their execution).

This article describes the modular design of *centos-art.sh* script.
It is a good place for you to start if you are planning to contribute
new module environments to *centos-art.sh* script or want to know more
about how it works. The next section delves into what a module
environment is, the three module types you can find in it and the
correct way of execute each one of them.

[[module-environment]]
Module Environment
------------------

When you execute the *centos-art.sh* script you create an execution
environment in which variables and functions are defined. The
execution environment is the higher environment inside *centos-art.sh*
script it is considered to have a ``global'' scope, so variables and
functions defined in it are always available for any function
execution made from it. You can control this execution environment
through the files +centos-art.sh+ and +centos-art.conf.sh+. These
files don't provide too much functionality so module environments are
executed inside it to extend its functionality.

Module environments are made of small functions that perform small
tasks and can be further executed in a specific order to create the
desired result.  Module environments are executed and destroyed at
demand.  Inside *centos-art.sh*, module environments can be either
``parent modules,'' ``child modules,'' or ``sibling modules.''

Parent Modules
~~~~~~~~~~~~~~

Parent modules are initiated by executing the
*tcar_setModuleEnvironment* function with the *-t parent* option set
on it. Parent modules are very simple in design and you can use them
to implement simple solutions quickly. Normally, when you execute a
parent module, you initiate the highest module environment possible
inside *centos-art.sh* script.  Because of such high scope, parent
modules are frequently used to define module's global variables,
interpret module-specific options passed through the command-line and
execute the appropriate actions based on them.

In <<debug-parent-modules>>, we have executed the *hello* module with
the *--greeting=hi* and *--debug* options through the command-line. In
this example, *centos-art.sh* script executes a parent module named
*hello*, processes the module-specific options passed through the
command-line, prints a greeting message to standard output and exits
successfully.

[[debug-parent-modules]]
.Debugging execution of parent modules
======================================================================
----------------------------------------------------------------------
Thu 10 Oct 2013 11:53:28 PM CDT =========================>      [0] | main
Thu 10 Oct 2013 11:53:28 PM CDT TCAR_MODULE_BASEDIR             Automation/Modules
Thu 10 Oct 2013 11:53:28 PM CDT TCAR_MODULE_NAME                [0]=hello
Thu 10 Oct 2013 11:53:28 PM CDT TCAR_MODULE_TYPE                parent
Thu 10 Oct 2013 11:53:28 PM CDT TCAR_MODULE_ARGUMENT            --greeting=hi  
Thu 10 Oct 2013 11:53:28 PM CDT TCAR_MODULE_LIST                hello|help|locale|prepare|render|tuneup|vcs
Thu 10 Oct 2013 11:53:28 PM CDT TCAR_MODULE_DIR                 Automation/Modules/Hello
Thu 10 Oct 2013 11:53:28 PM CDT TCAR_MODULE_DIR_MODULES         Automation/Modules/Hello/Modules
Thu 10 Oct 2013 11:53:28 PM CDT TCAR_MODULE_DIR_MANUALS         Automation/Modules/Hello/Manuals
Thu 10 Oct 2013 11:53:28 PM CDT TCAR_MODULE_DIR_LOCALES         Automation/Modules/Hello/Locales
Thu 10 Oct 2013 11:53:28 PM CDT TCAR_MODULE_DIR_CONFIGS         Automation/Modules/Hello/Configs
Thu 10 Oct 2013 11:53:28 PM CDT TCAR_MODULE_INIT_FILE           Automation/Modules/Hello/hello.sh
Thu 10 Oct 2013 11:53:28 PM CDT TEXTDOMAIN                      hello.sh
Thu 10 Oct 2013 11:53:28 PM CDT TEXTDOMAINDIR                   Automation/Modules/Hello/Locales
Thu 10 Oct 2013 11:53:28 PM CDT export -f                       hello
Thu 10 Oct 2013 11:53:28 PM CDT export -f                       hello_getOptions
Thu 10 Oct 2013 11:53:28 PM CDT ------------------------->      hello --greeting=hi  
hi             
Thu 10 Oct 2013 11:53:28 PM CDT <-------------------------      hello 
Thu 10 Oct 2013 11:53:28 PM CDT unset -f                        hello
Thu 10 Oct 2013 11:53:28 PM CDT unset -f                        hello_getOptions
Thu 10 Oct 2013 11:53:28 PM CDT <=========================      [0] | main
----------------------------------------------------------------------
======================================================================

<<debug-parent-modules>> describes an entire module environment in
action. With this information you can create your own module
environment, already. However, when your module is getting too much
complicated you probably want to divide it in smaller pieces that you
can execute accordingly, based on the purpose you defined for it. Such
kind of division can be implemented through ``modules' related
functions.''

Module's related functions are stored in the same directory of your
module's initialization file and they are very useful when you are
refactoring it.  Definitions of module's related functions are loaded
before the initialization file does, so it is a good practice to
create them only when you are absolutely sure they will be executed in
your module. Otherwise they may be loaded and never be used, which
make the script to waste memory unnecessarily. In these cases, when
you need to divide the logic of a module in smaller pieces where these
pieces may or may not be executed based on specific conditions, all
taking place in the same interaction, then using ``_child modules_''
is a more suitable approach.

[[child-modules]]
Child Modules
~~~~~~~~~~~~~

Child modules are initiated by executing the
*tcar_setModuleEnvironment* function with the *-t child* option set on
it.  Child modules have the characteristic of being nested modules.
They cannot be executed from the command-line. Normally, child modules
are executed from parent modules but they can be executed from other
child modules, too.  When several child modules are executed in one
single interaction of *centos-art.sh*, they create a chain of modules.
A chain of modules is very useful in situations where you want to
divide one large task into smaller tasks and also control which of
these smaller tasks is executed based on specific conditions (e.g.,
you may want to render images or documentation, but not both, in one
single interaction of *centos-art.sh* script).  In a chain of modules,
lower modules in the chain (those started last) have access to
information set by modules higher in the chain (those started first),
but not the opposite. When processing information this way, modules
aren't destroyed until the last module executed in the chain has
finished its work (e.g., all the commands inside it have been
executed). At that point, child modules are destroyed in the reverse
order they were executed.

For example, when you execute the *hello* module with both *--debug*
and *--upper* option, *centos-art.sh* script creates a chain of three
modules to produce the greeting message.  Firstly, it begins by
executing the parent module named *hello*, then it continues with the
child module named *output* which in turn executes the child module
name *lower* to finally print the expected greeting message.  In this
example, the module named *lower* is the last module in the chain of
executed modules. It has access to all information defined by earlier
modules (e.g., in *hello* and *output* modules) and none of its earlier
modules will be destroyed until it has finished its work. This process
becomes more visible when you take a look at <<debug-child-modules>>.

[[debug-child-modules]]
.Debugging execution of child modules
======================================================================
----------------------------------------------------------------------
Thu 10 Oct 2013 11:52:41 PM CDT =========================>      [0] | main
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_BASEDIR             Automation/Modules
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_NAME                [0]=hello
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_TYPE                parent
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_ARGUMENT            --upper --greeting=hi  
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_LIST                hello|help|locale|prepare|render|tuneup|vcs
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_DIR                 Automation/Modules/Hello
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_DIR_MODULES         Automation/Modules/Hello/Modules
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_DIR_MANUALS         Automation/Modules/Hello/Manuals
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_DIR_LOCALES         Automation/Modules/Hello/Locales
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_DIR_CONFIGS         Automation/Modules/Hello/Configs
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_INIT_FILE           Automation/Modules/Hello/hello.sh
Thu 10 Oct 2013 11:52:41 PM CDT TEXTDOMAIN                      hello.sh
Thu 10 Oct 2013 11:52:41 PM CDT TEXTDOMAINDIR                   Automation/Modules/Hello/Locales
Thu 10 Oct 2013 11:52:41 PM CDT export -f                       hello
Thu 10 Oct 2013 11:52:41 PM CDT export -f                       hello_getOptions
Thu 10 Oct 2013 11:52:41 PM CDT ------------------------->      hello --upper --greeting=hi  
Thu 10 Oct 2013 11:52:41 PM CDT =========================>      [1] | hello
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_BASEDIR             Automation/Modules/Hello/Modules
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_NAME                [1]=output
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_TYPE                child
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_ARGUMENT             
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_LIST                output
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_DIR                 Automation/Modules/Hello/Modules/Output
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_DIR_MODULES         Automation/Modules/Hello/Modules/Output/Modules
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_DIR_MANUALS         Automation/Modules/Hello/Modules/Output/Manuals
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_DIR_LOCALES         Automation/Modules/Hello/Modules/Output/Locales
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_DIR_CONFIGS         Automation/Modules/Hello/Modules/Output/Configs
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_INIT_FILE           Automation/Modules/Hello/Modules/Output/output.sh
Thu 10 Oct 2013 11:52:41 PM CDT TEXTDOMAIN                      output.sh
Thu 10 Oct 2013 11:52:41 PM CDT TEXTDOMAINDIR                   Automation/Modules/Hello/Modules/Output/Locales
Thu 10 Oct 2013 11:52:41 PM CDT export -f                       output
Thu 10 Oct 2013 11:52:41 PM CDT ------------------------->      output  
Thu 10 Oct 2013 11:52:41 PM CDT =========================>      [2] | output
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_BASEDIR             Automation/Modules/Hello/Modules/Output/Modules
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_NAME                [2]=upper
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_TYPE                child
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_ARGUMENT             
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_LIST                camel|lower|random|upper
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_DIR                 Automation/Modules/Hello/Modules/Output/Modules/Upper
Thu 10 Oct 2013 11:52:41 PM CDT TCAR_MODULE_DIR_MODULES         Automation/Modules/Hello/Modules/Output/Modules/Upper/Modules
Thu 10 Oct 2013 11:52:42 PM CDT TCAR_MODULE_DIR_MANUALS         Automation/Modules/Hello/Modules/Output/Modules/Upper/Manuals
Thu 10 Oct 2013 11:52:42 PM CDT TCAR_MODULE_DIR_LOCALES         Automation/Modules/Hello/Modules/Output/Modules/Upper/Locales
Thu 10 Oct 2013 11:52:42 PM CDT TCAR_MODULE_DIR_CONFIGS         Automation/Modules/Hello/Modules/Output/Modules/Upper/Configs
Thu 10 Oct 2013 11:52:42 PM CDT TCAR_MODULE_INIT_FILE           Automation/Modules/Hello/Modules/Output/Modules/Upper/upper.sh
Thu 10 Oct 2013 11:52:42 PM CDT TEXTDOMAIN                      upper.sh
Thu 10 Oct 2013 11:52:42 PM CDT TEXTDOMAINDIR                   Automation/Modules/Hello/Modules/Output/Modules/Upper/Locales
Thu 10 Oct 2013 11:52:42 PM CDT export -f                       upper
Thu 10 Oct 2013 11:52:42 PM CDT ------------------------->      upper  
HI             
Thu 10 Oct 2013 11:52:42 PM CDT <-------------------------      upper  
Thu 10 Oct 2013 11:52:42 PM CDT unset -f                        upper
Thu 10 Oct 2013 11:52:42 PM CDT <=========================      [2] | output 
Thu 10 Oct 2013 11:52:42 PM CDT <-------------------------      output  
Thu 10 Oct 2013 11:52:42 PM CDT unset -f                        output
Thu 10 Oct 2013 11:52:42 PM CDT <=========================      [1] | hello 
Thu 10 Oct 2013 11:52:42 PM CDT <-------------------------      hello 
Thu 10 Oct 2013 11:52:42 PM CDT unset -f                        hello
Thu 10 Oct 2013 11:52:42 PM CDT unset -f                        hello_getOptions
Thu 10 Oct 2013 11:52:42 PM CDT <=========================      [0] | main 
----------------------------------------------------------------------
======================================================================

The module environment described in <<debug-child-modules>> shows the
child modules' ability of reducing scope as they get deeper in the
chain of executed modules. However, child modules lack the possibility
of nest modules that share the same scope. For example, in the *hello*
module described above, you cannot execute the modules *lower*  or
*upper* from *camel* module, as if they were child modules of it.
That is not possible because they all have the same scope, which is,
to print the greeting message to standard output. Child modules are
conceived to reduce the module scope as new child modules are
executed. When you need to execute new module environments and, also,
retain the last scope from which the new module is executed, you need
to use ``_sibling modules_,'' instead.

Sibling Modules
~~~~~~~~~~~~~~~

Sibling modules are initiated by executing the
*tcar_setModuleEnvironment* function with the *-t sibling* option set
on it.  Sibling modules are another type of nested modules but, in
contrast with child modules, sibling modules cannot be executed from
parent modules. Normally, sibling modules are executed from other
sibling modules but, considering the context, they can be executed
from child module too, to initiate sibling processing. When several
siblings modules are executed, they also build a chain of modules. In
contrast with the chain of child modules, the chain of sibling modules
destroys the last sibling module executed before executing the next
sibling module. This make the chain to stop its growing at sibling
module processing, unless you call a child module from a sibling
module. In this case, the chain expansion would continue as long as
the number of child modules you execute. This process becomes more
visible when you take a look at <<debug-sibling-modules>>.

In <<debug-sibling-modules>>, we've executed the *hello* module with
the *--greeting=hi*, *--camel*, and *--debug* options. In this
example, *centos-art.sh* script executes the *hello* module then the
*output* module which in turn executes the *camel* module. At this
point, can appreciate how the chain of modules stop growing. Observe
that *camel* module has gained the position 2 in the chain of modules
and executes the *upper* module which takes the position 3, as
expected. Now, when *upper* module finishes its work it is destroyed
and the module's counter is reset to its previous value which is 2
(the one set by *camel* module). Then, *camel* executes the *lower*
module which take position 3 at the chain of modules until it
finishes. When it finishes, the *camel* module finishes its work and
is destroyed, then *output*, then *hello*.

[[debug-sibling-modules]]
.Debugging execution of sibling modules
======================================================================
----------------------------------------------------------------------
Thu 10 Oct 2013 11:51:42 PM CDT =========================>      [0] | main
Thu 10 Oct 2013 11:51:42 PM CDT TCAR_MODULE_BASEDIR             Automation/Modules
Thu 10 Oct 2013 11:51:42 PM CDT TCAR_MODULE_NAME                [0]=hello
Thu 10 Oct 2013 11:51:42 PM CDT TCAR_MODULE_TYPE                parent
Thu 10 Oct 2013 11:51:42 PM CDT TCAR_MODULE_ARGUMENT            --camel --greeting=hi  
Thu 10 Oct 2013 11:51:42 PM CDT TCAR_MODULE_LIST                hello|help|locale|prepare|render|tuneup|vcs
Thu 10 Oct 2013 11:51:42 PM CDT TCAR_MODULE_DIR                 Automation/Modules/Hello
Thu 10 Oct 2013 11:51:42 PM CDT TCAR_MODULE_DIR_MODULES         Automation/Modules/Hello/Modules
Thu 10 Oct 2013 11:51:42 PM CDT TCAR_MODULE_DIR_MANUALS         Automation/Modules/Hello/Manuals
Thu 10 Oct 2013 11:51:42 PM CDT TCAR_MODULE_DIR_LOCALES         Automation/Modules/Hello/Locales
Thu 10 Oct 2013 11:51:42 PM CDT TCAR_MODULE_DIR_CONFIGS         Automation/Modules/Hello/Configs
Thu 10 Oct 2013 11:51:42 PM CDT TCAR_MODULE_INIT_FILE           Automation/Modules/Hello/hello.sh
Thu 10 Oct 2013 11:51:42 PM CDT TEXTDOMAIN                      hello.sh
Thu 10 Oct 2013 11:51:42 PM CDT TEXTDOMAINDIR                   Automation/Modules/Hello/Locales
Thu 10 Oct 2013 11:51:43 PM CDT export -f                       hello
Thu 10 Oct 2013 11:51:43 PM CDT export -f                       hello_getOptions
Thu 10 Oct 2013 11:51:43 PM CDT ------------------------->      hello --camel --greeting=hi  
Thu 10 Oct 2013 11:51:43 PM CDT =========================>      [1] | hello
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_BASEDIR             Automation/Modules/Hello/Modules
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_NAME                [1]=output
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_TYPE                child
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_ARGUMENT             
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_LIST                output
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR                 Automation/Modules/Hello/Modules/Output
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_MODULES         Automation/Modules/Hello/Modules/Output/Modules
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_MANUALS         Automation/Modules/Hello/Modules/Output/Manuals
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_LOCALES         Automation/Modules/Hello/Modules/Output/Locales
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_CONFIGS         Automation/Modules/Hello/Modules/Output/Configs
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_INIT_FILE           Automation/Modules/Hello/Modules/Output/output.sh
Thu 10 Oct 2013 11:51:43 PM CDT TEXTDOMAIN                      output.sh
Thu 10 Oct 2013 11:51:43 PM CDT TEXTDOMAINDIR                   Automation/Modules/Hello/Modules/Output/Locales
Thu 10 Oct 2013 11:51:43 PM CDT export -f                       output
Thu 10 Oct 2013 11:51:43 PM CDT ------------------------->      output  
Thu 10 Oct 2013 11:51:43 PM CDT =========================>      [2] | output
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_BASEDIR             Automation/Modules/Hello/Modules/Output/Modules
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_NAME                [2]=camel
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_TYPE                child
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_ARGUMENT             
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_LIST                camel|lower|random|upper
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR                 Automation/Modules/Hello/Modules/Output/Modules/Camel
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_MODULES         Automation/Modules/Hello/Modules/Output/Modules/Camel/Modules
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_MANUALS         Automation/Modules/Hello/Modules/Output/Modules/Camel/Manuals
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_LOCALES         Automation/Modules/Hello/Modules/Output/Modules/Camel/Locales
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_CONFIGS         Automation/Modules/Hello/Modules/Output/Modules/Camel/Configs
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_INIT_FILE           Automation/Modules/Hello/Modules/Output/Modules/Camel/camel.sh
Thu 10 Oct 2013 11:51:43 PM CDT TEXTDOMAIN                      camel.sh
Thu 10 Oct 2013 11:51:43 PM CDT TEXTDOMAINDIR                   Automation/Modules/Hello/Modules/Output/Modules/Camel/Locales
Thu 10 Oct 2013 11:51:43 PM CDT export -f                       camel
Thu 10 Oct 2013 11:51:43 PM CDT ------------------------->      camel  
Thu 10 Oct 2013 11:51:43 PM CDT =========================>      [3] | camel
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_BASEDIR             Automation/Modules/Hello/Modules/Output/Modules
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_NAME                [3]=upper
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_TYPE                sibling
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_ARGUMENT             
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_LIST                camel|lower|random|upper
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR                 Automation/Modules/Hello/Modules/Output/Modules/Upper
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_MODULES         Automation/Modules/Hello/Modules/Output/Modules/Upper/Modules
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_MANUALS         Automation/Modules/Hello/Modules/Output/Modules/Upper/Manuals
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_LOCALES         Automation/Modules/Hello/Modules/Output/Modules/Upper/Locales
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_CONFIGS         Automation/Modules/Hello/Modules/Output/Modules/Upper/Configs
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_INIT_FILE           Automation/Modules/Hello/Modules/Output/Modules/Upper/upper.sh
Thu 10 Oct 2013 11:51:43 PM CDT TEXTDOMAIN                      upper.sh
Thu 10 Oct 2013 11:51:43 PM CDT TEXTDOMAINDIR                   Automation/Modules/Hello/Modules/Output/Modules/Upper/Locales
Thu 10 Oct 2013 11:51:43 PM CDT export -f                       upper
Thu 10 Oct 2013 11:51:43 PM CDT ------------------------->      upper  
H              
Thu 10 Oct 2013 11:51:43 PM CDT <-------------------------      upper  
Thu 10 Oct 2013 11:51:43 PM CDT unset -f                        upper
Thu 10 Oct 2013 11:51:43 PM CDT <=========================      [3] | camel 
Thu 10 Oct 2013 11:51:43 PM CDT =========================>      [3] | camel
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_BASEDIR             Automation/Modules/Hello/Modules/Output/Modules
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_NAME                [3]=lower
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_TYPE                sibling
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_ARGUMENT             
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_LIST                camel|lower|random|upper
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR                 Automation/Modules/Hello/Modules/Output/Modules/Lower
Thu 10 Oct 2013 11:51:43 PM CDT TCAR_MODULE_DIR_MODULES         Automation/Modules/Hello/Modules/Output/Modules/Lower/Modules
Thu 10 Oct 2013 11:51:44 PM CDT TCAR_MODULE_DIR_MANUALS         Automation/Modules/Hello/Modules/Output/Modules/Lower/Manuals
Thu 10 Oct 2013 11:51:44 PM CDT TCAR_MODULE_DIR_LOCALES         Automation/Modules/Hello/Modules/Output/Modules/Lower/Locales
Thu 10 Oct 2013 11:51:44 PM CDT TCAR_MODULE_DIR_CONFIGS         Automation/Modules/Hello/Modules/Output/Modules/Lower/Configs
Thu 10 Oct 2013 11:51:44 PM CDT TCAR_MODULE_INIT_FILE           Automation/Modules/Hello/Modules/Output/Modules/Lower/lower.sh
Thu 10 Oct 2013 11:51:44 PM CDT TEXTDOMAIN                      lower.sh
Thu 10 Oct 2013 11:51:44 PM CDT TEXTDOMAINDIR                   Automation/Modules/Hello/Modules/Output/Modules/Lower/Locales
Thu 10 Oct 2013 11:51:44 PM CDT export -f                       lower
Thu 10 Oct 2013 11:51:44 PM CDT ------------------------->      lower  
i              
Thu 10 Oct 2013 11:51:44 PM CDT <-------------------------      lower  
Thu 10 Oct 2013 11:51:44 PM CDT unset -f                        lower
Thu 10 Oct 2013 11:51:44 PM CDT <=========================      [3] | camel 
Thu 10 Oct 2013 11:51:44 PM CDT <-------------------------      camel  
Thu 10 Oct 2013 11:51:44 PM CDT unset -f                        camel
Thu 10 Oct 2013 11:51:44 PM CDT <=========================      [2] | output 
Thu 10 Oct 2013 11:51:44 PM CDT <-------------------------      output  
Thu 10 Oct 2013 11:51:44 PM CDT unset -f                        output
Thu 10 Oct 2013 11:51:44 PM CDT <=========================      [1] | hello 
Thu 10 Oct 2013 11:51:44 PM CDT <-------------------------      hello 
Thu 10 Oct 2013 11:51:44 PM CDT unset -f                        hello
Thu 10 Oct 2013 11:51:44 PM CDT unset -f                        hello_getOptions
Thu 10 Oct 2013 11:51:44 PM CDT <=========================      [0] | main
----------------------------------------------------------------------
======================================================================

<<debug-sibling-modules>> shows a single interaction of
*centos-art.sh* script executing different types of modules. Normally,
one module is executed at some point and destroyed at the same point
when it has finished its work, however, what if the next immediate
module you are about to execute is the same module you are about to
destroyed? This is, you need to execute the last module in the chain
of executed modules again, but, this time, from itself.  In cases like
this, the *centos-art.sh* script doesn't destroy the last module.  It
cannot, because you are certainly executing a new module from itself,
so it has to wait for this new call to finish in order to be
destroyed. This kind of processing is known as _processing modules
recursively._

Recursive Modules
~~~~~~~~~~~~~~~~~

When one module environment executes itself we are in presence of a
recursive module execution. The execution of modules recursively
doesn't destroy the last module in the chain of executed modules and
doesn't increment or decrement the module counter either. The module
counter is somehow frozen until a different module environment is
executed. In this cases, the last module environment remains in memory
for the new module execution to make use of. This process becomes more visible
when you take a look at <<debug-recursive-modules>>.

[CAUTION]
When you execute modules recursively, you should be very careful not
to get trapped into an endless loop.

In <<debug-recursive-modules>>, we've executed the *hello* module with
the *--greeting=hello*, *--random*, and *--debug* options. In this
example, *centos-art.sh* script executes a parent module named *hello*
which in turn executes a child module named *output* which in turn
executes a child module named *random*. At this point, the *random*
modules executes itself five times (the number of characters passed as
value to greeting option) to print out random letters from the
greeting message. The output may have no much sense on itself but the
related debugging information helps to understand the execution of
modules recursively.

[[debug-recursive-modules]]
.Processing execution of modules recursively
======================================================================
----------------------------------------------------------------------
Thu 10 Oct 2013 11:50:03 PM CDT =========================>      [0] | main
Thu 10 Oct 2013 11:50:03 PM CDT TCAR_MODULE_BASEDIR             Automation/Modules
Thu 10 Oct 2013 11:50:03 PM CDT TCAR_MODULE_NAME                [0]=hello
Thu 10 Oct 2013 11:50:03 PM CDT TCAR_MODULE_TYPE                parent
Thu 10 Oct 2013 11:50:03 PM CDT TCAR_MODULE_ARGUMENT            --random --greeting=Hello  
Thu 10 Oct 2013 11:50:03 PM CDT TCAR_MODULE_LIST                hello|help|locale|prepare|render|tuneup|vcs
Thu 10 Oct 2013 11:50:03 PM CDT TCAR_MODULE_DIR                 Automation/Modules/Hello
Thu 10 Oct 2013 11:50:03 PM CDT TCAR_MODULE_DIR_MODULES         Automation/Modules/Hello/Modules
Thu 10 Oct 2013 11:50:03 PM CDT TCAR_MODULE_DIR_MANUALS         Automation/Modules/Hello/Manuals
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_DIR_LOCALES         Automation/Modules/Hello/Locales
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_DIR_CONFIGS         Automation/Modules/Hello/Configs
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_INIT_FILE           Automation/Modules/Hello/hello.sh
Thu 10 Oct 2013 11:50:04 PM CDT TEXTDOMAIN                      hello.sh
Thu 10 Oct 2013 11:50:04 PM CDT TEXTDOMAINDIR                   Automation/Modules/Hello/Locales
Thu 10 Oct 2013 11:50:04 PM CDT export -f                       hello
Thu 10 Oct 2013 11:50:04 PM CDT export -f                       hello_getOptions
Thu 10 Oct 2013 11:50:04 PM CDT ------------------------->      hello --random --greeting=Hello  
Thu 10 Oct 2013 11:50:04 PM CDT =========================>      [1] | hello
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_BASEDIR             Automation/Modules/Hello/Modules
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_NAME                [1]=output
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_TYPE                child
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_ARGUMENT             
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_LIST                output
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_DIR                 Automation/Modules/Hello/Modules/Output
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_DIR_MODULES         Automation/Modules/Hello/Modules/Output/Modules
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_DIR_MANUALS         Automation/Modules/Hello/Modules/Output/Manuals
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_DIR_LOCALES         Automation/Modules/Hello/Modules/Output/Locales
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_DIR_CONFIGS         Automation/Modules/Hello/Modules/Output/Configs
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_INIT_FILE           Automation/Modules/Hello/Modules/Output/output.sh
Thu 10 Oct 2013 11:50:04 PM CDT TEXTDOMAIN                      output.sh
Thu 10 Oct 2013 11:50:04 PM CDT TEXTDOMAINDIR                   Automation/Modules/Hello/Modules/Output/Locales
Thu 10 Oct 2013 11:50:04 PM CDT export -f                       output
Thu 10 Oct 2013 11:50:04 PM CDT ------------------------->      output  
Thu 10 Oct 2013 11:50:04 PM CDT =========================>      [2] | output
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_BASEDIR             Automation/Modules/Hello/Modules/Output/Modules
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_NAME                [2]=random
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_TYPE                child
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_ARGUMENT             
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_LIST                camel|lower|random|upper
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_DIR                 Automation/Modules/Hello/Modules/Output/Modules/Random
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_DIR_MODULES         Automation/Modules/Hello/Modules/Output/Modules/Random/Modules
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_DIR_MANUALS         Automation/Modules/Hello/Modules/Output/Modules/Random/Manuals
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_DIR_LOCALES         Automation/Modules/Hello/Modules/Output/Modules/Random/Locales
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_DIR_CONFIGS         Automation/Modules/Hello/Modules/Output/Modules/Random/Configs
Thu 10 Oct 2013 11:50:04 PM CDT TCAR_MODULE_INIT_FILE           Automation/Modules/Hello/Modules/Output/Modules/Random/random.sh
Thu 10 Oct 2013 11:50:04 PM CDT TEXTDOMAIN                      random.sh
Thu 10 Oct 2013 11:50:04 PM CDT TEXTDOMAINDIR                   Automation/Modules/Hello/Modules/Output/Modules/Random/Locales
Thu 10 Oct 2013 11:50:04 PM CDT export -f                       random
Thu 10 Oct 2013 11:50:04 PM CDT ------------------------->      random  
H              
Thu 10 Oct 2013 11:50:04 PM CDT ~~~~~~~~~~~~~~~~~~~~~~~~~>      random  
H              
Thu 10 Oct 2013 11:50:04 PM CDT ~~~~~~~~~~~~~~~~~~~~~~~~~>      random  
l              
Thu 10 Oct 2013 11:50:04 PM CDT ~~~~~~~~~~~~~~~~~~~~~~~~~>      random  
l              
Thu 10 Oct 2013 11:50:04 PM CDT ~~~~~~~~~~~~~~~~~~~~~~~~~>      random  
H              
Thu 10 Oct 2013 11:50:04 PM CDT <-------------------------      random  
Thu 10 Oct 2013 11:50:04 PM CDT unset -f                        random
Thu 10 Oct 2013 11:50:04 PM CDT <=========================      [2] | output 
Thu 10 Oct 2013 11:50:04 PM CDT <-------------------------      output  
Thu 10 Oct 2013 11:50:05 PM CDT unset -f                        output
Thu 10 Oct 2013 11:50:05 PM CDT <=========================      [1] | hello 
Thu 10 Oct 2013 11:50:05 PM CDT <-------------------------      hello 
Thu 10 Oct 2013 11:50:05 PM CDT unset -f                        hello
Thu 10 Oct 2013 11:50:05 PM CDT unset -f                        hello_getOptions
Thu 10 Oct 2013 11:50:05 PM CDT <=========================      [0] | main 
----------------------------------------------------------------------
======================================================================

Recursive execution of modules occurs only when the module you are
executing is considered sibling of the last module executed in the
chain of executed modules and they both have the same name. The fact
that no variable name is printed out in <<debug-recursive-modules>>
means that they were not created. The change in the arrows shown in
the example, from +->+ to +~>+, means that module's related functions
weren't exported for the new module execution either. It also means
that the initialization script is reusing both module's related
functions variables from the last module's environment in the chain of
executed modules. In this case *random* module itself.

Summary
~~~~~~~

This section has covered the module environment inside *centos-art.sh*
script, including module types and possible combinations of them. The
next section takes these concepts and focuses on the implementation of
them. Once you finish it, you should be able of writing your own
module environments from scratch inside *centos-art.sh* script.

Module Implementation
---------------------

Parent Modules
~~~~~~~~~~~~~~

The <<hello-simplest-directory-structure>>, shows a basic module
structure. In this example, we see that module directories are written
capitalized while module initialization file and related functions are
all written in lower-case. Note also how the module directory and
files inside it use the module's name in their file names to get
identified. This is a convention that should be followed in order for
*centos-art.sh* script to execute modules. Another convention you
should follow, when creating related functions, is using underscore
(``_'') to separate the module's name from the function's descriptive
name. In these cases, the function's descriptive name is always
written in camel-case followed by the +.sh+ extension.

[[hello-simplest-directory-structure]]
.Simplest directory structure of hello module.
======================================================================
----------------------------------------------------------------------
.
|-- COPYING                     <-- Contains the GPL license.
|-- Locales/                    <-- localization of all sh files.
|-- Manuals/                    <-- manuals for main and global functions.
|-- Modules/                    <-- top-modules are stored here.
|   `-- Hello/
|       `-- hello.sh
|-- Scripts/                    <-- global functions are stored here.
|-- centos-art.conf.sh          <-- main configuration file.
`-- centos-art.sh               <-- main initialization file.
----------------------------------------------------------------------
======================================================================

The module's initialization file contains the main function definition
of your module. It is a good place to define variables that must be
always available inside the module. There is also a top-comment that
collects information about the function files you are writing (e.g., a
small description, a written by section, the copyright note and the
legal status of the file). Even using a top comment like this is not
required for *centos-art.sh* script to execute modules properly, it is
very useful as matter of consistency and style inside it (and the
copyright and legal notice might be required for legal protection of
your code as set by GPL).  Finally, there is the function definition
named +hello+ just as the directory that holds it but all in lower.
Inside this function definition is where we write what we want the
*hello* module does for us. This way, following with the *hello* example,
we create an array variable inside it holding all the suggestions we
would like to print, as described in <<initialization-file>>.

[[initialization-file]]
.The initialization file of hello module
======================================================================
----------------------------------------------------------------------
#!/bin/bash
######################################################################
#
#   hello.sh -- Print out greetings to standard output and exit
#   successfully.
#
#   Written by:
#   * Alain Reguera Delgado <al@centos.org.cu>, 2013
#
# Copyright (C) 2009-2013 The CentOS Artwork SIG
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
######################################################################

function hello {

    tcar_printMessage "Hello, World!"

}
----------------------------------------------------------------------
======================================================================

Child Modules
~~~~~~~~~~~~~
...

Sibling Modules
~~~~~~~~~~~~~~~

...

Recursive Modules
~~~~~~~~~~~~~~~~~

...

Summary
~~~~~~~

...

// vim: set syntax=asciidoc: