Writing a new tool

This section also covers the customization of an existing tool, which is very similar to writing a new one.

Tool definition file: repo_tools.toml

To write a new tool it needs to be defined in a tool definition file: repo_tools.toml.

Any repo_tools.toml can contain one or many tools.

To find a tool repo_tools.toml needs to be in python’s sys.path. Normally it is done in repo_man bootstrap script: tools/repoman/repoman.py.

Extra search paths can also be added in repo.toml of a particular repo:

[repo]
extra_tool_paths = [
	"${root}/new/tool/path",
]

Definining an entry point

Each top level entry in repo_tools.toml config can declare a tool if it contains both command and entry_point fields. To customize an existing tool (just for that repo) entry_point of a tool can be overridden in repo.toml.

Here is an example of a tool definition:

[repo_format]
# Tool name
command = "format"
# [python module name or path]:[function name]
entry_point = "omni.repo.format:setup_repo_tool"

entry_point can also be a path, e.g. entry_point = "${root}/tools/repo_format.py:setup_repo_tool".

[function name] expected signature is (parser: argparse.ArgumentParser, config: Dict) -> Callable[[options: Dict, config: Dict], None]. For example:

def setup_repo_tool(parser, config):

    parser.prog = "format"
    parser.description = "Format all C++ code (with clang-format) and all python code (with black)."
    parser.add_argument(
        "-p",
        "--python-only",
        action="store_true",
        dest="python_only",
        required=False,
        help="Only run python code formatting.",
    )    

    def run_repo_tool(options, config):
        repo_folders = config["repo"]["folders"]
        repo_format_config = config.get("repo_format", {})
        format_all(
            options.python_only,
            options.cpp_only,
            options.verify,
            repo_folders,
            py_exclude=repo_format_config.get("py_exclude", DEFAULT_PY_EXCLUDE),
            cpp_file_patterns=repo_format_config.get("cpp_file_patterns", DEFAULT_CPP_FILE_PATTERNS),
            modified_only=options.modified_only,
        )

    return run_repo_tool    

Here we setup arguments parser and return a function to be called if tools is running.

config - is a dictionary produced as a result of all configuraiton, described in “Configuration” section. options - is a dictionary of options parsed from a command line.

setup_repo_tool will be called for each tool regardless if it runs or not. This allows tools to disable themselves based on certain conditions and not appear in the list of tools.

If you are wrapping an existing tool it normally has API available in omni.repo.[tool_name] module. Python also allows any sort of monkey-patching on private methods, as nothing is truly private in Python.