Writing Your First Transform

Prior to following this tutorial, you’ll need to have a python package set up to extend HELIX (see Building a Python Package).

Writing the Transform

Similar to Components, Transforms are simply Python classes that implement the Transform interface.

Let’s start by adding a transforms directory to our Python package with an example module for our new Transform. The package directory structure should look like the following:

.
├── helix_example/
│   ├── transforms/
│   │   ├── example.py
│   │   ├── __init__.py
│   ├── __init__.py
└── setup.py

Inside of example.py we’ll create a simple Transform by subclassing Transform:

# example.py

import os
import shutil
import base64

from helix import transform


class ExampleTransform(transform.Transform):
    """A simple example transform."""

    name = "example-transform"
    verbose_name = "Example Transform"
    type = transform.Transform.TYPE_ARTIFACT
    version = "1.0.0"
    description = "A simple example transform"
    tags = (("group", "example"),)

    def transform(self, source, destination):
        """Print the contents of the binary.

        This transform doesn't actually do anything, it is just a simple
        example that prints the contents of the input file, base64 encoded.
        """

        source = os.path.abspath(source)
        destination = os.path.abspath(destination)

        with open(source, "rb") as f:
            print(base64.b64encode(f.read()))

        shutil.copy(source, destination)

This simple transform just prints the base64 encoding of the built artifact and does not modify it at all. There are a couple of things to note:

1. The transform type is TYPE_ARTIFACT - this indicates that the transform should be applied to artifacts after the Blueprint is built, as opposed to TYPE_SOURCE which is applied to source files before they are built.

2. The required transform method must always write a resulting file from source to destination, even if it does not modify the contents.

Registering the Transform

Similar to Components, Transforms must be added to the entrypoint group helix.transforms in our Python package’s setup.py. Make the following change to setup.py:

# setup.py

...
entry_points={
    ...
    "helix.transforms": [
        "example-transform = helix_example.transforms.example:ExampleTransform"
    ]
    ...
}
...

Note

Similar to Components, the name property of our new Component must match the name of the entrypoint.

To update the entrypoint list, reinstall the Python package (even if you installed it in editable mode):

pip install .

Check that our new Transform is registered with the HELIX CLI:

helix list

The output should include our new example Transform:

Available Transforms
    ...
    Example Transform (1.0.0) [example-transform]
    ...

Finally, build a cmake-cpp Blueprint with our Transform to make sure that it works:

helix build blueprint cmake-cpp ./example -t example-transform

Note

The generated binary will not do anything, but during generation you should see our Transform print the base64 encoding of the resulting artifact.

Adding Configuration Options

Adding and using configuration options to Transforms can be done in the same way as adding configuration options to Components (see Adding Configuration Options).

Adding Dependencies

Specifying Transform dependencies can be done in the same way as specifying Component dependencies (see Adding Dependencies).

Testing the Transform

Writing unit tests for Transforms can be done in the same way as writing unit tests for Components (see Testing the Component).