Convert a builder XML IOC instance to ibek YAML#

builder2ibek xml2yaml converts a DLS XMLbuilder IOC definition file (.xml) into an ibek ioc.yaml that can be consumed by ibek at runtime to generate st.cmd and database files.

Prerequisites#

In order to test the converted IOC you should be working inside a devcontainer.

There are two options:

builder2ibek devcontainer — the devcontainer shipped with this repository. It has the full ibek-support and ibek-support-dls submodule trees checked out, so every supported module’s YAML is available. Run builder2ibek with uv run:

uv run builder2ibek xml2yaml ...

Generic IOC devcontainer — the devcontainer for a specific Generic IOC (e.g. ioc-bl11i-rga). Only the ibek support YAML that was built into that container image is available, so schema validation can only validate entities that the target IOC already supports. Here builder2ibek is not installed in the repo but can be run directly with uvx:

uvx builder2ibek xml2yaml ...

In both cases the ibek support YAML for every module referenced in the XML must be present — either in the builder2ibek submodules or in the Generic IOC’s installed support tree.


1. Locate the builder XML#

DLS XMLbuilder IOC definitions are in the builder support module e.g.

/dls_sw/work/R3.14.12.7/support/BL11I-BUILDER/etc/makeIocs/BL11I-CS-IOC-09.xml

Example — BL11I-CS-IOC-09.xml:

<?xml version="1.0" ?>
<components arch="linux-x86_64">
    <devIocStats.devIocStatsHelper ioc="BL11I-CS-IOC-09" name="CSIOC2"/>
    <autosave.Autosave bl="True" iocName="BL11I-CS-IOC-09"
        name="BL11I-CS-IOC-09.AS" path="/dls_sw/i11/epics/autosave" skip_1="True"/>
    <pvlogging.PvLogging/>
    <asyn.AsynIP name="rgaPort" port="10.111.5.1:5025"/>
    <hidenRGA.hidenRGA_qga BUFFER_SIZE="100" P="BL11I-EA-RGA-01"
        PORT="rgaPort" Q="" name="ENV.RGA"/>
</components>

Each XML element maps to an ibek entity type: <module.Class attribute="value"/>.


2. Run xml2yaml#

uv run builder2ibek xml2yaml BL11I-CS-IOC-09.xml --yaml bl11i-cs-ioc-09.yaml

For the example above this produces bl11i-cs-ioc-09.yaml:

# yaml-language-server: $schema=/epics/ibek-defs/ioc.schema.json

ioc_name: "{{  _global.get_env('IOC_NAME') }}"

description: auto-generated by https://github.com/epics-containers/builder2ibek

entities:

  - type: epics.EpicsEnvSet
    name: EPICS_TS_MIN_WEST
    value: '0'

  - type: epics.EpicsEnvSet
    name: STREAM_PROTOCOL_PATH
    value: /epics/runtime/protocol/

  - type: devIocStats.iocAdminSoft
    IOC: '{{ ioc_name | upper }}'

  - type: autosave.Autosave
    P: 'BL11I-CS-IOC-09:'
    debug: false

  - type: pvlogging.PvLogging
    access_file: /epics/support/pvlogging/src/access.acf

  - type: asyn.AsynIP
    name: rgaPort
    port: 10.111.5.1:5025

  - type: hidenRGA.hidenRGA_qga
    BUFFER_SIZE: 100
    P: BL11I-EA-RGA-01
    PORT: rgaPort

Notice that asyn.AsynIP and hidenRGA.hidenRGA_qga remain as separate entities in the output, reflecting the original XML structure. The ibek entity models for both must be present in the ibek-support* submodules used by the Generic IOC.


3. Review and adjust#

Note

If your IOC uses the older vacuumValve, interlock, or temperature modules, xml2yaml will automatically translate many entities to their dlsPLC equivalents. Some cases (e.g. vacuumValveRead2, pump templates) require manual fixup. See the dlsPLC migration reference for the complete mapping table and argument transformation rules.

Auto-conversion is a best-effort translation; review the output for:

  • Commented-out elements: builder XML comments (<!-- ... -->) are skipped. If the original had alternative configurations in comments, choose the right one now.

  • Default values: some converters inject sensible defaults (e.g. autosave debug: false). Verify these are appropriate.

  • Module coverage: if a module has no converter, its entities will just have identical parameters to the XML attributes in the original. For some entities this will be perfectly OK as we try to make the xxx.ibek.support.yaml as compatible with the original XML as possible.

  • Schema validation: open the YAML in VSCode with the Red Hat YAML extension; the $schema line at the top will highlight any type mismatches.

Important

You will need to update the schema when you have made changes — see 6. Updating the schema.

For schema validation to work your ioc.yaml should have the following header:

# yaml-language-server: $schema=/epics/ibek-defs/ioc.schema.json

4. Add to the test suite#

If your IOC is using support modules that are not currently covered in the builder2ibek tests then it could be worth updating the tests as follows.

To prevent regressions, copy the XML into tests/samples/ and regenerate:

cp BL11I-CS-IOC-09.xml tests/samples/
cd tests/samples && ./make_samples.sh

make_samples.sh converts all XML files in the folder and updates the corresponding .yaml files. Review the diff, then commit both.


5. Verify with db-compare#

Once you have converted an IOC, the definitive verification is to generate the EPICS database inside the devcontainer and compare it record-by-record against the original builder _expanded.db. See Verify a converted IOC using db-compare for the full workflow. In brief:

# inside the devcontainer
ibek dev instance /workspaces/my-project/iocs/my-ioc
ibek runtime generate2 /epics/ioc/config
uv run builder2ibek db-compare \
    /dls_sw/.../MY-IOC_expanded.db \
    /epics/runtime/ioc.db

6. Updating the schema#

If you have added new entity models to ibek-support* or changed existing models, regenerate the global schema that VSCode uses for validation.

In the builder2ibek devcontainer:

./update-schema # first time only - after that use ibek to update schema as below

In a generic IOC devcontainer:

ibek ioc generate-schema > /epics/ibek-defs/ioc.schema.json

Both commands update the ioc instance schema in /epics/ibek-defs/ioc.schema.json#

Relationship between XML elements and ibek entity types#

XML element prefix

ibek entity type prefix

notes

devIocStats.devIocStatsHelper

devIocStats.iocAdminSoft

renamed by converter

autosave.Autosave

autosave.Autosave

converter adjusts path handling

pvlogging.PvLogging

pvlogging.PvLogging

direct mapping

asyn.AsynIP

asyn.AsynIP

direct mapping

hidenRGA.hidenRGA_qga

hidenRGA.hidenRGA_qga

direct mapping

EPICS_BASE.EpicsEnvSet

epics.EpicsEnvSet

renamed by converter

The converter modules in src/builder2ibek/converters/ handle the non-trivial mappings. Each file corresponds to one support module. See src/builder2ibek/converters/ for the full list.