diff --git a/.devcontainer/postCreateCommand b/.devcontainer/postCreateCommand index df4587c..f8160b3 100644 --- a/.devcontainer/postCreateCommand +++ b/.devcontainer/postCreateCommand @@ -7,8 +7,8 @@ if [[ $USER != "root" ]] ; then # make sure the non-root user can build iocs and (mounted in) support modules - sudo chown -R ${USER}:${USER} /epics/links /venv - sudo chown -h ${USER}:${USER} /epics /epics/ioc + sudo chown -R ${USER}:${USER} /epics/ibek-defs /epics/pvi-defs /epics/support/configure /venv + sudo chown -h ${USER}:${USER} /epics /epics/ioc /epics/support # also give non-root user access to the same bash config we use in podman sudo chmod a+rx /root @@ -23,7 +23,6 @@ fi # all epics-containers devcontainers ################################################################################ - # add user's custom profile container creation script if [ -f ~/.bashprofile_dev_container ]; then . ~/.bashprofile_dev_container diff --git a/.github/workflows/build.sh b/.github/workflows/build.sh deleted file mode 100755 index 412a0e9..0000000 --- a/.github/workflows/build.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -# A generic build script for epics-containers ioc repositories -# -# Note that this is implemented in bash to make it portable between -# CI frameworks. This approach uses the minimum of GitHub Actions. -# Also works locally for testing outside of CI -# -# INPUTS: -# PUSH: if true, push the container image to the registry -# TAG: the tag to use for the container image -# PLATFORM: the platform to build for (linux/amd64 or linux/arm64) -# CACHE: the directory to use for caching - -export EC_TAG="--tag ${TAG:-latest}" -export EC_PLATFORM="--platform ${PLATFORM:-linux/amd64}" -export EC_CACHE="${CACHE:-/tmp/ec-cache}" -if [[ "${PUSH}" == 'true' ]] ; then EC_PUSH='--push' ; fi - -THIS=$(dirname ${0}) -set -xe -mkdir -p ${EC_CACHE} - -# get the current version of ec CLI -pip install -r ${THIS}/../../requirements_ec.txt - -# add cache arguments - local file cache passed by github seems to be most reliable -export EC_CARGS=" - --cache-from type=local,src=${EC_CACHE} - --cache-to type=local,dest=${EC_CACHE} -" - -# add extra cross compilation platforms below if needed e.g. -# ec dev build --arch rtems ... for RTEMS cross compile - -# build runtime and developer images -ec -v dev build ${EC_TAG} ${EC_PLATFORM} ${EC_PUSH} ${EC_CARGS} - -# extract the ioc schema from the runtime image -ec dev launch-local ${EC_TAG} --execute 'ibek ioc generate-schema' > ibek.ioc.schema.json - -# run acceptance tests -shopt -s nullglob # expand to nothing if no tests are found -for t in "${THIS}/../../tests/*.sh"; do ${t}; done - diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4d85407..fe03d58 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,57 +11,60 @@ jobs: permissions: contents: read packages: write - env: - CACHE: /tmp/.buildx-cache strategy: fail-fast: false + max-parallel: 1 # take advantage of caching matrix: + target: [developer, runtime] + architecture: [linux] include: - - architecture: linux - os: ubuntu-latest - platform: linux/amd64 + - os: ubuntu-latest + platforms: linux/amd64 runs-on: ${{ matrix.os }} + env: + TAG: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}-${{ matrix.architecture }}-${{ matrix.target }}:${{ github.ref_name }} steps: - name: Checkout uses: actions/checkout@v3 with: submodules: recursive - - name: Cache Docker layers - uses: actions/cache@v2 - with: - path: ${{ env.CACHE }} - key: ${{ runner.os }}-${{ matrix.architecture }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-${{ matrix.architecture }}-buildx- - - name: Log in to GitHub Docker Registry - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: registry: ghcr.io/${{ github.repository_owner }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Setup python - uses: actions/setup-python@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build image + uses: docker/build-push-action@v5 with: - python-version: "3.10" + context: . + platforms: ${{ matrix.platforms }} + target: ${{ matrix.target }} + build-args: TARGET_ARCHITECTURE=${{ matrix.architecture }} + tags: ${{ env.TAG }} + cache-from: type=gha + cache-to: type=gha,mode=max + load: true - - name: Docker Build Script - env: - ARCH: ${{ matrix.architecture }} - PLATFORM: ${{ matrix.platform }} - TAG: ${{ github.ref_name }} - PUSH: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags') }} - CACHE: ${{ env.CACHE }} - run: .github/workflows/build.sh + - name: Test image + run: tests/run-tests.sh - - name: Upload schema as artifact - uses: actions/upload-artifact@v3 + - name: Push image + if: ${{ github.event_name == 'push' && github.ref_type == 'tag' }} + uses: docker/build-push-action@v5 with: - name: ioc-schema - path: ibek.ioc.schema.json + context: . + platforms: ${{ matrix.platforms }} + target: ${{ matrix.target }} + build-args: TARGET_ARCHITECTURE=${{ matrix.architecture }} + tags: ${{ env.TAG }} + push: true release: # Release on tag push - publish ioc schema @@ -69,11 +72,14 @@ jobs: if: ${{ github.event_name == 'push' && github.ref_type == 'tag' }} runs-on: ubuntu-latest + # this job runs in the (linux) developer container we just made + container: + image: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}-linux-developer:${{ github.ref_name }} + steps: - - uses: actions/download-artifact@v3 - with: - name: ioc-schema - path: ./ + - name: generate-schema + run: | + ibek ioc generate-schema --output ibek.ioc.schema.json - name: Github Release uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15 diff --git a/.gitignore b/.gitignore index b21013b..a13736e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ ibek # config folder is there to be replaced there is just a dummy with Readme. ioc/config + +# podman may leave this around in aborted builds +.build.swp diff --git a/build b/build index ca9d319..7c5d905 100755 --- a/build +++ b/build @@ -4,18 +4,24 @@ # generic local build script for epics-containers ioc repositories # ################################################################################ -# pass rtems as first argument to build RTEMS on cross-compiler -TARGET_ARCHITECTURE=${1:-linux} +# set TARGET_ARCHITECTURE to rtems for RTEMS based targets +T_A=${TARGET_ARCHITECTURE:-linux} +# set TARGET to runtime for runtime images +TARGET=${TARGET:-developer} +# set TAG to override the default tag +TAG=${TAG:-ec_test} +# log commands and stop on erros set -xe cd $(dirname ${0}) +# use docker if available else use podman +if ! docker version &>/dev/null; then alias docker=podman; fi + # make sure new repos get their submodule ibek-support git submodule update --init -# build runtime and developer images -ec dev build --arch ${TARGET_ARCHITECTURE} +# build and developer images +docker build -t ${TAG} --build-arg TARGET_ARCHITECTURE=$T_A --target $TARGET . -# get the schema file from the developer container and save it locally -ec dev launch-local --execute 'ibek ioc generate-schema' > ibek.ioc.schema.json diff --git a/ibek-support b/ibek-support index 035d2d4..cb08f9a 160000 --- a/ibek-support +++ b/ibek-support @@ -1 +1 @@ -Subproject commit 035d2d47f7a2a3cbcadecb95294a973fa3fd7246 +Subproject commit cb08f9aeacd566ea13ccdfe9f0731c2a3bb7f453 diff --git a/ioc/start.sh b/ioc/start.sh index b20b72f..344edef 100755 --- a/ioc/start.sh +++ b/ioc/start.sh @@ -63,19 +63,17 @@ description=' function ibek_error { echo "${1}" - # Wait indefinitely so the container does not exit and restart continually. - while true; do - sleep 1000 - done + # Wait for a bit so the container does not exit and restart continually + sleep 10 } # environment setup ************************************************************ -set -x -e +# log commands and stop on errors +set -xe -export TOP=$(realpath $(dirname $0)) -cd ${TOP} -CONFIG_DIR=${TOP}/config +cd ${IOC} +CONFIG_DIR=${IOC}/config # add module paths to environment for use in ioc startup script if [[ -f ${SUPPORT}/configure/RELEASE.shell ]]; then @@ -99,6 +97,14 @@ epics_db=${RUNTIME_DIR}/ioc.db # in case there are multiple YAML, pick the first one in the glob ibek_src=${ibek_yamls[0]} +if [ -d ${CONFIG_DIR} ]; then + echo "checking config folder ${CONFIG_DIR}" + ls -al ${CONFIG_DIR} +else + echo "ERROR: No config folder found." + ibek_error "${description}" +fi + # 1. start.sh override script ************************************************** if [ -f ${override} ]; then exec bash ${override} @@ -132,11 +138,9 @@ elif [ -f ${ioc_startup} ] ; then msi ${includes} -I${RUNTIME_DIR} -S ${CONFIG_DIR}/ioc.subst -o ${epics_db} fi final_ioc_startup=${ioc_startup} -# 4. empty config folder *************************************************** +# 4. incorrect config folder *************************************************** else - echo "No startup assets found in ${CONFIG_DIR}" - echo - + echo "ERROR: No startup assets found in ${CONFIG_DIR}" ibek_error "${description}" fi diff --git a/requirements_ec.txt b/requirements_ec.txt deleted file mode 100644 index 6033a85..0000000 --- a/requirements_ec.txt +++ /dev/null @@ -1,3 +0,0 @@ -epics-containers-cli==2.6.11 -# to install direct from github during development in the e.g. dev branch: -#git+https://github.com/epics-containers/epics-containers-cli.git@dev diff --git a/tests/config/bl00i-ea-test-ioc.yaml b/tests/config/bl00i-ea-test-ioc.yaml new file mode 100644 index 0000000..50c768d --- /dev/null +++ b/tests/config/bl00i-ea-test-ioc.yaml @@ -0,0 +1,29 @@ +# yaml-language-server: $schema=https://github.com/epics-containers/ioc-template/releases/download/2024.1.1/ibek.ioc.schema.json + +ioc_name: "{{ ioc_yaml_file_name }}" + +description: Very generic instance for testing generic IOCs + +entities: + - type: epics.EpicsEnvSet + name: EPICS_TZ + value: "GMT0BST" + + - type: devIocStats.iocAdminSoft + IOC: "{{ ioc_name | upper }}" + + - type: epics.StartupCommand + command: dbLoadRecords("/epics/ioc/config/ioc.db") + + - type: epics.dbpf + pv: EXAMPLE:IBEK:A + value: "2.54" + + - type: epics.dbpf + pv: EXAMPLE:IBEK:B + value: "2.61" + + - type: epics.PostStartupCommand + command: | + dbgf EXAMPLE:IBEK:SUM + dbgf BL00I-EA-TEST-IOC:ST_SCRIPT1 diff --git a/tests/example-ibek-config/ioc.db b/tests/config/ioc.db similarity index 100% rename from tests/example-ibek-config/ioc.db rename to tests/config/ioc.db diff --git a/tests/example-config/calc.db b/tests/example-config/calc.db deleted file mode 100644 index ae23846..0000000 --- a/tests/example-config/calc.db +++ /dev/null @@ -1,26 +0,0 @@ -record(calc, "EXAMPLE2:SUM") { - field(DESC, "Sum A and B") - field(CALC, "A+B") - field(INPA, "EXAMPLE2:A") - field(INPB, "EXAMPLE2:B") -} - -record(ao, "EXAMPLE2:A") { - field(DESC, "A voltage") - field(PREC, "3") - field(EGU, "Volts") - field(DRVL, "-10") - field(DRVH, "+10") - field(VAL, "0.000") - field(FLNK, "EXAMPLE2:SUM") -} - -record(ao, "EXAMPLE2:B") { - field(DESC, "B voltage") - field(PREC, "3") - field(EGU, "Volts") - field(DRVL, "-10") - field(DRVH, "+10") - field(VAL, "0.000") - field(FLNK, "EXAMPLE2:SUM") -} \ No newline at end of file diff --git a/tests/example-config/ioc.substitutions b/tests/example-config/ioc.substitutions deleted file mode 100644 index 4fa1884..0000000 --- a/tests/example-config/ioc.substitutions +++ /dev/null @@ -1,16 +0,0 @@ - -# Macros: -# IOC Device prefix -file $(IOCSTATS)/db/iocAdminSoft.db -{ -pattern { IOC } - { "test-ioc" } -} - -# Macros: -# IOC Device prefix -file $(IOCSTATS)/db/iocAdminScanMon.db -{ -pattern { IOC } - { "test-ioc" } -} \ No newline at end of file diff --git a/tests/example-config/st.cmd b/tests/example-config/st.cmd deleted file mode 100644 index 61720df..0000000 --- a/tests/example-config/st.cmd +++ /dev/null @@ -1,12 +0,0 @@ -# Example hand coded IOC startup script for example-config -cd "/epics/ioc" - -epicsEnvSet "EPICS_CA_MAX_ARRAY_BYTES", '6000000' - -dbLoadDatabase "dbd/ioc.dbd" -ioc_registerRecordDeviceDriver(pdbbase) - -dbLoadRecords("config/calc.db") -dbLoadRecords("/tmp/ioc.db") - -iocInit() diff --git a/tests/example-ibek-config/ioc.yaml b/tests/example-ibek-config/ioc.yaml deleted file mode 100644 index 5740795..0000000 --- a/tests/example-ibek-config/ioc.yaml +++ /dev/null @@ -1,9 +0,0 @@ -ioc_name: test-ibek-ioc -description: a basic example for testing ioc-template - -entities: - - type: devIocStats.iocAdminSoft - IOC: test-ibek-ioc - - - type: epics.StartupCommand - command: dbLoadRecords("/epics/ioc/config/ioc.db") diff --git a/tests/run-tests.sh b/tests/run-tests.sh index f56fde5..76ca99c 100755 --- a/tests/run-tests.sh +++ b/tests/run-tests.sh @@ -5,36 +5,35 @@ # all present and correct and that mounting IOC config or ibek config # works as expected. -THIS_DIR=$(realpath $(dirname $0)) -ROOT=$(realpath ${THIS_DIR}/..) +THIS=$(realpath $(dirname $0)) +ROOT=$(realpath ${THIS}/..) +CONF=/epics/ioc/config +# log commands and stop on errorsr set -ex +# use docker if available else use podman +if ! docker version &>/dev/null; then alias docker=podman; fi + cd ${ROOT} -# Build the container (inherit arguments from CI workflow if set) ############## -ec dev build ${EC_TAG} - -# try out an ibek config IOC instance with the generic IOC ##################### -ec dev launch-local tests/example-config --args '-dit' ${EC_TAG} -ec dev wait-pv EXAMPLE2:A --attempts 20 -ec dev exec 'caput EXAMPLE2:A 1.3' -ec dev exec 'caput EXAMPLE2:B 1.2' -ec dev exec 'caget EXAMPLE2:SUM' | grep '2.5' - -# Test an ibek IOC ############################################################# -ec dev launch-local tests/example-ibek-config --args '-dit' ${EC_TAG} -ec dev wait-pv EXAMPLE:IBEK:A --attempts 20 -ec dev exec 'caput EXAMPLE:IBEK:A 1.3' -ec dev exec 'caput EXAMPLE:IBEK:B 1.2' -ec dev exec 'caget EXAMPLE:IBEK:SUM' | grep '2.5' -ec dev exec 'caget test-ibek-ioc:EPICS_VERS' | grep 'R7.0.7' - -# Stop the test IOC ############################################################ -ec dev stop - -# Done ######################################################################### -echo -echo "All tests passed!" + +# if a tag was passed in this implies it was already built +export TAG=${TAG:-ec_test} +if [[ ${TAG} == "ec_test" ]] ; then TARGET=runtime ./build; fi + +# try out a test ibek config IOC instance with the generic IOC +result=$(docker run --rm -v ${THIS}/config:${CONF} ${TAG} /epics/ioc/start.sh 2>&1) + +# check that the IOC output expected results +if echo "${result}" | grep -i error; then + echo "ERROR: errors in IOC startup" + exit 1 +elif [[ ! ${result} =~ "5.15" || ! ${result} =~ "/epics/runtime/st.cmd" ]]; then + echo "ERROR: dbgf output not as expected" + exit 1 +fi + +echo "Tests passed!" diff --git a/user_examples/.bashprofile_dev_container b/user_examples/.bashprofile_dev_container new file mode 100644 index 0000000..e5af527 --- /dev/null +++ b/user_examples/.bashprofile_dev_container @@ -0,0 +1,15 @@ +#!/bin/bash + +################################################################################ +# Custom profile for epics-containers devcontainer # +# # +# This will run inside the devcontainer after creation # +################################################################################ + +# apt-get update +# apt-get -y --no-install-recommends install vimdiff +# apt-get install what you like + +# add command line completion to the ibek tool +ibek --install-completion bash + diff --git a/user_examples/.bashrc_dev_container b/user_examples/.bashrc_dev_container new file mode 100644 index 0000000..0ca306a --- /dev/null +++ b/user_examples/.bashrc_dev_container @@ -0,0 +1,28 @@ +#!/bin/bash + +################################################################################ +###### This is sourced by all terminals epics-containers IOC devcontainer ###### +###### personal .bashrc_dev for setting up environment in devcontainers ###### +################################################################################ + +export LS_OPTIONS='--color=auto' +eval "$(dircolors)" 2> /dev/null +alias ls='ls $LS_OPTIONS' +alias ll='ls $LS_OPTIONS -l' +alias l='ls $LS_OPTIONS -lA' + +# Save all history forever +# Add these to your user's .bashrc to keep a single history inside and out of containers +export HISTCONTROL=ignoreboth:erasedups # Remove adjacent duplicate entries +export HISTSIZE= # Unlimited history +export HISTFILESIZE= # Unlimited history +# Use a unique bash history file so it doesn't get manually trucated by applications +export HISTFILE=${HOME}/.bash_eternal_history +shopt -s histappend # Append to history, don't overwrite it +export PROMPT_COMMAND='history -a' + +# add git completion +if [[ ! -f /tmp/git-completion.bash ]]; then + wget -q -P /tmp https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash +fi +source /tmp/git-completion.bash diff --git a/user_examples/README.md b/user_examples/README.md new file mode 100644 index 0000000..94bc520 --- /dev/null +++ b/user_examples/README.md @@ -0,0 +1,13 @@ +User Customization Examples +=========================== + +Users can customize their epics-containers developer containers by copying +the files in this folder into their home directory and customizing them as +required. + +epics-containers .devcontainer configuration will automatically pick up +these files from the home directory. + +- .bashrc_dev_container: runs on start of every new shell in the container. +- /bashprofile_dev_container: runs once immediately after the creation + of a devcontainer. \ No newline at end of file