e3-core API highlights
======================

*e3-core* comes with many useful modules, you might find the above
selection useful to start using the *e3-core* API.

e3.fs and e3.os.fs
------------------

:py:mod:`e3.fs` and :py:mod:`e3.os.fs` modules contain several helpers
for writing portable and robust applications.

For instance :py:func:`rm` tries very hard to remove files or directories.
On Windows system it is using the :py:class:`e3.os.windows.fs.NTFile` class
that relies on ``ctypes`` to call the Windows native API. This made the removal
of files much more reliable on Windows. Using it is as simple as:

.. code-block:: python

    rm('/path/to/file')
    rm('/path/to/directory', recurive=True)
    rm('\*.py')


:py:mod:`e3.fs` also comes with many other useful functions such as :py:func:`e3.fs.sync_tree` which implement a local :program:`rsync`, with a very similar API.

Both modules implement many functions that tries to mimic the well known POSIX
tools and that are heavily tested on UNIX like platforms and Windows.

e3.os.process
-------------

In :py:mod:`e3.os.process` the :py:class:`e3.os.process.Run` class allows
running processes under a time limit.

Running:

.. code-block:: python

    Run(['python'], timeout=2)

will exit the :program:`python` program after 2 seconds whereas

.. code-block:: python

    Run(['python'])

will never end.

:py:class:`e3.os.process.Run` can also be used to pipe several commands, e.g.

.. code-block:: python

    p = Run([['tar', 'cf', '-', 'a_dir'], ['gzip', '-9']],
            output='a_dir.tgz',
            error=my_error_log_stream)
    assert p.status == 0


e3.main and e3.env
------------------

:py:class:`e3.main.Main` simply the writing of command line clients depending
on ``--build``, ``--host``, ``--target`` arguments. It uses
:py:class:`e3.env.Env` to set the platform environment, which is very useful if
your the tool you are writing supports multiple platforms and cross platform
environment.


Adding the following code in :program:`show-platform`

.. code-block:: python

    from e3.main import Main
    from e3.env import Env
    m = Main(platform_args=True)
    m.argument_parser.add_argument(
       '--show-platform')
    m.parse_args()
    print(Env().platform)

will print the following on a macos machine:

.. code-block:: shell

    $ show-platform
    x86_64-darwin

    $ show-platform --target=x86-windows --host=x86_64-linux
    x86-windows-linux64


Add ``print(Env().build`` will output more info on the build platform:

.. code-block:: yaml

    platform: x86_64-darwin
    machine:  ida
    is_hie:   False
    is_host:  True
    triplet:  x86_64-apple-darwin16.5.0
    domain:   unknown
    OS
       name:          darwin
       version:       16.5.0
       exeext:
       dllext:        .dylib
       is_bareboard:  False
    CPU
       name:   x86_64
       bits:   64
       endian: little
       cores:  4show-platform


e3.yaml
-------

:py:mod:`e3.yaml` comes with a *YAML* loader that loads mappings into
ordered dictionaries and with *case parser* adding case statement in
configuration files.

A case parser can be help when you want to pick different packages
depending on the build platform.

If we start with a file :file:`packages.yaml`:

.. code-block:: yaml

    packages:
        - args-0.1.0-py2-none-any.whl
        - enum34-1.1.6-py2-none-any.whl

    case_build_os_name:
        linux:
            +packages:
                - psutil-4.3.1.tar.gz
                - netifaces-0.10.4.tar.gz
        windows:
            +packages:
                - psutil-4.3.1-cp27-none-win32.whl
                - netifaces-0.10.4-cp27-none-win32.whl

Also note the special syntax ``+packages`` that adds the
new entries to the existing ``packages`` list.

The function :py:func:`e3.yaml.load_with_config` combines both:

.. code-block:: python

    e3.yaml.load_with_config('y.yaml', {'build_os_name': 'x86-windows'})

returns

.. code-block:: python

    {'packages': [
        'args-0.1.0-py2-none-any.whl',
        'enum34-1.1.6-py2-none-any.whl',
        'psutil-4.3.1-cp27-none-win32.whl',
        'netifaces-0.10.4-cp27-none-win32.whl']}
