.. _`build`:

#########################
PyVIX2 Build
#########################

The source for :mod:`PyVIX2` is a Sphinx project that depends on PyLit.
Yes.  The documentation spawns the code.

In addition to Python 2.7, there are two other projects required to build.

-   PyLit.  http://pylit.berlios.de/

-   Sphinx.  http://sphinx.pocoo.org/

The PyLit install is little more than a download and move the :file:`pylit.py` file to
the Python :file:`site-packages` directory.

Sphinx should be
installed with `easy_install <http://peak.telecommunity.com/DevCenter/EasyInstall>`_.

..  code-block:: bash

    easy_install sphinx

Build Procedure
==================

1.  Bootstrap the :file:`build.py` script by running PyLit.

    ..  code-block:: bash
    
        python2.7 -m pylit -t source/build.rst build.py

    This reports that an extract was written to :file:`build.py`.
    
2.  Use the :file:`build.py` script to create the ``PyVIX2`` source, unit
    tests, demonstration applications.  
    Build the Sphinx documentation.  
    And run the unit test, too.

    ..  code-block:: bash
    
        python2.7 build.py
        
    At the end of this step, the directory tree will include the following.
    
    -   :file:`build`.  The documentation.  In HTML.
    -   :file:`build.py`.  The build script.
    -   :file:`demo`.   Demonstration scripts that use ``PyVIX2``. 
        See :ref:`script`.
    -   :file:`pyvix2/__init__.py`.  The Python module, ready for installation.
    -   :file:`pyvix2/cli.py`.  The Command-line Interface, ready for installation.
    -   :file:`pyvix2/enum.py`.  The enums, built by :file:`pyvix2/get_enum.py`.
    -   :file:`test`.  The unit test script.

    This reports, also, that 139 tests were run.
    
Build Script
=====================

We're going to make use of two "applications".

-   Sphinx top-level application.

-   PyLit top-level application.

::

    """platform-independent build script"""
    from __future__ import print_function
    import os
    import sys
    import errno
    import runpy
    from sphinx.application import Sphinx
    from sphinx.util.console import nocolor
    import pylit

Sphinx Build
---------------

..  py:function:: sphinx_build( srcdir, outdir, buildername='html' )

This function handles the simple use case for the ``sphinx-build`` script.

::

    def sphinx_build( srcdir, outdir, buildername='html' ):
        """Essentially: ``sphinx-build $* -b html source build/html``"""
        nocolor()
        confdir= srcdir= os.path.abspath( srcdir )
        outdir= os.path.abspath( outdir )
        doctreedir = os.path.join(outdir, '.doctrees')
        app = Sphinx(srcdir, confdir, outdir, doctreedir, buildername)
        app.build(force_all=False, filenames=[])
        return app.statuscode

PyLit Build
---------------

..  py:function:: sphinx_build( srcdir, outdir, buildername='html' )

This function handles the simple use case for PyLit.

This also handles the necessary rewrite to modify standard paths to Windows paths.

::

    def pylit_build( infile, outfile ):
        """Essentially: ``python2.7 -m pylit -t source/demo/script1.rst demo/script1.py``
        
        The issue here is that we need to provide platform-specific paths.
        """
        if os.sep != '/':
            # Fix windows paths.
            infile= os.path.join( *infile.split('/') )
            outfile= os.path.join( *outfile.split('/') )
        pylit.main( txt2code= True, infile= infile, outfile= outfile )

Make Directories
-------------------

..  py:function:: mkdir( path )

This function handles the simple use case for assuring that the directory
tree exists.

This also handles a rewrite to modify standard paths to Windows paths.

::

    def mkdir( path ):
        if os.sep != '/':
            # Fix windows paths.
            path= os.path.join( *path.split('/') )
        try:
            os.makedirs( path )
        except OSError as e:
            if e.errno == errno.EEXIST: 
                pass
            else:
                raise

Run a Test Script
-----------------------

..  py:function:: run_test( )

In effect, this does ``python2.7 test/main.py``

::

    def run_test():
        from test.main import suite
        unittest.TextTestRunner().run(suite())

The subtlety here is that the module is just a wrapper
on an API.  A mock API would be perhaps more complex than
the wrapper.  This is more easily tested by simply
running the demo scripts.


The Build Sequence
---------------------

::
    
    def build():
        sphinx_build( 'source', 'build/html', 'html' )
        
        mkdir( 'pyvix2' )
        pylit_build( 'source/pyvix2.rst', 'pyvix2/__init__.py' )
        pylit_build( 'source/get_enum.rst', 'pyvix2/get_enum.py' )
        pylit_build( 'source/cli.rst', 'pyvix2/cli.py' )
        pylit_build( 'source/sample_config.rst', 'pyvix2.conf' )
        pylit_build( 'source/vmrun.rst', 'pyvix2/vmrun.py' )
        pylit_build( 'source/installation.rst', 'setup.py' )
        
        runpy.run_path( 'pyvix2/get_enum.py', run_name="__main__" )
                
        mkdir( 'demo' )
            
        pylit_build( 'source/demo1.rst', 'demo/script1.py' )
        pylit_build( 'source/demo2.rst', 'demo/script2.py' )
        
        #run_test()

Main Program Switch
---------------------

When the :file:`build.py` script is run from the command line,
it will execute the :py:func:`build` function.  When it is imported,
however, it will do nothing special.

::

    if __name__ == "__main__":
        build()
        
Additional Builds
=====================

Sometimes it's desriable to refresh the documentation.

The HTML pages are built with this command.

..  code-block:: bash

    sphinx-build $* -b html source build/html
    
The LaTeX document is built with this command.

..  code-block:: bash

    sphinx-build $* -b latex source build/latex