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

Overview
--------

From version 0.5, *centos-art.sh* script implements the idea of
modules to its base design. Modules are a collection of functions
written in Bash that can call themselves 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 they work. 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. This
execution environment is the higher environment inside *centos-art.sh*
script. It is considered to have a ``global'' scope, so variables and
functions defined inside it are always available for any function
execution made from it. You can control the execution environment of
*centos-art.sh* script through +centos-art.sh+ and
+centos-art.conf.sh+ files. These files don't provide too much
functionality so specific module environments are executed from
+centos-art.sh+ at demand, 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 produce a
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-environment]]
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 as described in
<<module-optimization>>.

Summary
~~~~~~~

This section has covered basic concepts related to module environment
inside *centos-art.sh* script. 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]]
Module Implementation
---------------------

The *centos-art.sh* script implements module environments inside the
``+Modules+'' directory, as described in <<module-structure>>.

[[module-implementation-parent]]
Parent Modules
~~~~~~~~~~~~~~

For example, consider the creation of a module named *hello*. The
purpose of this module is to print a greeting message to standard
output and then exit successfully. To create such a module, we need to
create a directory named ``Hello'' inside the ``Modules'' directory
and put an initialization file named ``hello.sh'' inside it.  Because
we want to execute the *hello* module from *centos-art.sh* script
command-line, we put it in the first level of directories of +Modules+
directory. See <<parent-module-layout>>.

