.. _flmake_api: flmake ====== Managing FLASH simulations can be a tedious task for both new and experienced users. The flmake command line utility eases the simulation/development cycle by providing a modular tool that implements many common elements of a user's workflow. Thus, flmake replaces the following workflow tasks: * setup/configuration * building * execution * logging * analysis & post-processing * and many others! Another important aim of the flmake infrastructure is to have every FLASH run be completely reproducible on a wide variety of systems. This document is not intended as a :ref:`flmake user's guide `. Rather these docs provide the API that flmake itself uses. This sub-package is called ``flmake``:: import flash.flmake contents ~~~~~~~~ .. toctree:: :maxdepth: 1 build clean diffpar flash_lib gen_files help_cmd lazy_file lib_union link_file_list log logger lsruns main merge metadata mv reproduce restart rm rp_info run setup setup_configuration setup_globals setup_parse template utils var_info writing additional flmake commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Exposing new commands to flmake and expanding the FLASH workflow options is a simple task which is explained in detail here. The flmake utility uses a dynamic registration pattern to find commands. Three tasks must be completed add a command to flmake: * register the main command function, * register the help/usage string or function, * and write command-specific bash completion (optional). As a fictional example, suppose that FLASH requires delicious, slightly burnt bread. A toast command seems imminent... -------------------------------------------------------------------------------- main function ------------- Every flmake command must have a main function which can have any name, but is by convention ``main()``. This function must have a very specific signature: .. function:: flash.flmake.toast.main(opts, rc, msg) Parameters ---------- opts : list The command line arguments, as a list of strings, that come after the flmake command. For ``flmake mv dir1 dir2`` opts would be ``['dir1', 'dir2']``. rc : dict The run control dictionary or an empty dict if the ``flashrc.py`` does not exist. msg : str or None The message given by the user on the command line or None if no message was supplied. Therefore, a toast command's main function - which accepts a toastiness level - may be implemented in a ``toast.py`` module:: from flash.flmake import logger def main(opts, rc, msg): """Makes delicious toast for you.""" toastiness = int(opts[0]) if 0 < len(opts) else 5 print "Engage the bread warming!" if msg is None: msg = "Toasting to level {}".format(toastiness) logger.info(msg, "toast") Moreover, the docstring of this function is used by ``flmake help`` as the command's summary description. This function must then be registered with the main flamke command itself. This is done by adding an entry to the ``commands`` dictionary in the ``flash.flmake.main`` module. The keys in the dictionary are the names of the commands at the command line. The values are 2-tuples of module relative import paths and the name of the main function in this module:: commands = { 'setup': ('setup', 'main'), 'build': ('build', 'main'), 'run': ('run', 'main'), 'ls-runs': ('lsruns', 'main'), # ... 'toast': ('toast', 'main'), } Enterprising developers may alter the commands dictionary from the ``flashrc.py`` run control file as flmake itself is running! -------------------------------------------------------------------------------- help/usage ---------- Similar to the commands main function, the flmake help command requires a usage string which may be dynamically registered. The usage object may be a string or a function which takes no arguments and returns a string. The latter function pattern is useful if the usage string may change based on the state of the system. Both static and dynamic examples are presented below:: import os # static USAGE = ("In flmake, command toasts you!\n\n" "usage: flmake toast []") # dynamic def usage(): slices = len(os.listdir('.')) msg = "You can make {} pieces of toast!".format(slices) This string or function object must then be added to the ``messages`` dictionary in the ``flash.flmake.help_cmd`` module. The keys are the same as the keys in the flmake main commands dictionary. The values are the usage objects themselves. For example:: from . import build from . import run from . import restart from . import clean from . import metadata from . import merge # ... from . import toast messages = { 'build': build.usage, 'run': run.usage, 'restart': restart.usage, 'merge': merge.USAGE, 'clean': clean.USAGE, 'metadata': metadata.USAGE, # ... 'toast': toast.USAGE, } -------------------------------------------------------------------------------- bash completion --------------- An optional, but useful, component of flmake is its support for bash completion. This is the tool whereby pressing tab on the command line the potential valid options are automatically filled in. Currently, whenever the Python API is installed the flmake bash completion file is regenerated. Therefore to add new command-specific options to flmake's bash completion the ``${FLASH_SRC_DIR}/tools/setup.py`` file must be edited. This module contains a template that may be adjusted as needed. Please refer to this tutorial for the new command's completion needs (`part 1 `_, `part 2 `_).