# 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`:

```bash
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`:

```bash
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
<?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

```bash
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
# 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
    name: ENV.RGA
```

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](../reference/dlsplc-migration.md)
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 be 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 [](#schema-update)

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

```yaml
# 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:

```bash
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 with devcontainer and db-compare](verify-with-devcontainer.md) for the
full workflow.  In brief:

```bash
# 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
```

(schema-update)=
## 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:
```bash
./update-schema
```

In a generic IOC devcontainer:
```bash
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.