[[parent-module-layout]]
.Directory layout used by parent modules
======================================================================
----------------------------------------------------------------------
.
|-- COPYING                     <1>
|-- Locales/                    <2>
|-- Manuals/                    <3>
|-- Modules/                    <4>
|   `-- Hello/                  <5>
|       |-- hello.sh            <6>
|       `-- hello_getOptions.sh <7>
|-- Scripts/                    <8>
|-- centos-art.conf.sh          <9>
`-- centos-art.sh               <10>
----------------------------------------------------------------------

<1> Script's copying conditions.
<2> Script's localization files.
<3> Script's documentation files.
<4> Script's modules. Here is where you store parent modules.
<5> Parent directory of module named hello.
<6> Initialization file of module named hello.
<7> Function related to module named hello.
<8> Script's global functions.
<9> Script's configuration file.
<10> Script's initialization file.
======================================================================

<<parent-module-layout>> presents a complete module layout you can use
as reference to create your own module implementations. However, it is
not complete yet.  At this point, when you execute *centos-art.sh*, it
is able to find out *hello* module's initialization file and execute
it but that prints an error message because the initialization file
doesn't have a function definition inside. It is completely empty.  In
order for *centos-art.sh* script to do something useful, you need to
write a function definition inside the initialization file, as
described in <<module-init-file>>.

[[module-init-file]]
The Initialization File
~~~~~~~~~~~~~~~~~~~~~~~

The module's initialization file contains the module's main function
definition and a comment describing what it does on top of it.  This
comment includes a small description about what the function does, a
written by section, the copyright note and the legal status of the
file. The function definition is set later and must be written using
the long definition format (i.e., it must begin with the word
``+function+,'' then the function name, and finally the ``+{+''
character).  The name of the function is exactly the same of the
initialization file but without the +.sh+ extension. These conditions
are required in order for *centos-art.sh* script to execute the
function definition and destroy it when it is no longer used.  See
<<initialization-file>>.

The function definition is where you write all the commands you want
the module runs, once executed.  The function definition can be as
simple as just one single line of code or as complex as you can
imagine. It is the place where you express your solutions. However,
when writing initialization files, it is considered a good practice to
avoid any sort of complexity.  Instead, try to write small and simple
initialization files.  In case you notice the initialization file is
growing up inevitably, you can reduce its code by refactoring it.  To
do this, you can use resources like module related functions and child
modules. These resources are described in <<module-optimization>>, and
they help you to keep the initialization file in a clean state, easy
to understand, maintain and debug.

[[initialization-file]]
.Initialization file used by 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 "`gettext "Hello, World!"`" --as-stdout-line

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

The function definition described in <<initialization-file>> uses the
*tcar_printMessage* global function to print localized versions of the
string ``Hello, World!'' to standard output. Because there isn't no
other command in the function definition, when the greeting message is
printed out, *centos-art.sh* destroys the *hello* module and exit
successfully. This process is more visible when also pass the
*--debug* option. See <<debug-parent-modules>>.

Summary
~~~~~~~

Congratulations! You've implemented a module environment inside
*centos-art.sh* script. With the information you have so far, you are
able to create your own module environment implementations. The next
section delves into available resources you can use to simplify module
environments when the initialization file starts growing inevitably
and complexity daemons begin hammering your head.

[[module-optimization]]
Module Optimization
-------------------

The *centos-art.sh* script provides four resources you can use to
optimize your module implementations. These resources are ``related
functions,'' ``child modules,'' ``sibling modules'' and ``recursive
modules''.

[[related-functions]]
Related Functions
~~~~~~~~~~~~~~~~~

Related functions are very useful when you need to simplify the
function definition of one initialization file. For example, consider
extending the *hello* module so it is able to interpret arguments
passed through the command-line.  Now, inside the initialization file,
we have some variable definitions, one function call to a module
related function named *hello_getOptions*, and a decision on how the
greeting message must be printed out based on the collected actions.
See <<initialization-file-extended>>.

[[initialization-file-extended]]
.Initialization file used by hello module (extended)
======================================================================
----------------------------------------------------------------------
function hello {

    # Define default greeting message.
    local HELLO_WORLD="`gettext "Hello, World!"`"

    # Define actions variable. Here is where actions related to
    # module-specific options are stored in for further processing.
    local ACTIONS=''

    # Interpret module-specific options and store related actions.
    hello_getOptions

    # Print greeting message
    if [[ -z ${ACTIONS} ]];then
        # Using parent module.
        tcar_printMessage "${HELLO_WORLD}" --as-stdout-line
    else
        # Using child module.
        tcar_setModuleEnvironment -m 'output' -t 'child'
    fi

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

When you execute the command *centos-art.sh hello* with the
*--greeting=hi* argument, *centos-art.sh* stores module-specific
arguments inside the +TCAR_MODULE_ARGUMENT+ variable, creates a list
of all function definitions inside the module directory and exports
them.  This includes the function definition of the initialization
file itself.  Then *centos-art.sh* executes the function definition
set inside the initialization file and leaves all other function
definitions, already in memory, waiting for further execution. At this
point, the *hello* initialization function sets some default values
and execute the *hello_getOptions* function to parse all the arguments
passed through the command-line and redefines the +ACTIONS+ variable
based on them. Using the +ACTIONS+ variables it decides whether to
print the greeting message immediately or execute the child modules
named *output* so it decides what to do with the information collected
so far.

<<hello_getOptions-definition>> defines the options you can pass to
*hello* module and the associated actions they must perform for each
of them. Actions aren't immediately executed here. Instead, they are
stored in the +ACTIONS+ variable for further processing (e.g., we
store the names of the modules we want to execute later). The
+ACTIONS+ variable was defined in the initialization file so it has a
global scope inside the module environment and is reachable from any
related function executed inside it.  Storing the actions this way
lets the *hello* module to collect information about different actions
and execute them all in just one command.  When all options have been
parsed, only non-option arguments remain in the +TCAR_MODULE_ARGUMENT+
variable.

[[hello_getOptions-definition]]
.Related function definition (hello_getOptions)
======================================================================
----------------------------------------------------------------------
function hello_getOptions {

    # Define short options we want to support.
    local ARGSS="h::,v,g:,l,u,c,r"

    # Define long options we want to support.
    local ARGSL="help::,version,greeting:,lower,upper,camel,random"

    # Redefine arguments using getopt(1) command parser.
    tcar_setModuleArguments

    # Reset positional parameters on this function, using output
    # produced from (getopt) arguments parser.
    eval set -- "${TCAR_MODULE_ARGUMENT}"

    # Look for options passed through command-line.
    while true; do
        case "${1}" in

            -h | --help )
                tcar_printHelp "${2}"
                ;;

            -v | --version )
                tcar_printVersion "${TCAR_MODULE_NAME}"
                ;;

            -g | --greeting )
                HELLO_WORLD="${2:-${HELLO_WORLD}}"
                shift 2
                ;;

            -l | --lower )
                ACTIONS="lower ${ACTIONS}"
                shift 1
                ;;

            -u | --upper )
                ACTIONS="upper ${ACTIONS}"
                shift 1
                ;;

            -c | --camel )
                ACTIONS="camel ${ACTIONS}"
                shift 1
                ;;

            -r | --random )
                ACTIONS="random ${ACTIONS}"
                shift 1
                ;;

            -- )
                shift 1
                break
                ;;
        esac
    done

    # Redefine arguments using current positional parameters. Only
    # paths should remain as arguments, at this point.
    TCAR_MODULE_ARGUMENT="${@}"

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

[IMPORTANT]
<<hello_getOptions-definition>> presents the standard construction we
use inside *centos-art.sh* script for parsing arguments passed through
the command-line in a per-module basis.  As convention, all the parent
modules you write must be able to interpret the *--help* and
*--version* options using the construction described here.

Related functions are very useful when you are refactoring the
initialization file of a module. However, they aren't so efficient
when you need to execute them at demand (e.g., based on specific
conditions). When a module is executed, related functions are exported
to *centos-art.sh* script execution environment. They remain there,
consuming memory, until the module they belong to is destroyed. If you
create a related function and never execute it, it will consume
memory, as well. So, use related functions when you are absolutely
sure they will be executed at some point, in one single iteration of
*centos-art.sh* script.  If you need to execute functions at demand,
use child modules, instead.

[[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 iteration 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 iteration 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
~~~~~~~~~~~~~~~

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 iteration 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]]
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 these 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 arrows change 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 related functions and variables from the last module
environment in the chain of executed modules. In this case the
*random* module.

Summary
~~~~~~~

This section covered the resources you can use to optimize module
environments inside *centos-art.sh* script. The next section
summarizes the base files and directories you might find inside one
module environment.

[[module-structure]]
Module Structure
----------------

The module structure takes place at the root location of
*centos-art.sh* script, specifically, in a directory named +Modules+.
The +Modules+ directory at *centos-art.sh* root location is the
highest level which you can store modules in.  Modules stored in this
location are known as parent modules. Parent modules can optimize
their structure by using related functions, child modules, sibling
modules and recursive modules. Basically, all these types of modules
share the same structure.  They all have function files and,
optionally, module related stuff like locales, documentation,
configuration and dependent modules. See <<module-directory-layout>>.

[IMPORTANT]
From version 0.7 on, child modules no longer have +Locales+, +Manuals+
and +Configs+ directories inside. Only initialization files, related
functions and +Modules+ directory are supported inside child modules.
See https://centos.org.cu/bugs/view.php?id=114[Bug 114].

[[module-directory-layout]]
.The directory structure of hello module
======================================================================
----------------------------------------------------------------------
.
|-- COPYING
|-- Locales/
|-- Manuals/
|-- Modules/
|   `-- Hello/                          <1>
|       |-- Locales
|       |   |-- es_ES
|       |   |   |-- LC_MESSAGES
|       |   |   |   `-- hello.sh.mo     <2>
|       |   |   `-- hello.sh.po
|       |   `-- hello.sh.pot
|       |-- Manuals
|       |   |-- hello.asciidoc
|       |   |-- man1
|       |   |   `-- hello.1             <3>
|       |   `-- render.conf             <4>
|       |-- Modules
|       |   `-- Output                  <5>
|       |       |-- Modules
|       |       |   |-- Camel
|       |       |   |   `-- camel.sh
|       |       |   |-- Lower           <6>
|       |       |   |   `-- lower.sh    <7>
|       |       |   |-- Random
|       |       |   |   `-- random.sh
|       |       |   `-- Upper
|       |       |       `-- upper.sh
|       |       `-- output.sh           <8>
|       |-- hello.sh                    <9>
|       `-- hello_getOptions.sh         <10>
|-- Scripts/
|-- centos-art.conf.sh
`-- centos-art.sh
----------------------------------------------------------------------

