|  | .. _chapter-pw-cli: | 
|  |  | 
|  | .. default-domain:: python | 
|  |  | 
|  | .. highlight:: sh | 
|  |  | 
|  | ------ | 
|  | pw_cli | 
|  | ------ | 
|  | This directory contains the ``pw`` command line interface (CLI) that facilitates | 
|  | working with Pigweed. The CLI module adds several subcommands prefixed with | 
|  | ``pw``, and provides a mechanism for other Pigweed modules to behave as | 
|  | "plugins" and register themselves as ``pw`` commands as well. After activating | 
|  | the Pigweed environment, these commands will be available for use. | 
|  |  | 
|  | ``pw`` includes the following commands by default: | 
|  |  | 
|  | .. code-block:: text | 
|  |  | 
|  | doctor        Check that the environment is set up correctly for Pigweed. | 
|  | format        Check and fix formatting for source files. | 
|  | help          Display detailed information about pw commands. | 
|  | logdemo       Show how logs look at various levels. | 
|  | module-check  Check that a module matches Pigweed's module guidelines. | 
|  | test          Run Pigweed unit tests built using GN. | 
|  | watch         Watch files for changes and rebuild. | 
|  |  | 
|  | To see an up-to-date list of ``pw`` subcommands, run ``pw --help``. | 
|  |  | 
|  | Invoking  ``pw`` | 
|  | ================ | 
|  | ``pw`` subcommands are invoked by providing the command name. Arguments prior to | 
|  | the command are interpreted by ``pw`` itself; all arguments after the command | 
|  | name are interpreted by the command. | 
|  |  | 
|  | Here are some example invocations of ``pw``: | 
|  |  | 
|  | .. code-block:: text | 
|  |  | 
|  | # Run the doctor command | 
|  | $ pw doctor | 
|  |  | 
|  | # Run format --fix with debug-level logs | 
|  | $ pw --loglevel debug format --fix | 
|  |  | 
|  | # Display help for the pw command | 
|  | $ pw -h watch | 
|  |  | 
|  | # Display help for the watch command | 
|  | $ pw watch -h | 
|  |  | 
|  | Registering ``pw`` plugins | 
|  | ========================== | 
|  | Projects can register their own Python scripts as ``pw`` commands. ``pw`` | 
|  | plugins are registered by providing the command name, module, and function in a | 
|  | ``PW_PLUGINS`` file. ``PW_PLUGINS`` files can add new commands or override | 
|  | built-in commands. Since they are accessed by module name, plugins must be | 
|  | defined in Python packages that are installed in the Pigweed virtual | 
|  | environment. | 
|  |  | 
|  | Plugin registrations in a ``PW_PLUGINS`` file apply to the their directory and | 
|  | all subdirectories, similarly to configuration files like ``.clang-format``. | 
|  | Registered plugins appear as commands in the ``pw`` tool when ``pw`` is run from | 
|  | those directories. | 
|  |  | 
|  | Projects that wish to register commands might place a ``PW_PLUGINS`` file in the | 
|  | root of their repo. Multiple ``PW_PLUGINS`` files may be applied, but the ``pw`` | 
|  | tool gives precedence to a ``PW_PLUGINS`` file in the current working directory | 
|  | or the nearest parent directory. | 
|  |  | 
|  | PW_PLUGINS file format | 
|  | ---------------------- | 
|  | ``PW_PLUGINS`` contains one plugin entry per line in the following format: | 
|  |  | 
|  | .. code-block:: python | 
|  |  | 
|  | # Lines that start with a # are ignored. | 
|  | <command name> <Python module> <function> | 
|  |  | 
|  | The following example registers three commands: | 
|  |  | 
|  | .. code-block:: python | 
|  |  | 
|  | # Register the presubmit script as pw presubmit | 
|  | presubmit my_cool_project.tools run_presubmit | 
|  |  | 
|  | # Override the pw test command with a custom version | 
|  | test my_cool_project.testing run_test | 
|  |  | 
|  | # Add a custom command | 
|  | flash my_cool_project.flash main | 
|  |  | 
|  | Defining a plugin function | 
|  | -------------------------- | 
|  | Any function without required arguments may be used as a plugin function. The | 
|  | function should return an int, which the ``pw`` uses as the exit code. The | 
|  | ``pw`` tool uses the function docstring as the help string for the command. | 
|  |  | 
|  | Typically, ``pw`` commands parse their arguments with the ``argparse`` module. | 
|  | ``pw`` sets ``sys.argv`` so it contains only the arguments for the plugin, | 
|  | so plugins can behave the same whether they are executed independently or | 
|  | through ``pw``. | 
|  |  | 
|  | Example | 
|  | ^^^^^^^ | 
|  | This example shows a function that is registered as a ``pw`` plugin. | 
|  |  | 
|  | .. code-block:: python | 
|  |  | 
|  | # my_package/my_module.py | 
|  |  | 
|  | def _do_something(device): | 
|  | ... | 
|  |  | 
|  | def main() -> int: | 
|  | """Do something to a connected device.""" | 
|  |  | 
|  | parser = argparse.ArgumentParser(description=__doc__) | 
|  | parser.add_argument('--device', help='Set which device to target') | 
|  | return _do_something(**vars(parser.parse_args())) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | logging.basicConfig(format='%(message)s', level=logging.INFO) | 
|  | sys.exit(main()) | 
|  |  | 
|  | This plugin is registered in a ``PW_PLUGINS`` file in the current working | 
|  | directory or a parent of it. | 
|  |  | 
|  | .. code-block:: python | 
|  |  | 
|  | # Register my_commmand | 
|  | my_command my_package.my_module main | 
|  |  | 
|  | The function is now available through the ``pw`` command, and will be listed in | 
|  | ``pw``'s help. Arguments after the command name are passed to the plugin. | 
|  |  | 
|  | .. code-block:: text | 
|  |  | 
|  | $ pw | 
|  |  | 
|  | ▒█████▄   █▓  ▄███▒  ▒█    ▒█ ░▓████▒ ░▓████▒ ▒▓████▄ | 
|  | ▒█░  █░ ░█▒ ██▒ ▀█▒ ▒█░ █ ▒█  ▒█   ▀  ▒█   ▀  ▒█  ▀█▌ | 
|  | ▒█▄▄▄█░ ░█▒ █▓░ ▄▄░ ▒█░ █ ▒█  ▒███    ▒███    ░█   █▌ | 
|  | ▒█▀     ░█░ ▓█   █▓ ░█░ █ ▒█  ▒█   ▄  ▒█   ▄  ░█  ▄█▌ | 
|  | ▒█      ░█░ ░▓███▀   ▒█▓▀▓█░ ░▓████▒ ░▓████▒ ▒▓████▀ | 
|  |  | 
|  | usage: pw [-h] [-C DIRECTORY] [-l LOGLEVEL] [--no-banner] [command] ... | 
|  |  | 
|  | The Pigweed command line interface (CLI). | 
|  |  | 
|  | ... | 
|  |  | 
|  | supported commands: | 
|  | doctor        Check that the environment is set up correctly for Pigweed. | 
|  | format        Check and fix formatting for source files. | 
|  | help          Display detailed information about pw commands. | 
|  | ... | 
|  | my_command    Do something to a connected device. | 
|  |  | 
|  | $ pw my_command -h | 
|  |  | 
|  | ▒█████▄   █▓  ▄███▒  ▒█    ▒█ ░▓████▒ ░▓████▒ ▒▓████▄ | 
|  | ▒█░  █░ ░█▒ ██▒ ▀█▒ ▒█░ █ ▒█  ▒█   ▀  ▒█   ▀  ▒█  ▀█▌ | 
|  | ▒█▄▄▄█░ ░█▒ █▓░ ▄▄░ ▒█░ █ ▒█  ▒███    ▒███    ░█   █▌ | 
|  | ▒█▀     ░█░ ▓█   █▓ ░█░ █ ▒█  ▒█   ▄  ▒█   ▄  ░█  ▄█▌ | 
|  | ▒█      ░█░ ░▓███▀   ▒█▓▀▓█░ ░▓████▒ ░▓████▒ ▒▓████▀ | 
|  |  | 
|  | usage: pw my_command [-h] [--device DEVICE] | 
|  |  | 
|  | Do something to a connected device. | 
|  |  | 
|  | optional arguments: | 
|  | -h, --help       show this help message and exit | 
|  | --device DEVICE  Set which device to target | 
|  |  | 
|  | Branding Pigweed's tooling | 
|  | ========================== | 
|  | An important part of starting a new project is picking a name, and in the case | 
|  | of Pigweed, designing a banner for the project. Pigweed supports configuring | 
|  | the banners by setting environment variables: | 
|  |  | 
|  | * ``PW_BRANDING_BANNER`` - Absolute path to a filename containing a banner to | 
|  | display when running the ``pw`` commands. See the example below. | 
|  | * ``PW_BRANDING_BANNER_COLOR`` - Color of the banner. Possible values include: | 
|  | ``red``, ``bold_red``, ``yellow``, ``bold_yellow``, ``green``, | 
|  | ``bold_green``, ``blue``, ``cyan``, ``magenta``, ``bold_white``, | 
|  | ``black_on_white``. See ``pw_cli.colors`` for details. | 
|  |  | 
|  | The below example shows how to manually change the branding at the command | 
|  | line. However, these environment variables should be set in the project root's | 
|  | ``bootstrap.sh`` before delegating to Pigweed's upstream ``bootstrap.sh``. | 
|  |  | 
|  | .. code-block:: text | 
|  |  | 
|  | $ cat foo-banner.txt | 
|  |  | 
|  | ▒██████  ░▓██▓░  ░▓██▓░ | 
|  | ▒█░    ▒█   ▒█ ▒█   ▒█ | 
|  | ▒█▄▄▄▄ ▒█ █ ▒█ ▒█ █ ▒█ | 
|  | ▒█▀    ▒█   ▒█ ▒█   ▒█ | 
|  | ▒█      ░▓██▓░  ░▓██▓░ | 
|  |  | 
|  | $ export PW_BRANDING_BANNER="$(pwd)/foo-banner.txt" | 
|  | $ export PW_BRANDING_BANNER_COLOR="bold_red" | 
|  | $ pw logdemo | 
|  |  | 
|  | ▒██████  ░▓██▓░  ░▓██▓░ | 
|  | ▒█░    ▒█   ▒█ ▒█   ▒█ | 
|  | ▒█▄▄▄▄ ▒█ █ ▒█ ▒█ █ ▒█ | 
|  | ▒█▀    ▒█   ▒█ ▒█   ▒█ | 
|  | ▒█      ░▓██▓░  ░▓██▓░ | 
|  |  | 
|  | 20200610 12:03:44 CRT This is a critical message | 
|  | 20200610 12:03:44 ERR There was an error on our last operation | 
|  | 20200610 12:03:44 WRN Looks like something is amiss; consider investigating | 
|  | 20200610 12:03:44 INF The operation went as expected | 
|  | 20200610 12:03:44 OUT Standard output of subprocess | 
|  |  | 
|  | The branding is not purely visual; it serves to make it clear which project an | 
|  | engineer is working with. | 
|  |  | 
|  | Making the ASCII / ANSI art | 
|  | --------------------------- | 
|  | The most direct way to make the ASCII art is to create it with a text editor. | 
|  | However, there are some tools to make the process faster and easier. | 
|  |  | 
|  | * `Patorjk's ASCII art generator <http://patorjk.com/software/taag/>`_ - A | 
|  | great starting place, since you can copy and paste straight from the browser | 
|  | into a file, and then point ``PW_BRANDING_BANNER`` at it.  Most of the fonts | 
|  | use normal ASCII characters; and fonts with extended ASCII characters use the | 
|  | Unicode versions of them (needed for modern terminals). | 
|  | * `Online ANSII Edit by Andy Herbert | 
|  | <http://andyherbert.github.io/ansiedit/public/index.html>`_ - Browser based | 
|  | editor that can export to mixed UTF-8 and ANSII color. It's also `open source | 
|  | <https://github.com/andyherbert/ansiedit>`_. What's nice about this editor is | 
|  | that you can create a multi-color banner, and save it with the ``File`` --> | 
|  | ``Export as ANSi (UTF-8)`` option, and use it directly as a Pigweed banner. | 
|  | One caveat is that the editor uses UTF-8 box drawing characters, which don't | 
|  | work well with all terminals. However, the box drawing characters look so | 
|  | slick on terminals that support them that we feel this is a worthwhile | 
|  | tradeoff. | 
|  |  | 
|  | There are other options, but these require additional work to put into Pigweed | 
|  | since they only export in the traditional ANS or ICE formats. The old ANS | 
|  | formats do not have a converter (contributions welcome!). Here are some of the | 
|  | options as of mid-2020: | 
|  |  | 
|  | * `Playscii <http://vectorpoem.com/playscii/>`_ - Actively maintained. | 
|  | * `Moebius <https://github.com/blocktronics/moebius>`_ - Actively maintained. | 
|  | * `SyncDraw <http://syncdraw.bbsdev.net/>`_ - Actively maintained, in 2020, in | 
|  | a CVS repository. | 
|  | * `PabloDraw <http://picoe.ca/products/pablodraw/>`_ - Works on most desktop | 
|  | machines thanks to being written in .NET. Not maintained, but works well. Has | 
|  | an impresive brush system for organic style drawing. | 
|  | * `TheDraw <https://en.wikipedia.org/wiki/TheDraw>`_ - One of the most popular | 
|  | ANSI art editors back in the 90s. Requires DOSBox to run on modern machines, | 
|  | but otherwise works. It has some of the most impressive capabilities, | 
|  | including supporting full-color multi-character fonts. | 
|  |  | 
|  | Future branding improvements | 
|  | ---------------------------- | 
|  | Branding the ``pw`` tool is a great start, but more changes are planned: | 
|  |  | 
|  | - Supporting branding the ``bootstrap/activate`` banner, which for technical | 
|  | reasons is not the same code as the banner printing from the Python tooling. | 
|  | These will use the same ``PW_BRANDING_BANNER`` and | 
|  | ``PW_BRANDING_BANNER_COLOR`` environment variables. | 
|  | - Supporting renaming the ``pw`` command to something project specific, like | 
|  | ``foo`` in this case. | 
|  | - Re-coloring the log headers from the ``pw`` tool. |