<1> Child module of *centos-art.sh* script and parent module of
*output* module.
<2> Spanish translated strings of *hello* module.
<3> Manpage shown when you request help of *hello* module.
<4> Configuration file used to produce the manpage of *hello* module.
<5> Child module of *hello* module and parent module of *camel,*
*lower,* *random* and *upper* modules.
<6> Child module of *output* module and sibling module of *camel,*
*random* and *upper* module.
<7> Initialization file of *lower* module.
<8> Initialization file of *output* module.
<9> Initialization file of *hello* module.
<10> Function file related to *hello* module.
======================================================================

<<module-directory-layout>> presents a complete structure for module
environments you can use as reference for writing your own modules. It
begins with a parent module directory named ``Hello'' which contains
an initialization file (``hello.sh'') and one related function file
(``hello_getOptions.sh''). These files work together with a child
module named *output* which in turn has four child modules inside
named *camel,* *lower,* *random,* and *upper.* The +Locales+ directory
contains the required information to print *hello* messages in
different languages (e.g., it only supports Spanish language in our
example, but it can be extended to other languages as needed).  The
+Manuals+ directory contains all the files required to produce
documentation for the *hello* module (e.g., the information you read
when provide the *--help* option in the command-line).

The Function Files
~~~~~~~~~~~~~~~~~~

The function files are used to create the initialization file of a
module and the related functions of it.  As convention, both
initialization file and related function files are stored in the
module's directory, see <<module-directory-layout>>.

At execution time, the definition of related function are exported to
*centos-art.sh* execution environment before executing the function
definition set inside the initialization file, so related functions
are always available for you to use in the initialization file file
and other related functions as well. This is rather useful when you
are refactoring your initialization scripts and probably related
functions as well.

As naming convention, related function files are written using the
module's name, then an underscore (``_''), then a descriptive name
and, finally, the ``+.sh+'' extension. The function definition inside
the function file also follows this convention but excludes the
``+.sh+'' extension from name (e.g., the function file
``+hello_getOptions.sh+'' has a function definition named
``+hello_getOptions+'' inside). The *centos-art.sh* script relays in
these conventions to export and destroy related functions when new
module environments are created and destroyed.  If you create related
function files with a pattern different from that described here, they
will not be executed nor available inside the initialization file of
the module environment being currently executed.

See also: <<module-init-file>> and <<related-functions>>.

[[module-directory-modules]]
The +Modules+ Directory
~~~~~~~~~~~~~~~~~~~~~~~

This directory contains nested modules (e.g., child modules) and is
used for extending the current module functionality in a modular way.
There isn't a visible limitation in the number of +Modules+ directory
you can nest inside one module to achieve certain functionality so,
you can create as many levels of +Modules+ directories as you need.

[[module-directory-locales]]
The +Locales+ Directory
~~~~~~~~~~~~~~~~~~~~~~~

This directory contains module-specific localization files. The
content of this directory is automatically generated by *locale*
module of *centos-art.sh* script, when you execute it using the
initialization file as source and the *--update --sibling* options.
Once the localization files have been created, you need to edit PO
files to translate the strings from English to your preferred
language.  If the translatable strings inside the module's source
files change, you need to run the *locale* module again to update the
PO files and repeat the localization process all over again.

[[module-directory-manuals]]
The +Manuals+ Directory
~~~~~~~~~~~~~~~~~~~~~~~

This directory contains module-specific documentation. Documentation
in this directory is written in asciidoc format and produced through
the *render* module of *centos-art.sh* script to different formats,
including man pages and html.

[[module-directory-configs]]
The +Configs+ Directory
~~~~~~~~~~~~~~~~~~~~~~~

This directory contains module-specific configuration. Some modules
(e.g., ``tuneup'') need to store auxiliary files required to achieve
its main goal (e.g., the ``tuneup'' module uses sed files to transform
the top-comment of scripts each time it is executed, the sed file
itself is stored in this directory). Whenever you need to make
reference to a file inside this directory, use the
``TCAR_MODULE_DIR_CONFIGS'' variable. This variable provides the
absolute path of module-related configuration file.

Summary
~~~~~~~

This section has covered the directories and files a module is made of
inside the *centos-art.sh* script.

// vim: set syntax=asciidoc: